diff --git a/.builds/debian-stable.yml b/.builds/debian-stable.yml new file mode 100644 index 0000000000..77872e5184 --- /dev/null +++ b/.builds/debian-stable.yml @@ -0,0 +1,59 @@ +image: debian/stable +sources: +- https://git.sr.ht/~singpolyma/cheogram-android +artifacts: +- cheogram.apk +- cheogram_google_play.apk +- cheogram_google_play.aab +packages: +- wget +- unzip +- openjdk-17-jdk-headless +- android-sdk +secrets: +- 6b782fde-a43b-4988-b102-38fa541bb788 +- 7eed327c-05c7-49b4-baed-a4d8785588d5 +- b1f1df57-d41c-45d9-9684-b66d3fa8d063 +- b412b263-bdde-410b-997e-6326aba90132 +environment: + ANDROID_SDK_ROOT: /home/build/android + SENTRY_ORG: mboa + SENTRY_PROJECT: android +tasks: +- sdk: | + wget -qO android.zip https://dl.google.com/android/repository/commandlinetools-linux-6987402_latest.zip + unzip -qq android.zip + mkdir -p android/cmdline-tools + mv cmdline-tools android/cmdline-tools/tools + echo y | android/cmdline-tools/tools/bin/sdkmanager "platforms;android-29" + echo y | android/cmdline-tools/tools/bin/sdkmanager "platform-tools" + echo y | android/cmdline-tools/tools/bin/sdkmanager "build-tools;29.0.2" + touch ~/.android/repositories.cfg + yes | android/cmdline-tools/tools/bin/sdkmanager --licenses +- sentry: | + cd cheogram-android + sed -ie 's///' src/cheogram/AndroidManifest.xml + sed -ie 's/\/\/ PLUGIN INSERT/id "io.sentry.android.gradle" version "4.2.0"/' build.gradle + sed -ie 's/\/\/ ROOT INSERT/sentry { includeSourceContext = true }/' build.gradle +- build_free: | + set +x + export SENTRY_AUTH_TOKEN=$(cat ~/sentry_auth_token) + set -x + cd cheogram-android + ./gradlew assembleCheogramFreeDebug +- build_google_play: | + set +x + export SENTRY_AUTH_TOKEN=$(cat ~/sentry_auth_token) + set -x + cd cheogram-android + mkdir -p src/playstore/res/values/ + mv ~/push.xml src/playstore/res/values/ + ./gradlew assembleCheogramPlaystoreDebug + echo keystore=$HOME/.android/cheogram.keystore > signing.properties + echo keystore.password=cheogram >> signing.properties + echo keystore.alias=cheogram >> signing.properties + ./gradlew bundleCheogramPlaystoreRelease +- assets: | + mv cheogram-android/build/outputs/apk/cheogramFree/debug/*universal*.apk cheogram.apk + mv cheogram-android/build/outputs/apk/cheogramPlaystore/debug/*universal*.apk cheogram_google_play.apk + mv cheogram-android/build/outputs/bundle/cheogramPlaystoreRelease/*.aab cheogram_google_play.aab diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index d0c9ffa55b..0000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,77 +0,0 @@ -version: 2 -jobs: - test: - docker: - - image: registry.gitlab.com/fdroid/ci-images-client:latest - steps: - - checkout - - restore_cache: - key: gradle-{{ checksum "build.gradle" }}-{{ checksum ".circleci/config.yml" }} - - run: export GRADLE_USER_HOME=$PWD/.gradle - - run: wget -O libs/libwebrtc-m85.aar https://www.pix-art.de/files/libwebrtc-m85.aar - - run: echo y | sdkmanager "platforms;android-$(sed -n 's,.*compileSdkVersion\s*\([0-9][0-9]*\).*,\1,p' build.gradle)" > /dev/null - - run: ./gradlew lintGitDebug - - save_cache: - paths: - - .gradle/caches - - .gradle/wrapper - key: gradle-{{ checksum "build.gradle" }}-{{ checksum ".circleci/config.yml" }} - - store_artifacts: - path: build/outputs/apk/standard - destination: apk - build: - docker: - - image: registry.gitlab.com/fdroid/ci-images-client:latest - steps: - - checkout - - restore_cache: - key: android - - run: export GRADLE_USER_HOME=$PWD/.gradle - - run: wget -O libs/libwebrtc-m85.aar https://www.pix-art.de/files/libwebrtc-m85.aar - - run: echo y | sdkmanager "platforms;android-$(sed -n 's,.*compileSdkVersion\s*\([0-9][0-9]*\).*,\1,p' build.gradle)" > /dev/null - # build - - run: ./gradlew assembleGit - - save_cache: - paths: - - ~/.android - key: android - - store_artifacts: - path: build/outputs/apk/git - - publish: - docker: - - image: registry.gitlab.com/fdroid/ci-images-client:latest - steps: - - checkout - - restore_cache: - key: android - - run: export GRADLE_USER_HOME=$PWD/.gradle - - run: wget -O libs/libwebrtc-m85.aar https://www.pix-art.de/files/libwebrtc-m85.aar - - run: echo y | sdkmanager "platforms;android-$(sed -n 's,.*compileSdkVersion\s*\([0-9][0-9]*\).*,\1,p' build.gradle)" > /dev/null - # workaround for fdroid nightly circleci bug - - run: sed -i "s/os.getenv('CIRCLE_REPOSITORY_URL')/\"https:\/\/github.com\/kriztan\/Pix-Art-Messenger\"/" /usr/lib/python3/dist-packages/fdroidserver/nightly.py - # generate version number - - run: sed -i "s/^\(\s*versionCode\s*\).*$/\1$(git rev-list --first-parent --count HEAD)/" build.gradle - - run: sed -i "0,/versionName/s/^\(\s*versionName\).*/\1 \"$(printf '%s-%05d' $(git describe --tag --abbrev=0) $(git rev-list --first-parent --count HEAD))\"/" build.gradle - - run: cat -n build.gradle - # build - - run: ./gradlew assembleGit - # publish on nightly fdroid repo - - run: fdroid nightly - - save_cache: - paths: - - ~/.android - key: android - -workflows: - version: 2 - test_build: - jobs: - - build: - filters: - branches: - ignore: master - - publish: - filters: - branches: - only: master diff --git a/.project b/.project deleted file mode 100644 index ccd5dd982f..0000000000 --- a/.project +++ /dev/null @@ -1,34 +0,0 @@ - - - monocles chat - Project monocles_chat created by Buildship. - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.buildship.core.gradleprojectbuilder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.buildship.core.gradleprojectnature - - - - 1632834367800 - - 30 - - org.eclipse.core.resources.regexFilterMatcher - node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ - - - - diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000000..affaf71106 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,7 @@ +steps: + build: + image: codeberg.org/freeyourgadget/android-fdroid-tools:latest + commands: + - ./gradlew clean + - ./gradlew assembleConversationsFreeDebug + - ./gradlew assembleQuicksyFreeDebug diff --git a/CHANGELOG.md b/CHANGELOG.md index 4137e3b6ff..fedfe63c24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,1203 @@ -### Changelog +# Changelog -#### Version 1.1 -* presettings correction to avoid connection problems -* some text corrections -* added optional monocles registration link -* changed appicon -* changed registration and usage for monocles users only +### Version 2.15.3 -#### Version 1.0 -* initial release +* fix call integration on some Android 14 devices +* Introduce 'Invites from Strangers' setting + +### Version 2.15.2 + +* Fix Quicksy registration on Android 6/7 +* Play incoming call ringtone on notification channel + +### Version 2.15.1 + +* Show message status as icons +* Introduce 'Large font' setting for message bubbles + +### Version 2.15.0 + +* Use Material 3 theme +* Reorganize settings +* Synchronize read state across devices + +### Version 2.14.2 + +* Restore access to Channel Discovery for Android 6+7 +* Improve logging for failed call integration + +### Version 2.14.1 + +* Fix A/V calls on Android 8 +* Fix race conditions in new call integration +* Fix video compression sticking around + +### Version 2.14.0 + +* Improve integration of A/V calls into the operating system + +### Version 2.13.4 + +* Fix minor regressions introduced with 2.13.1 + +### Version 2.13.3 + +* Provide easier access to 'Privacy Policy' on Play Store version (Quicksy and Conversations) +* Remove address book integration on Play Store version of Conversations + +### Version 2.13.2 + +* minor bug fixes +* slight modifications in Quicksy onboard flow + +### Version 2.13.1 + +* Support P2P file transfer via WebRTC data channels +* Fix interoperability issues with Bind 2.0 on ejabberd +* Bundle Let’s Encrypt root certificates for Android <= 7 + +### Version 2.13.0 + +* Easier access to 'Show QR code' +* Support PEP Native Bookmarks +* Add support for SDP Offer / Answer Model (Used by SIP gateways) +* Raise target API to Android 14 + +### Version 2.12.12 + +* Support Private DNS (DNS over TLS) +* Support themed launcher icon +* Fix rare permission issue when sharing files on Android 11+ + +### Version 2.12.11 + +* Bump libwebrtc dependency to M117 and bump libvpx +* Go back to AAC for voice messages +* Support per app language settings + +### Version 2.12.10 + +* support per conversation notification settings +* use opus for voice messages on Android 10 + +### Version 2.12.9 + +* Introduce new backup file format + +### Version 2.12.8 + +* Disable opening backup files (.ceb) from file manager + +### Version 2.12.7 + +* Remove channel discovery feature from Google Play version + +### Version 2.12.6 + +* Fix 'q' falsely being recognized as cyrillic + +### Version 2.12.5 + +* Bump Target SDK to 33 again +* Fix issues on servers supporting SASL2 w/o inline Stream Management + +### Version 2.12.4 + +* Revert Target SDK bump (back to 32) to fix various issues on Android 13 + +### Version 2.12.3 + +* Improve support for new emojis +* Add ability to remove account from server +* Show timestamp for calls + +### Version 2.12.2 + +* Increase corner radius on profile pictures + +### Version 2.12.1 + +* Fix crash in UnifiedPush Distributor + +### Version 2.12.0 + +* Integrate UnifiedPush Distributor to facilitate push messages to other UnifiedPush enabled apps like Tusky and Fedilab + +### Version 2.11.3 + +* Fix messages getting resend when using SASL2 +* Fix black video between some devices +* Fix crash on empty passwords + +### Version 2.11.2 + +* Fixed regression in P2P file transfer + +### Version 2.11.1 + +* Fix resend loop on servers that support only sm:2 +* Show 'Switch to video' only if other party supports video + +### Version 2.11.0 + +* Implement Extensible SASL Profile, Bind 2.0 and Fast for faster reconnects +* Implement Channel Binding +* Add ability to switch from audio call to video call +* Add ability to delete own avatar +* Add notification for missed calls + +### Version 2.10.10 + +* Minor bug fixes +* Restore ability to call out via JMP and other services (Playstore version) + +### Version 2.10.9 + +* Ask for Bluetooth permissions when making A/V calls (You can reject this if you don’t use Bluetooth headsets) +* Fix bug when calling Movim + +### Version 2.10.8 + +* Fix wrong avatar being shown for group chats + +### Version 2.10.7 + +* always ask for battery optimizations opt-out +* set local only flag on 'x connected accounts' notifications +* Minor bug fixes + +### Version 2.10.6 + +* Minor bug fixes + +### Version 2.10.5 + +* Security: Stop downloading files that exceed advertised file size +* Security: Limit POSH files to 10K + +### Version 2.10.4 + +* Fix interaction with Google Maps Share Location Plugin +* Remove footnote with regards to server fee + +### Version 2.10.3 + +* Store files in location appropriate for Android 11 +* Attempt to reconnect call after network switch +* Show caller JID and account JID in incoming call screen + +### Version 2.10.2 + +* Fix crash when rendering some quotes +* Fix crash in welcome screen + +### Version 2.10.1 + +* Fix issue with some videos not being compressed +* Fix rare crash when opening notification + +### Version 2.10.0 + +* Show black bars when remote video does not match aspect ratio of screen +* Improve search performance +* Add setting to prevent screenshots + +### Version 2.9.13 + +* minor A/V improvements + +### Version 2.9.12 + +* Always verify domain name. No user overwrite +* Support roster pre authentication + +### Version 2.9.11 + +* Fixed 'No Connectivity' issues on Android 7.1 + +### Version 2.9.10 +* fix HTTP up/download for users that don’t trust system CAs + +### Version 2.9.9 + +* Various bug fixes around Tor support +* Improve call compatibility with Dino + +### Version 2.9.8 + +* Verify A/V calls with preexisting OMEMO sessions +* Improve compatibility with non libwebrtc WebRTC implementations + +### Version 2.9.7 + +* Ability to select incoming call ringtone +* Fix OpenPGP key id discovery for OpenKeychain 5.6+ +* Properly verify punycode TLS certificates +* Improve stability of RTP session establishment (calling) + +### Version 2.9.6 + +* Show call button for offline contacts if they previously announced support +* Back button no longer ends call when call is connected +* bug fixes + +### Version 2.9.5 + +* Quicksy: Automatically receive verification SMS + +### Version 2.9.4 +* minor stability improvements for A/V calls +* Conversations releases from here on forward require Android 5 + +### Version 2.9.3 + +* Fixed connectivity issues when different accounts used different SCRAM mechanisms +* Add support for SCRAM-SHA-512 +* Allow P2P (Jingle) file transfer with self contact + +### Version 2.9.2 + +* Offer Easy Invite generation on supporting servers +* Display GIFs send from Movim +* store avatars in cache + +### Version 2.9.1 + +* fixed search on Android <= 5 +* optimize memory consumption + +### Version 2.9.0 + +* Search individual conversations +* Notify user if message delivery fails +* Remember display names (nicks) from Quicksy users across restarts +* Add button to start Orbot (Tor) from notification if necessary + +### Version 2.8.10 + +* Handle GPX files +* Improve performance for backup restore +* bug fixes + +### Version 2.8.9 + +* add 'Return to chat' to audio call screen +* Improve keyboard shortcuts +* bug fixes + +### Version 2.8.8 + +* Fixed notifications not showing up under certain conditions +* Fixed compatibility issues and crashes related to A/V calls + +### Version 2.8.7 + +* Show help button if A/V call fails +* Fixed some annoying crashes +* Fixed Jingle connections (file transfer + calls) with bare JIDs + +### Version 2.8.6 + +* Offer to record voice message when callee is busy + +### Version 2.8.5 + +* Reduce echo during calls on some devices +* Fix login when passwords contains special characters +* Play dial and busy tones on speaker during video calls + +### Version 2.8.4 + +* Rework Login with certificate UI +* Add ability to pin chats on top (add to favorites) + +### Version 2.8.3 + +* Move call icon to the left in order to keep other toolbar icons in a consistent place +* Show call duration during audio calls +* Tie breaking for A/V calls (the same two people calling each other at the same time) + +### Version 2.8.2 + +* Add button to switch camera during video call +* Fixed voice calls on tablets + +### Version 2.8.1 + +* Audible feedback (dialing, call started, call ended) for voice calls. +* Fixed issue with retrying failed video call + +### Version 2.8.0 + +* Audio/Video calls (Requires server support in form of STUN and TURN servers discoverable via XEP-0215) + + +### Version 2.7.1 + +* Fix avatar selection on some Android 10 devices +* Fix file transfer for larger files + +### Version 2.7.0 + +* Provide PDF preview on Android 5+ +* Use 12 byte IVs for OMEMO + +### Version 2.6.4 + +* Support automatic theme switching on Android 10 + +### Version 2.6.3 + +* Support for ?register and ?register;preauth XMPP uri parameters + +### Version 2.6.2 +* let users set their own nick name +* resume download of OMEMO encrypted files +* Channels now use '#' as symbol in avatar +* Quicksy uses 'always' as OMEMO encryption default (hides lock icon) + +### Version 2.6.1 +* fixes for Jingle IBB file transfer +* fixes for repeated corrections filling up the database +* switched to Last Message Correction v1.1 + +### Version 2.6.0 +* Introduce expert setting to perform channel discovery on local server instead of [search.jabber.network](https://search.jabber.network) +* Enable delivery check marks by default and remove setting +* Enable ‘Send button indicates status’ by default and remove setting +* Move Backup and Foreground Service settings to main screen + +### Version 2.5.12 +* Jingle file transfer fixes +* Fixed OMEMO self healing (after backup restore) on servers w/o MAM + +### Version 2.5.11 +* Fixed crash on Android <5.0 + +### Version 2.5.10 +* Fixed crash on Xiaomi devices running Android 8.0 + 8.1 + +### Version 2.5.9 +* fixed minor security issues +* Share XMPP uri from channel search by long pressing a result + +### Version 2.5.8 +* fixed connection issues over Tor +* P2P file transfer (Jingle) now offers direct candidates +* Support XEP-0396: Jingle Encrypted Transports - OMEMO + +### Version 2.5.7 +* fixed crash when scanning QR codes on Android 6 and lower +* when sharing a message from and to Conversations insert it as quote + +### Version 2.5.6 +* fixes for Jingle file transfer +* fixed some rare crashes + +### Version 2.5.5 +* allow backups to be restored from anywhere +* bug fixes + +### Version 2.5.4 +* stability improvements for group chats and channels + +### Version 2.5.3 +* bug fixes for peer to peer file transfer (Jingle) +* fixed server info for unlimited/unknown max file size + +### Version 2.5.2 +* bug fixes + +### Version 2.5.1 +* minor bug fixes +* Set own OMEMO devices to inactive after not seeing them for 14 days. (was 7 days) + +### Version 2.5.0 +* Added channel search via search.jabbercat.org +* Reworked onboarding screens +* Warn when trying to enter domain address or channel address in Add Contact dialog + +### Version 2.4.3 +* Fixed display of private messages sent from another client +* Fixed backup creation on long time installations + +### Version 2.4.2 +* Fix image preview on older Android version + +### Version 2.4.1 +* Fixed crash in message view + +### Version 2.4.0 +* New Backup / Restore feature +* Clearly distinguish between (private) group chats and (public) channels +* Redesigned participants view for group chats and channels +* Redesigned create new contact/group chat/channel flow in Start Conversation screen + + +### Version 2.3.12 +* Fixed rare crash on start up +* Fixed avatar not being refreshed in group chats + +### Version 2.3.11 +* Support for Android 9 'message style' notifications +* OMEMO stability improvements +* Added ability to destroy group chats +* Do not show deleted files in media browser +* Added 'Keep Original' as video quality choice + +### Version 2.3.10 +* lower minimum required Android version to 4.1 +* Synchronize group chat join/leaves across multiple clients +* Fixed sending PGP encrypted messages from quick reply + +### Version 2.3.9 +* OMEMO stability improvements +* Context menu when long pressing avatar in 1:1 chat + +### Version 2.3.8 +* make PEP avatars public to play nice with Prosody 0.11 +* Fixed re-sending failed files in group chats + +### Version 2.3.7 +* long press on 'allow' or 'add back' snackbar to bring up 'reject' +* bug fixes for Android 9 + +### Version 2.3.6 +* Improved handling of bookmark nicks +* Show send PM menu entry in anonymous MUCs + +### Version 2.3.5 +* Fixed group chat mentions when nick ends in . (dot) +* Fixed Conversations not asking for permissions after direct share +* Fixed CVE-2018-18467 + +### Version 2.3.4 +* Fixed sending OMEMO files to ChatSecure + +### Version 2.3.3 +* Fixed connection issues with user@ip type JIDs + +### Version 2.3.2 +* Fixed OMEMO on Android 5.1 & 6.0 +* Added setting for video quality +* bug fixes + +### Version 2.3.1 +* Stronger compression for video files +* Use SNI on STARTTLS to fix gtalk +* Fix Quiet Hours on Android 8+ +* Use Consistent Color Generation (XEP-0392) + +### Version 2.3.0 +* Preview and ask for confirmation before sending media files +* View per conversation media files in contact and conference details screens +* Enable foreground service by default for Android 8 (notification can be disabled by long pressing it) +* Audio player: disable screen and switch to ear piece +* Support TLSv1.3 (ejabberd ≤ 18.06 is incompatible with openssl 1.1.1 - Update ejabberd or downgrade openssl if you get ›Stream opening error‹) + + +### Version 2.2.9 +* Store bookmarks in PEP if server has ability to convert to old bookmarks +* Show Jabber IDs from address book in Start Conversation screen + +### Version 2.2.8 +* fixed regression that broke XMPP uris + +### Version 2.2.7 +* stability improvements + +### Version 2.2.6 +* support old MAM version to work with Prosody + +### Version 2.2.5 +* Persist MUC avatar across restarts / show in bookmarks +* Offer Paste as quote for HTML content + +### Version 2.2.4 +* Use group chat name as primary identifier +* Show group name and subject in group chat details +* Upload group chat avatar on compatible servers + +### Version 2.2.3 +* Introduce Expert Setting to enable direct search +* Introduce Paste As Quote on Android 6+ +* Fixed issues with HTTP Upload + +### Version 2.2.2 +* Fixed connection problems with TLS1.3 servers +* Attempt to delete broken bundles from PEP +* Use FCM instead of GCM + +### Version 2.2.1 +* improved recording quality +* load map tiles over Tor if enabled + +### Version 2.2.0 +* Integrate Voice Recorder +* Integrate Share Location +* Added ability to search messages + +### Version 2.1.4 +* bug fixes + +### Version 2.1.3 +* Do not process stanzas with invalid JIDs + +### Version 2.1.2 +* Fixed avatars not being displayed on new installs + +### Version 2.1.1 +* Improved start up performance +* bug fixes + +### Version 2.1.0 +* Added configurable font size +* Added global OMEMO preference +* Added scroll to bottom button +* Only mark visible messages as read + + +### Version 2.0.0 +* OMEMO by default for everything but public group chats +* Integrate QR code scanner (requires camera permission) +* Removed support for OTR +* Removed support for customizable resources +* Removed slide out panel for conversation overview +* Add ability to change status message +* Highlight irregular unicode code blocks in Jabber IDs +* Conversations now requires Android 4.4+ + +### Version 1.23.8 +* bug fixes + +### Version 1.23.7 +* Improved MAM support + bug fixes + +### Version 1.23.6 +* Fixed crash on receiving invalid HTTP slot response + +### Version 1.23.5 +* improved self chat + +### Version 1.23.4 +* keep screen on while playing audio +* send delivery receipts after MAM catch-up +* reduce number of wake locks + +### Version 1.23.3 +* Fixed OMEMO device list not being announced + +### Version 1.23.2 +* Removed NFC support +* upload Avatars as JPEG +* reduce APK size + +### Version 1.23.1 +* Show icon instead of image preview in conversation overview +* fixed loop when trying to decrypt with YubiKey + +### Version 1.23.0 +* Support for read markers in private, non-anonymous group chats + +### Version 1.22.1 +* Disable swipe to left to end conversation +* Fixed 'No permission to access …' when opening files shared from the SD card +* Always open URLs in new tab + +### Version 1.22.0 +* Text markup *bold*, _italic_,`monospace` and ~strikethrough~ +* Use same emoji style on all Android versions +* Display emojis slightly larger within continuous text + +### Version 1.21.0 +* Inline player for audio messages +* Stronger compression for long videos +* Long press the 'add back' button to show block menu + +### Version 1.20.1 +* fixed OTR encrypted file transfer + +### Version 1.20.0 +* presence subscription no longer required for OMEMO on compatible servers +* display emoji-only messages slightly larger + +### Version 1.19.5 +* fixed connection loop on Android <4.4 + +### Version 1.19.4 +* work around for OpensFire’s self signed certs +* use VPN’s DNS servers first + +### Version 1.19.3 +* Do not create foreground service when all accounts are disabled +* bug fixes + +### Version 1.19.2 +* bug fixes + +### Version 1.19.1 +* Made DNSSEC hostname validation opt-in + +### Version 1.19.0 +* Added 'App Shortcuts' to quickly access frequent contacts +* Use DNSSEC to verify hostname instead of domain in certificate +* Setting to enable Heads-up notifications +* Added date separators in message view + +### Version 1.18.5 +* colorize send button only after history is caught up +* improved MAM catchup strategy + +### Version 1.18.4 +* fixed UI freezes during connection timeout +* fixed notification sound playing twice +* fixed conversations being marked as read +* removed 'copy text' in favor of 'select text' and 'share with' + +### Version 1.18.3 +* limited GPG encryption for MUC offline members + +### Version 1.18.2 +* added support for Android Auto +* fixed HTTP Download over Tor +* work around for nimbuzz.com MUCs + +### Version 1.18.1 +* bug fixes + +### Version 1.18.0 +* Conversations <1.16.0 will be unable to receive OMEMO encrypted messages +* OMEMO: put auth tag into key (verify auth tag as well) +* offer to block entire domain in message from stranger snackbar +* treat URL as file if URL is in oob or contains key + +### Version 1.17.1 +* Switch Aztec to QR for faster scans +* Fixed unread counter for image messages + +### Version 1.17.0 +* Do not notify for messages from strangers by default +* Blocking a JID closes the corresponding conversation +* Show message sender in conversation overview +* Show unread counter for every conversation +* Send typing notifications in private, non-anonymous MUCs +* Support for the latest MAM namespace +* Icons for attach menu + +### Version 1.16.2 +* change mam catchup strategy. support mam:1 +* bug fixes + +### Version 1.16.1 +* UI performance fixes +* bug fixes + +### Version 1.16.0 +* configurable client side message retention period +* compress videos before sending them + +### Version 1.15.5 +* show nick as bold text when mentioned in conference +* bug fixes + +### Version 1.15.4 +* bug fixes + +### Version 1.15.3 +* show offline contacts in MUC as grayed-out +* don't transcode gifs. add overlay indication to gifs +* bug fixes + +### Version 1.15.2 +* bug fixes + +### Version 1.15.1 +* support for POSH (RFC7711) +* support for quoting messages (via select text) +* verified messages show shield icon. unverified messages show lock + +### Version 1.15.0 +* New [Blind Trust Before Verification](https://gultsch.de/trust.html) mode +* Easily share Barcode and XMPP uri from Account details +* Automatically deactivate own devices after 7 day of inactivity +* Improvements fo doze/push mode +* bug fixes + +### Version 1.14.9 +* warn in account details when data saver is enabled +* automatically enable foreground service after detecting frequent restarts +* bug fixes + +### Version 1.14.8 +* bug fixes + +### Version 1.14.7 +* error message accessible via context menu for failed messages +* don't include pgp signature in anonymous mucs +* bug fixes + +### Version 1.14.6 +* make error notification dismissible +* bug fixes + + +### Version 1.14.5 +* expert setting to delete OMEMO identities +* bug fixes + +### Version 1.14.4 +* bug fixes + +### Version 1.14.3 +* XEP-0377: Spam Reporting +* fix rare start up crashes + +### Version 1.14.2 +* support ANONYMOUS SASL +* bug fixes + +### Version 1.14.1 +* Press lock icon to see why OMEMO is deactivated +* bug fixes + +### Version 1.14.0 +* Improvements for N +* Quick Reply to Notifications on N +* Don't download avatars and files when data saver is on +* bug fixes + +### Version 1.13.9 +* bug fixes + +### Version 1.13.8 +* show identities instead of resources in selection dialog +* allow TLS direct connect when port is set to 5223 +* bug fixes + +### Version 1.13.7 +* bug fixes + +### Version 1.13.6 +* thumbnails for videos +* bug fixes + +### Version 1.13.5 +* bug fixes + +### Version 1.13.4 +* support jingle ft:4 +* show contact as DND if one resource is +* bug fixes + +### Version 1.13.3 +* bug fixes + +### Version 1.13.2 +* new PGP decryption logic +* bug fixes + +### Version 1.13.1 +* changed some colors in dark theme +* fixed fall-back message for OMEMO + +### Version 1.13.0 +* configurable dark theme +* opt-in to share Last User Interaction + +### Version 1.12.9 +* make grace period configurable + +### Version 1.12.8 +* more bug fixes :-( + +### Version 1.12.7 +* bug fixes + +### Version 1.12.6 +* bug fixes + +### Version 1.12.5 +* new create conference dialog +* show first unread message on top +* show geo uri as links +* circumvent long message DOS + +### Version 1.12.4 +* show offline members in conference (needs server support) +* various bug fixes + +### Version 1.12.3 +* make omemo default when all resources support it +* show presence of other resources as template +* start typing in StartConversationsActivity to search +* various bug fixes and improvements + +### Version 1.12.2 +* fixed pgp presence signing + +### Version 1.12.1 +* small bug fixes + +### Version 1.12.0 +* new welcome screen that makes it easier to register account +* expert setting to modify presence + +### Version 1.11.7 +* Share xmpp uri from conference details +* add setting to allow quick sharing +* various bug fixes + +### Version 1.11.6 +* added preference to disable notification light +* various bug fixes + +### Version 1.11.5 +* check file ownership to not accidentally share private files + +### Version 1.11.4 +* fixed a bug where contacts are shown as offline +* improved broken PEP detection + +### Version 1.11.3 +* check maximum file size when using HTTP Upload +* properly calculate caps hash + +### Version 1.11.2 +* only add image files to media scanner +* allow to delete files +* various bug fixes + +### Version 1.11.1 +* fixed some bugs when sharing files with Conversations + +### Version 1.11.0 +* OMEMO encrypted conferences + +### Version 1.10.1 +* made message correction opt-in +* various bug fixes + +### Version 1.10.0 +* Support for XEP-0357: Push Notifications +* Support for XEP-0308: Last Message Correction +* introduced build flavors to make dependence on play-services optional + +### Version 1.9.4 +* prevent cleared Conversations from reloading history with MAM +* various MAM fixes + +### Version 1.9.3 +* expert setting that enables host and port configuration +* expert setting opt-out of bookmark autojoin handling +* offer to rejoin a conference after server sent unavailable +* internal rewrites + +### Version 1.9.2 +* prevent startup crash on Sailfish OS +* minor bug fixes + +### Version 1.9.1 +* minor bug fixes incl. a workaround for nimbuzz.com + +### Version 1.9.0 +* Per conference notification settings +* Let user decide whether to compress pictures +* Support for XEP-0368 +* Ask user to exclude Conversations from battery optimizations + +### Version 1.8.4 +* prompt to trust own OMEMO devices +* fixed rotation issues in avatar publication +* invite non-contact JIDs to conferences + +### Version 1.8.3 +* brought text selection back + +### Version 1.8.2 +* fixed stuck at 'connecting...' bug +* make message box behave correctly with multiple links + +### Version 1.8.1 +* enabled direct share on Android 6.0 +* ask for permissions on Android 6.0 +* notify on MAM catchup messages +* bug fixes + +### Version 1.8.0 +* TOR/ORBOT support in advanced settings +* show vcard avatars of participants in a conference + +### Version 1.7.3 +* fixed PGP encrypted file transfer +* fixed repeating messages in slack conferences + +### Version 1.7.2 +* decode PGP messages in background + +### Version 1.7.1 +* performance improvements when opening a conversation + +### Version 1.7.0 +* CAPTCHA support +* SASL EXTERNAL (client certificates) +* fetching MUC history via MAM +* redownload deleted files from HTTP hosts +* Expert setting to automatically set presence +* bug fixes + +### Version 1.6.11 +* tab completion for MUC nicks +* history export +* bug fixes + +### Version 1.6.10 +* fixed facebook login +* fixed bug with ejabberd mam +* use official HTTP File Upload namespace + +### Version 1.6.9 +* basic keyboard support + +### Version 1.6.8 +* reworked 'enter is send' setting +* reworked DNS server discovery on lolipop devices +* various bug fixes + +### Version 1.6.7 +* bug fixes + +### Version 1.6.6 +* best 1.6 release yet + +### Version 1.6.5 +* more OMEMO fixes + +### Version 1.6.4 +* setting to enable white chat bubbles +* limit OMEMO key publish attempts to work around broken PEP +* various bug fixes + +### Version 1.6.3 +* bug fixes + +### Version 1.6.2 +* fixed issues with connection time out when server does not support ping + +### Version 1.6.1 +* fixed crashes + +### Version 1.6.0 +* new multi-end-to-multi-end encryption method +* redesigned chat bubbles +* show unexpected encryption changes as red chat bubbles +* always notify in private/non-anonymous conferences + +### Version 1.5.1 +* fixed rare crashes +* improved otr support + +### Version 1.5.0 +* upload files to HTTP host and share them in MUCs. requires new [HttpUploadComponent](https://github.com/siacs/HttpUploadComponent) on server side + +### Version 1.4.5 +* fixes to message parser to not display some ejabberd muc status messages + +### Version 1.4.4 +* added unread count badges on supported devices +* rewrote message parser + +### Version 1.4.0 +* send button turns into quick action button to offer faster access to take photo, send location or record audio +* visually separate merged messages +* faster reconnects of failed accounts after network switches +* r/o vcard avatars for contacts +* various bug fixes + +### Version 1.3.0 +* swipe conversations to end them +* quickly enable / disable account via slider +* share multiple images at once +* expert option to distrust system CAs +* mlink compatibility +* bug fixes + +### Version 1.2.0 +* Send current location. (requires [plugin](https://play.google.com/store/apps/details?id=eu.siacs.conversations.sharelocation)) +* Invite multiple contacts at once +* performance improvements +* bug fixes + +### Version 1.1.0 +* Typing notifications (must be turned on in settings) +* Various UI performance improvements +* bug fixes + +### Version 1.0.4 +* load avatars asynchronously on start up +* support for XEP-0092: Software Version + +### Version 1.0.3 +* load messages asynchronously on start up +* bug fixes + +### Version 1.0.2 +* skipped + +### Version 1.0.1 +* accept more ciphers + +### Version 1.0 +* MUC controls (Affiliation changes) +* Added download button to notification +* Added check box to hide offline contacts +* Use Material theme and icons on Android L +* Improved security +* bug fixes + code clean up + +### Version 0.10 +* Support for Message Archive Management +* Dynamically load message history +* Ability to block contacts +* New UI to verify fingerprints +* Ability to change password on server +* removed stream compression +* quiet hours +* fixed connection issues on ipv6 servers + +### Version 0.9.3 +* bug fixes + +### Version 0.9.2 +* more bug fixes + +### Version 0.9.1 +* bug fixes including some that caused Conversations to crash on start + +### Version 0.9 +* arbitrary file transfer +* more options to verify OTR (SMP, QR Codes, NFC) +* ability to create instant conferences +* r/o dynamic tags (presence and roster groups) +* optional foreground service (expert option) +* added SCRAM-SHA1 login method +* bug fixes + +### Version 0.8.4 +* bug fixes + +### Version 0.8.3 +* increased UI performance +* fixed rotation bugs + +### Version 0.8.2 +* Share contacts via QR codes or NFC +* Slightly improved UI +* minor bug fixes + +### Version 0.8.1 +* minor bug fixes + +### Version 0.8 +* Download HTTP images +* Show avatars in MUC tiles +* Disabled SSLv3 +* Performance improvements +* bug fixes + +### Version 0.7.3 +* revised tablet ui +* internal rewrites +* bug fixes + +### Version 0.7.2 +* show full timestamp in messages +* brought back option to use JID to identify conferences +* optionally request delivery receipts (expert option) +* more languages +* bug fixes + +### Version 0.7.1 +* Optionally use send button as status indicator + +### Version 0.7 +* Ability to disable notifications for single conversations +* Merge messages in chat bubbles +* Fixes for OpenPGP and OTR (please republish your public key) +* Improved reliability on sending messages +* Join password protected Conferences +* Configurable font size +* Expert options for encryption + +### Version 0.6 +* Support for server side avatars +* save images in gallery +* show contact name and picture in non-anonymous conferences +* reworked account creation +* various bug fixes + +### Version 0.5.2 +* minor bug fixes + +### Version 0.5.1 +* couple of small bug fixes that have been missed in 0.5 +* complete translations for Swedish, Dutch, German, Spanish, French, Russian + +### Version 0.5 +* UI overhaul +* MUC / Conference bookmarks +* A lot of bug fixes + +### Version 0.4 +* OTR file encryption +* keep OTR messages and files on device until both parties or online at the same time +* XEP-0333. Mark whether the other party has read your messages +* Delayed messages are now tagged properly +* Share images from the Gallery +* Infinite history scrolling +* Mark the last used presence in presence selection dialog + +### Version 0.3 +* Mostly bug fixes and internal rewrites +* Touch contact picture in conference to highlight +* Long press on received image to share +* made OTR more reliable +* improved issues with occasional message lost +* experimental conference encryption. (see FAQ) + +### Version 0.2.3 +* regression fix with receiving encrypted images + +### Version 0.2.2 +* Ability to take photos directly +* Improved openPGP offline handling +* Various bug fixes +* Updated Translations + +### Version 0.2.1 +* Various bug fixes +* Updated Translations + +### Version 0.2 +* Image file transfer +* Better integration with OpenKeychain (PGP encryption) +* Nicer conversation tiles for conferences +* Ability to clear conversation history +* A lot of bug fixes and code clean up + +### Version 0.1.3 +* Switched to minidns library to resolve SRV records +* Faster DNS in some cases +* Enabled stream compression +* Added permanent notification when an account fails to connect +* Various bug fixes involving message notifications +* Added support for DIGEST-MD5 auth + +### Version 0.1.2 +* Various bug fixes relating to conferences +* Further DNS lookup improvements + +### Version 0.1.1 +* Fixed the 'server not found' bug + +### Version 0.1 +* Initial release diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000..bc1d46abce --- /dev/null +++ b/Gemfile @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gem "fastlane" +gem "screengrab" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..22cbee2577 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,221 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.5) + rexml + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + artifactory (3.0.15) + atomos (0.1.3) + aws-eventstream (1.2.0) + aws-partitions (1.566.0) + aws-sdk-core (3.130.0) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.525.0) + aws-sigv4 (~> 1.1) + jmespath (~> 1.0) + aws-sdk-kms (1.55.0) + aws-sdk-core (~> 3, >= 3.127.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.113.0) + aws-sdk-core (~> 3, >= 3.127.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.4) + aws-sigv4 (1.4.0) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + claide (1.1.0) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + declarative (0.0.20) + digest-crc (0.6.4) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.7.6) + emoji_regex (3.2.3) + excon (0.91.0) + faraday (1.10.0) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) + http-cookie (~> 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.3) + multipart-post (>= 1.2, < 3) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) + faraday (~> 1.0) + fastimage (2.2.6) + fastlane (2.204.3) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander (~> 4.6) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + json (< 3.0.0) + jwt (>= 2.1.0, < 3) + mini_magick (>= 4.9.4, < 5.0.0) + multipart-post (~> 2.0.0) + naturally (~> 2.2) + optparse (~> 0.1.1) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (>= 1.4.5, < 2.0.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + gh_inspector (1.1.3) + google-apis-androidpublisher_v3 (0.16.0) + google-apis-core (>= 0.4, < 2.a) + google-apis-core (0.4.2) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.10.0) + google-apis-core (>= 0.4, < 2.a) + google-apis-playcustomapp_v1 (0.7.0) + google-apis-core (>= 0.4, < 2.a) + google-apis-storage_v1 (0.11.0) + google-apis-core (>= 0.4, < 2.a) + google-cloud-core (1.6.0) + google-cloud-env (~> 1.0) + google-cloud-errors (~> 1.0) + google-cloud-env (1.5.0) + faraday (>= 0.17.3, < 2.0) + google-cloud-errors (1.2.0) + google-cloud-storage (1.36.1) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.1) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) + mini_mime (~> 1.0) + googleauth (1.1.2) + faraday (>= 0.17.3, < 3.a) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.4) + domain_name (~> 0.5) + httpclient (2.8.3) + jmespath (1.6.1) + json (2.6.1) + jwt (2.3.0) + memoist (0.16.2) + mini_magick (4.11.0) + mini_mime (1.1.2) + multi_json (1.15.0) + multipart-post (2.0.0) + nanaimo (0.3.0) + naturally (2.2.1) + optparse (0.1.1) + os (1.1.4) + plist (3.6.0) + public_suffix (4.0.6) + rake (13.0.6) + representable (3.1.1) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rexml (3.2.5) + rouge (2.0.7) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + screengrab (1.0.0) + fastlane (>= 2.0.0, < 3.0.0) + security (0.1.3) + signet (0.16.1) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.0) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.8) + CFPropertyList + naturally + terminal-notifier (2.0.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.1) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.8) + unicode-display_width (1.8.0) + webrick (1.7.0) + word_wrap (1.0.0) + xcodeproj (1.21.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + fastlane + screengrab + +BUNDLED WITH + 2.2.5 diff --git a/README-en.md b/README-en.md deleted file mode 100644 index a8b3fad6fc..0000000000 --- a/README-en.md +++ /dev/null @@ -1,149 +0,0 @@ -# Announcement: - -## Monocles Messenger becomes monocles chat - -What you can expect: -- Range of functions remains the same -- Support chat rooms are merged -- Colors and logos are adapted to monocles chat -- App is still available for free on codeberg and F-Droid Store - -Your monocles Team - ------ - -# monocles chat - -🇩🇪… [Deutsche Version der Readme hier verfügbar.](README.md) / [Francais ici](README-fr.md) - -monocles chat is a modern and secure Android XMPP client. Based on blabber.im and [Conversations](https://github.com/siacs/Conversations) but with a lot of changes and additional features. -The changes aim to improve usability and ease transition from pre-installed and other widespread chats. Here are some screenshots: - - - -Screens designed by Pigeonalley (https://pigeonalley.com) -### Presettings - -monocles chat has different presettings compared to blabber.im: - -* don't show previews of weblinks in chat -* don't show previews of locations in chat -* don't automatically download all attachments - -### OTR - -monocles chat supports OTR encryption! Though it's not easy to use OTR does have some advantages: -https://en.wikipedia.org/wiki/Off-the-Record_Messaging#Implementation - -## Download -monocles chat is available for install in the F-Droid -Alternatively beta-release APKs are available via codeberg: [Releases](https://codeberg.org/Arne/monocles_chat/releases) - -#### monocles chat nightly and beta - -nightly or beta-release APKs are available via codeberg: [Releases](https://codeberg.org/Arne/monocles_chat/releases) - -## Social Media -Follow us on monocles social - -There are also English and German speaking XMPP-room focusing on support and development of the monocles chat. - -If you are interested in the development of the chat, here is a MUC for you (English and German speaking): - -Development-Chat: [development@conference.monocles.de](https://monocles.chat/) - - -There also is an Support-MUC where you can ask questions and get help with issues you may encounter, see further below for details. - - -## How can I support translations ? -You can create merge request and add new languages as locales and add and edit translations already existing. - - - -## Help! I've encountered issues! -The easiest way to get some help is to join our support-MUC (both English and German). - -Support-Chat invite link: [support@conference.monocles.de](https://monocles.chat/) - -If we can't fix your problem there, you can open an issue [here](https://codeberg.org/Arne/monocles_chat/issues), detailing your problem, how to reproduce it and provide logs. See instructions below on how to create log files. - - - -### How to create debug logs? (adb) - -#### GNU/Linux, OSX and other Unix-like systems: - -1. First install The **A**ndroid **D**ebugging **B**ridge, if not already present. - ###### Debian and derivates like Ubuntu / Linux Mint - ``` - sudo apt-get update - sudo apt-get update adb - # Debian Jessie or older: - # sudo apt-get install android-tools-adb - ``` - ###### openSUSE 42.2 and 42.3 - ``` - sudo zypper ref - sudo zypper install android-tools - ``` - ###### openSUSE Tumbleweed - here you need to add the following repo (e.g. via Yast): - http://download.opensuse.org/repositories/hardware/openSUSE_Tumbleweed/ - - alternatively you have the option to use the `1 Click installer` - https://software.opensuse.org/package/android-tools - ###### other systems - install adb using a method appropriate for your system - -2. Now open a terminal in a directory of you're choice, or navigate to the directory using `cd`. - -3. Follow steps [6] to [10] of the Windows instructions. - -4. Start outputting your log to a file on your computer. We will be using `logcat.txt`. Enter: - ``` - $ adb -d logcat -v time | grep -i monocles_chat > logcat.txt - ``` - -5. Follow the remaining steps [12] and [13] of the Windows instructions. - - -#### Windows: - -1. Download Google's SDK-platform tools for your operating system: - - https://developer.android.com/studio/releases/platform-tools.html -2. In case they were not included: You also need the ADB_drivers for your version of Microsoft Windows: - - https://developer.android.com/studio/run/win-usb.html -3. Extract the zip-archive (e.g. to `C:\ADB\`) -4. Open the command line (CMD) using the start menu: Start > Execute: cmd -5. Navigate to the directory you extracted the zip to as following. We will be using `C:\ADB\` - ``` - c: - cd ADB - ``` -6. On your smartphone open the settings and search for the item `Developer Options`. If this option is not already present on your phone you will need to unlock it beforehand. To do this navigate to `Settings > About phone`, there locate `Build number` (or similar) and tap it 7-times in succession. You should now see a notification, that you are now a developer. Congrats, `Developer Options` are now available in your settings menu. -7. Inside `Developer Options` search activate the setting `USB-Debugging` (sometimes just called `Android Debugging`). -8. Connect your phone to your computer via USB cable. The necessary drivers should now be downloaded and installed if not already present. On Windows all necessary drivers should be downloaded automatically if you followed step [2] beforehand. On most GNU/Linux systems no additional action is required. -9. If everything worked out, you can now return to the command line and test if your device is being recognised. Enter `adb devices -l`; you should see output similar to: - ``` - > adb devices -l - List of devices attached - * daemon not running. starting it now on port 5037 * - * daemon started successfully * - 042111560169500303f4 unauthorized - ``` -10. If your devices is labelled as `unautorized`, you must first accept a prompt on your phone asking if debugging over USB should be allowed. When rerunning `adb devices` you should now see: - ``` - > adb devices - List of devices attached - 042111560169500303f4 device - ``` -11. Start outputting your log to a file on your computer. We will be using `logcat.txt` in `C:\ADB\`. Just enter the following (without `> ` into the command line): - ``` - > adb -d logcat -v time | FINDSTR monocles_chat > logcat.txt - ``` -12. Now reproduce the issue encountered. - -13. Stop logging (`Ctrl+C`). Now take a close look at your log file and remove any personal and private information you may find before sending it together with a detailed description of your issue, instructions on how to reproduce to me. You can use GitHub's issue tracker: [Issues](https://github.com/kriztan/Monocles-Messenger/issues) diff --git a/README-fr.md b/README-fr.md deleted file mode 100644 index 57300ff90a..0000000000 --- a/README-fr.md +++ /dev/null @@ -1,135 +0,0 @@ -# Annonce: - -## Monocles Messenger devient monocles chat - -Ce que vous pouvez attendre : -- La gamme de fonctions reste la même -- Les salons de chat du support sont fusionnés -- Les couleurs et les logos sont adaptés au chat de monocles. -- L'application est toujours disponible gratuitement sur codeberg et F-Droid Store. - -L'équipe monocles - ------ - -# monocles chat - -🇩🇪… [Deutsche Version der Readme hier verfügbar.](README.md) / 🇬🇧🇺🇸… [English Readme version available here](README-en.md) - -monocles chat est un fork de blabber.im et [Conversations] (https://github.com/siacs/Conversations). -Les changements visent à améliorer la convivialité et à faciliter la transition depuis les chats préinstallés et d'autres chats répandus. Voici quelques captures d'écran : - - - -## Télécharger -monocles chat est disponible dans F-Droid -Alternativement, les APKs de la release et de la beta-release sont disponibles via codeberg : [Releases](https://codeberg.org/Arne/monocles_chat/releases/latest) - -#### monocles chat nightly et beta - -Les APK nightly ou beta-release sont disponibles via codeberg : [Releases](https://codeberg.org/Arne/monocles_chat/releases/nightly) - -## Réseaux sociaux -Suivez-nous sur monocles social - -Il existe également des sales XMPP anglophones et germanophones qui se concentrent sur le support et le développement de monocles chat. - -Si vous êtes intéressé par le développement du chat, voici un MUC pour vous (en anglais et en allemand) : - -Développement-Chat : [development@conference.monocles.de](https://monocles.chat/) - - -Il existe également un Support-MUC où vous pouvez poser des questions et obtenir de l'aide pour les problèmes que vous pouvez rencontrer, voir ci-dessous pour plus de détails. - - -## Comment puis-je aider à la traduction ? -Vous pouvez créer une demande de fusion et ajouter de nouvelles langues en tant que locales et ajouter et modifier des traductions déjà existantes. - - - -## Aidez-moi ! J'ai rencontré des problèmes ! -La façon la plus simple d'obtenir de l'aide est de rejoindre notre support-MUC (en anglais et en allemand). - -Lien d'invitation à la discussion de soutien : [support@conference.monocles.eu] - -Si nous ne pouvons pas résoudre votre problème, vous pouvez ouvrir une question [ici](https://codeberg.org/Arne/monocles_chat/issues), en détaillant votre problème, comment le reproduire et en fournissant des journaux. Voir les instructions ci-dessous sur la façon de créer des fichiers journaux. - - - -### Comment créer des journaux de débogage ? (adb) - -#### GNU/Linux, OSX et d'autres systèmes de type Unix : - -1. Installez d'abord **A**ndroid **D**ebugging **B**ridge, si ce n'est pas déjà fait. - ###### Debian et ses dérivés comme Linux Mint / Ubuntu - ``` - sudo apt-get update - sudo apt-get update adb - # Debian Jessie or older: - # sudo apt-get install android-tools-adb - ``` - ###### openSUSE 42.2 et 42.3 - ``` - sudo zypper ref - sudo zypper install android-tools - ``` - ###### openSUSE Tumbleweed - ici, vous devez ajouter le dépôt suivant (par exemple via Yast) : - http://download.opensuse.org/repositories/hardware/openSUSE_Tumbleweed/ - - Vous avez également la possibilité d'utiliser le programme d'installation en un clic. - https://software.opensuse.org/package/android-tools - ###### autres systèmes - installer adb en utilisant une méthode appropriée à votre système - -2. Maintenant, ouvrez un terminal dans un répertoire de votre choix, ou naviguez vers le répertoire en utilisant `cd`. - -3. Suivez les étapes [6] à [10] des instructions Windows. - -4. Commencez à sortir votre journal dans un fichier sur votre ordinateur. Nous allons utiliser `logcat.txt`. Entrez : - ``` - $ adb -d logcat -v time | grep -i monocles_chat > logcat.txt - ``` - -5. Suivez les autres étapes [12] et [13] des instructions Windows. - - -#### Windows: - -1. Téléchargez les outils de la plateforme SDK de Google pour votre système d'exploitation : - - https://developer.android.com/studio/releases/platform-tools.html -2. Au cas où ils n'auraient pas été inclus : Vous avez également besoin des ADB_drivers pour votre version de Microsoft Windows : - - https://developer.android.com/studio/run/win-usb.html -3. Extrayez l'archive zip (par exemple vers "C:\ADB\"). -4. Ouvrez la ligne de commande (CMD) à l'aide du menu Démarrer : Démarrer > Exécuter : cmd -5. Naviguez vers le répertoire dans lequel vous avez extrait le zip comme suit. Nous allons utiliser `C:\ADB\`. - ``` - c: - cd ADB - ``` -6. Sur votre smartphone, ouvrez les paramètres et recherchez "Options développeur". Si cette option n'est pas déjà présente sur votre téléphone, vous devrez le déverrouiller au préalable. Pour ce faire, allez dans `Paramètres > À propos du téléphone`, localisez le `Numéro de construction` (ou similaire) et appuyez dessus 7 fois de suite. Vous devriez maintenant voir une notification indiquant que vous êtes maintenant un développeur. Félicitations, les `Options développeur` sont maintenant disponibles dans votre menu de paramètres. -7. Dans la recherche `Options développeur`, activez le paramètre `USB-Debugging` (parfois juste appelé `Android Debugging`). -8. Connectez votre téléphone à votre ordinateur via un câble USB. Les pilotes nécessaires doivent maintenant être téléchargés et installés s'ils ne sont pas déjà présents. Sous Windows, tous les pilotes nécessaires devraient être téléchargés automatiquement si vous avez suivi l'étape [2] au préalable. Sur la plupart des systèmes GNU/Linux, aucune action supplémentaire n'est requise. -9. Si tout a fonctionné, vous pouvez maintenant retourner à la ligne de commande et tester si votre périphérique est reconnu. Entrez `adb devices -l` ; vous devriez voir une sortie similaire à celle-ci : - ``` - > adb devices -l - List of devices attached - * daemon not running. starting it now on port 5037 * - * daemon started successfully * - 042111560169500303f4 unauthorized - ``` -10. Si votre appareil est étiqueté comme `unautorized`, vous devez d'abord accepter une invite sur votre téléphone demandant si le débogage par USB doit être autorisé. En relançant `adb devices` vous devriez maintenant voir : - ``` - > adb devices - List of devices attached - 042111560169500303f4 device - ``` -11. Commencez à sortir votre journal dans un fichier sur votre ordinateur. Nous allons utiliser `logcat.txt` dans `C:\ADB\`. Entrez simplement ce qui suit (sans `> ` dans la ligne de commande) : - ``` - > adb -d logcat -v time | FINDSTR monocles_chat > logcat.txt - ``` -12. Reproduisez maintenant le problème rencontré. - -13. Arrêtez la journalisation (`Ctrl+C`). Maintenant, regardez attentivement votre fichier de log et supprimez toute information personnelle et privée que vous pourriez trouver avant de me l'envoyer avec une description détaillée de votre problème et des instructions sur la façon de le reproduire. Vous pouvez utiliser le gestionnaire de problèmes de GitHub : [Issues](https://github.com/kriztan/Monocles-Messenger/issues) \ No newline at end of file diff --git a/README.md b/README.md index 9a1ba1948c..900b16b22b 100644 --- a/README.md +++ b/README.md @@ -1,105 +1,40 @@ -# monocles chat +# Cheogram Android -🇬🇧🇺🇸… [English Readme version available here](README-en.md) / [Francais ici](README-fr.md) +This is a fork of [Conversations](https://conversations.im) to implement features of use to the [Sopranica](https://soprani.ca) project. -monocles chat ist moderner und sicherer Android XMPP-Client. Basierend auf blabber.im und der offiziellen Android-App [Conversations](https://github.com/siacs/Conversations) mit einigen Änderungen, insbesondere zur Verbesserung der Benutzerfreundlichkeit, um den Umstieg von oftmals vorinstallierten Messengern zu erleichtern. Die folgenden Bilder geben erste Eindrücke der App: +The Cheogram Android app allows you to join a worldwide communication network. It especially focuses on features useful to users who want to contact those on other networks as well, such as SMS-enabled phone numbers. - +Based on the app Conversations, but with unique features: -Vorschaubilder erstellt von Pigeonalley (https://pigeonalley.com) +* Messages with both media and text, including animated media +* Unobtrusive display of subject lines, where present +* Links to known contacts are shown with their name +* Show timestamps for calls +* Integrates with gateways' add contact flows +* When using a gateway to the phone network, integrate with the native Android Phone app +* Address book integration +* Tag contacts and channels and browse by tag +* Command UI -Download ist hier möglich: -Jetzt bei F-Droid +## Getting Help -Folge uns auf monocles social +If you have any questions about this app, or wish to report a bug, please send email to dev@singpolyma.net or join us in [xmpp:support@conference.monocles.eu?join](xmpp:support@conference.monocles.eu?join) -#### monocles chat nightly bzw. beta +## Contributing -nightly oder beta Versionen kann man direkt hier von Codeberg unter [Releases](https://codeberg.org/Arne/monocles_chat/releases) herunterladen. +If you have code or patches you wish to contribute, the maintainer's preferred mechanism is a git pull request. Push your changes to a git repository somewhere, for example: -#### Wie kann ich bei der Übersetzung helfen? -Du kannst einen Merge Request erstellen in dem du Verbesserungen oder neue Sprachen hinzugefügt hast. + git remote rename origin upstream + git remote add origin git@git.sr.ht:~yourname/cheogram-android + git push -u origin master -#### Ich habe Probleme, was soll ich tun? -Am einfachsten ist es, wenn du unserer Support-Gruppe beitrittst, dort werden deine Probleme mit Sicherheit schnell gelöst. +Then generate the pull request: -Support-Chat: [support@conference.monocles.eu](https://monocles.chat) + git fetch upstream master + git request-pull -p upstream/master origin -Development-Chat: [development@conference.monocles.de](https://monocles.chat) +And copy-paste the result into a plain-text email to: dev@singpolyma.net +You may alternately use a patch-based approach as described on https://git-send-email.io -Solltest du dort nicht weiter kommen kannst du [hier](https://codeberg.org/Arne/monocles_chat/issues) ein Issue erstellen, in welchem du dein Problem genau beschreibst und welche Schritte erforderlich sind, um zu dem Problem zu gelangen. - -#### Wie erstelle ich Debug- bzw. ADB-Logs? - -##### Linux: - -1. Installation von ADB - ###### Debian und Derivate wie Ubuntu / Linux Mint - ``` - sudo apt-get update - sudo apt-get install adb - # For Debian Jessie and older - # sudo apt-get install android-tools-adb - ``` - ###### openSUSE 42.2 und 42.3 - ``` - sudo zypper ref - sudo zypper install android-tools - ``` - ###### openSUSE Tumbleweed - hier muss für das benötigte Packet folgende Repo eingebunden werden (z.B. bequem über Yast): - http://download.opensuse.org/repositories/hardware/openSUSE_Tumbleweed/ - - alternativ kann auch der `1 Click Installer` benutzt werden: - https://software.opensuse.org/package/android-tools - -2. Navigiere im Terminal mit `cd` in das Verzeichnis deines Vertrauens -3. Folge den Schritten [6] bis [10] unter [Windows]. s.u. -4. Nun kannst du mit der Ausgabe der Debug-Logs beginnen. Nenne die Log-Datei bspw `logcat.txt`: - ``` - $ adb -d logcat -v time | grep -i monocles_chat > logcat.txt - ``` -5. Fahre nun mit den verbliebenen Schritten unter [Windows] ab Schritt [12] fort. - -##### Windows: - -1. Lade dir die SDK-Plattform-Tools für dein Betriebssystem von Google herunter: - - https://developer.android.com/studio/releases/platform-tools.html -2. Falls noch nicht getan, lade dir die ADB Treiber für dein Betriebssystem von Google herunter, für Windows hier: - - https://developer.android.com/studio/run/win-usb.html -3. Entpacke die zip (z.B. nach C:\ADB\) -4. Öffne die Kommandozeile (CMD) mit Start > Ausführen: cmd -5. Wechsele in der Kommandozeile in das Verzeichnis C:\ADB wie folgt - ``` - c: - cd ADB - ``` -6. Auf deinem Telefon gehst du in die Einstellungen und suchst nach dem Punkt `Entwickleroptionen`. Sollte dieser bei dir nicht vorhanden sein, musst du diese Optionen erst noch freischalten. Dazu wechselst du in den Einstellungen in den Punkt `über das Telefon` und suchst dort nach `Buildnummer` oder Ähnlichem. Diese Zeile musst Du mindestens 7 mal hintereinander antippen, es sollte dann ein Hinweis eingeblendet werden, der dir bestätigt, dass du nun Entwickler bist. -7. In den `Entwickleroptionen` suchst du nach dem Eintrag `USB-Debugging` und aktivierst ihn. -8. Schließe dein Handy mit dem USB-Kabel an deinen PC an. Die erforderlichen Treiber sollten zumindest in Windows automatisch installiert werden. -9. Wenn alles ohne Fehler geklappt hat, kannst du wieder in die Kommandozeile gehen und testen, ob alles funktioniert. Gib dazu in CMD `adb devices -l` ein, es sollte in etwa sowas bei dir stehen: - ``` - > adb devices -l - List of devices attached - * daemon not running. starting it now on port 5037 * - * daemon started successfully * - 042111560169500303f4 unauthorized - ``` -10. Falls dein Handy als `unauthorized` markiert wird, sollte am Handy eine Meldung `USB-Debugging zulassen?` kommen, diese mit `OK` bestätigen, sodass bei `adb devices` folgendes dort stehen sollte: - ``` - > adb devices - List of devices attached - 042111560169500303f4 device - ``` -11. Nun kannst du mit der Ausgabe der Debug-Logs beginnen. Dazu gibst du im CMD folgendes ein und die Ausgabe beginnt in die Datei `logcat.txt` im Verzeichnis `C:\ADB`: - ``` - > adb -d logcat -v time | FINDSTR monocles_chat > logcat.txt - ``` -12. Führe nun die Schritte aus, die zum Fehler führen. - -13. Nachdem der Fehler reproduziert wurde, kann das Loggen im Terminal mit `Strg+C` beendet werden. - -14. Zum Schluss schaue dir die `logcat.txt` an, lösche ggf. persönliche Angaben und sende diese Datei zur Problemlösung mit einer Beschreibung des Fehlers und was man tun muss, um diesen Fehler zu erhalten, an mich. Nutz dafür den Menüpunkt [Issues](https://codeberg.org/Arne/monocles_chat/issues) +Contributions follow an inbound=outbound model -- you (or your employer) keep all copyright on your patches, but agree to license them according to this project's COPYING file. diff --git a/art/LICENSE b/art/LICENSE new file mode 100644 index 0000000000..34ec65f344 --- /dev/null +++ b/art/LICENSE @@ -0,0 +1,425 @@ +Attribution-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-ShareAlike 4.0 International Public +License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-ShareAlike 4.0 International Public License ("Public +License"). To the extent this Public License may be interpreted as a +contract, You are granted the Licensed Rights in consideration of Your +acceptance of these terms and conditions, and the Licensor grants You +such rights in consideration of benefits the Licensor receives from +making the Licensed Material available under these terms and +conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + l. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + m. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + + including for purposes of Section 3(b); and + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public licenses. +Notwithstanding, Creative Commons may elect to apply one of its public +licenses to material it publishes and in those instances will be +considered the "Licensor." Except for the limited purpose of indicating +that material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the public +licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/art/conversations_mono.svg b/art/conversations_mono.svg new file mode 100644 index 0000000000..8bd2947362 --- /dev/null +++ b/art/conversations_mono.svg @@ -0,0 +1,337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/art/conversations_mono_dashed.svg b/art/conversations_mono_dashed.svg new file mode 100644 index 0000000000..a8bba9414e --- /dev/null +++ b/art/conversations_mono_dashed.svg @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/art/date_bubble_grey.svg b/art/date_bubble_grey.svg new file mode 100644 index 0000000000..38db49f9b6 --- /dev/null +++ b/art/date_bubble_grey.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/art/date_bubble_white.svg b/art/date_bubble_white.svg new file mode 100644 index 0000000000..452ae92723 --- /dev/null +++ b/art/date_bubble_white.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/art/flip_camera_android-black-24dp.svg b/art/flip_camera_android-black-24dp.svg new file mode 100644 index 0000000000..f50c0d721e --- /dev/null +++ b/art/flip_camera_android-black-24dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/art/ic_launcher.svg b/art/ic_launcher.svg new file mode 100644 index 0000000000..68c403ecb7 --- /dev/null +++ b/art/ic_launcher.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/art/ic_missed_call_notification.svg b/art/ic_missed_call_notification.svg new file mode 100644 index 0000000000..78f0acead8 --- /dev/null +++ b/art/ic_missed_call_notification.svg @@ -0,0 +1,344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/art/ic_no_results_black.svg b/art/ic_no_results_black.svg new file mode 100644 index 0000000000..fb0f78117f --- /dev/null +++ b/art/ic_no_results_black.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_no_results_white.svg b/art/ic_no_results_white.svg new file mode 100644 index 0000000000..744616a480 --- /dev/null +++ b/art/ic_no_results_white.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_notifications_none_white80.svg b/art/ic_notifications_none_white80.svg new file mode 100644 index 0000000000..d333130ff3 --- /dev/null +++ b/art/ic_notifications_none_white80.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_notifications_off_white80.svg b/art/ic_notifications_off_white80.svg new file mode 100644 index 0000000000..f0af47b618 --- /dev/null +++ b/art/ic_notifications_off_white80.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_notifications_paused_white80.svg b/art/ic_notifications_paused_white80.svg new file mode 100644 index 0000000000..4f92e8475f --- /dev/null +++ b/art/ic_notifications_paused_white80.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_notifications_white80.svg b/art/ic_notifications_white80.svg new file mode 100644 index 0000000000..398e51385e --- /dev/null +++ b/art/ic_notifications_white80.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_search_black.svg b/art/ic_search_black.svg new file mode 100644 index 0000000000..e3d0e8096a --- /dev/null +++ b/art/ic_search_black.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_search_white.svg b/art/ic_search_white.svg new file mode 100644 index 0000000000..7186d8e23f --- /dev/null +++ b/art/ic_search_white.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_secure_indicator.xcf b/art/ic_secure_indicator.xcf new file mode 100644 index 0000000000..a9069c9bb5 Binary files /dev/null and b/art/ic_secure_indicator.xcf differ diff --git a/art/ic_send_cancel_away.svg b/art/ic_send_cancel_away.svg new file mode 100644 index 0000000000..1ee9c40f61 --- /dev/null +++ b/art/ic_send_cancel_away.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_cancel_dnd.svg b/art/ic_send_cancel_dnd.svg new file mode 100644 index 0000000000..67a562b2f4 --- /dev/null +++ b/art/ic_send_cancel_dnd.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_cancel_offline.svg b/art/ic_send_cancel_offline.svg new file mode 100644 index 0000000000..b88ade09db --- /dev/null +++ b/art/ic_send_cancel_offline.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_cancel_offline_white.svg b/art/ic_send_cancel_offline_white.svg new file mode 100644 index 0000000000..f84f62f571 --- /dev/null +++ b/art/ic_send_cancel_offline_white.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_cancel_online.svg b/art/ic_send_cancel_online.svg new file mode 100644 index 0000000000..133e69f113 --- /dev/null +++ b/art/ic_send_cancel_online.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_location_away.svg b/art/ic_send_location_away.svg new file mode 100644 index 0000000000..fcd50b5211 --- /dev/null +++ b/art/ic_send_location_away.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_location_dnd.svg b/art/ic_send_location_dnd.svg new file mode 100644 index 0000000000..705cdb6f4e --- /dev/null +++ b/art/ic_send_location_dnd.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_location_offline.svg b/art/ic_send_location_offline.svg new file mode 100644 index 0000000000..56529b7230 --- /dev/null +++ b/art/ic_send_location_offline.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_location_offline_white.svg b/art/ic_send_location_offline_white.svg new file mode 100644 index 0000000000..f7f60a8f4d --- /dev/null +++ b/art/ic_send_location_offline_white.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_location_online.svg b/art/ic_send_location_online.svg new file mode 100644 index 0000000000..76d146ccf3 --- /dev/null +++ b/art/ic_send_location_online.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_photo_away.svg b/art/ic_send_photo_away.svg new file mode 100644 index 0000000000..31a20e09f8 --- /dev/null +++ b/art/ic_send_photo_away.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/ic_send_photo_dnd.svg b/art/ic_send_photo_dnd.svg new file mode 100644 index 0000000000..9ef8b7821b --- /dev/null +++ b/art/ic_send_photo_dnd.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/ic_send_photo_offline.svg b/art/ic_send_photo_offline.svg new file mode 100644 index 0000000000..b2ca20a6f5 --- /dev/null +++ b/art/ic_send_photo_offline.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/ic_send_photo_offline_white.svg b/art/ic_send_photo_offline_white.svg new file mode 100644 index 0000000000..45875731c8 --- /dev/null +++ b/art/ic_send_photo_offline_white.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/ic_send_photo_online.svg b/art/ic_send_photo_online.svg new file mode 100644 index 0000000000..f29c3c7c76 --- /dev/null +++ b/art/ic_send_photo_online.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/ic_send_picture_away.svg b/art/ic_send_picture_away.svg new file mode 100644 index 0000000000..a85a1eecbb --- /dev/null +++ b/art/ic_send_picture_away.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/ic_send_picture_dnd.svg b/art/ic_send_picture_dnd.svg new file mode 100644 index 0000000000..0c7d06356a --- /dev/null +++ b/art/ic_send_picture_dnd.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/ic_send_picture_offline.svg b/art/ic_send_picture_offline.svg new file mode 100644 index 0000000000..048508a356 --- /dev/null +++ b/art/ic_send_picture_offline.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/ic_send_picture_offline_white.svg b/art/ic_send_picture_offline_white.svg new file mode 100644 index 0000000000..16131740f9 --- /dev/null +++ b/art/ic_send_picture_offline_white.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/ic_send_picture_online.svg b/art/ic_send_picture_online.svg new file mode 100644 index 0000000000..ff388a4d4b --- /dev/null +++ b/art/ic_send_picture_online.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/ic_send_text_away.svg b/art/ic_send_text_away.svg new file mode 100644 index 0000000000..ea83086aea --- /dev/null +++ b/art/ic_send_text_away.svg @@ -0,0 +1,69 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/art/ic_send_text_dnd.svg b/art/ic_send_text_dnd.svg new file mode 100644 index 0000000000..1b7ad51f43 --- /dev/null +++ b/art/ic_send_text_dnd.svg @@ -0,0 +1,69 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/art/ic_send_text_offline.svg b/art/ic_send_text_offline.svg new file mode 100644 index 0000000000..c87bfaac66 --- /dev/null +++ b/art/ic_send_text_offline.svg @@ -0,0 +1,69 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/art/ic_send_text_offline_white.svg b/art/ic_send_text_offline_white.svg new file mode 100644 index 0000000000..4434d33db9 --- /dev/null +++ b/art/ic_send_text_offline_white.svg @@ -0,0 +1,70 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/art/ic_send_text_online.svg b/art/ic_send_text_online.svg new file mode 100644 index 0000000000..ff01bd6ef7 --- /dev/null +++ b/art/ic_send_text_online.svg @@ -0,0 +1,69 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/art/ic_send_videocam_away.svg b/art/ic_send_videocam_away.svg new file mode 100644 index 0000000000..52b8478cfa --- /dev/null +++ b/art/ic_send_videocam_away.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_videocam_dnd.svg b/art/ic_send_videocam_dnd.svg new file mode 100644 index 0000000000..254e3859a1 --- /dev/null +++ b/art/ic_send_videocam_dnd.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_videocam_offline.svg b/art/ic_send_videocam_offline.svg new file mode 100644 index 0000000000..91a7778d65 --- /dev/null +++ b/art/ic_send_videocam_offline.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_videocam_offline_white.svg b/art/ic_send_videocam_offline_white.svg new file mode 100644 index 0000000000..67f5563a63 --- /dev/null +++ b/art/ic_send_videocam_offline_white.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_videocam_online.svg b/art/ic_send_videocam_online.svg new file mode 100644 index 0000000000..7ee2fff979 --- /dev/null +++ b/art/ic_send_videocam_online.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/ic_send_voice_away.svg b/art/ic_send_voice_away.svg new file mode 100644 index 0000000000..379f55b7db --- /dev/null +++ b/art/ic_send_voice_away.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_voice_dnd.svg b/art/ic_send_voice_dnd.svg new file mode 100644 index 0000000000..b1b7a7a978 --- /dev/null +++ b/art/ic_send_voice_dnd.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_voice_offline.svg b/art/ic_send_voice_offline.svg new file mode 100644 index 0000000000..64ea447317 --- /dev/null +++ b/art/ic_send_voice_offline.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_voice_offline_white.svg b/art/ic_send_voice_offline_white.svg new file mode 100644 index 0000000000..25ffe3223a --- /dev/null +++ b/art/ic_send_voice_offline_white.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_send_voice_online.svg b/art/ic_send_voice_online.svg new file mode 100644 index 0000000000..2c54052361 --- /dev/null +++ b/art/ic_send_voice_online.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/ic_verified_fingerprint.svg b/art/ic_verified_fingerprint.svg new file mode 100644 index 0000000000..689c42ebdd --- /dev/null +++ b/art/ic_verified_fingerprint.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/art/logo.png b/art/logo.png new file mode 100644 index 0000000000..c606a58291 Binary files /dev/null and b/art/logo.png differ diff --git a/art/main_logo.svg b/art/main_logo.svg new file mode 120000 index 0000000000..e62f735a00 --- /dev/null +++ b/art/main_logo.svg @@ -0,0 +1 @@ +ic_launcher.svg \ No newline at end of file diff --git a/art/marker.svg b/art/marker.svg new file mode 100644 index 0000000000..f73c1537b9 --- /dev/null +++ b/art/marker.svg @@ -0,0 +1,110 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/art/message_bubble_received.svg b/art/message_bubble_received.svg new file mode 100644 index 0000000000..06c9bf92c4 --- /dev/null +++ b/art/message_bubble_received.svg @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/art/message_bubble_received_dark.svg b/art/message_bubble_received_dark.svg new file mode 100644 index 0000000000..06c9bf92c4 --- /dev/null +++ b/art/message_bubble_received_dark.svg @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/art/message_bubble_received_grey.svg b/art/message_bubble_received_grey.svg new file mode 100644 index 0000000000..e1d8347fc7 --- /dev/null +++ b/art/message_bubble_received_grey.svg @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/art/message_bubble_received_obsidian.svg b/art/message_bubble_received_obsidian.svg new file mode 100644 index 0000000000..a1e7437330 --- /dev/null +++ b/art/message_bubble_received_obsidian.svg @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/art/message_bubble_received_warning.svg b/art/message_bubble_received_warning.svg new file mode 100644 index 0000000000..765ca70419 --- /dev/null +++ b/art/message_bubble_received_warning.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/art/message_bubble_received_white.svg b/art/message_bubble_received_white.svg new file mode 100644 index 0000000000..52e599f057 --- /dev/null +++ b/art/message_bubble_received_white.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/art/message_bubble_sent.svg b/art/message_bubble_sent.svg new file mode 100644 index 0000000000..90ad5091a0 --- /dev/null +++ b/art/message_bubble_sent.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/art/message_bubble_sent_grey.svg b/art/message_bubble_sent_grey.svg new file mode 100644 index 0000000000..23e13d665f --- /dev/null +++ b/art/message_bubble_sent_grey.svg @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/art/omemo_logo.svg b/art/omemo_logo.svg new file mode 100644 index 0000000000..ca20a5b945 --- /dev/null +++ b/art/omemo_logo.svg @@ -0,0 +1,273 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/art/open_pdf_black.svg b/art/open_pdf_black.svg new file mode 100644 index 0000000000..0fa22285ab --- /dev/null +++ b/art/open_pdf_black.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/open_pdf_white.svg b/art/open_pdf_white.svg new file mode 100644 index 0000000000..a307529bb5 --- /dev/null +++ b/art/open_pdf_white.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/art/play_gif_black.svg b/art/play_gif_black.svg new file mode 100644 index 0000000000..a2b426a240 --- /dev/null +++ b/art/play_gif_black.svg @@ -0,0 +1,68 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/art/play_gif_white.svg b/art/play_gif_white.svg new file mode 100644 index 0000000000..f8ec27426e --- /dev/null +++ b/art/play_gif_white.svg @@ -0,0 +1,68 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/art/play_video_black.svg b/art/play_video_black.svg new file mode 100644 index 0000000000..72d6e756ff --- /dev/null +++ b/art/play_video_black.svg @@ -0,0 +1,59 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/art/play_video_white.svg b/art/play_video_white.svg new file mode 100644 index 0000000000..c8a1558ba3 --- /dev/null +++ b/art/play_video_white.svg @@ -0,0 +1,59 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/art/qrcode-scan.svg b/art/qrcode-scan.svg new file mode 100644 index 0000000000..63f1f6a158 --- /dev/null +++ b/art/qrcode-scan.svg @@ -0,0 +1,48 @@ + +image/svg+xml \ No newline at end of file diff --git a/art/quicksy.svg b/art/quicksy.svg new file mode 100644 index 0000000000..e70bf4f01b --- /dev/null +++ b/art/quicksy.svg @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/art/quicksy_main_logo.svg b/art/quicksy_main_logo.svg new file mode 120000 index 0000000000..6fce608d91 --- /dev/null +++ b/art/quicksy_main_logo.svg @@ -0,0 +1 @@ +quicksy.svg \ No newline at end of file diff --git a/art/quicksy_mono.svg b/art/quicksy_mono.svg new file mode 100644 index 0000000000..8ca8d3e475 --- /dev/null +++ b/art/quicksy_mono.svg @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/art/quicksy_splash_logo.svg b/art/quicksy_splash_logo.svg new file mode 120000 index 0000000000..6fce608d91 --- /dev/null +++ b/art/quicksy_splash_logo.svg @@ -0,0 +1 @@ +quicksy.svg \ No newline at end of file diff --git a/art/render.rb b/art/render.rb new file mode 100755 index 0000000000..59cd7b1562 --- /dev/null +++ b/art/render.rb @@ -0,0 +1,157 @@ +#!/bin/env ruby +# frozen_string_literal: true + +require 'xml' + +resolutions = { + 'mdpi' => 1, + 'hdpi' => 1.5, + 'xhdpi' => 2, + 'xxhdpi' => 3, + 'xxxhdpi' => 4 +} + +images = { + 'main_logo.svg' => ['conversations/main_logo', 200], + 'quicksy_main_logo.svg' => ['quicksy/main_logo', 200], + 'splash_logo.svg' => ['conversations/splash_logo', 144], + 'quicksy_splash_logo.svg' => ['quicksy/splash_logo', 144], + 'ic_search_black.svg' => ['ic_search_background_black', 144], + 'ic_search_white.svg' => ['ic_search_background_white', 144], + 'ic_no_results_white.svg' => ['ic_no_results_background_white', 144], + 'ic_no_results_black.svg' => ['ic_no_results_background_black', 144], + 'play_video_white.svg' => ['play_video_white', 128], + 'play_gif_white.svg' => ['play_gif_white', 128], + 'play_video_black.svg' => ['play_video_black', 128], + 'play_gif_black.svg' => ['play_gif_black', 128], + 'open_pdf_black.svg' => ['open_pdf_black', 128], + 'open_pdf_white.svg' => ['open_pdf_white', 128], + 'conversations_mono.svg' => ['conversations/ic_notification', 24], + 'quicksy_mono.svg' => ['quicksy/ic_notification', 24], + 'flip_camera_android-black-24dp.svg' => ['ic_flip_camera_android_black_24dp', 24], + 'ic_send_text_offline.svg' => ['ic_send_text_offline', 36], + 'ic_send_text_offline_white.svg' => ['ic_send_text_offline_white', 36], + 'ic_send_text_online.svg' => ['ic_send_text_online', 36], + 'ic_send_text_away.svg' => ['ic_send_text_away', 36], + 'ic_send_text_dnd.svg' => ['ic_send_text_dnd', 36], + 'ic_send_photo_online.svg' => ['ic_send_photo_online', 36], + 'ic_send_photo_offline.svg' => ['ic_send_photo_offline', 36], + 'ic_send_photo_offline_white.svg' => ['ic_send_photo_offline_white', 36], + 'ic_send_photo_away.svg' => ['ic_send_photo_away', 36], + 'ic_send_photo_dnd.svg' => ['ic_send_photo_dnd', 36], + 'ic_send_location_online.svg' => ['ic_send_location_online', 36], + 'ic_send_location_offline.svg' => ['ic_send_location_offline', 36], + 'ic_send_location_offline_white.svg' => ['ic_send_location_offline_white', 36], + 'ic_send_location_away.svg' => ['ic_send_location_away', 36], + 'ic_send_location_dnd.svg' => ['ic_send_location_dnd', 36], + 'ic_send_voice_online.svg' => ['ic_send_voice_online', 36], + 'ic_send_voice_offline.svg' => ['ic_send_voice_offline', 36], + 'ic_send_voice_offline_white.svg' => ['ic_send_voice_offline_white', 36], + 'ic_send_voice_away.svg' => ['ic_send_voice_away', 36], + 'ic_send_voice_dnd.svg' => ['ic_send_voice_dnd', 36], + 'ic_send_cancel_online.svg' => ['ic_send_cancel_online', 36], + 'ic_send_cancel_offline.svg' => ['ic_send_cancel_offline', 36], + 'ic_send_cancel_offline_white.svg' => ['ic_send_cancel_offline_white', 36], + 'ic_send_cancel_away.svg' => ['ic_send_cancel_away', 36], + 'ic_send_cancel_dnd.svg' => ['ic_send_cancel_dnd', 36], + 'ic_send_picture_online.svg' => ['ic_send_picture_online', 36], + 'ic_send_picture_offline.svg' => ['ic_send_picture_offline', 36], + 'ic_send_picture_offline_white.svg' => ['ic_send_picture_offline_white', 36], + 'ic_send_picture_away.svg' => ['ic_send_picture_away', 36], + 'ic_send_picture_dnd.svg' => ['ic_send_picture_dnd', 36], + 'ic_send_videocam_online.svg' => ['ic_send_videocam_online', 36], + 'ic_send_videocam_offline.svg' => ['ic_send_videocam_offline', 36], + 'ic_send_videocam_offline_white.svg' => ['ic_send_videocam_offline_white', 36], + 'ic_send_videocam_away.svg' => ['ic_send_videocam_away', 36], + 'ic_send_videocam_dnd.svg' => ['ic_send_videocam_dnd', 36], + 'ic_notifications_none_white80.svg' => ['ic_notifications_none_white80', 24], + 'ic_notifications_off_white80.svg' => ['ic_notifications_off_white80', 24], + 'ic_notifications_paused_white80.svg' => ['ic_notifications_paused_white80', 24], + 'ic_notifications_white80.svg' => ['ic_notifications_white80', 24], + 'ic_verified_fingerprint.svg' => ['ic_verified_fingerprint', 36], + 'qrcode-scan.svg' => ['ic_qr_code_scan_white_24dp', 24], + 'message_bubble_received.svg' => ['message_bubble_received.9', 0], + 'message_bubble_received_grey.svg' => ['message_bubble_received_grey.9', 0], + 'message_bubble_received_dark.svg' => ['message_bubble_received_dark.9', 0], + 'message_bubble_received_warning.svg' => ['message_bubble_received_warning.9', 0], + 'message_bubble_received_white.svg' => ['message_bubble_received_white.9', 0], + 'message_bubble_sent.svg' => ['message_bubble_sent.9', 0], + 'message_bubble_sent_grey.svg' => ['message_bubble_sent_grey.9', 0], + 'date_bubble_white.svg' => ['date_bubble_white.9', 0], + 'date_bubble_grey.svg' => ['date_bubble_grey.9', 0], + 'marker.svg' => ['marker', 0] +} + +inkscape = 'inkscape' +imagemagick = 'convert' + +def execute_cmd(cmd) + puts cmd + system cmd +end + +images.each do |source_filename, settings| + svg_content = File.read(source_filename) + output_filename, base_size = settings + + svg = XML::Document.string(svg_content) + base_width = svg.root['width'].to_i + base_height = svg.root['height'].to_i + + guides = svg.find('.//sodipodi:guide', 'sodipodi:http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd') + + resolutions.each do |resolution, factor| + if base_size.positive? + width = factor * base_size + height = factor * base_size + else + width = factor * base_width + height = factor * base_height + end + + output_parts = output_filename.split('/') + + path = if output_parts.count != 2 + "../src/main/res/drawable-#{resolution}/#{output_filename}.png" + else + "../src/#{output_parts[0]}/res/drawable-#{resolution}/#{output_parts[1]}.png" + end + execute_cmd "#{inkscape} #{source_filename} -C -w #{width.to_i} -h #{height.to_i} --export-filename=#{path}" + + top = [] + right = [] + bottom = [] + left = [] + + guides.each do |guide| + orientation = guide['orientation'] + x, y = guide['position'].split(',') + x = x.to_i + y = y.to_i + + top.push(x * factor) if (orientation == '1,0') && (y == base_height) + + right.push((base_height - y) * factor) if (orientation == '0,1') && (x == base_width) + + bottom.push(x * factor) if (orientation == '1,0') && y.zero? + + left.push((base_height - y) * factor) if (orientation == '0,1') && x.zero? + end + + next if top.length != 2 + next if right.length != 2 + next if bottom.length != 2 + next if left.length != 2 + + execute_cmd "#{imagemagick} -background none PNG32:#{path} -gravity center -extent #{width + 2}x#{height + 2} PNG32:#{path}" + + draw_format = '-draw "line %d,%d %d,%d"' + top_line = format(draw_format, top.min + 1, 0, top.max, 0) + right_line = format(draw_format, width + 1, right.min + 1, width + 1, right.max) + bottom_line = format(draw_format, bottom.min + 1, height + 1, bottom.max, height + 1) + left_line = format(draw_format, 0, left.min + 1, 0, left.max) + draws = "#{top_line} #{right_line} #{bottom_line} #{left_line}" + + execute_cmd "#{imagemagick} -background none PNG32:#{path} -fill black -stroke none #{draws} PNG32:#{path}" + end +end diff --git a/art/splash_logo.svg b/art/splash_logo.svg new file mode 120000 index 0000000000..e62f735a00 --- /dev/null +++ b/art/splash_logo.svg @@ -0,0 +1 @@ +ic_launcher.svg \ No newline at end of file diff --git a/build.gradle b/build.gradle index 564eda7e7a..1a63bc19e7 100644 --- a/build.gradle +++ b/build.gradle @@ -6,130 +6,121 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.5.2' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.10" - classpath "com.diffplug.spotless:spotless-plugin-gradle:6.23.3" - classpath 'com.novoda:bintray-release:0.8.0' + classpath 'com.android.tools.build:gradle:8.3.2' } } plugins { id 'org.ajoberstar.grgit' version '4.1.1' + // PLUGIN INSERT } apply plugin: 'com.android.application' -apply plugin: "com.diffplug.spotless" - -allprojects { - repositories { - google() - mavenCentral() - maven { url "https://jitpack.io" } - } -} repositories { google() mavenCentral() - maven { url "https://jitpack.io" } + maven { url='https://jitpack.io'} } +def tags = grgit.tag.list().findAll { it.dateTime != null }.sort { it.dateTime } + +// ROOT INSERT + configurations { playstoreImplementation - gitImplementation - implementation.exclude group: 'org.jetbrains' , module:'annotations' + freeImplementation + conversationsFreeImplementation + monocleschatPlaystoreImplementation + conversationsPlaystoreImplementation + quicksyPlaystoreImplementation + quicksyPlaystoreImplementation + quicksyFreeImplementation + quicksyImplementation } dependencies { - constraints { - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0") { - because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib") - } - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { - because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") - } - } + androidTestImplementation 'tools.fastlane:screengrab:2.1.1' + androidTestImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test:runner:1.3.0' + androidTestImplementation 'androidx.test:rules:1.3.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + + implementation "androidx.core:core:1.10.1" + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' - implementation "androidx.core:core:1.13.1" implementation 'androidx.viewpager:viewpager:1.0.0' - playstoreImplementation('com.google.firebase:firebase-messaging:24.0.1') { + playstoreImplementation('com.google.firebase:firebase-messaging:23.4.1') { exclude group: 'com.google.firebase', module: 'firebase-core' exclude group: 'com.google.firebase', module: 'firebase-analytics' exclude group: 'com.google.firebase', module: 'firebase-measurement-connector' } - playstoreImplementation 'com.android.installreferrer:installreferrer:2.2' + monocleschatPlaystoreImplementation("com.android.installreferrer:installreferrer:2.2") + monocleschatPlaystoreImplementation 'com.github.singpolyma:play-licensing:1c637ea03c' + conversationsPlaystoreImplementation("com.android.installreferrer:installreferrer:2.2") + quicksyPlaystoreImplementation 'com.google.android.gms:play-services-auth-api-phone:18.0.2' implementation 'com.github.open-keychain.open-keychain:openpgp-api:v5.7.1' implementation("com.github.CanHub:Android-Image-Cropper:2.0.0") - implementation 'im.conversations.webrtc:webrtc-android:119.0.1' - implementation 'org.jitsi:org.otr4j:0.23' - implementation 'org.bouncycastle:bcmail-jdk18on:1.78.1' - implementation 'org.gnu.inet:libidn:1.15' - implementation 'com.google.zxing:core:3.5.0' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.exifinterface:exifinterface:1.3.7' + implementation 'androidx.cardview:cardview:1.0.0' + implementation "androidx.preference:preference:1.2.1" + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' + implementation 'com.google.android.material:material:1.11.0' + implementation 'androidx.work:work-runtime:2.9.0' + + implementation "androidx.emoji2:emoji2:1.4.0" + freeImplementation "androidx.emoji2:emoji2-bundled:1.4.0" + + implementation 'org.bouncycastle:bcmail-jdk15on:1.64' + //zxing stopped supporting Java 7 so we have to stick with 3.3.3 + //https://github.com/zxing/zxing/issues/1170 + implementation 'com.google.zxing:core:3.3.3' implementation 'org.minidns:minidns-hla:1.0.5' implementation 'me.leolin:ShortcutBadger:1.1.22@aar' - implementation 'org.whispersystems:signal-protocol-android:2.6.2' - implementation 'com.google.code.gson:gson:2.10.1' - implementation 'androidx.multidex:multidex:2.0.1' - implementation 'androidx.legacy:legacy-support-v13:1.0.0' - implementation 'androidx.appcompat:appcompat:1.7.0' - implementation 'androidx.exifinterface:exifinterface:1.3.7' - implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.emoji2:emoji2:1.4.0' - gitImplementation "androidx.emoji2:emoji2-bundled:1.4.0" - implementation 'androidx.recyclerview:recyclerview:1.3.2' - implementation 'com.google.android.material:material:1.12.0' - implementation 'androidx.cardview:cardview:1.0.0' // for compatibility - implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0' - implementation 'com.google.android.exoplayer:exoplayer-core:2.19.1' - implementation 'com.google.android.exoplayer:exoplayer-ui:2.19.1' - implementation 'com.google.android.exoplayer:extension-mediasession:2.19.1' - implementation 'pub.devrel:easypermissions:3.0.0' // version >= 3.0.0 needs android X libraries - implementation 'com.wefika:flowlayout:0.4.1' - implementation 'com.googlecode.ez-vcard:ez-vcard:0.11.3' - implementation 'org.jxmpp:jxmpp-jid:1.0.3' - implementation 'org.hsluv:hsluv:0.2' - implementation 'com.github.martin-stone:hsv-alpha-color-picker-android:2.4.2' - implementation 'org.conscrypt:conscrypt-android:2.5.2' - implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.25' - implementation 'me.drakeet.support:toastcompat:1.1.0' - implementation 'org.osmdroid:osmdroid-android:6.1.16' - implementation 'com.leinardi.android:speed-dial:3.3.0' - implementation "com.squareup.okhttp3:okhttp:4.12.0" - implementation 'com.squareup.retrofit2:retrofit:2.11.0' - implementation 'com.squareup.retrofit2:converter-gson:2.11.0' - implementation 'com.google.guava:guava:32.1.3-android' - implementation 'com.github.AppIntro:AppIntro:6.2.0' - implementation 'androidx.browser:browser:1.8.0' + implementation 'org.whispersystems:signal-protocol-java:2.6.2' + implementation "com.wefika:flowlayout:0.4.1" + //noinspection GradleDependency implementation('com.github.natario1:Transcoder:v0.9.1') { exclude group: 'com.otaliastudios.opengl', module: 'egloo' } implementation 'com.github.natario1:Egloo:v0.4.0' - implementation 'com.github.singpolyma:Better-Link-Movement-Method:4df081e1e4' - implementation project(':libs:AXML') - implementation 'com.github.ipld:java-cid:v1.3.1' - implementation 'com.github.woltapp:blurhash:master' - implementation 'org.tomlj:tomlj:1.1.0' - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' + + implementation 'org.jxmpp:jxmpp-jid:1.0.3' + implementation 'org.jxmpp:jxmpp-stringprep-libidn:1.0.3' + implementation 'org.osmdroid:osmdroid-android:6.1.11' + implementation 'org.hsluv:hsluv:0.2' + implementation 'org.conscrypt:conscrypt-android:2.5.2' + implementation 'me.drakeet.support:toastcompat:1.1.0' + implementation "com.leinardi.android:speed-dial:3.3.0" + + implementation "com.squareup.retrofit2:retrofit:2.9.0" + implementation "com.squareup.retrofit2:converter-gson:2.9.0" + implementation "com.squareup.okhttp3:okhttp:4.12.0" + + implementation 'com.google.guava:guava:32.1.3-android' implementation 'io.michaelrocks:libphonenumber-android:8.13.28' + implementation 'im.conversations.webrtc:webrtc-android:119.0.1' implementation 'io.github.nishkarsh:android-permissions:2.1.6' + implementation 'androidx.recyclerview:recyclerview:1.1.0' + implementation 'androidx.documentfile:documentfile:1.0.1' + implementation 'androidx.browser:browser:1.8.0' + implementation 'com.github.martin-stone:hsv-alpha-color-picker-android:3.1.0' + implementation 'com.github.ipld:java-cid:v1.3.1' + //implementation 'com.splitwise:tokenautocomplete:3.0.2' implementation 'com.github.singpolyma:TokenAutoComplete:bfa93780e0' + implementation 'com.github.singpolyma:Better-Link-Movement-Method:4df081e1e4' implementation 'com.github.singpolyma:android-identicons:3361281bd4' implementation 'com.github.woltapp:blurhash:master' - implementation 'androidx.documentfile:documentfile:1.0.1' implementation 'com.caverock:androidsvg-aar:1.4' implementation 'org.tomlj:tomlj:1.1.0' - implementation 'org.jxmpp:jxmpp-stringprep-libidn:1.0.3' implementation 'com.tbuonomo:dotsindicator:4.2' - implementation "com.daimajia.swipelayout:library:1.2.0@aar" - implementation 'com.nineoldandroids:library:2.4.0' - implementation "androidx.core:core-ktx:1.13.1" - implementation "androidx.compose.material3:material3-android:1.2.1" - implementation "androidx.emoji2:emoji2-emojipicker:1.4.0" implementation 'com.github.Priyansh-Kedia:OpenGraphParser:2.5.6' - implementation 'com.github.bumptech.glide:glide:4.16.0' implementation 'me.xdrop:fuzzywuzzy:1.4.0' + implementation 'net.fellbaum:jemoji:1.4.1' } ext { @@ -137,54 +128,38 @@ ext { abiCodes = ['armeabi-v7a': 1, 'x86': 2, 'x86_64': 3, 'arm64-v8a': 4] } - - -def tags = grgit.tag.list().findAll { it.dateTime != null }.sort { it.dateTime } - android { namespace 'eu.siacs.conversations' - //noinspection GradleCompatible compileSdk 34 defaultConfig { minSdkVersion 23 targetSdkVersion 34 - - // versionNameSuffix " -beta_(2023-10-26)" // " beta_(XXXX-XX-XX)" // activate for beta versions - versionCode 174 - versionName "1.7.11" - //resConfigs "en" - - archivesBaseName += "-$versionName" - // archivesBaseName += "$versionNameSuffix" // activate for beta versions - applicationId "de.monocles.chat" - multiDexEnabled true - //versionName grgit.describe(always: true) - buildConfigField("String", "LOGTAG", '"monocles chat"') - buildConfigField("String", "DOMAIN_LOCK", 'null') - buildConfigField("String", "MAGIC_CREATE_DOMAIN", '"monocles.eu"') - buildConfigField("boolean", "SHOW_INTRO", 'true') - buildConfigField("String", "UPDATE_URL", '"https://monocles.eu/chat/update/"') - resValue "string", "applicationId", applicationId - resValue "string", "app_name", "monocles chat" - resValue "string", "short_app_name", "chat" + versionCode 42025 + tags.size() + versionName grgit.describe(always: true) + applicationId "eu.siacs.conversations" + def appName = "Conversations" + resValue "string", "app_name", appName + buildConfigField "String", "APP_NAME", "\"$appName\""; + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } + splits { abi { universalApk true enable true reset() + //noinspection ChromeOsAbiSupport include project.ext.abiCodes.keySet() as String[] } } - dataBinding { - enabled true + + configurations { + implementation.exclude group: 'org.jetbrains' , module:'annotations' } - packagingOptions { - resources { - excludes += ['META-INF/BCKEY.DSA', 'META-INF/BCKEY.SF', 'META-INF/versions/9/OSGI-INF/MANIFEST.MF'] - } + dataBinding { + enabled true } compileOptions { @@ -193,53 +168,119 @@ android { targetCompatibility JavaVersion.VERSION_17 } - flavorDimensions("distribution") + flavorDimensions += "mode" + flavorDimensions += "distribution" productFlavors { + + quicksy { + dimension "mode" + applicationId = "im.quicksy.client" + + def appName = "Quicksy" + resValue "string", "app_name", appName + buildConfigField "String", "APP_NAME", "\"$appName\"" + buildConfigField "String", "PRIVACY_POLICY", "\"https://quicksy.im/privacy.htm\"" + } + + conversations { + dimension "mode" + buildConfigField "String", "PRIVACY_POLICY", "\"https://conversations.im/privacy.html\"" + } + + monocleschat { + dimension "mode" + + applicationId = "de.monocles.chat" + + def appName = "monocles chat" + resValue "string", "app_name", appName + buildConfigField "String", "APP_NAME", "\"$appName\""; + buildConfigField "String", "PRIVACY_POLICY", "\"https://monocles.eu/legal-privacy/#policies-section\"" + } + playstore { dimension "distribution" - versionNameSuffix "-playstore" - applicationId "de.monocles.chat" - buildConfigField("boolean", "SHOW_MIGRATION_INFO", 'false') - resValue "string", "applicationId", applicationId + versionNameSuffix "+playstore" + applicationIdSuffix "playstore" } - git { + free { dimension "distribution" - buildConfigField("boolean", "SHOW_MIGRATION_INFO", 'true') + versionNameSuffix "+free" } } - if (project.hasProperty('mStoreFile') && - project.hasProperty('mStorePassword') && - project.hasProperty('mKeyAlias') && - project.hasProperty('mKeyPassword')) { + + applicationVariants.all { variant -> + variant.resValue "string", "applicationId", applicationId + } + + sourceSets { + quicksyFree { + java { + srcDir 'src/quicksyFree/java' + } + } + quicksyPlaystore { + java { + srcDir 'src/quicksyPlaystore/java' + } + res { + srcDir 'src/quicksyPlaystore/res' + } + } + conversationsFree { + java { + srcDir 'src/conversationsFree/java' + } + } + monocleschatFree { + java { + srcDir 'src/conversationsFree/java' + } + } + conversationsPlaystore { + java { + srcDir 'src/conversationsPlaystore/java' + } + res { + srcDir 'src/conversationsPlaystore/res' + } + } + } + + buildTypes { + release { + shrinkResources true + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + ndk.debugSymbolLevel = 'full' + } + debug { + shrinkResources true + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + + if (new File("signing.properties").exists()) { + Properties props = new Properties() + props.load(new FileInputStream(file("signing.properties"))) + signingConfigs { release { - storeFile file(mStoreFile) - storePassword mStorePassword - keyAlias mKeyAlias - keyPassword mKeyPassword + storeFile file(props['keystore']) + storePassword props['keystore.password'] + keyAlias props['keystore.alias'] + keyPassword props['keystore.password'] } } - buildTypes { - release { - debuggable false - signingConfig = signingConfigs.release - minifyEnabled true - shrinkResources true - runProguard true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } + buildTypes.release.signingConfig = signingConfigs.release + } - debug { - debuggable true - signingConfig null - minifyEnabled true - shrinkResources true - runProguard true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - - } + lintOptions { + disable 'MissingTranslation', 'InvalidPackage','AppCompatResource' + abortOnError false } subprojects { @@ -250,29 +291,31 @@ android { configure(android.lintOptions) { disable 'AndroidGradlePluginVersion', 'MissingTranslation' + abortOnError false } } } } - + packagingOptions { + resources { + excludes += ['META-INF/BCKEY.DSA', 'META-INF/BCKEY.SF'] + } + } lint { - abortOnError false - checkReleaseBuilds true - disable 'ExtraTranslation', 'MissingTranslation', 'InvalidPackage', 'MissingQuantity', 'AppCompatResource', 'RestrictedApi' - error 'StringFormatInvalid', 'StringFormatMatches' + disable 'MissingTranslation', 'InvalidPackage', 'AppCompatResource' } buildFeatures { buildConfig true - viewBinding true } - android.applicationVariants.all { variant -> + + android.applicationVariants.configureEach { variant -> variant.outputs.each { output -> def baseAbiVersionCode = project.ext.abiCodes.get(output.getFilter(com.android.build.OutputFile.ABI)) if (baseAbiVersionCode != null) { output.versionCodeOverride = (100 * project.android.defaultConfig.versionCode) + baseAbiVersionCode } else { - //output.versionCodeOverride = (100 * project.android.defaultConfig.versionCode) + grgit.log(includes: ["HEAD"], excludes: [tags.last()]).size() + output.versionCodeOverride = (100 * project.android.defaultConfig.versionCode) + grgit.log(includes: ["HEAD"], excludes: [tags.last()]).size() } } diff --git a/crowdin.yml b/crowdin.yml deleted file mode 100644 index 4602c94261..0000000000 --- a/crowdin.yml +++ /dev/null @@ -1,6 +0,0 @@ -files: - - source: /src/main/res/values/strings.xml - translation: /src/main/res/values-%two_letters_code%/strings.xml - translate_content: '0' - translate_attributes: '0' - content_segmentation: '0' diff --git a/docs/MISSION.md b/docs/MISSION.md deleted file mode 100644 index 1fe8915b84..0000000000 --- a/docs/MISSION.md +++ /dev/null @@ -1,25 +0,0 @@ -Conversations is a chat for the next decade. Based on already established -internet standards that have been around for over ten years Conversations isn’t -trying to replace current commercial chats. It will simply outlive them. -Commercial, closed source products are coming and going. 15 years ago we had ICQ -which was replaced by Skype. MySpace was replaced by Facebook. WhatsApp and -Hangouts will disappear soon. Internet standards however stick around. People -are still using IRC and e-mail even though these protocols have been around for -decades. Utilizing proven standards doesn’t mean one can not evolve. GMail has -revolutionized the way we look at e-mail. Firefox and Chrome have changed the -way we use the Web. Conversations will change the way we look at instant -messaging. Being less obtrusive than a telephone call instant messaging has -always played an important role in modern society. Conversations will show that -instant messaging can be fast, reliable and private. Conversations will not -force its security and privacy aspects upon the user. For those willing to use -encryption Conversations will make it as uncomplicated as possible. However -Conversations is aware that end-to-end encryption by the very principle isn’t -trivial. Instead of trying the impossible and making encryption easier than -comparing a fingerprint Conversations will try to educate the willing user and -explain the necessary steps and the reasons behind them. Those unwilling to -learn about encryption will still be protected by the design principals of -Conversations. Conversations will simply not share or generate certain -information for example by encouraging the use of federated servers. -Conversations will always utilize the best available standards for encryption -and media encoding instead of reinventing the wheel. However it isn’t afraid to -break with behavior patterns that have been proven ineffective. diff --git a/docs/XEPs.md b/docs/XEPs.md deleted file mode 100644 index 19aa9b64e6..0000000000 --- a/docs/XEPs.md +++ /dev/null @@ -1,32 +0,0 @@ -* XEP-0027: Current Jabber OpenPGP Usage -* XEP-0030: Service Discovery -* XEP-0045: Multi-User Chat -* XEP-0048: Bookmarks -* XEP-0084: User Avatar -* XEP-0085: Chat State Notifications -* XEP-0092: Software Version -* XEP-0115: Entity Capabilities -* XEP-0163: Personal Eventing Protocol (avatars and nicks) -* XEP-0166: Jingle (only used for file transfer) -* XEP-0172: User Nickname -* XEP-0184: Message Delivery Receipts (reply only) -* XEP-0191: Blocking command -* XEP-0198: Stream Management -* XEP-0199: XMPP Ping -* XEP-0234: Jingle File Transfer -* XEP-0237: Roster Versioning -* XEP-0245: The /me Command -* XEP-0249: Direct MUC Invitations (receiving only) -* XEP-0260: Jingle SOCKS5 Bytestreams Transport Method -* XEP-0261: Jingle In-Band Bytestreams Transport Method -* XEP-0280: Message Carbons -* XEP-0308: Last Message Correction -* XEP-0313: Message Archive Management -* XEP-0319: Last User Interaction in Presence -* XEP-0333: Chat Markers -* XEP-0352: Client State Indication -* XEP-0357: Push Notifications -* XEP-0363: HTTP File Upload -* XEP-0368: SRV records for XMPP over TLS -* XEP-0377: Spam Reporting -* XEP-0384: OMEMO Encryption diff --git a/docs/encryption.md b/docs/encryption.md deleted file mode 100644 index 8557779e12..0000000000 --- a/docs/encryption.md +++ /dev/null @@ -1,18 +0,0 @@ -Dear users, - -Monocles Messenger will remove the implementation of OTR encryption by 30th June of 2020 with version 1.0 - -Unfortunately, it does not make sense to continue support on a rather out-dated technology, even as we see some users keep using it. For the moment, OTR (as well as OpenPGP) can be activated via the expert settings for advanced users. Monocles Messenger always tries to be usable for even [non-technical users](https://github.com/kriztan/Monocles-Messenger/issues/227), OTR however is not counted as appropriate for this. - -Please consider to use OMEMO in the future, many other clients has implemented this, have a look at [omemo.top](https://omemo.top/). However, if you really need to continue using it, please refer to e.g. [Miranda](https://www.miranda-ng.org/de/), [Pidgin plugin](https://github.com/gkdr/lurch/), [Profanity](https://profanity-im.github.io/) or [Coy.im](https://coy.im/). You are also able to fork Monocles Messenger and continue the implementation on your own. - -Please consider the differences between encryption protocols and also advantages of OMEMO: - - -Source: [https://conversations.im/omemo](https://conversations.im/omemo) - -Some limitations of OTR: [wikipedia.org/wiki/Off-the-Record](https://en.wikipedia.org/wiki/Off-the-Record_Messaging#Limitations) - -Please inform your contacts who may also use it. - -Mastodon: https://monocles.social/@monocles diff --git a/docs/observations.md b/docs/observations.md deleted file mode 100644 index 71502424c7..0000000000 --- a/docs/observations.md +++ /dev/null @@ -1,97 +0,0 @@ -Observations on implementing XMPP -================================= -After spending the last two and a half month basically writing my own XMPP -library from scratch I decided to share some of the observations I made in the -process. In part this article can be seen as a response to a blog post made by -Dr. Ing. Georg Lukas. The blog post introduces a couple of XEP (XMPP Extensions) -which make the life on mobile devices a lot easier but states that they are -currently very few implementations of those XEPs. So I went ahead and -implemented all of them in my Android XMPP client. - -###General observations -The first thing I noticed is that XMPP is actually okish designed. If you were -to design a new chat protocol today you probably wouldn’t choose XML again -however the protocol basically consists of only three different packages which -are quickly hidden under some sort of abstraction layer within your library. -Getting from zero to sending messages to other users actually was very simple -and straight forward. But then came the XEPs. - -###Multi-User Chat -The first one was XEP-0045 Multi-User Chat. This is the one XEP of the XEPs I’m -going to mention in my article which is actually wildly adopted. Most clients -and servers I know of support MUC. However the level of completeness varies. -MUC actually introduces access and permission roles which are far more complex -than what some of us are used to from IRC but a lot of clients just don’t -implement them. I’m not implementing them myself (at least for now) because I -somewhat doubt that someone would actually use them (however this might be some -sort of chicken or egg problem). I did find some strange bugs though which might -be interesting for other library developers. In theory a MUC server -implementation can allow a single user (same jid) to join a conference room -multiple times with the same nick from different clients. This means if someone -wants to participate in a conference from two different devices (mobile and -desktop for example) one wouldn’t have to name oneself `userDesktop` and -`userMobile` but just `user`. Both ejabberd and prosody support this but with -strange side effects. Prosody for example doesn’t allow a user to change its -name once two clients are “merged” by having the same nick. - -###Carbons and Stream Management -Two of the other XEPs Lukas mentions — Carbons (XEP-0280) and Stream Management -(XEP-0198) — were actually fairly easy to implement. The only challenges were to -find a server to support them (I ended up running my own Prosody server) and a -desktop client to test them with. For carbons there is a patched Mcabber version -and Gajim. After implementing stream management I had very good results on my -mobile device. I had sessions running for up to 24 hours with a walking outside, -loosing mobile coverage for a few minutes and so on. The only limitation was -that I had to keep on developing and reinstalling my app. - -###Off the record -And then came OTR... This is were I spend the most time debugging stuff and -trying to get things right and compatible with other clients. This is the part -were I want to help other developers not to make the same mistakes and maybe -come to some sort of consent among XMPP developers to ultimately increase the -interoperability. OTR has some down sides which make it difficult or at times -even dangerous to implement within XMPP. First of all it is a synchronous -protocol which is tunneled through a different protocol (XMPP). Synchronous -means — among other things — auto replies. (An OTR session begins with “hi I’m -speaking otr give me your key” “ok cool here is my key”) And auto replies — we -know that since the first time an out of office auto responder went postal — are -dangerous. Things really start to get messy when you use one of the best -features of XMPP — multiple clients. The way XMPP works is that clients are -encouraged to send their messages to the raw jid and let the server decide what -full jid the messages are routed to. If in doubt even all of them. So what -happens when Alice sends a start-otr-message to Bobs raw jid? Bob receives the -message on his notebook as well as his cell phone. Both of them answer. Alice -gets two different replies. Shit explodes. Even if Alice sends the message to -bob/notebook chances are that Bob has carbon messages enabled and still receives -the messages on both devices. Now assuming that Bobs client is clever enough not -to auto reply to carbonated messages Bob/cellphone will still end up with a lot -of garbage messages. (Essentially the entire conversation between Alice and -Bob/notebook but unreadable of course) Therefor it should be good practice to -tag OTR messages as both private and no-copy (private is part of the carbons -XEP, no-copy is a general hint). I found that prosody for some reasons doesn’t -honor the private tag on outgoing messages. While this is easily fixed I presume -that having both the private and the no-copy tag will make it more compatible -with servers or clients I don’t know about yet. - -####Rules to follow when implementing OTR -To summarize my observations on implementing OTR in XMPP let me make the -following three statements. - -1. While it is good practice for unencrypted messages to be send to the raw jid -and have the receiving server or user decide how they should be routed OTR -messages must be send to a specific resource. To make this work the user should -be given the option to select the presence (which can be assisted with some -educated guessing by the client based on previous messages). Furthermore a -client should encourage a user to choose meaningful presences instead of the -clients name or even random ones. Something like `/mobile`, `/notebook`, -`/desktop` is a greater assist to any one who wants to start an otr session then -`/Gajim`, `/mcabber` or `/pidgin`. - -2. Messages should be tagged private and no-copy to avoid unnecessary traffic or -otr error loops with faulty clients. This tagging should be done even if your -own client doesn’t support carbons. - -3. When dealing with “legacy clients” — meaning clients which don’t follow my -advise — a client should be extra careful not to create message loops. This -means to not respond with otr errors if a client is not 100% sure it is the only -client which received the message diff --git a/docs/user/backup.md b/docs/user/backup.md new file mode 100644 index 0000000000..4d81d8ddda --- /dev/null +++ b/docs/user/backup.md @@ -0,0 +1,19 @@ +# Making a backup of Conversations + +This tutorial explains how you can backup your Conversations data. + +**WARNING**: Do not use the restore backup feature in an attempt to clone (run simultaneously) an installation. Restoring a backup is only meant for migrations or in case you’ve lost the original device. + +1. Make sure that you know the password to your account(s)! You will need it later to decrypt your backup. +2. Deactivate all your account(s): on the chat screen, tap on the three buttons in the upper right, and go to "manage accounts". +3. Go back to Settings, scroll down until you find the option to create a new backup. Tap on that option. +4. Wait, until the notification tells you that the backup is finished. +5. Move the backup to whatever location you feel save with. + +Done! + +## Further information / troubleshooting +### Unable to decrypt +This backup method will include your OMEMO keys. Due to forward secrecy you will not be able to recover messages sent and received between creating the backup and restoring it. If you have a server side archive (MAM) those messages will be retrieved but displayed as *unable to decrypt*. For technical reasons you might also lose the first message you either sent or receive after the restore; for each conversation you have. This message will then also show up as *unable to decrypt*, but this will automatically recover itself as long as both participants are on Conversations 2.3.11+. Note that this doesn’t happen if you just transfer to a new phone and no messages have been exchanged between backup and restore. + +In the vast, vast majority of cases you won’t have to manually delete OMEMO keys or do anything like that. Conversations only introduced the official backup feature in 2.4.0 after making sure the *OMEMO self healing* mechanism introduced in 2.3.11 works fine. diff --git a/docs/user/migrating_to_new_device.md b/docs/user/migrating_to_new_device.md new file mode 100644 index 0000000000..e7d50a1ce3 --- /dev/null +++ b/docs/user/migrating_to_new_device.md @@ -0,0 +1,41 @@ +# Migrating to a new device + +This tutorial explains how you can transfer your Conversations data from an old to a new device. It assumes that you do not have Conversations installed on your new device, yet. It basically consists of three steps: + +1. Make a backup (old device) +2. Move that backup to your new device +3. Import the backup (new device) + +**WARNING**: Do not use the restore backup feature in an attempt to clone (run simultaneously) an installation. Restoring a backup is only meant for migrations or in case you’ve lost the original device. + +## 1. Make a backup (old device) +1. Make sure that you know the password to your account(s)! You will need it later to decrypt your backup. +2. Deactivate all your account(s): on the chat screen, tap on the three buttons in the upper right, and go to "manage accounts". +3. Go back to Settings, scroll down until you find the option to create a new backup. Tap on that option. +4. Wait, until the notification tells you that the backup is finished. + +## 2. Move that backup to your new device +1. Locate the backup. You should find it in your Files, either in *Conversations/Backup* or in *Download/Conversations/Backup*. The file is named after your account (*e.g. kim@example.org*). If you have multiple accounts, you find one file for each. +2. Use your USB cable or bluetooth, your Nextcloud or other cloud storage or pretty much anything you want to copy the backup from the old device to the new device. +3. Remember the location you saved your backup to. For instance, you might want to save them to the *Download* folder. + +## 3. Import the backup (new device) +1. Install Conversations on your new device. +2. Open Conversations for the first time. +3. Tap on the three dot menu in the upper right corner and tap on "Import backup" +4. If your backup files are not listed, tap on the cloud symbol in the upper right corner to choose the files from where you saved them. +5. Enter your account password to decrypt the backup. +6. Remember to activate your account (head back to "manage accounts", see step 1.2). +7. Check if chats work. + +Once confirmed that the new device is running fine you can just uninstall the app from the old device. + +Note: The backup only contains your text chats and required encryption keys, all the files need to be transferred separately and put on the new device in the same locations. + +Done! + +## Further information / troubleshooting +### Unable to decrypt +This backup method will include your OMEMO keys. Due to forward secrecy you will not be able to recover messages sent and received between creating the backup and restoring it. If you have a server side archive (MAM) those messages will be retrieved but displayed as *unable to decrypt*. For technical reasons you might also lose the first message you either sent or receive after the restore; for each conversation you have. This message will then also show up as *unable to decrypt*, but this will automatically recover itself as long as both participants are on Conversations 2.3.11+. Note that this doesn’t happen if you just transfer to a new phone and no messages have been exchanged between backup and restore. + +In the vast, vast majority of cases you won’t have to manually delete OMEMO keys or do anything like that. Conversations only introduced the official backup feature in 2.4.0 after making sure the *OMEMO self healing* mechanism introduced in 2.3.11 works fine. diff --git a/drawable/baseline_tour_black_48.png b/drawable/baseline_tour_black_48.png deleted file mode 100644 index 10e2511d15..0000000000 Binary files a/drawable/baseline_tour_black_48.png and /dev/null differ diff --git a/drawable/baseline_tour_white_48.png b/drawable/baseline_tour_white_48.png deleted file mode 100644 index d220b14475..0000000000 Binary files a/drawable/baseline_tour_white_48.png and /dev/null differ diff --git a/drawable/chat_graphic.svg b/drawable/chat_graphic.svg deleted file mode 100644 index f3f2c37514..0000000000 --- a/drawable/chat_graphic.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/drawable/ic_account_card_details_grey600_48dp.png b/drawable/ic_account_card_details_grey600_48dp.png deleted file mode 100644 index aa3f0faee3..0000000000 Binary files a/drawable/ic_account_card_details_grey600_48dp.png and /dev/null differ diff --git a/drawable/ic_account_multiple_plus_grey600_48dp.png b/drawable/ic_account_multiple_plus_grey600_48dp.png deleted file mode 100644 index bc1099bd27..0000000000 Binary files a/drawable/ic_account_multiple_plus_grey600_48dp.png and /dev/null differ diff --git a/drawable/ic_account_plus_grey600_48dp.png b/drawable/ic_account_plus_grey600_48dp.png deleted file mode 100644 index da2e9201d7..0000000000 Binary files a/drawable/ic_account_plus_grey600_48dp.png and /dev/null differ diff --git a/drawable/ic_action_chat.png b/drawable/ic_action_chat.png deleted file mode 100644 index c7109a2f16..0000000000 Binary files a/drawable/ic_action_chat.png and /dev/null differ diff --git a/drawable/ic_action_reply.png b/drawable/ic_action_reply.png deleted file mode 100644 index ce00dbc4b4..0000000000 Binary files a/drawable/ic_action_reply.png and /dev/null differ diff --git a/drawable/ic_add_white_24dp.png b/drawable/ic_add_white_24dp.png deleted file mode 100644 index c5d5ae2fed..0000000000 Binary files a/drawable/ic_add_white_24dp.png and /dev/null differ diff --git a/drawable/ic_android_black_48dp.png b/drawable/ic_android_black_48dp.png deleted file mode 100644 index 4f25964bed..0000000000 Binary files a/drawable/ic_android_black_48dp.png and /dev/null differ diff --git a/drawable/ic_android_grey600_48dp.png b/drawable/ic_android_grey600_48dp.png deleted file mode 100644 index 5040f8ef24..0000000000 Binary files a/drawable/ic_android_grey600_48dp.png and /dev/null differ diff --git a/drawable/ic_android_white_48dp.png b/drawable/ic_android_white_48dp.png deleted file mode 100644 index 032fe27811..0000000000 Binary files a/drawable/ic_android_white_48dp.png and /dev/null differ diff --git a/drawable/ic_archive_black_48dp.png b/drawable/ic_archive_black_48dp.png deleted file mode 100644 index e9d5ed1b4f..0000000000 Binary files a/drawable/ic_archive_black_48dp.png and /dev/null differ diff --git a/drawable/ic_archive_white_24dp.png b/drawable/ic_archive_white_24dp.png deleted file mode 100644 index 7944feb2a3..0000000000 Binary files a/drawable/ic_archive_white_24dp.png and /dev/null differ diff --git a/drawable/ic_archive_white_48dp.png b/drawable/ic_archive_white_48dp.png deleted file mode 100644 index 82be164074..0000000000 Binary files a/drawable/ic_archive_white_48dp.png and /dev/null differ diff --git a/drawable/ic_arrow_back_white_24dp.png b/drawable/ic_arrow_back_white_24dp.png deleted file mode 100644 index 4ef72eec99..0000000000 Binary files a/drawable/ic_arrow_back_white_24dp.png and /dev/null differ diff --git a/drawable/ic_attach_camera.png b/drawable/ic_attach_camera.png deleted file mode 100644 index 6e351cbfbc..0000000000 Binary files a/drawable/ic_attach_camera.png and /dev/null differ diff --git a/drawable/ic_attach_camera_white.png b/drawable/ic_attach_camera_white.png deleted file mode 100644 index 4786809533..0000000000 Binary files a/drawable/ic_attach_camera_white.png and /dev/null differ diff --git a/drawable/ic_attach_document.png b/drawable/ic_attach_document.png deleted file mode 100644 index 623de59699..0000000000 Binary files a/drawable/ic_attach_document.png and /dev/null differ diff --git a/drawable/ic_attach_document_white.png b/drawable/ic_attach_document_white.png deleted file mode 100644 index 4112e30f2d..0000000000 Binary files a/drawable/ic_attach_document_white.png and /dev/null differ diff --git a/drawable/ic_attach_file_white_24dp.png b/drawable/ic_attach_file_white_24dp.png deleted file mode 100644 index 0611da2b1a..0000000000 Binary files a/drawable/ic_attach_file_white_24dp.png and /dev/null differ diff --git a/drawable/ic_attach_location.png b/drawable/ic_attach_location.png deleted file mode 100644 index e6570e527d..0000000000 Binary files a/drawable/ic_attach_location.png and /dev/null differ diff --git a/drawable/ic_attach_location_white.png b/drawable/ic_attach_location_white.png deleted file mode 100644 index 43af9ad9e6..0000000000 Binary files a/drawable/ic_attach_location_white.png and /dev/null differ diff --git a/drawable/ic_attach_photo.png b/drawable/ic_attach_photo.png deleted file mode 100644 index fe4d3b2544..0000000000 Binary files a/drawable/ic_attach_photo.png and /dev/null differ diff --git a/drawable/ic_attach_photo_white.png b/drawable/ic_attach_photo_white.png deleted file mode 100644 index ae19aee6b7..0000000000 Binary files a/drawable/ic_attach_photo_white.png and /dev/null differ diff --git a/drawable/ic_attach_record.png b/drawable/ic_attach_record.png deleted file mode 100644 index 3aab59bd02..0000000000 Binary files a/drawable/ic_attach_record.png and /dev/null differ diff --git a/drawable/ic_attach_record_white.png b/drawable/ic_attach_record_white.png deleted file mode 100644 index 667061c21c..0000000000 Binary files a/drawable/ic_attach_record_white.png and /dev/null differ diff --git a/drawable/ic_attach_video.png b/drawable/ic_attach_video.png deleted file mode 100644 index 36581178c4..0000000000 Binary files a/drawable/ic_attach_video.png and /dev/null differ diff --git a/drawable/ic_attach_videocam.png b/drawable/ic_attach_videocam.png deleted file mode 100644 index 66aa2fe49c..0000000000 Binary files a/drawable/ic_attach_videocam.png and /dev/null differ diff --git a/drawable/ic_attach_videocam_white.png b/drawable/ic_attach_videocam_white.png deleted file mode 100644 index 3878cb8125..0000000000 Binary files a/drawable/ic_attach_videocam_white.png and /dev/null differ diff --git a/drawable/ic_attachment_black_24dp.png b/drawable/ic_attachment_black_24dp.png deleted file mode 100644 index b37e94a312..0000000000 Binary files a/drawable/ic_attachment_black_24dp.png and /dev/null differ diff --git a/drawable/ic_attachment_white_24dp.png b/drawable/ic_attachment_white_24dp.png deleted file mode 100644 index e6e585bab9..0000000000 Binary files a/drawable/ic_attachment_white_24dp.png and /dev/null differ diff --git a/drawable/ic_audio_grey600_48dp.png b/drawable/ic_audio_grey600_48dp.png deleted file mode 100644 index af727b96b3..0000000000 Binary files a/drawable/ic_audio_grey600_48dp.png and /dev/null differ diff --git a/drawable/ic_autorenew_white_24dp.png b/drawable/ic_autorenew_white_24dp.png deleted file mode 100644 index 29f643e12a..0000000000 Binary files a/drawable/ic_autorenew_white_24dp.png and /dev/null differ diff --git a/drawable/ic_backup_black_48dp.png b/drawable/ic_backup_black_48dp.png deleted file mode 100644 index f83b4a0749..0000000000 Binary files a/drawable/ic_backup_black_48dp.png and /dev/null differ diff --git a/drawable/ic_backup_white_48dp.png b/drawable/ic_backup_white_48dp.png deleted file mode 100644 index cc199bd789..0000000000 Binary files a/drawable/ic_backup_white_48dp.png and /dev/null differ diff --git a/drawable/ic_bluetooth_audio_black_24dp.png b/drawable/ic_bluetooth_audio_black_24dp.png deleted file mode 100644 index 5feb0c03a8..0000000000 Binary files a/drawable/ic_bluetooth_audio_black_24dp.png and /dev/null differ diff --git a/drawable/ic_book_black_48dp.png b/drawable/ic_book_black_48dp.png deleted file mode 100644 index 1cdaa97a2d..0000000000 Binary files a/drawable/ic_book_black_48dp.png and /dev/null differ diff --git a/drawable/ic_book_white_48dp.png b/drawable/ic_book_white_48dp.png deleted file mode 100644 index 0a1430a083..0000000000 Binary files a/drawable/ic_book_white_48dp.png and /dev/null differ diff --git a/drawable/ic_calendar_grey600_48dp.png b/drawable/ic_calendar_grey600_48dp.png deleted file mode 100644 index f02cc537bd..0000000000 Binary files a/drawable/ic_calendar_grey600_48dp.png and /dev/null differ diff --git a/drawable/ic_call_black_24dp.png b/drawable/ic_call_black_24dp.png deleted file mode 100644 index 55ed026bce..0000000000 Binary files a/drawable/ic_call_black_24dp.png and /dev/null differ diff --git a/drawable/ic_call_end_white_48dp.png b/drawable/ic_call_end_white_48dp.png deleted file mode 100644 index a4fe6889d1..0000000000 Binary files a/drawable/ic_call_end_white_48dp.png and /dev/null differ diff --git a/drawable/ic_call_made_black_18dp.png b/drawable/ic_call_made_black_18dp.png deleted file mode 100644 index e7293a0a90..0000000000 Binary files a/drawable/ic_call_made_black_18dp.png and /dev/null differ diff --git a/drawable/ic_call_made_white_18dp.png b/drawable/ic_call_made_white_18dp.png deleted file mode 100644 index 3c6a23529c..0000000000 Binary files a/drawable/ic_call_made_white_18dp.png and /dev/null differ diff --git a/drawable/ic_call_missed_black_18dp.png b/drawable/ic_call_missed_black_18dp.png deleted file mode 100644 index fb61875a19..0000000000 Binary files a/drawable/ic_call_missed_black_18dp.png and /dev/null differ diff --git a/drawable/ic_call_missed_outgoing_black_18dp.png b/drawable/ic_call_missed_outgoing_black_18dp.png deleted file mode 100644 index ef4ad96223..0000000000 Binary files a/drawable/ic_call_missed_outgoing_black_18dp.png and /dev/null differ diff --git a/drawable/ic_call_missed_outgoing_white_18dp.png b/drawable/ic_call_missed_outgoing_white_18dp.png deleted file mode 100644 index 8fe42b28cb..0000000000 Binary files a/drawable/ic_call_missed_outgoing_white_18dp.png and /dev/null differ diff --git a/drawable/ic_call_missed_white_18dp.png b/drawable/ic_call_missed_white_18dp.png deleted file mode 100644 index 4d6d77962a..0000000000 Binary files a/drawable/ic_call_missed_white_18dp.png and /dev/null differ diff --git a/drawable/ic_call_received_black_18dp.png b/drawable/ic_call_received_black_18dp.png deleted file mode 100644 index fe45b55175..0000000000 Binary files a/drawable/ic_call_received_black_18dp.png and /dev/null differ diff --git a/drawable/ic_call_received_white_18dp.png b/drawable/ic_call_received_white_18dp.png deleted file mode 100644 index 9accbbf36a..0000000000 Binary files a/drawable/ic_call_received_white_18dp.png and /dev/null differ diff --git a/drawable/ic_call_white_24dp.png b/drawable/ic_call_white_24dp.png deleted file mode 100644 index 77f9de5e3c..0000000000 Binary files a/drawable/ic_call_white_24dp.png and /dev/null differ diff --git a/drawable/ic_call_white_48dp.png b/drawable/ic_call_white_48dp.png deleted file mode 100644 index ef45e933a9..0000000000 Binary files a/drawable/ic_call_white_48dp.png and /dev/null differ diff --git a/drawable/ic_cancel_black_24dp.png b/drawable/ic_cancel_black_24dp.png deleted file mode 100644 index 7867e72cfd..0000000000 Binary files a/drawable/ic_cancel_black_24dp.png and /dev/null differ diff --git a/drawable/ic_cancel_white_24dp.png b/drawable/ic_cancel_white_24dp.png deleted file mode 100644 index 7ba7a596a0..0000000000 Binary files a/drawable/ic_cancel_white_24dp.png and /dev/null differ diff --git a/drawable/ic_chat_white_24dp.png b/drawable/ic_chat_white_24dp.png deleted file mode 100644 index 96cfcfe58f..0000000000 Binary files a/drawable/ic_chat_white_24dp.png and /dev/null differ diff --git a/drawable/ic_check_all_black_18dp.png b/drawable/ic_check_all_black_18dp.png deleted file mode 100644 index f87da8b232..0000000000 Binary files a/drawable/ic_check_all_black_18dp.png and /dev/null differ diff --git a/drawable/ic_check_all_white_18dp.png b/drawable/ic_check_all_white_18dp.png deleted file mode 100644 index 39571a2ee2..0000000000 Binary files a/drawable/ic_check_all_white_18dp.png and /dev/null differ diff --git a/drawable/ic_check_black_18dp.png b/drawable/ic_check_black_18dp.png deleted file mode 100644 index 7f66179d5e..0000000000 Binary files a/drawable/ic_check_black_18dp.png and /dev/null differ diff --git a/drawable/ic_check_white_18dp.png b/drawable/ic_check_white_18dp.png deleted file mode 100644 index 84ca0053f2..0000000000 Binary files a/drawable/ic_check_white_18dp.png and /dev/null differ diff --git a/drawable/ic_clear_white_48dp.png b/drawable/ic_clear_white_48dp.png deleted file mode 100644 index b7c7ffd0e7..0000000000 Binary files a/drawable/ic_clear_white_48dp.png and /dev/null differ diff --git a/drawable/ic_close_white_24dp.png b/drawable/ic_close_white_24dp.png deleted file mode 100644 index 27c293b2e7..0000000000 Binary files a/drawable/ic_close_white_24dp.png and /dev/null differ diff --git a/drawable/ic_cloud_download_white_24dp.png b/drawable/ic_cloud_download_white_24dp.png deleted file mode 100644 index 1936cf196d..0000000000 Binary files a/drawable/ic_cloud_download_white_24dp.png and /dev/null differ diff --git a/drawable/ic_cloud_white_24dp.png b/drawable/ic_cloud_white_24dp.png deleted file mode 100644 index a503ce8f29..0000000000 Binary files a/drawable/ic_cloud_white_24dp.png and /dev/null differ diff --git a/drawable/ic_contact_white_24dp.png b/drawable/ic_contact_white_24dp.png deleted file mode 100644 index c61747dc26..0000000000 Binary files a/drawable/ic_contact_white_24dp.png and /dev/null differ diff --git a/drawable/ic_contacts_white_24dp.png b/drawable/ic_contacts_white_24dp.png deleted file mode 100644 index eff5707aab..0000000000 Binary files a/drawable/ic_contacts_white_24dp.png and /dev/null differ diff --git a/drawable/ic_content_copy_grey600_24dp.png b/drawable/ic_content_copy_grey600_24dp.png deleted file mode 100644 index d458f01a84..0000000000 Binary files a/drawable/ic_content_copy_grey600_24dp.png and /dev/null differ diff --git a/drawable/ic_content_copy_white_24dp.png b/drawable/ic_content_copy_white_24dp.png deleted file mode 100644 index 72997d04ee..0000000000 Binary files a/drawable/ic_content_copy_white_24dp.png and /dev/null differ diff --git a/drawable/ic_delete_black_24dp.png b/drawable/ic_delete_black_24dp.png deleted file mode 100644 index 7981a3def4..0000000000 Binary files a/drawable/ic_delete_black_24dp.png and /dev/null differ diff --git a/drawable/ic_delete_grey600_24dp.png b/drawable/ic_delete_grey600_24dp.png deleted file mode 100644 index 472383c20f..0000000000 Binary files a/drawable/ic_delete_grey600_24dp.png and /dev/null differ diff --git a/drawable/ic_delete_white_24dp.png b/drawable/ic_delete_white_24dp.png deleted file mode 100644 index 375924994d..0000000000 Binary files a/drawable/ic_delete_white_24dp.png and /dev/null differ diff --git a/drawable/ic_description_black_48dp.png b/drawable/ic_description_black_48dp.png deleted file mode 100644 index 7bc6a6846c..0000000000 Binary files a/drawable/ic_description_black_48dp.png and /dev/null differ diff --git a/drawable/ic_description_white_48dp.png b/drawable/ic_description_white_48dp.png deleted file mode 100644 index 9759bde298..0000000000 Binary files a/drawable/ic_description_white_48dp.png and /dev/null differ diff --git a/drawable/ic_done_black_24dp.png b/drawable/ic_done_black_24dp.png deleted file mode 100644 index 5e5e7cf2b1..0000000000 Binary files a/drawable/ic_done_black_24dp.png and /dev/null differ diff --git a/drawable/ic_download_grey600_48dp.png b/drawable/ic_download_grey600_48dp.png deleted file mode 100644 index 6b1d1ed418..0000000000 Binary files a/drawable/ic_download_grey600_48dp.png and /dev/null differ diff --git a/drawable/ic_edit_black_24dp.png b/drawable/ic_edit_black_24dp.png deleted file mode 100644 index 365d70d2f9..0000000000 Binary files a/drawable/ic_edit_black_24dp.png and /dev/null differ diff --git a/drawable/ic_edit_white_24dp.png b/drawable/ic_edit_white_24dp.png deleted file mode 100644 index cd5c69a253..0000000000 Binary files a/drawable/ic_edit_white_24dp.png and /dev/null differ diff --git a/drawable/ic_email_open_outline_white_24dp.png b/drawable/ic_email_open_outline_white_24dp.png deleted file mode 100644 index 9cfa92a0ee..0000000000 Binary files a/drawable/ic_email_open_outline_white_24dp.png and /dev/null differ diff --git a/drawable/ic_error_white_24dp.png b/drawable/ic_error_white_24dp.png deleted file mode 100644 index ca148fc7ca..0000000000 Binary files a/drawable/ic_error_white_24dp.png and /dev/null differ diff --git a/drawable/ic_event_black_48dp.png b/drawable/ic_event_black_48dp.png deleted file mode 100644 index 8266743b4d..0000000000 Binary files a/drawable/ic_event_black_48dp.png and /dev/null differ diff --git a/drawable/ic_event_white_48dp.png b/drawable/ic_event_white_48dp.png deleted file mode 100644 index 2fb9a7a2c7..0000000000 Binary files a/drawable/ic_event_white_48dp.png and /dev/null differ diff --git a/drawable/ic_file_download_white_24dp.png b/drawable/ic_file_download_white_24dp.png deleted file mode 100644 index 5cf7333355..0000000000 Binary files a/drawable/ic_file_download_white_24dp.png and /dev/null differ diff --git a/drawable/ic_file_grey600_48dp.png b/drawable/ic_file_grey600_48dp.png deleted file mode 100644 index 0a97d3d448..0000000000 Binary files a/drawable/ic_file_grey600_48dp.png and /dev/null differ diff --git a/drawable/ic_file_pdf_grey600_48dp.png b/drawable/ic_file_pdf_grey600_48dp.png deleted file mode 100644 index 291968bf54..0000000000 Binary files a/drawable/ic_file_pdf_grey600_48dp.png and /dev/null differ diff --git a/drawable/ic_flip_camera_android_black_24dp.png b/drawable/ic_flip_camera_android_black_24dp.png deleted file mode 100644 index 79d201f485..0000000000 Binary files a/drawable/ic_flip_camera_android_black_24dp.png and /dev/null differ diff --git a/drawable/ic_forward_white_24dp.png b/drawable/ic_forward_white_24dp.png deleted file mode 100644 index ec881edda5..0000000000 Binary files a/drawable/ic_forward_white_24dp.png and /dev/null differ diff --git a/drawable/ic_group_add_white_24dp.png b/drawable/ic_group_add_white_24dp.png deleted file mode 100644 index b89567331e..0000000000 Binary files a/drawable/ic_group_add_white_24dp.png and /dev/null differ diff --git a/drawable/ic_group_white_24dp.png b/drawable/ic_group_white_24dp.png deleted file mode 100644 index 754249bca3..0000000000 Binary files a/drawable/ic_group_white_24dp.png and /dev/null differ diff --git a/drawable/ic_headset_black_24dp.png b/drawable/ic_headset_black_24dp.png deleted file mode 100644 index d872b05d5c..0000000000 Binary files a/drawable/ic_headset_black_24dp.png and /dev/null differ diff --git a/drawable/ic_headset_black_48dp.png b/drawable/ic_headset_black_48dp.png deleted file mode 100644 index 36b5139487..0000000000 Binary files a/drawable/ic_headset_black_48dp.png and /dev/null differ diff --git a/drawable/ic_headset_white_48dp.png b/drawable/ic_headset_white_48dp.png deleted file mode 100644 index 798e229c7b..0000000000 Binary files a/drawable/ic_headset_white_48dp.png and /dev/null differ diff --git a/drawable/ic_help_black_24dp.png b/drawable/ic_help_black_24dp.png deleted file mode 100644 index f6e789ba1f..0000000000 Binary files a/drawable/ic_help_black_24dp.png and /dev/null differ diff --git a/drawable/ic_help_black_48dp.png b/drawable/ic_help_black_48dp.png deleted file mode 100644 index 3678f6f23a..0000000000 Binary files a/drawable/ic_help_black_48dp.png and /dev/null differ diff --git a/drawable/ic_help_circle_outline_black_24dp.png b/drawable/ic_help_circle_outline_black_24dp.png deleted file mode 100644 index e7f0d63b59..0000000000 Binary files a/drawable/ic_help_circle_outline_black_24dp.png and /dev/null differ diff --git a/drawable/ic_help_circle_outline_white_24dp.png b/drawable/ic_help_circle_outline_white_24dp.png deleted file mode 100644 index 2b14e173bc..0000000000 Binary files a/drawable/ic_help_circle_outline_white_24dp.png and /dev/null differ diff --git a/drawable/ic_help_circle_white_24dp.png b/drawable/ic_help_circle_white_24dp.png deleted file mode 100644 index ff85938296..0000000000 Binary files a/drawable/ic_help_circle_white_24dp.png and /dev/null differ diff --git a/drawable/ic_help_white_24dp.png b/drawable/ic_help_white_24dp.png deleted file mode 100644 index db699622bc..0000000000 Binary files a/drawable/ic_help_white_24dp.png and /dev/null differ diff --git a/drawable/ic_help_white_48dp.png b/drawable/ic_help_white_48dp.png deleted file mode 100644 index 68e4b15630..0000000000 Binary files a/drawable/ic_help_white_48dp.png and /dev/null differ diff --git a/drawable/ic_hourglass_empty_white_24dp.png b/drawable/ic_hourglass_empty_white_24dp.png deleted file mode 100644 index 616df098dc..0000000000 Binary files a/drawable/ic_hourglass_empty_white_24dp.png and /dev/null differ diff --git a/drawable/ic_image_black_24dp.png b/drawable/ic_image_black_24dp.png deleted file mode 100644 index 377ce13318..0000000000 Binary files a/drawable/ic_image_black_24dp.png and /dev/null differ diff --git a/drawable/ic_image_black_48dp.png b/drawable/ic_image_black_48dp.png deleted file mode 100644 index 6b7cd7838b..0000000000 Binary files a/drawable/ic_image_black_48dp.png and /dev/null differ diff --git a/drawable/ic_image_grey600_48dp.png b/drawable/ic_image_grey600_48dp.png deleted file mode 100644 index 32e5edc294..0000000000 Binary files a/drawable/ic_image_grey600_48dp.png and /dev/null differ diff --git a/drawable/ic_image_white_24dp.png b/drawable/ic_image_white_24dp.png deleted file mode 100644 index 0626807e05..0000000000 Binary files a/drawable/ic_image_white_24dp.png and /dev/null differ diff --git a/drawable/ic_image_white_48dp.png b/drawable/ic_image_white_48dp.png deleted file mode 100644 index 2642b9e09e..0000000000 Binary files a/drawable/ic_image_white_48dp.png and /dev/null differ diff --git a/drawable/ic_input_white_24dp.png b/drawable/ic_input_white_24dp.png deleted file mode 100644 index 5bcfac74ce..0000000000 Binary files a/drawable/ic_input_white_24dp.png and /dev/null differ diff --git a/drawable/ic_link_off_white_24dp.png b/drawable/ic_link_off_white_24dp.png deleted file mode 100644 index f1a75d4859..0000000000 Binary files a/drawable/ic_link_off_white_24dp.png and /dev/null differ diff --git a/drawable/ic_link_white_24dp.png b/drawable/ic_link_white_24dp.png deleted file mode 100644 index bc32d7bfee..0000000000 Binary files a/drawable/ic_link_white_24dp.png and /dev/null differ diff --git a/drawable/ic_lock_black_18dp.png b/drawable/ic_lock_black_18dp.png deleted file mode 100644 index 472922f85b..0000000000 Binary files a/drawable/ic_lock_black_18dp.png and /dev/null differ diff --git a/drawable/ic_lock_open_white_24dp.png b/drawable/ic_lock_open_white_24dp.png deleted file mode 100644 index 7c07b701a2..0000000000 Binary files a/drawable/ic_lock_open_white_24dp.png and /dev/null differ diff --git a/drawable/ic_lock_white_18dp.png b/drawable/ic_lock_white_18dp.png deleted file mode 100644 index e9b327fd00..0000000000 Binary files a/drawable/ic_lock_white_18dp.png and /dev/null differ diff --git a/drawable/ic_lock_white_24dp.png b/drawable/ic_lock_white_24dp.png deleted file mode 100644 index efe76e8768..0000000000 Binary files a/drawable/ic_lock_white_24dp.png and /dev/null differ diff --git a/drawable/ic_map_marker_grey600_48dp.png b/drawable/ic_map_marker_grey600_48dp.png deleted file mode 100644 index 7f2eea80f4..0000000000 Binary files a/drawable/ic_map_marker_grey600_48dp.png and /dev/null differ diff --git a/drawable/ic_menu_white_24dp.png b/drawable/ic_menu_white_24dp.png deleted file mode 100644 index 60e4398a35..0000000000 Binary files a/drawable/ic_menu_white_24dp.png and /dev/null differ diff --git a/drawable/ic_mic_black_24dp.png b/drawable/ic_mic_black_24dp.png deleted file mode 100644 index 19a16138fe..0000000000 Binary files a/drawable/ic_mic_black_24dp.png and /dev/null differ diff --git a/drawable/ic_mic_black_48dp.png b/drawable/ic_mic_black_48dp.png deleted file mode 100644 index 9c7caa2956..0000000000 Binary files a/drawable/ic_mic_black_48dp.png and /dev/null differ diff --git a/drawable/ic_mic_off_black_24dp.png b/drawable/ic_mic_off_black_24dp.png deleted file mode 100644 index da605a5a19..0000000000 Binary files a/drawable/ic_mic_off_black_24dp.png and /dev/null differ diff --git a/drawable/ic_mic_white_48dp.png b/drawable/ic_mic_white_48dp.png deleted file mode 100644 index 80d851e951..0000000000 Binary files a/drawable/ic_mic_white_48dp.png and /dev/null differ diff --git a/drawable/ic_missed_call_notification.png b/drawable/ic_missed_call_notification.png deleted file mode 100644 index 9a7f39cf0f..0000000000 Binary files a/drawable/ic_missed_call_notification.png and /dev/null differ diff --git a/drawable/ic_mode_edit_black_18dp.png b/drawable/ic_mode_edit_black_18dp.png deleted file mode 100644 index 81fc6d74bc..0000000000 Binary files a/drawable/ic_mode_edit_black_18dp.png and /dev/null differ diff --git a/drawable/ic_mode_edit_white_18dp.png b/drawable/ic_mode_edit_white_18dp.png deleted file mode 100644 index 2ee70ae714..0000000000 Binary files a/drawable/ic_mode_edit_white_18dp.png and /dev/null differ diff --git a/drawable/ic_navigation_white_24dp.png b/drawable/ic_navigation_white_24dp.png deleted file mode 100644 index c445d26207..0000000000 Binary files a/drawable/ic_navigation_white_24dp.png and /dev/null differ diff --git a/drawable/ic_new_releases_black_24dp.png b/drawable/ic_new_releases_black_24dp.png deleted file mode 100644 index f8f4f111e8..0000000000 Binary files a/drawable/ic_new_releases_black_24dp.png and /dev/null differ diff --git a/drawable/ic_new_releases_white_24dp.png b/drawable/ic_new_releases_white_24dp.png deleted file mode 100644 index 8e7ba807fc..0000000000 Binary files a/drawable/ic_new_releases_white_24dp.png and /dev/null differ diff --git a/drawable/ic_no_results_background_black.png b/drawable/ic_no_results_background_black.png deleted file mode 100644 index 52da4021cb..0000000000 Binary files a/drawable/ic_no_results_background_black.png and /dev/null differ diff --git a/drawable/ic_no_results_background_white.png b/drawable/ic_no_results_background_white.png deleted file mode 100644 index 4c1b5e3a71..0000000000 Binary files a/drawable/ic_no_results_background_white.png and /dev/null differ diff --git a/drawable/ic_notification.png b/drawable/ic_notification.png deleted file mode 100644 index 9bb538d895..0000000000 Binary files a/drawable/ic_notification.png and /dev/null differ diff --git a/drawable/ic_notifications_black_24dp.png b/drawable/ic_notifications_black_24dp.png deleted file mode 100644 index 520cf1bfe2..0000000000 Binary files a/drawable/ic_notifications_black_24dp.png and /dev/null differ diff --git a/drawable/ic_notifications_grey600_24dp.png b/drawable/ic_notifications_grey600_24dp.png deleted file mode 100644 index 25809a4b02..0000000000 Binary files a/drawable/ic_notifications_grey600_24dp.png and /dev/null differ diff --git a/drawable/ic_notifications_none_black_24dp.png b/drawable/ic_notifications_none_black_24dp.png deleted file mode 100644 index 237c8eb01d..0000000000 Binary files a/drawable/ic_notifications_none_black_24dp.png and /dev/null differ diff --git a/drawable/ic_notifications_none_white_24dp.png b/drawable/ic_notifications_none_white_24dp.png deleted file mode 100644 index d945e688cd..0000000000 Binary files a/drawable/ic_notifications_none_white_24dp.png and /dev/null differ diff --git a/drawable/ic_notifications_off_black_24dp.png b/drawable/ic_notifications_off_black_24dp.png deleted file mode 100644 index a022840eb5..0000000000 Binary files a/drawable/ic_notifications_off_black_24dp.png and /dev/null differ diff --git a/drawable/ic_notifications_off_white_24dp.png b/drawable/ic_notifications_off_white_24dp.png deleted file mode 100644 index 38ba80cb98..0000000000 Binary files a/drawable/ic_notifications_off_white_24dp.png and /dev/null differ diff --git a/drawable/ic_notifications_paused_black_24dp.png b/drawable/ic_notifications_paused_black_24dp.png deleted file mode 100644 index 076df76112..0000000000 Binary files a/drawable/ic_notifications_paused_black_24dp.png and /dev/null differ diff --git a/drawable/ic_notifications_paused_white_24dp.png b/drawable/ic_notifications_paused_white_24dp.png deleted file mode 100644 index 37f202d5f4..0000000000 Binary files a/drawable/ic_notifications_paused_white_24dp.png and /dev/null differ diff --git a/drawable/ic_notifications_white_24dp.png b/drawable/ic_notifications_white_24dp.png deleted file mode 100644 index 0047ea2cdc..0000000000 Binary files a/drawable/ic_notifications_white_24dp.png and /dev/null differ diff --git a/drawable/ic_open_in_new_white_24dp.png b/drawable/ic_open_in_new_white_24dp.png deleted file mode 100644 index 56aa521361..0000000000 Binary files a/drawable/ic_open_in_new_white_24dp.png and /dev/null differ diff --git a/drawable/ic_pause_black_36dp.png b/drawable/ic_pause_black_36dp.png deleted file mode 100644 index 4dffa8e53c..0000000000 Binary files a/drawable/ic_pause_black_36dp.png and /dev/null differ diff --git a/drawable/ic_pause_white_36dp.png b/drawable/ic_pause_white_36dp.png deleted file mode 100644 index e81331fdc5..0000000000 Binary files a/drawable/ic_pause_white_36dp.png and /dev/null differ diff --git a/drawable/ic_person_add_white_24dp.png b/drawable/ic_person_add_white_24dp.png deleted file mode 100644 index 7d84d062d4..0000000000 Binary files a/drawable/ic_person_add_white_24dp.png and /dev/null differ diff --git a/drawable/ic_person_black_48dp.png b/drawable/ic_person_black_48dp.png deleted file mode 100644 index 76858f7016..0000000000 Binary files a/drawable/ic_person_black_48dp.png and /dev/null differ diff --git a/drawable/ic_person_white_48dp.png b/drawable/ic_person_white_48dp.png deleted file mode 100644 index 4966999857..0000000000 Binary files a/drawable/ic_person_white_48dp.png and /dev/null differ diff --git a/drawable/ic_phone_in_talk_black_18dp.png b/drawable/ic_phone_in_talk_black_18dp.png deleted file mode 100644 index ee45268537..0000000000 Binary files a/drawable/ic_phone_in_talk_black_18dp.png and /dev/null differ diff --git a/drawable/ic_phone_in_talk_white_18dp.png b/drawable/ic_phone_in_talk_white_18dp.png deleted file mode 100644 index 833386bbcd..0000000000 Binary files a/drawable/ic_phone_in_talk_white_18dp.png and /dev/null differ diff --git a/drawable/ic_phone_in_talk_white_24dp.png b/drawable/ic_phone_in_talk_white_24dp.png deleted file mode 100644 index e6f98af95b..0000000000 Binary files a/drawable/ic_phone_in_talk_white_24dp.png and /dev/null differ diff --git a/drawable/ic_play_arrow_black_36dp.png b/drawable/ic_play_arrow_black_36dp.png deleted file mode 100644 index e9c288c991..0000000000 Binary files a/drawable/ic_play_arrow_black_36dp.png and /dev/null differ diff --git a/drawable/ic_play_arrow_white_36dp.png b/drawable/ic_play_arrow_white_36dp.png deleted file mode 100644 index 57c9fa5460..0000000000 Binary files a/drawable/ic_play_arrow_white_36dp.png and /dev/null differ diff --git a/drawable/ic_play_circle_filled_white_48dp.png b/drawable/ic_play_circle_filled_white_48dp.png deleted file mode 100644 index 5dcdf0d7a4..0000000000 Binary files a/drawable/ic_play_circle_filled_white_48dp.png and /dev/null differ diff --git a/drawable/ic_public_white_24dp.png b/drawable/ic_public_white_24dp.png deleted file mode 100644 index 5b99884ade..0000000000 Binary files a/drawable/ic_public_white_24dp.png and /dev/null differ diff --git a/drawable/ic_qrcode_grey600_24dp.png b/drawable/ic_qrcode_grey600_24dp.png deleted file mode 100644 index 24cb66d423..0000000000 Binary files a/drawable/ic_qrcode_grey600_24dp.png and /dev/null differ diff --git a/drawable/ic_qrcode_scan_white_24dp.png b/drawable/ic_qrcode_scan_white_24dp.png deleted file mode 100644 index ad5be5cdf6..0000000000 Binary files a/drawable/ic_qrcode_scan_white_24dp.png and /dev/null differ diff --git a/drawable/ic_qrcode_white_24dp.png b/drawable/ic_qrcode_white_24dp.png deleted file mode 100644 index 7e28f95dc1..0000000000 Binary files a/drawable/ic_qrcode_white_24dp.png and /dev/null differ diff --git a/drawable/ic_question_answer_white_24dp.png b/drawable/ic_question_answer_white_24dp.png deleted file mode 100644 index dad29526ae..0000000000 Binary files a/drawable/ic_question_answer_white_24dp.png and /dev/null differ diff --git a/drawable/ic_read_indicator.png b/drawable/ic_read_indicator.png deleted file mode 100644 index 310f4283eb..0000000000 Binary files a/drawable/ic_read_indicator.png and /dev/null differ diff --git a/drawable/ic_received_indicator.png b/drawable/ic_received_indicator.png deleted file mode 100644 index e7a09b7bf5..0000000000 Binary files a/drawable/ic_received_indicator.png and /dev/null differ diff --git a/drawable/ic_refresh_grey600_24dp.png b/drawable/ic_refresh_grey600_24dp.png deleted file mode 100644 index 34edda8016..0000000000 Binary files a/drawable/ic_refresh_grey600_24dp.png and /dev/null differ diff --git a/drawable/ic_refresh_white_24dp.png b/drawable/ic_refresh_white_24dp.png deleted file mode 100644 index 9b5f21cea9..0000000000 Binary files a/drawable/ic_refresh_white_24dp.png and /dev/null differ diff --git a/drawable/ic_replay_white_48dp.png b/drawable/ic_replay_white_48dp.png deleted file mode 100644 index 3b41913257..0000000000 Binary files a/drawable/ic_replay_white_48dp.png and /dev/null differ diff --git a/drawable/ic_reply_circle_black_24dp.png b/drawable/ic_reply_circle_black_24dp.png deleted file mode 100644 index 575e1fd9e5..0000000000 Binary files a/drawable/ic_reply_circle_black_24dp.png and /dev/null differ diff --git a/drawable/ic_reply_white_24dp.png b/drawable/ic_reply_white_24dp.png deleted file mode 100644 index 4beb49bcfc..0000000000 Binary files a/drawable/ic_reply_white_24dp.png and /dev/null differ diff --git a/drawable/ic_room_black_48dp.png b/drawable/ic_room_black_48dp.png deleted file mode 100644 index e604545372..0000000000 Binary files a/drawable/ic_room_black_48dp.png and /dev/null differ diff --git a/drawable/ic_room_white_24dp.png b/drawable/ic_room_white_24dp.png deleted file mode 100644 index 417c7a826d..0000000000 Binary files a/drawable/ic_room_white_24dp.png and /dev/null differ diff --git a/drawable/ic_room_white_48dp.png b/drawable/ic_room_white_48dp.png deleted file mode 100644 index 8c51d01ad8..0000000000 Binary files a/drawable/ic_room_white_48dp.png and /dev/null differ diff --git a/drawable/ic_save_black_24dp.png b/drawable/ic_save_black_24dp.png deleted file mode 100644 index 280cb23301..0000000000 Binary files a/drawable/ic_save_black_24dp.png and /dev/null differ diff --git a/drawable/ic_save_white_24dp.png b/drawable/ic_save_white_24dp.png deleted file mode 100644 index 24eb15f8d6..0000000000 Binary files a/drawable/ic_save_white_24dp.png and /dev/null differ diff --git a/drawable/ic_search_background_black.png b/drawable/ic_search_background_black.png deleted file mode 100644 index 9d40a03ee4..0000000000 Binary files a/drawable/ic_search_background_black.png and /dev/null differ diff --git a/drawable/ic_search_background_white.png b/drawable/ic_search_background_white.png deleted file mode 100644 index 6b63fbd999..0000000000 Binary files a/drawable/ic_search_background_white.png and /dev/null differ diff --git a/drawable/ic_search_white_24dp.png b/drawable/ic_search_white_24dp.png deleted file mode 100644 index d36447557b..0000000000 Binary files a/drawable/ic_search_white_24dp.png and /dev/null differ diff --git a/drawable/ic_security_black_24dp.png b/drawable/ic_security_black_24dp.png deleted file mode 100644 index b86d686347..0000000000 Binary files a/drawable/ic_security_black_24dp.png and /dev/null differ diff --git a/drawable/ic_security_white_24dp.png b/drawable/ic_security_white_24dp.png deleted file mode 100644 index 45c2aa1e73..0000000000 Binary files a/drawable/ic_security_white_24dp.png and /dev/null differ diff --git a/drawable/ic_send_attachment_away.svg b/drawable/ic_send_attachment_away.svg deleted file mode 100644 index cd43bbefed..0000000000 --- a/drawable/ic_send_attachment_away.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_attachment_dnd.svg b/drawable/ic_send_attachment_dnd.svg deleted file mode 100644 index b6a51c1633..0000000000 --- a/drawable/ic_send_attachment_dnd.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_attachment_offline.svg b/drawable/ic_send_attachment_offline.svg deleted file mode 100644 index bcf8abed1b..0000000000 --- a/drawable/ic_send_attachment_offline.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_attachment_offline_white.svg b/drawable/ic_send_attachment_offline_white.svg deleted file mode 100644 index 2df228a099..0000000000 --- a/drawable/ic_send_attachment_offline_white.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_attachment_online.svg b/drawable/ic_send_attachment_online.svg deleted file mode 100644 index 2c3c9134fb..0000000000 --- a/drawable/ic_send_attachment_online.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_cancel_away.svg b/drawable/ic_send_cancel_away.svg deleted file mode 100644 index 510edc3248..0000000000 --- a/drawable/ic_send_cancel_away.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_cancel_dnd.svg b/drawable/ic_send_cancel_dnd.svg deleted file mode 100644 index 0e70479e34..0000000000 --- a/drawable/ic_send_cancel_dnd.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_cancel_offline.svg b/drawable/ic_send_cancel_offline.svg deleted file mode 100644 index c247af3a6b..0000000000 --- a/drawable/ic_send_cancel_offline.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_cancel_offline_white.svg b/drawable/ic_send_cancel_offline_white.svg deleted file mode 100644 index 6d847d7003..0000000000 --- a/drawable/ic_send_cancel_offline_white.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_cancel_online.svg b/drawable/ic_send_cancel_online.svg deleted file mode 100644 index 291dcfa776..0000000000 --- a/drawable/ic_send_cancel_online.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_location_away.svg b/drawable/ic_send_location_away.svg deleted file mode 100644 index c92ed2f31e..0000000000 --- a/drawable/ic_send_location_away.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_location_dnd.svg b/drawable/ic_send_location_dnd.svg deleted file mode 100644 index 354604776b..0000000000 --- a/drawable/ic_send_location_dnd.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_location_offline.svg b/drawable/ic_send_location_offline.svg deleted file mode 100644 index f7826cf94e..0000000000 --- a/drawable/ic_send_location_offline.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_location_offline_white.svg b/drawable/ic_send_location_offline_white.svg deleted file mode 100644 index f990af9ffe..0000000000 --- a/drawable/ic_send_location_offline_white.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_location_online.svg b/drawable/ic_send_location_online.svg deleted file mode 100644 index 4faecf0994..0000000000 --- a/drawable/ic_send_location_online.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_photo_away.svg b/drawable/ic_send_photo_away.svg deleted file mode 100644 index b1a34fa0f5..0000000000 --- a/drawable/ic_send_photo_away.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/drawable/ic_send_photo_dnd.svg b/drawable/ic_send_photo_dnd.svg deleted file mode 100644 index dc4fe32bca..0000000000 --- a/drawable/ic_send_photo_dnd.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/drawable/ic_send_photo_offline.svg b/drawable/ic_send_photo_offline.svg deleted file mode 100644 index f5769ac042..0000000000 --- a/drawable/ic_send_photo_offline.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - diff --git a/drawable/ic_send_photo_offline_white.svg b/drawable/ic_send_photo_offline_white.svg deleted file mode 100644 index 7588164ce7..0000000000 --- a/drawable/ic_send_photo_offline_white.svg +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - diff --git a/drawable/ic_send_photo_online.svg b/drawable/ic_send_photo_online.svg deleted file mode 100644 index a43cfd232e..0000000000 --- a/drawable/ic_send_photo_online.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/drawable/ic_send_picture_away.svg b/drawable/ic_send_picture_away.svg deleted file mode 100644 index 0cc1b450e6..0000000000 --- a/drawable/ic_send_picture_away.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_picture_dnd.svg b/drawable/ic_send_picture_dnd.svg deleted file mode 100644 index a2ebab5cae..0000000000 --- a/drawable/ic_send_picture_dnd.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_picture_offline.svg b/drawable/ic_send_picture_offline.svg deleted file mode 100644 index 2c5727dfee..0000000000 --- a/drawable/ic_send_picture_offline.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_picture_offline_white.svg b/drawable/ic_send_picture_offline_white.svg deleted file mode 100644 index d043c2d154..0000000000 --- a/drawable/ic_send_picture_offline_white.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_picture_online.svg b/drawable/ic_send_picture_online.svg deleted file mode 100644 index 94aace0229..0000000000 --- a/drawable/ic_send_picture_online.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_text_away.svg b/drawable/ic_send_text_away.svg deleted file mode 100644 index 266c484ac9..0000000000 --- a/drawable/ic_send_text_away.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - diff --git a/drawable/ic_send_text_dnd.svg b/drawable/ic_send_text_dnd.svg deleted file mode 100644 index 471fe78bc3..0000000000 --- a/drawable/ic_send_text_dnd.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - diff --git a/drawable/ic_send_text_offline.svg b/drawable/ic_send_text_offline.svg deleted file mode 100644 index efdea008b6..0000000000 --- a/drawable/ic_send_text_offline.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - diff --git a/drawable/ic_send_text_offline_white.svg b/drawable/ic_send_text_offline_white.svg deleted file mode 100644 index 4d7dd5470c..0000000000 --- a/drawable/ic_send_text_offline_white.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_text_online.svg b/drawable/ic_send_text_online.svg deleted file mode 100644 index ebd007b859..0000000000 --- a/drawable/ic_send_text_online.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_videocam_away.svg b/drawable/ic_send_videocam_away.svg deleted file mode 100644 index ceb472e738..0000000000 --- a/drawable/ic_send_videocam_away.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_videocam_dnd.svg b/drawable/ic_send_videocam_dnd.svg deleted file mode 100644 index 6681b854d7..0000000000 --- a/drawable/ic_send_videocam_dnd.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_videocam_offline.svg b/drawable/ic_send_videocam_offline.svg deleted file mode 100644 index a0c8205321..0000000000 --- a/drawable/ic_send_videocam_offline.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_videocam_offline_white.svg b/drawable/ic_send_videocam_offline_white.svg deleted file mode 100644 index af282b7f60..0000000000 --- a/drawable/ic_send_videocam_offline_white.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_videocam_online.svg b/drawable/ic_send_videocam_online.svg deleted file mode 100644 index aa8d5d82e5..0000000000 --- a/drawable/ic_send_videocam_online.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_voice_away.svg b/drawable/ic_send_voice_away.svg deleted file mode 100644 index 61039bb82e..0000000000 --- a/drawable/ic_send_voice_away.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_voice_dnd.svg b/drawable/ic_send_voice_dnd.svg deleted file mode 100644 index 2f95543b1b..0000000000 --- a/drawable/ic_send_voice_dnd.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_voice_offline.svg b/drawable/ic_send_voice_offline.svg deleted file mode 100644 index f0d1ff12b8..0000000000 --- a/drawable/ic_send_voice_offline.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_voice_offline_white.svg b/drawable/ic_send_voice_offline_white.svg deleted file mode 100644 index 6b5dc13482..0000000000 --- a/drawable/ic_send_voice_offline_white.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - diff --git a/drawable/ic_send_voice_online.svg b/drawable/ic_send_voice_online.svg deleted file mode 100644 index 3c99c1e5fa..0000000000 --- a/drawable/ic_send_voice_online.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/drawable/ic_settings_black_24dp.png b/drawable/ic_settings_black_24dp.png deleted file mode 100644 index c59419c02b..0000000000 Binary files a/drawable/ic_settings_black_24dp.png and /dev/null differ diff --git a/drawable/ic_settings_white_24dp.png b/drawable/ic_settings_white_24dp.png deleted file mode 100644 index 064996b8d9..0000000000 Binary files a/drawable/ic_settings_white_24dp.png and /dev/null differ diff --git a/drawable/ic_share_black_24dp.png b/drawable/ic_share_black_24dp.png deleted file mode 100644 index d4ebebd063..0000000000 Binary files a/drawable/ic_share_black_24dp.png and /dev/null differ diff --git a/drawable/ic_share_white_24dp.png b/drawable/ic_share_white_24dp.png deleted file mode 100644 index 58cd61e17f..0000000000 Binary files a/drawable/ic_share_white_24dp.png and /dev/null differ diff --git a/drawable/ic_speaker_notes_off_white_24dp.png b/drawable/ic_speaker_notes_off_white_24dp.png deleted file mode 100644 index 2378a9f051..0000000000 Binary files a/drawable/ic_speaker_notes_off_white_24dp.png and /dev/null differ diff --git a/drawable/ic_speaker_notes_white_24dp.png b/drawable/ic_speaker_notes_white_24dp.png deleted file mode 100644 index fc41de624e..0000000000 Binary files a/drawable/ic_speaker_notes_white_24dp.png and /dev/null differ diff --git a/drawable/ic_star_black_24dp.png b/drawable/ic_star_black_24dp.png deleted file mode 100644 index a728afe600..0000000000 Binary files a/drawable/ic_star_black_24dp.png and /dev/null differ diff --git a/drawable/ic_star_white_24dp.png b/drawable/ic_star_white_24dp.png deleted file mode 100644 index d2cbe4c92b..0000000000 Binary files a/drawable/ic_star_white_24dp.png and /dev/null differ diff --git a/drawable/ic_unarchive_white_24dp.png b/drawable/ic_unarchive_white_24dp.png deleted file mode 100644 index 0480fea982..0000000000 Binary files a/drawable/ic_unarchive_white_24dp.png and /dev/null differ diff --git a/drawable/ic_update_notification.png b/drawable/ic_update_notification.png deleted file mode 100644 index 4274329772..0000000000 Binary files a/drawable/ic_update_notification.png and /dev/null differ diff --git a/drawable/ic_verified_fingerprint.png b/drawable/ic_verified_fingerprint.png deleted file mode 100644 index a1d188ddb8..0000000000 Binary files a/drawable/ic_verified_fingerprint.png and /dev/null differ diff --git a/drawable/ic_verified_user_black_18dp.png b/drawable/ic_verified_user_black_18dp.png deleted file mode 100644 index 87ad3d5490..0000000000 Binary files a/drawable/ic_verified_user_black_18dp.png and /dev/null differ diff --git a/drawable/ic_verified_user_white_18dp.png b/drawable/ic_verified_user_white_18dp.png deleted file mode 100644 index 10ccdca7bf..0000000000 Binary files a/drawable/ic_verified_user_white_18dp.png and /dev/null differ diff --git a/drawable/ic_video_grey600_48dp.png b/drawable/ic_video_grey600_48dp.png deleted file mode 100644 index 2e25833955..0000000000 Binary files a/drawable/ic_video_grey600_48dp.png and /dev/null differ diff --git a/drawable/ic_videocam_black_24dp.png b/drawable/ic_videocam_black_24dp.png deleted file mode 100644 index 0722a69290..0000000000 Binary files a/drawable/ic_videocam_black_24dp.png and /dev/null differ diff --git a/drawable/ic_videocam_off_black_24dp.png b/drawable/ic_videocam_off_black_24dp.png deleted file mode 100644 index c71d75cebc..0000000000 Binary files a/drawable/ic_videocam_off_black_24dp.png and /dev/null differ diff --git a/drawable/ic_videocam_white_24dp.png b/drawable/ic_videocam_white_24dp.png deleted file mode 100644 index d146209a51..0000000000 Binary files a/drawable/ic_videocam_white_24dp.png and /dev/null differ diff --git a/drawable/ic_voicemail_white_24dp.png b/drawable/ic_voicemail_white_24dp.png deleted file mode 100644 index e5aa7db055..0000000000 Binary files a/drawable/ic_voicemail_white_24dp.png and /dev/null differ diff --git a/drawable/ic_volume_off_black_24dp.png b/drawable/ic_volume_off_black_24dp.png deleted file mode 100644 index a629cfff53..0000000000 Binary files a/drawable/ic_volume_off_black_24dp.png and /dev/null differ diff --git a/drawable/ic_volume_up_black_24dp.png b/drawable/ic_volume_up_black_24dp.png deleted file mode 100644 index 4ed27786a1..0000000000 Binary files a/drawable/ic_volume_up_black_24dp.png and /dev/null differ diff --git a/drawable/ic_vpn_key_white_24dp.png b/drawable/ic_vpn_key_white_24dp.png deleted file mode 100644 index 21ba921790..0000000000 Binary files a/drawable/ic_vpn_key_white_24dp.png and /dev/null differ diff --git a/drawable/ic_warning_white_24dp.png b/drawable/ic_warning_white_24dp.png deleted file mode 100644 index 28f95e0756..0000000000 Binary files a/drawable/ic_warning_white_24dp.png and /dev/null differ diff --git a/drawable/ic_warning_white_48dp.png b/drawable/ic_warning_white_48dp.png deleted file mode 100644 index a43fa3c27d..0000000000 Binary files a/drawable/ic_warning_white_48dp.png and /dev/null differ diff --git a/drawable/ic_wear_reply.png b/drawable/ic_wear_reply.png deleted file mode 100644 index 6fa6a03c9c..0000000000 Binary files a/drawable/ic_wear_reply.png and /dev/null differ diff --git a/drawable/ic_web_grey600_48.png b/drawable/ic_web_grey600_48.png deleted file mode 100644 index 0aa17eabfe..0000000000 Binary files a/drawable/ic_web_grey600_48.png and /dev/null differ diff --git a/drawable/intro_account_details_icon.png b/drawable/intro_account_details_icon.png deleted file mode 100644 index 3b2fd3f10a..0000000000 Binary files a/drawable/intro_account_details_icon.png and /dev/null differ diff --git a/drawable/intro_account_icon.png b/drawable/intro_account_icon.png deleted file mode 100644 index b5449c366f..0000000000 Binary files a/drawable/intro_account_icon.png and /dev/null differ diff --git a/drawable/intro_contacts_icon.png b/drawable/intro_contacts_icon.png deleted file mode 100644 index 493ffa0fea..0000000000 Binary files a/drawable/intro_contacts_icon.png and /dev/null differ diff --git a/drawable/intro_location_icon.png b/drawable/intro_location_icon.png deleted file mode 100644 index 3c67dea97a..0000000000 Binary files a/drawable/intro_location_icon.png and /dev/null differ diff --git a/drawable/intro_memory_icon.png b/drawable/intro_memory_icon.png deleted file mode 100644 index 9de4df9115..0000000000 Binary files a/drawable/intro_memory_icon.png and /dev/null differ diff --git a/drawable/intro_security_icon.png b/drawable/intro_security_icon.png deleted file mode 100644 index 55395f0107..0000000000 Binary files a/drawable/intro_security_icon.png and /dev/null differ diff --git a/drawable/intro_start_chat_icon.png b/drawable/intro_start_chat_icon.png deleted file mode 100644 index 09356f98d9..0000000000 Binary files a/drawable/intro_start_chat_icon.png and /dev/null differ diff --git a/drawable/intro_xmpp_icon.png b/drawable/intro_xmpp_icon.png deleted file mode 100644 index 635cf19635..0000000000 Binary files a/drawable/intro_xmpp_icon.png and /dev/null differ diff --git a/drawable/logo_800.png b/drawable/logo_800.png deleted file mode 100644 index 05a1d575a4..0000000000 Binary files a/drawable/logo_800.png and /dev/null differ diff --git a/drawable/logo_actionbar.png b/drawable/logo_actionbar.png deleted file mode 100644 index af2b15416e..0000000000 Binary files a/drawable/logo_actionbar.png and /dev/null differ diff --git a/drawable/monocleslogo_chat-signet.svg b/drawable/monocleslogo_chat-signet.svg deleted file mode 100644 index 73c64b516f..0000000000 --- a/drawable/monocleslogo_chat-signet.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/drawable/pencil_overlay.png b/drawable/pencil_overlay.png deleted file mode 100644 index daedd4d9f1..0000000000 Binary files a/drawable/pencil_overlay.png and /dev/null differ diff --git a/drawable/play_gif.png b/drawable/play_gif.png deleted file mode 100644 index 9c3212d630..0000000000 Binary files a/drawable/play_gif.png and /dev/null differ diff --git a/drawable/play_video.png b/drawable/play_video.png deleted file mode 100644 index 6516ad94b3..0000000000 Binary files a/drawable/play_video.png and /dev/null differ diff --git a/drawable/raster.sh b/drawable/raster.sh deleted file mode 100644 index b48426082e..0000000000 --- a/drawable/raster.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -SIZES="1 1.5 2 3 4" -EXPORT="../src/main/res/" -ICON="../Arcticons/scalable/apps" - -for DIR in $(find -name "*.svg") -do - FILE=${DIR##*/} - NAME=${FILE%.*} - cp ${FILE} ${FILE}.tmp - rm ${FILE}.tmp - #cp -f ${FILE} ${ICON}/${FILE} - echo "Working on" ${FILE} - for SIZE in ${SIZES} - do - svgexport ${NAME}.svg ${NAME}.png ${SIZE}x - case ${SIZE} in - 1) - mv ${NAME}.png ${EXPORT}/drawable-mdpi/ - ;; - 1.5) - mv ${NAME}.png ${EXPORT}/drawable-hdpi/ - ;; - 2) - mv ${NAME}.png ${EXPORT}/drawable-xhdpi/ - ;; - 3) - mv ${NAME}.png ${EXPORT}/drawable-xxhdpi/ - ;; - 4) - mv ${NAME}.png ${EXPORT}/drawable-xxxhdpi/ - ;; - esac - done -done diff --git a/drawable/show_pdf.png b/drawable/show_pdf.png deleted file mode 100644 index 9a2dbae315..0000000000 Binary files a/drawable/show_pdf.png and /dev/null differ diff --git a/git/release/output-metadata.json b/git/release/output-metadata.json deleted file mode 100644 index 9451eaa0f7..0000000000 --- a/git/release/output-metadata.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "version": 3, - "artifactType": { - "type": "APK", - "kind": "Directory" - }, - "applicationId": "de.monocles.chat", - "variantName": "gitRelease", - "elements": [ - { - "type": "UNIVERSAL", - "filters": [], - "attributes": [], - "versionCode": 174, - "versionName": "1.7.11", - "outputFile": "monocles chat-1.7.11-git-universal-release.apk" - }, - { - "type": "ONE_OF_MANY", - "filters": [ - { - "filterType": "ABI", - "value": "arm64-v8a" - } - ], - "attributes": [], - "versionCode": 17404, - "versionName": "1.7.11", - "outputFile": "monocles chat-1.7.11-git-arm64-v8a-release.apk" - }, - { - "type": "ONE_OF_MANY", - "filters": [ - { - "filterType": "ABI", - "value": "x86" - } - ], - "attributes": [], - "versionCode": 17402, - "versionName": "1.7.11", - "outputFile": "monocles chat-1.7.11-git-x86-release.apk" - }, - { - "type": "ONE_OF_MANY", - "filters": [ - { - "filterType": "ABI", - "value": "armeabi-v7a" - } - ], - "attributes": [], - "versionCode": 17401, - "versionName": "1.7.11", - "outputFile": "monocles chat-1.7.11-git-armeabi-v7a-release.apk" - }, - { - "type": "ONE_OF_MANY", - "filters": [ - { - "filterType": "ABI", - "value": "x86_64" - } - ], - "attributes": [], - "versionCode": 17403, - "versionName": "1.7.11", - "outputFile": "monocles chat-1.7.11-git-x86_64-release.apk" - } - ], - "elementType": "File", - "baselineProfiles": [ - { - "minApi": 28, - "maxApi": 30, - "baselineProfiles": [ - "baselineProfiles/1/monocles chat-1.7.11-git-universal-release.dm", - "baselineProfiles/1/monocles chat-1.7.11-git-arm64-v8a-release.dm", - "baselineProfiles/1/monocles chat-1.7.11-git-x86-release.dm", - "baselineProfiles/1/monocles chat-1.7.11-git-armeabi-v7a-release.dm", - "baselineProfiles/1/monocles chat-1.7.11-git-x86_64-release.dm" - ] - }, - { - "minApi": 31, - "maxApi": 2147483647, - "baselineProfiles": [ - "baselineProfiles/0/monocles chat-1.7.11-git-universal-release.dm", - "baselineProfiles/0/monocles chat-1.7.11-git-arm64-v8a-release.dm", - "baselineProfiles/0/monocles chat-1.7.11-git-x86-release.dm", - "baselineProfiles/0/monocles chat-1.7.11-git-armeabi-v7a-release.dm", - "baselineProfiles/0/monocles chat-1.7.11-git-x86_64-release.dm" - ] - } - ], - "minSdkVersionForDexing": 23 -} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index cd8a7cb3c7..af22f69548 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,22 +1,6 @@ - -## For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx1024m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -# -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -#Sat Jan 22 19:25:52 CET 2022 -org.gradle.parallel=true -org.gradle.jvmargs=-Xmx6144m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC -android.enableJetifier=true android.useAndroidX=true -org.gradle.gradle-args=--max-workers=32 +android.enableJetifier=true android.nonTransitiveRClass=true android.nonFinalResIds=false -org.gradle.daemon=false \ No newline at end of file +org.gradle.jvmargs=-Xmx4096m +org.gradle.daemon=false diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..7454180f2a Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f92f67ffe3..f9b6580c25 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,8 @@ -#Mon Mar 06 22:35:58 CET 2023 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0c81..1aa94a4269 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,99 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +119,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index ac1b06f938..7101f8e467 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/libs/AXML/.gitignore b/libs/AXML/.gitignore deleted file mode 100644 index 796b96d1c4..0000000000 --- a/libs/AXML/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/libs/AXML/build.gradle b/libs/AXML/build.gradle deleted file mode 100644 index e2a71a2c25..0000000000 --- a/libs/AXML/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -apply plugin: 'java' - -group = 'fr.xgouchet' - - -dependencies { - // TODO UNIT TESTS -} - -// Additional tasks for jitpack.io - -// build a jar with source files -task sourcesJar(type: Jar) { - from sourceSets.main.java.srcDirs - archiveClassifier.set("sources") -} - -// build a jar with javadoc -task javadocJar(type: Jar, dependsOn: javadoc) { - archiveClassifier.set("javadoc") - from javadoc.destinationDir -} - -artifacts { - archives sourcesJar - archives javadocJar -} -java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 -} \ No newline at end of file diff --git a/libs/AXML/proguard-rules.pro b/libs/AXML/proguard-rules.pro deleted file mode 100644 index 1ecf581f67..0000000000 --- a/libs/AXML/proguard-rules.pro +++ /dev/null @@ -1,17 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /opt/android/sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/libs/AXML/src/main/java/fr/xgouchet/axml/Attribute.java b/libs/AXML/src/main/java/fr/xgouchet/axml/Attribute.java deleted file mode 100644 index 67fdf2b09c..0000000000 --- a/libs/AXML/src/main/java/fr/xgouchet/axml/Attribute.java +++ /dev/null @@ -1,66 +0,0 @@ -package fr.xgouchet.axml; - -public class Attribute { - - /** - * @return the name - */ - public String getName() { - return mName; - } - - /** - * @return the prefix - */ - public String getPrefix() { - return mPrefix; - } - - /** - * @return the namespace - */ - public String getNamespace() { - return mNamespace; - } - - /** - * @return the value - */ - public String getValue() { - return mValue; - } - - /** - * @param name - * the name to set - */ - public void setName(final String name) { - mName = name; - } - - /** - * @param prefix - * the prefix to set - */ - public void setPrefix(final String prefix) { - mPrefix = prefix; - } - - /** - * @param namespace - * the namespace to set - */ - public void setNamespace(final String namespace) { - mNamespace = namespace; - } - - /** - * @param value - * the value to set - */ - public void setValue(final String value) { - mValue = value; - } - - private String mName, mPrefix, mNamespace, mValue; -} \ No newline at end of file diff --git a/libs/AXML/src/main/java/fr/xgouchet/axml/CompressedXmlDomListener.java b/libs/AXML/src/main/java/fr/xgouchet/axml/CompressedXmlDomListener.java deleted file mode 100644 index da2584f1ee..0000000000 --- a/libs/AXML/src/main/java/fr/xgouchet/axml/CompressedXmlDomListener.java +++ /dev/null @@ -1,92 +0,0 @@ -package fr.xgouchet.axml; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import java.util.Stack; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -public class CompressedXmlDomListener implements CompressedXmlParserListener { - - /** - * @throws ParserConfigurationException if a DocumentBuilder can't be created - */ - public CompressedXmlDomListener() throws ParserConfigurationException { - mBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - mStack = new Stack<>(); - } - - public void startDocument() { - mDocument = mBuilder.newDocument(); - mStack.push(mDocument); - } - - public void endDocument() { - } - - public void startPrefixMapping(String prefix, String uri) { - } - - public void endPrefixMapping(String prefix, String uri) { - } - - public void startElement(final String uri, final String localName, - final String qName, final Attribute[] attrs) { - Element elt; - - // create elt - if (isEmpty(uri)) { - elt = mDocument.createElement(localName); - } else { - elt = mDocument.createElementNS(uri, qName); - } - - // add attrs - for (Attribute attr : attrs) { - if (isEmpty(attr.getNamespace())) { - elt.setAttribute(attr.getName(), attr.getValue()); - } else { - elt.setAttributeNS(attr.getNamespace(), attr.getPrefix() + ':' - + attr.getName(), attr.getValue()); - } - } - - // handle stack - mStack.peek().appendChild(elt); - mStack.push(elt); - } - - public void endElement(String uri, String localName, String qName) { - mStack.pop(); - } - - public void characterData(String data) { - mStack.peek().appendChild(mDocument.createCDATASection(data)); - } - - public void text(String data) { - mStack.peek().appendChild(mDocument.createTextNode(data)); - } - - public void processingInstruction(String target, String data) { - } - - /** - * @return the parsed document - */ - public Document getDocument() { - return mDocument; - } - - private static boolean isEmpty(String text) { - return (text == null) || "".equals(text); - } - - private Stack mStack; - private Document mDocument; - private final DocumentBuilder mBuilder; -} diff --git a/libs/AXML/src/main/java/fr/xgouchet/axml/CompressedXmlParser.java b/libs/AXML/src/main/java/fr/xgouchet/axml/CompressedXmlParser.java deleted file mode 100644 index 5e3c28959d..0000000000 --- a/libs/AXML/src/main/java/fr/xgouchet/axml/CompressedXmlParser.java +++ /dev/null @@ -1,515 +0,0 @@ -package fr.xgouchet.axml; - -import org.w3c.dom.Document; - -import java.io.IOException; -import java.io.InputStream; -import java.text.DecimalFormat; -import java.util.HashMap; -import java.util.Map; - -import javax.xml.parsers.ParserConfigurationException; - - -public class CompressedXmlParser { - - public static final String TAG = "CXP"; - - public static final int WORD_START_DOCUMENT = 0x00080003; - - public static final int WORD_STRING_TABLE = 0x001C0001; - public static final int WORD_RES_TABLE = 0x00080180; - - public static final int WORD_START_NS = 0x00100100; - public static final int WORD_END_NS = 0x00100101; - public static final int WORD_START_TAG = 0x00100102; - public static final int WORD_END_TAG = 0x00100103; - public static final int WORD_TEXT = 0x00100104; - public static final int WORD_EOS = 0xFFFFFFFF; - public static final int WORD_SIZE = 4; - - private static final int TYPE_ID_REF = 0x01000008; - private static final int TYPE_ATTR_REF = 0x02000008; - private static final int TYPE_STRING = 0x03000008; - private static final int TYPE_DIMEN = 0x05000008; - private static final int TYPE_FRACTION = 0x06000008; - private static final int TYPE_INT = 0x10000008; - private static final int TYPE_FLOAT = 0x04000008; - - private static final int TYPE_FLAGS = 0x11000008; - private static final int TYPE_BOOL = 0x12000008; - private static final int TYPE_COLOR = 0x1C000008; - private static final int TYPE_COLOR2 = 0x1D000008; - - private static final String[] DIMEN = new String[]{"px", "dp", "sp", - "pt", "in", "mm"}; - - public CompressedXmlParser() { - mNamespaces = new HashMap<>(); - } - - /** - * Parses the xml data in the given file, - * - * @param input the source input to parse - * @param listener the listener for XML events (must not be null) - * @throws IOException if the input can't be read - */ - public void parse(final InputStream input, - final CompressedXmlParserListener listener) throws IOException { - - if (listener == null) { - throw new IllegalArgumentException( - "CompressedXmlParser Listener can' be null"); - } - mListener = listener; - - // TODO is.available may not be accurate !!! - mData = new byte[input.available()]; - input.read(mData); - input.close(); - - // parseCompressedHeader(); - parseCompressedXml(); - - } - - /** - * Parses the xml data in the given file, - * - * @param input the source file to parse - * @return the DOM document object - * @throws IOException if the input can't be read - * @throws ParserConfigurationException if a DocumentBuilder can't be created - */ - public Document parseDOM(final InputStream input) throws IOException, - ParserConfigurationException { - CompressedXmlDomListener dom = new CompressedXmlDomListener(); - - parse(input, dom); - - return dom.getDocument(); - } - - /** - * Each tag starts with a 32 bits word (different for start tag, end tag and - * end doc) - */ - private void parseCompressedXml() { - int word0; - - while (mParserOffset < mData.length) { - word0 = getLEWord(mParserOffset); - switch (word0) { - case WORD_START_DOCUMENT: - parseStartDocument(); - break; - case WORD_STRING_TABLE: - parseStringTable(); - break; - case WORD_RES_TABLE: - parseResourceTable(); - break; - case WORD_START_NS: - parseNamespace(true); - break; - case WORD_END_NS: - parseNamespace(false); - break; - case WORD_START_TAG: - parseStartTag(); - break; - case WORD_END_TAG: - parseEndTag(); - break; - case WORD_TEXT: - parseText(); - break; - case WORD_EOS: - mListener.endDocument(); - break; - default: - mParserOffset += WORD_SIZE; -// Log.w(TAG, "Unknown word 0x" + Integer.toHexString(word0) -// + " @" + mParserOffset); - break; - } - } - - mListener.endDocument(); - } - - /** - * A doc starts with the following 4bytes words : - * - */ - private void parseStartDocument() { - mListener.startDocument(); - mParserOffset += (2 * WORD_SIZE); - } - - /** - * the string table starts with the following 4bytes words : - * - */ - private void parseStringTable() { - - int chunk = getLEWord(mParserOffset + (1 * WORD_SIZE)); - mStringsCount = getLEWord(mParserOffset + (2 * WORD_SIZE)); - mStylesCount = getLEWord(mParserOffset + (3 * WORD_SIZE)); - int strOffset = mParserOffset - + getLEWord(mParserOffset + (5 * WORD_SIZE)); - int styleOffset = getLEWord(mParserOffset + (6 * WORD_SIZE)); - - mStringsTable = new String[mStringsCount]; - int offset; - for (int i = 0; i < mStringsCount; ++i) { - offset = strOffset - + getLEWord(mParserOffset + ((i + 7) * WORD_SIZE)); - mStringsTable[i] = getStringFromStringTable(offset); - } - - if (styleOffset > 0) { -// Log.w(TAG, "Unread styles"); - for (int i = 0; i < mStylesCount; ++i) { - // TODO read the styles ??? - } - } - - mParserOffset += chunk; - } - - /** - * the resource ids table starts with the following 4bytes words : - * - */ - private void parseResourceTable() { - int chunk = getLEWord(mParserOffset + (1 * WORD_SIZE)); - mResCount = (chunk / 4) - 2; - - mResourcesIds = new int[mResCount]; - for (int i = 0; i < mResCount; ++i) { - mResourcesIds[i] = getLEWord(mParserOffset + ((i + 2) * WORD_SIZE)); - } - - mParserOffset += chunk; - } - - /** - * A namespace tag contains the following 4bytes words : - * - */ - private void parseNamespace(boolean start) { - final int prefixIdx = getLEWord(mParserOffset + (4 * WORD_SIZE)); - final int uriIdx = getLEWord(mParserOffset + (5 * WORD_SIZE)); - - final String uri = getString(uriIdx); - final String prefix = getString(prefixIdx); - - if (start) { - mListener.startPrefixMapping(prefix, uri); - mNamespaces.put(uri, prefix); - } else { - mListener.endPrefixMapping(prefix, uri); - mNamespaces.remove(uri); - } - - // Offset to first tag - mParserOffset += (6 * WORD_SIZE); - } - - /** - * A start tag will start with the following 4bytes words : - * - */ - private void parseStartTag() { - // get tag info - final int uriIdx = getLEWord(mParserOffset + (4 * WORD_SIZE)); - final int nameIdx = getLEWord(mParserOffset + (5 * WORD_SIZE)); - final int attrCount = getLEShort(mParserOffset + (7 * WORD_SIZE)); - - final String name = getString(nameIdx); - String uri, qname; - if (uriIdx == 0xFFFFFFFF) { - uri = ""; - qname = name; - } else { - uri = getString(uriIdx); - if (mNamespaces.containsKey(uri)) { - qname = mNamespaces.get(uri) + ':' + name; - } else { - qname = name; - } - } - - // offset to start of attributes - mParserOffset += (9 * WORD_SIZE); - - final Attribute[] attrs = new Attribute[attrCount]; // NOPMD - for (int a = 0; a < attrCount; a++) { - attrs[a] = parseAttribute(); // NOPMD - - // offset to next attribute or tag - mParserOffset += (5 * 4); - } - - mListener.startElement(uri, name, qname, attrs); - } - - /** - * An attribute will have the following 4bytes words : - * - */ - private Attribute parseAttribute() { - final int attrNSIdx = getLEWord(mParserOffset); - final int attrNameIdx = getLEWord(mParserOffset + (1 * WORD_SIZE)); - final int attrValueIdx = getLEWord(mParserOffset + (2 * WORD_SIZE)); - final int attrType = getLEWord(mParserOffset + (3 * WORD_SIZE)); - final int attrData = getLEWord(mParserOffset + (4 * WORD_SIZE)); - - final Attribute attr = new Attribute(); - attr.setName(getString(attrNameIdx)); - - if (attrNSIdx == 0xFFFFFFFF) { - attr.setNamespace(null); - attr.setPrefix(null); - } else { - String uri = getString(attrNSIdx); - if (mNamespaces.containsKey(uri)) { - attr.setNamespace(uri); - attr.setPrefix(mNamespaces.get(uri)); - } - } - - if (attrValueIdx == 0xFFFFFFFF) { - attr.setValue(getAttributeValue(attrType, attrData)); - } else { - attr.setValue(getString(attrValueIdx)); - } - - return attr; - - } - - /** - * A text will start with the following 4bytes word : - * - */ - private void parseText() { - // get tag infos - final int strIndex = getLEWord(mParserOffset + (4 * WORD_SIZE)); - - String data = getString(strIndex); - mListener.characterData(data); - - // offset to next node - mParserOffset += (7 * WORD_SIZE); - } - - /** - * EndTag contains the following 4bytes words : - * - */ - private void parseEndTag() { - // get tag info - final int uriIdx = getLEWord(mParserOffset + (4 * WORD_SIZE)); - final int nameIdx = getLEWord(mParserOffset + (5 * WORD_SIZE)); - - final String name = getString(nameIdx); - String uri; - if (uriIdx == 0xFFFFFFFF) { - uri = ""; - } else { - uri = getString(uriIdx); - } - - mListener.endElement(uri, name, null); - - // offset to start of next tag - mParserOffset += (6 * WORD_SIZE); - } - - /** - * @param index the index of the string in the StringIndexTable - * @return the string - */ - private String getString(final int index) { - String res; - if ((index >= 0) && (index < mStringsCount)) { - res = mStringsTable[index]; - } else { - res = null; // NOPMD - } - - return res; - } - - /** - * @param offset offset of the beginning of the string inside the StringTable - * (and not the whole data array) - * @return the String - */ - private String getStringFromStringTable(final int offset) { - int strLength; - byte chars[]; - if (mData[offset + 1] == mData[offset]) { - strLength = mData[offset]; - chars = new byte[strLength];// NOPMD - for (int i = 0; i < strLength; i++) { - chars[i] = mData[offset + 2 + i]; // NOPMD - } - } else { - - strLength = ((mData[offset + 1] << 8) & 0xFF00) - | (mData[offset] & 0xFF); - chars = new byte[strLength]; // NOPMD - for (int i = 0; i < strLength; i++) { - chars[i] = mData[offset + 2 + (i * 2)]; // NOPMD - } - - } - return new String(chars); - } - - /** - * @param off the offset of the word to read - * @return value of a Little Endian 32 bit word from the byte arrayat offset - * off. - */ - private int getLEWord(final int off) { - return ((mData[off + 3] << 24) & 0xff000000) - | ((mData[off + 2] << 16) & 0x00ff0000) - | ((mData[off + 1] << 8) & 0x0000ff00) - | ((mData[off + 0] << 0) & 0x000000ff); - } - - /** - * @param off the offset of the word to read - * @return value of a Little Endian 16 bit word from the byte array at offset - * off. - */ - private int getLEShort(final int off) { - return ((mData[off + 1] << 8) & 0xff00) - | ((mData[off + 0] << 0) & 0x00ff); - } - - /** - * @param type the attribute type - * @param data the data value - * @return the typed value - */ - private String getAttributeValue(final int type, final int data) { - String res; - - switch (type) { - case TYPE_STRING: - res = getString(data); - break; - case TYPE_DIMEN: - res = Integer.toString(data >> 8) + DIMEN[data & 0xFF]; - break; - case TYPE_FRACTION: - double fracValue = (((double) data) / ((double) 0x7FFFFFFF)); - // res = String.format("%.2f%%", fracValue); - res = new DecimalFormat("#.##%").format(fracValue); - break; - case TYPE_FLOAT: - res = Float.toString(Float.intBitsToFloat(data)); - break; - case TYPE_INT: - case TYPE_FLAGS: - res = Integer.toString(data); - break; - case TYPE_BOOL: - res = Boolean.toString(data != 0); - break; - case TYPE_COLOR: - case TYPE_COLOR2: - res = String.format("#%08X", data); - break; - case TYPE_ID_REF: - res = String.format("@id/0x%08X", data); - break; - case TYPE_ATTR_REF: - res = String.format("?id/0x%08X", data); - break; - default: -// Log.w(TAG, "(type=" + Integer.toHexString(type) + ") : " + data -// + " (0x" + Integer.toHexString(data) + ") @" -// + mParserOffset); - res = String.format("%08X/0x%08X", type, data); - break; - } - - return res; - } - - // Data - private CompressedXmlParserListener mListener; - - // Internal - private Map mNamespaces; - private byte[] mData; - - private String[] mStringsTable; - private int[] mResourcesIds; - private int mStringsCount, mStylesCount, mResCount; - private int mParserOffset; - -} diff --git a/libs/AXML/src/main/java/fr/xgouchet/axml/CompressedXmlParserListener.java b/libs/AXML/src/main/java/fr/xgouchet/axml/CompressedXmlParserListener.java deleted file mode 100644 index 2738713d62..0000000000 --- a/libs/AXML/src/main/java/fr/xgouchet/axml/CompressedXmlParserListener.java +++ /dev/null @@ -1,101 +0,0 @@ -package fr.xgouchet.axml; - -public interface CompressedXmlParserListener { - - /** - * Receive notification of the beginning of a document. - */ - void startDocument(); - - /** - * Receive notification of the end of a document. - */ - void endDocument(); - - /** - * Begin the scope of a prefix-URI Namespace mapping. - * - * @param prefix - * the Namespace prefix being declared. An empty string is used - * for the default element namespace, which has no prefix. - * @param uri - * the Namespace URI the prefix is mapped to - */ - void startPrefixMapping(String prefix, String uri); - - /** - * End the scope of a prefix-URI mapping. - * - * @param prefix - * the prefix that was being mapped. This is the empty string - * when a default mapping scope ends. - * @param uri - * the Namespace URI the prefix is mapped to - */ - void endPrefixMapping(String prefix, String uri); - - /** - * Receive notification of the beginning of an element. - * - * @param uri - * the Namespace URI, or the empty string if the element has no - * Namespace URI or if Namespace processing is not being - * performed - * @param localName - * the local name (without prefix), or the empty string if - * Namespace processing is not being performed - * @param qName - * the qualified name (with prefix), or the empty string if - * qualified names are not available - * @param atts - * the attributes attached to the element. If there are no - * attributes, it shall be an empty Attributes object. The value - * of this object after startElement returns is undefined - */ - void startElement(String uri, String localName, String qName, - Attribute[] atts); - - /** - * Receive notification of the end of an element. - * - * @param uri - * the Namespace URI, or the empty string if the element has no - * Namespace URI or if Namespace processing is not being - * performed - * @param localName - * the local name (without prefix), or the empty string if - * Namespace processing is not being performed - * @param qName - * the qualified XML name (with prefix), or the empty string if - * qualified names are not available - */ - void endElement(String uri, String localName, String qName); - - /** - * Receive notification of text. - * - * @param data - * the text data - */ - void text(String data); - - /** - * Receive notification of character data (in a <![CDATA[ ]]> block). - * - * @param data - * the text data - */ - void characterData(String data); - - /** - * Receive notification of a processing instruction. - * - * @param target - * the processing instruction target - * @param data - * the processing instruction data, or null if none was supplied. - * The data does not include any whitespace separating it from - * the target - */ - void processingInstruction(String target, String data); -} diff --git a/libs/AXML/src/main/java/fr/xgouchet/axml/CompressedXmlUtils.java b/libs/AXML/src/main/java/fr/xgouchet/axml/CompressedXmlUtils.java deleted file mode 100644 index 5e3d24b318..0000000000 --- a/libs/AXML/src/main/java/fr/xgouchet/axml/CompressedXmlUtils.java +++ /dev/null @@ -1,60 +0,0 @@ -package fr.xgouchet.axml; - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; - -public final class CompressedXmlUtils { - - /** - * @param input an input stream - * @return if the given input stream looks like an AXML document - */ - public static boolean isCompressedXml(final InputStream input) { - if (input == null) return false; - - boolean result; - - try { - final byte[] header = new byte[4]; - int read = input.read(header, 0, 4); - if (read < 4) return false; - - result = (header[0] == 0x03) - && (header[1] == 0x00) - && (header[2] == 0x08) - && (header[3] == 0x00); - - } catch (Exception e) { - result = false; - } finally { - try { - input.close(); - } catch (Exception e) { - // ignore this exception - } - } - - return result; - } - - /** - * @param source a source file - * @return if the given file looks like an AXML file - */ - public static boolean isCompressedXml(final File source) { - boolean result; - - try { - final InputStream input = new FileInputStream(source.getPath()); - result = isCompressedXml(input); - } catch (Exception e) { - result = false; - } - - return result; - } - - private CompressedXmlUtils() { - } -} diff --git a/monocles.doap b/monocles.doap new file mode 100644 index 0000000000..9fe876acf0 --- /dev/null +++ b/monocles.doap @@ -0,0 +1,531 @@ + + + + + monocles chat + + 2021-06-12 + + Android Jabber Client + + monocles chat is a freedomware client for the Jabber network (using the XMPP protocol) with a focus on features for gateway users. + + + + + + + + + + + en + + + + + + + + + + Java + + Android + + + + + + + + + Soprani.ca + + + + + + + + + + + + + + + + + + + + partial + 1.0 + When used with XEP-0050, images over HTTPS only + + + + + + partial + 1.0 + For MUC members + + + + + + complete + 0.2.1 + + + + + + partial + 0.2.0 + For XEP-0033 and XEP-0066 + + + + + + partial + 0.2.1 + Receiving, hashes, thumbnails, one HTTP source + + + + + + complete + 1.1.3 + + + + + + partial + 2.13.0 + As part of XEP-0050 and XEP-0077 + + + + + + partial + 1.0.2 + When used with XEP-0050 + + + + + + complete + 1.3.0 + + + + + + partial + 1.0 + jabber:iq:gateway + + + + + + complete + 1.4 + + + + + + complete + 2.5rc3 + + + + + + complete + 1.32.0 + + + + + + complete + 1.2 + + + + + + complete + 1.2 + + + + + + partial + 1.2 + Avatars only + + + + + + complete + 1.1.3 + + + + + + complete + 2.1 + + + + + + complete + 1.1 + + + + + + complete + 1.5.1 + + + + + + partial + 1.1 + Read only. Publication via XEP-0398 + + + + + + complete + 1.2.1 + Avatar, Nick, OMEMO + + + + + + complete + 1.1.2 + File transfer + A/V calls + + + + + + complete + 1.2.1 + + + + + + complete + 1.1 + read only + + + + + + complete + 1.1 + + + + + + complete + 1.4.0 + + + + + + complete + 1.3 + + + + + + complete + 1.6 + + + + + + complete + 2.0.1 + + + + + + complete + 2.0.1 + + + + + + complete + 0.7 + + + + + + complete + 1.1 + + + + + + complete + 0.19.1 + + + + + + complete + 1.3 + + + + + + complete + 1.0 + + + + + + complete + 1.2 + + + + + + complete + 1.0.3 + + + + + + complete + 1.0 + + + + + + complete + 0.13.1 + + + + + + complete + 1.0.1 + + + + + + complete + 1.0 + + + + + + complete + 1.2.0 + + + + + + complete + 0.6.3 + + + + + + complete + 1.0.2 + opt-in + + + + + + complete + 1.0.0 + + + + + + complete + 0.3 + + + + + + complete + 1.0.0 + + + + + + complete + 1.0.0 + + + + + + complete + 0.3.0 + + + + + + complete + 0.3.0 + + + + + + complete + 0.4.0 + Only available in the version distributed over Google Play + + + + + + complete + 1.0.0 + + + + + + complete + 1.1.0 + + + + + + complete + 0.2 + + + + + + complete + 0.3.0 + + + + + + complete + 0.1.2 + 2.5.8 + + + + + + complete + 0.6.0 + 2.3.1 + + + + + + complete + 0.1.4 + 1.22.0 + + + + + + complete + 0.1 + 2.5.8 + + + + + + complete + 0.2.1 + + + + + + complete + 1.0.1 + 2.5.4 + + + + + + complete + 0.2.0 + + + + + + complete + 0.1.0 + + + + diff --git a/monocles_chat.doap b/monocles_chat.doap deleted file mode 100644 index 6e37477ae0..0000000000 --- a/monocles_chat.doap +++ /dev/null @@ -1,579 +0,0 @@ - - - - - monocles chat - - 2021-05-04 - - Userfriendly XMPP Client for Android - - monocles chat is a modern and secure chat app using XMPP. Based on Conversations and Blabber.im but with many changes. - - - - - - - - - - - - en - - - - - - - - - - - - Java - - Android - - - - - - - - Arne-Brün Vogelsang - - - - - - - - - - - - - - - - - - - - - partial - 1.0 - When used with XEP-0050, images over HTTPS only - - - - - - partial - 1.0 - For MUC members - - - - - - partial - 0.2.0 - For XEP-0033 and XEP-0066 - - - - - - partial - 0.2.1 - Receiving, hashes, thumbnails, one HTTP source - - - - - - complete - 1.1.3 - - - - - - partial - 2.13.0 - As part of XEP-0050 and XEP-0077 - - - - - - partial - 1.0.2 - When used with XEP-0050 - - - - - - complete - 1.3.0 - - - - - - partial - 1.0 - jabber:iq:gateway - - - - - - complete - 1.4 - - - - - - complete - 2.5rc3 - - - - - - complete - 1.32.0 - - - - - - complete - 1.2 - - - - - - complete - 1.2 - - - - - - partial - 1.2 - Avatars only - - - - - - complete - 1.1.3 - - - - - - complete - 2.1 - - - - - - complete - 1.1 - - - - - - complete - 1.5.1 - - - - - - partial - 1.1 - Read only. Publication via XEP-0398 - - - - - - complete - 1.2.1 - Avatar, Nick, OMEMO - - - - - - complete - 1.1.2 - File transfer + A/V calls - - - - - - complete - 1.2.1 - - - - - - complete - 1.1 - read only - - - - - - complete - 1.1 - - - - - - complete - 1.4.0 - - - - - - complete - 1.3 - - - - - - complete - 1.6 - - - - - - complete - 2.0.1 - - - - - - complete - 2.0.1 - - - - - - complete - 0.7 - - - - - - partial - 1.0 - When used with XEP-0050, images over HTTPS only - - - - - - complete - 1.1 - - - - - - complete - 0.19.1 - - - - - - complete - 1.3 - - - - - - complete - 1.0 - - - - - - complete - 1.2 - - - - - - complete - 1.0.3 - - - - - - complete - 1.0 - - - - - - complete - 0.13.1 - - - - - - complete - 1.0.1 - - - - - - complete - 1.0 - - - - - - complete - 1.2.0 - - - - - - complete - 0.6.3 - - - - - - complete - 1.0.2 - opt-in - - - - - - complete - 1.0.0 - - - - - - complete - 0.3 - - - - - - complete - 1.0.0 - - - - - - complete - 1.0.0 - - - - - - complete - 0.3.0 - - - - - - complete - 0.3.0 - - - - - - complete - 0.4.0 - Only available in the version distributed over Google Play - - - - - - complete - 1.0.0 - - - - - - complete - 1.1.0 - - - - - - complete - 0.3.1 - - - - - - complete - 0.3.0 - - - - - - complete - 0.1.2 - 1.0 - - - - - - complete - 0.6.0 - 1.0 - - - - - - complete - 0.1.4 - 1.0 - - - - - - complete - 0.1 - 1.0 - - - - - - complete - 0.2.1 - - - - - - complete - 1.0.1 - 1.0 - - - - - - complete - 0.2.0 - - - - - - complete - 0.2.1 - - - - - - complete - 0.4.0 - - - - - - complete - 0.1.0 - - - - - - complete - 0.1.0 - - - - - - partial - 0.3.2 - 1.4.3 - - - - - - complete - 0.1.0 - - - - - - 1.7.10 - 2024-06-01 - - - - - diff --git a/monocleschatFree/debug/output-metadata.json b/monocleschatFree/debug/output-metadata.json new file mode 100644 index 0000000000..a3bb9e6acc --- /dev/null +++ b/monocleschatFree/debug/output-metadata.json @@ -0,0 +1,73 @@ +{ + "version": 3, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "de.monocles.chat", + "variantName": "monocleschatFreeDebug", + "elements": [ + { + "type": "UNIVERSAL", + "filters": [], + "attributes": [], + "versionCode": 4209171, + "versionName": "29082ff+free", + "outputFile": "Conversations-monocleschat-free-universal-debug.apk" + }, + { + "type": "ONE_OF_MANY", + "filters": [ + { + "filterType": "ABI", + "value": "arm64-v8a" + } + ], + "attributes": [], + "versionCode": 4205304, + "versionName": "29082ff+free", + "outputFile": "Conversations-monocleschat-free-arm64-v8a-debug.apk" + }, + { + "type": "ONE_OF_MANY", + "filters": [ + { + "filterType": "ABI", + "value": "x86" + } + ], + "attributes": [], + "versionCode": 4205302, + "versionName": "29082ff+free", + "outputFile": "Conversations-monocleschat-free-x86-debug.apk" + }, + { + "type": "ONE_OF_MANY", + "filters": [ + { + "filterType": "ABI", + "value": "armeabi-v7a" + } + ], + "attributes": [], + "versionCode": 4205301, + "versionName": "29082ff+free", + "outputFile": "Conversations-monocleschat-free-armeabi-v7a-debug.apk" + }, + { + "type": "ONE_OF_MANY", + "filters": [ + { + "filterType": "ABI", + "value": "x86_64" + } + ], + "attributes": [], + "versionCode": 4205303, + "versionName": "29082ff+free", + "outputFile": "Conversations-monocleschat-free-x86_64-debug.apk" + } + ], + "elementType": "File", + "minSdkVersionForDexing": 23 +} \ No newline at end of file diff --git a/playstore/release/output-metadata.json b/playstore/release/output-metadata.json deleted file mode 100644 index 99887c8510..0000000000 --- a/playstore/release/output-metadata.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "version": 3, - "artifactType": { - "type": "APK", - "kind": "Directory" - }, - "applicationId": "de.monocles.chat", - "variantName": "playstoreRelease", - "elements": [ - { - "type": "UNIVERSAL", - "filters": [], - "attributes": [], - "versionCode": 138, - "versionName": "4135a60-playstore", - "outputFile": "monocles chat-1.7.6-playstore-universal-release.apk" - }, - { - "type": "ONE_OF_MANY", - "filters": [ - { - "filterType": "ABI", - "value": "arm64-v8a" - } - ], - "attributes": [], - "versionCode": 13804, - "versionName": "4135a60-playstore", - "outputFile": "monocles chat-1.7.6-playstore-arm64-v8a-release.apk" - }, - { - "type": "ONE_OF_MANY", - "filters": [ - { - "filterType": "ABI", - "value": "armeabi-v7a" - } - ], - "attributes": [], - "versionCode": 13801, - "versionName": "4135a60-playstore", - "outputFile": "monocles chat-1.7.6-playstore-armeabi-v7a-release.apk" - }, - { - "type": "ONE_OF_MANY", - "filters": [ - { - "filterType": "ABI", - "value": "x86_64" - } - ], - "attributes": [], - "versionCode": 13803, - "versionName": "4135a60-playstore", - "outputFile": "monocles chat-1.7.6-playstore-x86_64-release.apk" - }, - { - "type": "ONE_OF_MANY", - "filters": [ - { - "filterType": "ABI", - "value": "x86" - } - ], - "attributes": [], - "versionCode": 13802, - "versionName": "4135a60-playstore", - "outputFile": "monocles chat-1.7.6-playstore-x86-release.apk" - } - ], - "elementType": "File" -} \ No newline at end of file diff --git a/proguard-rules.pro b/proguard-rules.pro index 75902f0798..7098945c6a 100644 --- a/proguard-rules.pro +++ b/proguard-rules.pro @@ -1,7 +1,5 @@ -dontobfuscate --keep class de.monocles.chat.** --keep class de.pixart.messenger.** -keep class eu.siacs.conversations.** -keep class org.whispersystems.** @@ -15,9 +13,6 @@ -keep class org.openintents.openpgp.* -keep class org.webrtc.** { *; } --keep class com.squareup.okhttp.** { *; } --keep interface com.squareup.okhttp.** { *; } - -dontwarn javax.mail.internet.MimeMessage -dontwarn javax.mail.internet.MimeBodyPart -dontwarn javax.mail.internet.SharedInputStream @@ -39,25 +34,12 @@ -dontwarn org.openjsse.javax.net.ssl.SSLParameters -dontwarn org.openjsse.javax.net.ssl.SSLSocket -dontwarn org.openjsse.net.ssl.OpenJSSE +-dontwarn org.jetbrains.annotations.** -keepclassmembers class eu.siacs.conversations.http.services.** { !transient ; } -# JSR 305 annotations are for embedding nullability information. --dontwarn javax.annotation.** - -# A resource is loaded with a relative path so the package of this class must be preserved. --keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase - -# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. --dontwarn org.codehaus.mojo.animal_sniffer.* - -# OkHttp platform used only on JVM and when Conscrypt dependency is available. --dontwarn okhttp3.internal.platform.ConscryptPlatform - - - # Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and # EnclosingMethod is required to use InnerClasses. -keepattributes Signature, InnerClasses, EnclosingMethod diff --git a/settings.gradle b/settings.gradle index 609b973132..4193570fa7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1 @@ -include ':libs:AXML' -include ':libs:xmpp-addr' -rootProject.name = 'monocles chat' +rootProject.name = 'Conversations' diff --git a/src/androidTest/java/de/monocles/chat/test/ScreenshotTest.java b/src/androidTest/java/de/monocles/chat/test/ScreenshotTest.java new file mode 100644 index 0000000000..a35c96379e --- /dev/null +++ b/src/androidTest/java/de/monocles/chat/test/ScreenshotTest.java @@ -0,0 +1,169 @@ +package de.monocles.chat.test; + +import java.util.concurrent.TimeoutException; +import java.lang.Thread; +import java.util.Arrays; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; + +import androidx.test.InstrumentationRegistry; +import androidx.test.core.app.ActivityScenario; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.rule.ServiceTestRule; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.matcher.ViewMatchers.withId; + +import tools.fastlane.screengrab.Screengrab; +import tools.fastlane.screengrab.cleanstatusbar.CleanStatusBar; +import tools.fastlane.screengrab.locale.LocaleTestRule; + +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Contact; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.entities.Presence; +import eu.siacs.conversations.entities.ServiceDiscoveryResult; +import eu.siacs.conversations.entities.TransferablePlaceholder; +import eu.siacs.conversations.persistance.FileBackend; +import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder; +import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.test.R; +import eu.siacs.conversations.ui.ConversationsActivity; +import eu.siacs.conversations.ui.StartConversationActivity; +import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xmpp.Jid; +import eu.siacs.conversations.xmpp.pep.Avatar; +import eu.siacs.conversations.xmpp.stanzas.IqPacket; + +@RunWith(AndroidJUnit4.class) +public class ScreenshotTest { + + static String pkg = InstrumentationRegistry.getInstrumentation().getContext().getPackageName(); + static XmppConnectionService xmppConnectionService; + static Account account; + + @ClassRule + public static final LocaleTestRule localeTestRule = new LocaleTestRule(); + + @ClassRule + public static final ServiceTestRule xmppServiceRule = new ServiceTestRule(); + + @BeforeClass + public static void setup() throws TimeoutException { + CleanStatusBar.enableWithDefaults(); + + Intent intent = new Intent(ApplicationProvider.getApplicationContext(), XmppConnectionService.class); + intent.setAction("ui"); + xmppConnectionService = ((XmppConnectionBinder) xmppServiceRule.bindService(intent)).getService(); + account = xmppConnectionService.findAccountByJid(Jid.of("carrot@chaosah.hereva")); + if (account == null) { + account = new Account( + Jid.of("carrot@chaosah.hereva"), + "orangeandfurry" + ); + xmppConnectionService.createAccount(account); + } + + Uri avatarUri = Uri.parse("android.resource://" + pkg + "/" + String.valueOf(R.drawable.carrot)); + final Avatar avatar = xmppConnectionService.getFileBackend().getPepAvatar(avatarUri, 192, Bitmap.CompressFormat.WEBP); + xmppConnectionService.getFileBackend().save(avatar); + account.setAvatar(avatar.getFilename()); + + Contact cheogram = account.getRoster().getContact(Jid.of("cheogram.com")); + cheogram.setOption(Contact.Options.IN_ROSTER); + cheogram.setPhotoUri("android.resource://" + pkg + "/" + String.valueOf(R.drawable.cheogram)); + Presence cheogramPresence = Presence.parse(null, null, ""); + IqPacket discoPacket = new IqPacket(IqPacket.TYPE.RESULT); + Element query = discoPacket.addChild("query", "http://jabber.org/protocol/disco#info"); + Element identity = query.addChild("identity"); + identity.setAttribute("category", "gateway"); + identity.setAttribute("type", "pstn"); + cheogramPresence.setServiceDiscoveryResult(new ServiceDiscoveryResult(discoPacket)); + cheogram.updatePresence("gw", cheogramPresence); + } + + @AfterClass + public static void teardown() { + CleanStatusBar.disable(); + } + + @Test + public void testConversation() throws FileBackend.FileCopyException, InterruptedException { + Conversation conversation = xmppConnectionService.findOrCreateConversation(account, Jid.of("+15550737737@cheogram.com"), false, false); + conversation.getContact().setOption(Contact.Options.IN_ROSTER); + conversation.getContact().setSystemName("Pepper"); + conversation.getContact().setPhotoUri("android.resource://" + pkg + "/" + String.valueOf(R.drawable.pepper)); + + Message voicemail = new Message(conversation, "", 0, Message.STATUS_RECEIVED); + voicemail.setOob("https://example.com/thing.mp3"); + voicemail.setFileParams(new Message.FileParams("https://example.com/thing.mp3|5000|0|0|10000")); + voicemail.setType(Message.TYPE_FILE); + voicemail.setSubject("Voicemail Recording"); + + Message transcript = new Message(conversation, "Where are you?", 0, Message.STATUS_RECEIVED); + transcript.setSubject("Voicemail Transcription"); + + Message picture = new Message(conversation, "", 0, Message.STATUS_SEND_RECEIVED); + picture.setOob("https://example.com/thing.webp"); + picture.setType(Message.TYPE_FILE); + xmppConnectionService.getFileBackend().copyFileToPrivateStorage( + picture, + Uri.parse("android.resource://" + pkg + "/" + String.valueOf(R.drawable.komona)), + "image/webp" + ); + xmppConnectionService.getFileBackend().updateFileParams(picture); + + conversation.addAll(0, Arrays.asList( + voicemail, + transcript, + new Message(conversation, "Meow", 0, Message.STATUS_SEND_RECEIVED), + picture, + new Message(conversation, "👍", 0, Message.STATUS_RECEIVED) + )); + + ActivityScenario scenario = ActivityScenario.launch(ConversationsActivity.class); + scenario.onActivity((Activity activity) -> { + ((ConversationsActivity) activity).switchToConversation(conversation); + }); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + Thread.sleep(100); // ImageView not paited yet after waitForIdleSync + Screengrab.screenshot("conversation"); + } + + @Test + public void testStartConversation() throws InterruptedException { + ActivityScenario scenario = ActivityScenario.launch(StartConversationActivity.class); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + Thread.sleep(100); // ImageView not paited yet after waitForIdleSync + Screengrab.screenshot("startConversation"); + } + + @Test + public void testAddContact() throws InterruptedException { + ActivityScenario scenario = ActivityScenario.launch(StartConversationActivity.class); + onView(withId(eu.siacs.conversations.R.id.speed_dial)).perform(click()); + Screengrab.screenshot("startConversationOptions"); + + // Not actually online, so can't screenshot the gateway selector yet + /*onView(withId(eu.siacs.conversations.R.id.create_contact)).perform(click()); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + Thread.sleep(10000); // ImageView not paited yet after waitForIdleSync + Screengrab.screenshot("addContact");*/ + } +} diff --git a/src/androidTest/res/drawable/carrot.webp b/src/androidTest/res/drawable/carrot.webp new file mode 100644 index 0000000000..cf0cd12885 Binary files /dev/null and b/src/androidTest/res/drawable/carrot.webp differ diff --git a/src/androidTest/res/drawable/cheogram.png b/src/androidTest/res/drawable/cheogram.png new file mode 100644 index 0000000000..ff4b5cf9c7 Binary files /dev/null and b/src/androidTest/res/drawable/cheogram.png differ diff --git a/src/androidTest/res/drawable/komona.webp b/src/androidTest/res/drawable/komona.webp new file mode 100644 index 0000000000..19cb20d1d3 Binary files /dev/null and b/src/androidTest/res/drawable/komona.webp differ diff --git a/src/androidTest/res/drawable/pepper.webp b/src/androidTest/res/drawable/pepper.webp new file mode 100644 index 0000000000..fd3d822f0d Binary files /dev/null and b/src/androidTest/res/drawable/pepper.webp differ diff --git a/src/conversations/AndroidManifest.xml b/src/conversations/AndroidManifest.xml new file mode 100644 index 0000000000..5b111101e3 --- /dev/null +++ b/src/conversations/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + diff --git a/src/conversations/fastlane/metadata/android/da-DK/short_description.txt b/src/conversations/fastlane/metadata/android/da-DK/short_description.txt new file mode 100644 index 0000000000..166643398f --- /dev/null +++ b/src/conversations/fastlane/metadata/android/da-DK/short_description.txt @@ -0,0 +1 @@ +Krypteret, brugervenlig XMPP instant messenger til din mobile enhed diff --git a/src/conversations/fastlane/metadata/android/de-DE/full_description.txt b/src/conversations/fastlane/metadata/android/de-DE/full_description.txt new file mode 100644 index 0000000000..d6b5d4b1ec --- /dev/null +++ b/src/conversations/fastlane/metadata/android/de-DE/full_description.txt @@ -0,0 +1,39 @@ +Einfach zu bedienen, zuverlässig, batteriefreundlich. Mit integrierter Unterstützung für Bilder, Gruppenchats und E2E-Verschlüsselung. + +Designprinzipien: + +* Möglichst schön und benutzerfreundlich, ohne Abstriche bei der Sicherheit und Privatsphäre +* Auf bestehende, gut etablierte Protokolle zurückgreifen +* Kein Google-Konto oder speziell Google Cloud Messaging (GCM) erforderlich +* So wenig Berechtigungen wie möglich erfordern + +Funktionen: + +* Ende-zu-Ende-Verschlüsselung entweder mit OMEMO oder OpenPGP +* Senden und Empfangen von Bildern +* Verschlüsselte Audio- und Videoanrufe (DTLS-SRTP) +* Intuitives UI, das den Android Design Richtlinien folgt +* Bilder / Profilbilder für deine Kontakte +* Synchronisation mit Desktop-Client +* Konferenzen (mit Unterstützung für Lesezeichen) +* Adressbucheinbindung +* Mehrere Konten / einheitlicher Posteingang +* Sehr geringe Auswirkungen auf die Akkulaufzeit + +Mit Conversations ist es sehr einfach, ein Konto auf dem kostenlosen conversations.im-Server zu erstellen. Dennoch funktioniert Conversations auch mit jedem anderen XMPP-Server. Zahlreiche XMPP-Server werden von Freiwilligen betrieben und sind kostenlos. + +XMPP-Funktionen: + +Conversations funktioniert mit jedem XMPP-Server. XMPP ist jedoch ein erweiterbares Protokoll. Diese Erweiterungen sind ebenfalls in sogenannten XEP's standardisiert. Conversations unterstützt einige davon, um die Benutzerfreundlichkeit zu verbessern. Es besteht die Möglichkeit, dass Ihr aktueller XMPP-Server diese Erweiterungen nicht unterstützt. Um Conversations optimal nutzen zu können, solltest du daher entweder zu einem XMPP-Server wechseln, der dies unterstützt, oder - noch besser - einen eigenen XMPP-Server für dich und deine Freunde betreiben. + +Diese XEPs sind es derzeit: + +* XEP-0065: SOCKS5 Bytestreams (oder mod_proxy65). Wird für die Übertragung von Dateien verwendet, wenn sich beide Parteien hinter einer Firewall (NAT) befinden. +* XEP-0163: Personal Eventing Protocol für Profilbilder +* XEP-0191: Mit dem Blockierungsbefehl kannst du Spammer auf eine schwarze Liste setzen oder Kontakte blockieren, ohne sie aus deiner Liste zu entfernen. +* XEP-0198: Stream Management ermöglicht es XMPP, kleinere Netzwerkausfälle und Änderungen der zugrunde liegenden TCP-Verbindung zu überstehen. +* XEP-0280: Message Carbons, das die von dir gesendeten Nachrichten automatisch mit deinem Desktop-Client synchronisiert und es dir somit ermöglicht, innerhalb einer Unterhaltung nahtlos von deinem mobilen Client zu deinem Desktop-Client und zurück zu wechseln. +* XEP-0237: Roster Versioning hauptsächlich, um Bandbreite bei schlechten mobilen Verbindungen zu sparen +* XEP-0313: Nachrichtenarchiv-Management synchronisiert den Nachrichtenverlauf mit dem Server. Aufholen von Nachrichten, die gesendet wurden, während Conversations offline war. +* XEP-0352: Client State Indication lässt den Server wissen, ob Conversations im Hintergrund läuft oder nicht. Ermöglicht es dem Server, Bandbreite zu sparen, indem er unwichtige Pakete zurückhält. +* XEP-0363: HTTP File Upload ermöglicht den Austausch von Dateien in Konferenzen und mit Offline-Kontakten. Erfordert eine zusätzliche Komponente auf deinem Server. diff --git a/src/conversations/fastlane/metadata/android/de-DE/short_description.txt b/src/conversations/fastlane/metadata/android/de-DE/short_description.txt new file mode 100644 index 0000000000..5249bddf27 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/de-DE/short_description.txt @@ -0,0 +1 @@ +Verschlüsselter, benutzerfreundlicher XMPP-Instant-Messenger für dein Smartphone diff --git a/src/conversations/fastlane/metadata/android/en-US/full_description.txt b/src/conversations/fastlane/metadata/android/en-US/full_description.txt new file mode 100644 index 0000000000..998dc68326 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/en-US/full_description.txt @@ -0,0 +1,19 @@ +The monocles chat app allows you to join a worldwide communication network. It especially focuses on features useful to users who want to contact those on other networks as well, such as SMS-enabled phone numbers. + +Based on the app Conversations, but with unique features: + +* Messages with both media and text, including animated media +* Unobtrusive display of subject lines, where present +* Links to known contacts are shown with their name +* Show timestamps for calls +* Integrates with gateways' add contact flows +* When using a gateway to the phone network, integrate with the native Android Phone app +* Address book integration +* Tag contacts and channels and browse by tag +* Command UI + +Where to get service: + +monocles chat requires you have an account with a Jabber service. You can run your own service, or use one provided by someone else, for example: https://snikket.org/hosting/ + +Art in screenshots is from https://www.peppercarrot.com by David Revoy, CC-BY. Artwork has been modified to crop out sections for avatars and photos, and in some cases add transparency. Use of this artwork does not imply endorsement of this project by the artist. diff --git a/src/conversations/fastlane/metadata/android/en-US/images/icon.png b/src/conversations/fastlane/metadata/android/en-US/images/icon.png new file mode 100644 index 0000000000..046dbfb3a0 Binary files /dev/null and b/src/conversations/fastlane/metadata/android/en-US/images/icon.png differ diff --git a/src/conversations/fastlane/metadata/android/en-US/short_description.txt b/src/conversations/fastlane/metadata/android/en-US/short_description.txt new file mode 100644 index 0000000000..cfce968a08 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/en-US/short_description.txt @@ -0,0 +1 @@ +Chat on the Jabber network (XMPP protocol); focus on features for gateway users diff --git a/src/conversations/fastlane/metadata/android/eo/short_description.txt b/src/conversations/fastlane/metadata/android/eo/short_description.txt new file mode 100644 index 0000000000..514cca5bdd --- /dev/null +++ b/src/conversations/fastlane/metadata/android/eo/short_description.txt @@ -0,0 +1 @@ +Ĉifrita, facile uzebla XMPP tujmesaĝilo por via poŝtelefono diff --git a/src/conversations/fastlane/metadata/android/es-ES/full_description.txt b/src/conversations/fastlane/metadata/android/es-ES/full_description.txt new file mode 100644 index 0000000000..8535495474 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/es-ES/full_description.txt @@ -0,0 +1,39 @@ +Fácil de usar, fiable y con poca batería. Con soporte integrado para imágenes, chats de grupo y cifrado e2e. + +Principios de diseño: + +* Ser lo más bonito y fácil de usar posible sin sacrificar la seguridad ni la privacidad. +* Basarse en protocolos existentes y bien establecidos. +* No requerir una cuenta de Google o, específicamente, Google Cloud Messaging (GCM). +* Requerir el menor número de permisos posible + +Características: + +* Cifrado de extremo a extremo con OMEMO o OpenPGP. +* Envío y recepción de imágenes +* Llamadas de audio y vídeo cifradas (DTLS-SRTP) +* Interfaz de usuario intuitiva que sigue las directrices de diseño de Android +* Imágenes / Avatares para tus contactos +* Sincronización con el cliente de escritorio +* Conferencias (con soporte para marcadores) +* Integración de la libreta de direcciones +* Múltiples cuentas / bandeja de entrada unificada +* Muy bajo impacto en la duración de la batería + +Conversations hace que sea muy fácil crear una cuenta en el servidor gratuito conversations.im. Sin embargo, Conversations también funciona con cualquier otro servidor XMPP. Muchos servidores XMPP están gestionados por voluntarios y son gratuitos. + +Características de XMPP: + +Conversations funciona con todos los servidores XMPP existentes. Sin embargo, XMPP es un protocolo extensible. Estas extensiones también están estandarizadas en los llamados XEP. Conversations soporta un par de ellas para mejorar la experiencia general del usuario. Existe la posibilidad de que su actual servidor XMPP no soporte estas extensiones. Por lo tanto, para sacar el máximo provecho de Conversaciones deberías considerar o bien cambiar a un servidor XMPP que lo haga o - mejor aún - ejecutar tu propio servidor XMPP para ti y tus amigos. + +Estos XEPs son (por el momento): + +* XEP-0065: SOCKS5 Bytestreams (o mod_proxy65). Se utilizará para transferir archivos si ambas partes están detrás de un cortafuegos (NAT). +* XEP-0163: Protocolo de Evento Personal para avatares +* XEP-0191: El comando de bloqueo te permite hacer una lista negra de spammers o bloquear contactos sin eliminarlos de tu lista. +* XEP-0198: Stream Management permite a XMPP sobrevivir a pequeños cortes de red y cambios de la conexión TCP subyacente. +* XEP-0280: Message Carbons que sincroniza automáticamente los mensajes que envías a tu cliente de escritorio y por lo tanto te permite cambiar sin problemas de tu cliente móvil a tu cliente de escritorio y viceversa en una sola conversación. +* XEP-0237: Versionado de listas, principalmente para ahorrar ancho de banda en conexiones móviles deficientes. +* XEP-0313: Gestión de Archivo de Mensajes sincroniza el historial de mensajes con el servidor. Ponerse al día con los mensajes que fueron enviados mientras Conversaciones estaba fuera de línea. +* XEP-0352: Indicación del Estado del Cliente permite al servidor saber si Conversaciones está o no en segundo plano. Permite al servidor ahorrar ancho de banda reteniendo paquetes sin importancia. +* XEP-0363: Carga de Archivos HTTP permite compartir archivos en conferencias y con contactos sin conexión. Requiere un componente adicional en su servidor. diff --git a/src/conversations/fastlane/metadata/android/es-ES/short_description.txt b/src/conversations/fastlane/metadata/android/es-ES/short_description.txt new file mode 100644 index 0000000000..7ed0476724 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/es-ES/short_description.txt @@ -0,0 +1 @@ +Mensajería instantánea XMPP cifrada y fácil de usar para tu dispositivo móvil diff --git a/src/conversations/fastlane/metadata/android/fi-FI/full_description.txt b/src/conversations/fastlane/metadata/android/fi-FI/full_description.txt new file mode 100644 index 0000000000..8071c92d06 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/fi-FI/full_description.txt @@ -0,0 +1,39 @@ +Helppokäyttöinen, luotettava ja vähän akkua käyttävä. Sisäänrakennettu tuki kuville, ryhmille ja päästä päähän -salaukselle. + +Periaatteet: + +* Ole niin kaunis ja helppokäyttöinen kuin on mahdolista turvallisuudesta ja ykstyisyydestä tinkimättä +* Käytä valmiita ja vakiintuneita protokollia +* Älä riipu Google-tunnuksesta äläkä Google Cloud Messaging -palvelusta (GCM) +* Vaadi niin vähän käyttöoikeuksia kuin mahdollista + +Ominaisuudet: + +* Päästä päähän -salaus joko OMEMO:lla tai OpenPGP:llä +* Lähetä ja vastaanota kuvia +* Salatut ääni- ja videopuhelut (DTLS-SRTP) +* Intuitiivinen käyttöliittymä joka noudattaa Androidin muotoilukieltä +* Profiilikuvat yhteystiedoille +* Synkronoi työpöytäversion kanssa +* Konferenssit (kirjanmerkkituella) +* Osoitekirjaintegrointi +* Useampi tili yhdessä näkymässä +* Todella pieni akun kulutus + +Conversations:lla on helppo luoda tili conversations.im-palvelimella. Silti Conversations toimii myös minkä tahansa muun XMPP-palvelimen kanssa. Monia XMPP-palvelimia ylläpidetään ilmaiseksi vapaaehtoisvoimin. + +XMPP-ominaisuudet: + +Conversations toimii kaikkien XMPP-palvelinten kanssa. XMPP on kuitenkin laajennettava protokolla. Nämä laajennukset on standardoitu niin kutsuttuina XEP:inä. Conversations tukee muutamaa näistä tehdäkseen käyttäjäkokemuksesta paremman. On mahdollista että nykyinen XMPP-palvelimesi ei tue kaikkia näitä laajennoksia. Siispä saadaksesi kaiken ilon irti Conversationsista kannattaa harkita joko sellaiseen palvelimeen, joka tukee näitä, vaihtamista tai oman XMPP-palvelimen ylläpitämistä itsellesi ja kavereillesi. + +XEP:t ovat tällä hetkellä: + +* XEP-0065: SOCKS5 Bytestreams (tai mod_proxy65). Käytetään tiedostojen siirtoon jos molemmat osapuolet ovat palomuurin tai NAT:n takana. +* XEP-0163: Personal Eventing Protocol profiilikuville +* XEP-0191: Blocking command lets you blacklist spammers or block contacts without removing them from your roster. +* XEP-0198: Stream Management mahdollistaa XMPP:n selviämisen pienestä verkon pätkimisestä ja TCP-yhteyden muutoksista. +* XEP-0280: Kopiot lähettämistäsi viesteistä muille laitteillesi. Mahdolistaa laitteiden vaihdon kesken keskustelun täysin saumoitta. +* XEP-0237: Roster Versioning säästää dataa heikoila yhteyksillä +* XEP-0313: Message Archive Management synchronize message history with the server. Catch up with messages that were sent while Conversations was offline. +* XEP-0352: Client State Indication lets the server know whether or not Conversations is in the background. Allows the server to save bandwidth by withholding unimportant packages. +* XEP-0363: HTTP File Upload allows you to share files in conferences and with offline contacts. Requires an additional component on your server. diff --git a/src/conversations/fastlane/metadata/android/fi-FI/short_description.txt b/src/conversations/fastlane/metadata/android/fi-FI/short_description.txt new file mode 100644 index 0000000000..2713b6efd1 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/fi-FI/short_description.txt @@ -0,0 +1 @@ +Salattu ja helppokäyttöinen XMPP-pikaviestin mobiililaitteellesi diff --git a/src/conversations/fastlane/metadata/android/fr-FR/full_description.txt b/src/conversations/fastlane/metadata/android/fr-FR/full_description.txt new file mode 100644 index 0000000000..653bdec105 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/fr-FR/full_description.txt @@ -0,0 +1,38 @@ +Facile à utiliser, fiable, respectueux de votre batterie. Prend en charge les images, les conversations de groupe et le chiffrement de bout-en-bout. + +Principes de conception : + +* Être le plus joli et simple d'utilisation possible, sans compromis sur la sécurité ou la vie privée. +* S'appuyer sur des protocoles existants, bien établis +* Ne pas nécessiter de compte Google ou spécifiquement le Google Cloud Messaging (GCM) +* Nécessiter le moins de permissions possible + +Fonctionnalités : +* Chiffrement de bout-en-bout avec au choix, OMEMO ou OpenPGP +* Envoi et réception d'images +* Appels audio et vidéo chiffrés (DTLS-SRTP) +* Interface utilisateur intuitive qui suit les directives de conception d'Android +* Images / avatars pour vos contacts +* Synchronisation avec des clients de bureau +* Conférences (avec prise en charge des marque-pages) +* Intégration avec le carnet d'adresses +* Plusieurs comptes / boîte de réception unifiée +* Impact très faible sur l'autonomie de la batterie + +Conversations facilite la création de compte sur le serveur gratuit conversations.im. Cependant Conversations fonctionne également avec n'importe quel autre serveur XMPP. De nombreux serveurs XMPP sont gérés par des bénévoles et gratuits. + +Fonctionnalités de XMPP : + +Conversations fonctionne avec n'importe quel serveur XMPP. Cependant XMPP est un protocole extensible. Ces extensions sont aussi standardisées dans ce que l'on appelle les XEP. Conversations en prend en charge quelques-unes pour rendre l'expérience utilisateur meilleure dans l'ensemble. Il y a des chances que votre serveur XMPP actuel ne les prenne pas en charge. Ainsi, pour tirer le meilleur parti de Conversations, vous devriez envisager soit de passer à un serveur XMPP qui le fait, ou encore mieux, gérer votre propre serveur XMPP pour vous et vos amis. + +Ces XEP sont actuellement : + +* XEP-0065: SOCKS5 Bytestreams (ou mod_proxy65). Sera utilisé pour transférer des fichiers si les deux correspondants sont derrière un pare-feu (NAT). +* XEP-0163: Personal Eventing Protocol pour les avatars +* XEP-0191: Blocking Command vous permet de mettre des spammeurs sur liste noire ou bloquer des contacts sans les retirer de vos contacts. +* XEP-0198: Stream Management permet à XMPP de survivre à des petites pannes de réseau et aux changements de la connexion TCP sous-jacente. +* XEP-0280: Message Carbons qui synchronise automatiquement les messages que vous envoyez à votre client de bureau et vous permet ainsi de passer sans heurt de votre client mobile à votre client de bureau et inversement dans une conversation. +* XEP-0237: Roster Versioning principalement pour économiser de la bande passante sur les connexions mobiles de mauvaise qualité. +* XEP-0313: Message Archive Management synchronise l'historique des messages avec le serveur. Retrouvez des messages qui ont été envoyés pendant que Conversations était hors ligne. +* XEP-0352: Client State Indication fait savoir au serveur si Conversations est ou n'est pas en arrière-plan. Permet au serveur d'économiser de la bande passante en différant des paquets non importants. +* XEP-0363: HTTP File Upload vous permet de partager des fichiers dans les conférences et avec des contacts hors-ligne. Nécessite un composant supplémentaire sur votre serveur. diff --git a/src/conversations/fastlane/metadata/android/fr-FR/short_description.txt b/src/conversations/fastlane/metadata/android/fr-FR/short_description.txt new file mode 100644 index 0000000000..b4ae66d63e --- /dev/null +++ b/src/conversations/fastlane/metadata/android/fr-FR/short_description.txt @@ -0,0 +1 @@ +Messagerie instantanée XMPP chiffrée, facile à utiliser avec votre appareil mobile diff --git a/src/conversations/fastlane/metadata/android/gl-ES/full_description.txt b/src/conversations/fastlane/metadata/android/gl-ES/full_description.txt new file mode 100644 index 0000000000..9bdcf9042d --- /dev/null +++ b/src/conversations/fastlane/metadata/android/gl-ES/full_description.txt @@ -0,0 +1,40 @@ +Fácil de usar, fiable, baixo consumo de batería. Con soporte para imaxes, conversas en grupo e cifraxe e2e. + +Principios do deseño: + +* Ser tan fermosa e doada de usar como sexa posible sen sacrificar a seguridade ou privacidade +* Apoiarse en protocolos existentes e ben establecidos +* Non precisar dunha Conta de Google ou concretamente Google Cloud Messaging (GCM) +* Solicitar os mínimos permisos posibles + +Características: + +* Cifraxe extremo-a-extremo, ben con OMEMO ou con OpenPGP +* Enviar e recibir imaxes +* Chamadas de audio e vídeo cifradas (DTLS-SRTP) +* Interface intuitiva seguindo as recomendacións Android Design +* Imaxes/Avatares para os Contactos +* Sicronizada co cliente de escritorio +* Conferencias (con soporte para marcadores) +* Integración coa Libreta de enderezos +* Varias contas cunha lista de conversas unificada +* Consumo de enerxía moi baixo + +Con Conversations é moi doado crear unha conta no servidor gratuíto conversations.im. Con todo, Conversations funcionará igualmente con calquera outro servidor XMPP. Existen moitos servidores XMPP xestionados por voluntarios e gratuítos. + +Características de XMPP: + +Conversations funciona con calquera sevidor XMPP, mais XMPP é un protocolo extensible. Estas extensións tamén están estadarizadas nos chamados XEP's. +Conversations da soporte a un par delas que axudan a mellorar a experiencia de uso da aplicación. Pode acontecer que o teu servidor XMPP actual non dé soporte para estas extensións. Por tanto para obter o mellor resultado ao usar Conversations debes ter considerar usar un servidor XMPP que si o faga - ou incluso mellor - xestionar o teu propio servidor para as túas amizades. + +Estes XEPs son - neste intre: + +* XEP-0065: SOCKS5 Bytestreams (ou mod_proxy65). Usado para a transferencia de ficheiros se as dúas partes están detrás dun cortalumes (NAT). +* XEP-0163: Personal Eventing Protocol para os avatares +* XEP-0191: O bloqueo de ordes permiteche bloquear spammer ou contactos sen eliminalos das túas listaxes. +* XEP-0198: Stream Management permite que XMPP sobreviva a caídas da rede e cambios na conexión TCP. +* XEP-0280: Message Carbons permite sincronizar automáticamente as mensaxes co teu cliente de escritorio e por tanto cambiar dun a outro sen perder mensaxes da conversa. +* XEP-0237: Roster Versioning fundamentalmente para aforrar datos en conexións móbiles +* XEP-0313: Message Archive Management sincroniza o historial de mensaxes co servidor. Para obter as mensaxes recibidas cando Conversations non teña conexión. +* XEP-0352: Client State Indication permítelle ao servidor saber se Conversations está a funcionar en segundo plano. Permítelle ao servidor aforrar ancho de banda retendo paquetes de datos de pouca importancia. +* XEP-0363: HTTP File Upload permíteche compartir ficheiros en salas de conferencia e con contactos que non están conectados. Require un compoñente adicional no teu servidor. diff --git a/src/conversations/fastlane/metadata/android/gl-ES/short_description.txt b/src/conversations/fastlane/metadata/android/gl-ES/short_description.txt new file mode 100644 index 0000000000..79c77166e9 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/gl-ES/short_description.txt @@ -0,0 +1 @@ +Mensaxería instantánea XMPP cifrada e fácil de usar para o teu dispositivo móbil diff --git a/src/conversations/fastlane/metadata/android/it-IT/full_description.txt b/src/conversations/fastlane/metadata/android/it-IT/full_description.txt new file mode 100644 index 0000000000..d390af6613 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/it-IT/full_description.txt @@ -0,0 +1,39 @@ +Facile da usare, affidabile, leggero sulla batteria. Con supporto integrato per immagini, chat di gruppo e crittografia e2e. + +Principi di design: + +* Essere il più bello e facile da usare possibile senza sacrificare la sicurezza o la privacy +* Affidarsi a protocolli esistenti ben affermati +* Non richiedere un account Google o nello specifico Google Cloud Messaging (GCM) +* Richiedere il minor numero di autorizzazioni possibile + +Caratteristiche: + +* Crittografia end-to-end con OMEMO o OpenPGP +* Invio e ricezione di immagini +* Chiamate audio e video crittografate (DTLS-SRTP) +* Interfaccia utente intuitiva che segue le linee guida del design di Android +* Immagini / Avatar per i tuoi contatti +* Sincronizzazione con client desktop +* Conferenze (con supporto ai segnalibri) +* Integrazione della rubrica +* Profili multipli / messaggi unificati +* Consumo molto basso della batteria + +Conversations rende veramente facile creare un profilo sul server gratuito conversations.im. Tuttavia Conversations funzionerà anche con qualsiasi altro server XMPP. Molti server XMPP vengono gestiti da volontari e sono gratuiti. + +Caratteristiche di XMPP: + +Conversations funziona con tutti i server XMPP. Tuttavia XMPP è un protocollo estensibile. Anche queste estensioni sono standardizzate, con il nome XEP. Conversations supporta alcune di esse per rendere migliore l'esperienza utente. È possibile che il server XMPP che stai usando non supporti queste estensioni. Perciò, per ottenere il meglio da Conversations dovresti considerare di passare ad un server XMPP che le supporta o, ancora meglio, installarne uno tuo per te e i tuoi amici. + +Queste XEP sono, ad oggi: + +* XEP-0065: SOCKS5 Bytestreams (o mod_proxy65). Usata per trasferire file se entrambe le parti sono dietro un firewall (NAT). +* XEP-0163: Personal Eventing Protocol. Per gli avatar. +* XEP-0191: Blocking command. Ti consente di bloccare lo spam o i contatti senza rimuoverli dal tuo elenco. +* XEP-0198: Stream Management. Consente a XMPP di resistere a brevi disconnessioni e cambi della connessione TCP sottostante. +* XEP-0280: Message Carbons. Sincronizza automaticamente i messaggi che invii al client desktop, quindi ti consente di passare senza problemi dal mobile al desktop e viceversa con un'unica conversazione. +* XEP-0237: Roster Versioning. Principalmente per risparmiare banda di rete in connessioni mobili deboli +* XEP-0313: Message Archive Management. Sincronizza la cronologia dei messaggi con il server. Recupera i messaggi che sono stati inviati mentre Conversations era offline. +* XEP-0352: Client State Indication. Fa sapere al server se Conversations è in secondo piano o no. Permette al server di risparmiare banda di rete trattenendo i pacchetti non importanti. +* XEP-0363: HTTP File Upload. Ti consente di condividere file nelle conferenze e con i contatti offline. Richiede un componente aggiuntivo sul tuo server. diff --git a/src/conversations/fastlane/metadata/android/it-IT/short_description.txt b/src/conversations/fastlane/metadata/android/it-IT/short_description.txt new file mode 100644 index 0000000000..fd4dfa96d1 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/it-IT/short_description.txt @@ -0,0 +1 @@ +Client di messaggistica XMPP facile e criptato, per il tuo dispositivo mobile diff --git a/src/conversations/fastlane/metadata/android/ja-JP/short_description.txt b/src/conversations/fastlane/metadata/android/ja-JP/short_description.txt new file mode 100644 index 0000000000..ade292722c --- /dev/null +++ b/src/conversations/fastlane/metadata/android/ja-JP/short_description.txt @@ -0,0 +1 @@ +携帯端末で簡単に操作できるXMPP暗号化インスタント・メッセンジャー diff --git a/src/conversations/fastlane/metadata/android/pl-PL/full_description.txt b/src/conversations/fastlane/metadata/android/pl-PL/full_description.txt new file mode 100644 index 0000000000..442e1e8263 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/pl-PL/full_description.txt @@ -0,0 +1,39 @@ +Łatwy w użyciu, godny zaufania, przyjazny dla baterii. Wbudowane wsparcie dla obrazków, rozmów grupowych i szyfrowania od nadawcy do odbiorcy. + +Zasady projektu: + +* ma być tak ładny i prosty w użyciu jak to możliwe bez uszczerbku na bezpieczeństwie lub prywatności; +* używa istniejących, dobrze znanych protokołów; +* nie wymaga Konta Google ani, w szczególności, Google Cloud Messaging (GCM); +* wymaga tylko naprawdę koniecznych uprawnień. + +Funkcjonalność: + +* szyfrowanie od nadawcy do odbiorcy (E2EE) z użyciem OMEMO lub OpenPGP; +* wysyłanie i odbieranie obrazków; +* szyfrowane rozmowy głosowe i wideo; +* intuicyjny interfejs użytkownika, zgodny z wytycznymi Android Design; +* obrazki/awatary dla Twoich kontaktów; +* synchronizacja z klientem desktopowym; +* konferencje (z obsługą zakładek); +* integracja z książką adresową; +* wiele kont, zintegrowana skrzynka odbiorcza; +* bardzo ograniczony wpływ na zużycie baterii. + +Conversations bardzo ułatwia rejestrację konta na darmowym serwerze conversations.im, jednak będzie działać również z każdym innym serwerem XMPP. Wiele serwerów jest uruchamianych przez wolontariuszy i są dostępne bez opłat. + +Funkcjonalność XMPP: + +Conversations działa z każdym dostępnym serwerem XMPP, jednak XMPP to rozszerzalny protokół. Rozszerzenia są ustandaryzowane w tak zwanych XEP. Conversations obsługuje sporo z nich, dzięki czemu można go przyjemniej używać. Jest jednak możliwość, że Twój obecny serwer nie obsługuje tych rozszerzeń. Aby wyciągnąć jak najwięcej z Conversations rozważ przeniesienie się na taki serwer, który je obsługuje, lub — jeszcze lepiej — uruchom własny serwer dla Ciebie i Twoich przyjaciół. + +Obecnie są obsługiwane następujące rozszerzenia: + +* XEP-0065: SOCKS5 Bytestreams (lub mod_proxy65). Będzie używany do przesyłania plików jeżeli obie strony znajdują się za zaporą (NAT); +* XEP-0163: Personal Eventing Protocol dla awatarów; +* XEP-0191: Blocking Command umożliwia ochronę przed spamerami lub blokowanie bez usuwanie ich z rostera; +* XEP-0198: Stream Management pozwala na przetrwanie krótkich braków połączenia z siecią oraz zmian używanego połączenia TCP; +* XEP-0280: Message Carbons automatycznie synchronizuje wysyłane wiadomości z klientem desktopowym i w ten sposób pozwala na proste używanie zarówno klienta mobilnego, jak i desktopowego, w jednej konwersacji; +* XEP-0237: Roster Versioning, dzięki któremu można ograniczyć używanie sieci na słabych połączeniach komórkowych; +* XEP-0313: Message Archive Management synchronizuje historię wiadomości z serwerem. Bądź na bieżąco z wiadomości wysłanymi gdy Conversations był rozłączony; +* XEP-0352: Client State Indication informuje serwer o tym, czy Conversations działa w tle. Pozwala to na oszczędzanie łącza przez wstrzymywanie mniej ważnych komunikatów; +* XEP-0363: HTTP File Upload umożliwia udostępnianie plików w konferencjach oraz rozłączonym kontaktom. Wymaga dodatkowego komponentu na Twoim serwerze. diff --git a/src/conversations/fastlane/metadata/android/pl-PL/short_description.txt b/src/conversations/fastlane/metadata/android/pl-PL/short_description.txt new file mode 100644 index 0000000000..7869c1ba5a --- /dev/null +++ b/src/conversations/fastlane/metadata/android/pl-PL/short_description.txt @@ -0,0 +1 @@ +Szyfrowany, prosty w użyciu komunikator XMPP dla Twojego urządzenia mobilnego diff --git a/src/conversations/fastlane/metadata/android/ro/full_description.txt b/src/conversations/fastlane/metadata/android/ro/full_description.txt new file mode 100644 index 0000000000..2d4ae419dc --- /dev/null +++ b/src/conversations/fastlane/metadata/android/ro/full_description.txt @@ -0,0 +1,38 @@ +Ușor de utilizat, fiabil, prietenos cu bateria. Cu suport încorporat pentru imagini, discuții de grup și criptare E2E. + +Principii de proiectare: + +* Să fie cât mai frumos și mai ușor de utilizat posibil, fără a sacrifica securitatea sau confidențialitatea. +* Să se bazeze pe protocoale existente și bine stabilite +* Nu necesită un cont Google sau în mod specific Google Cloud Messaging (GCM). +* Să necesite cât mai puține permisiuni posibil + +Caracteristici: + +* Criptare de la un capăt-la-altul (E2E) cu OMEMO sau OpenPGP +* Trimiterea și primirea de imagini +* Apeluri audio și video criptate (DTLS-SRTP) +* Interfață intuitivă care respectă liniile directoare Android Design +* Imagini / Avataruri pentru contactele dvs. +* Se sincronizează cu clientul desktop +* Conferințe (cu suport pentru marcaje) +* Integrare cu lista de contacte +* Conturi multiple / căsuță de mesaje unificată +* Impact foarte redus asupra duratei de viață a bateriei + +Conversations face foarte ușoară crearea unui cont pe serverul gratuit conversations.im. Cu toate acestea, Conversations va funcționa și cu orice alt server XMPP. O mulțime de servere XMPP sunt administrate de voluntari și sunt gratuite. + +Caracteristici XMPP: + +Conversations funcționează cu orice server XMPP existent. Cu toate acestea, XMPP este un protocol extensibil. Aceste extensii sunt, de asemenea, standardizate în așa-numitele XEP-uri. Conversations suportă câteva dintre acestea pentru a îmbunătăți experiența generală a utilizatorului. Există o șansă ca serverul XMPP actual să nu suporte aceste extensii. Prin urmare, pentru a profita la maximum de Conversations, ar trebui să luați în considerare fie trecerea la un server XMPP care să suporte aceste extensii, fie - și mai bine - să rulați propriul server XMPP pentru dumneavoastră și prietenii dumneavoastră. + +Aceste XEP-uri sunt - deocamdată: +* XEP-0065: SOCKS5 Bytestreams (sau mod_proxy65). Va fi utilizat pentru a transfera fișiere dacă ambele părți se află în spatele unui firewall (NAT). +* XEP-0163: Protocol de evenimente personale pentru avatare. +* XEP-0191: Comanda de blocare vă permite să puneți pe lista neagră spamerii sau să blocați contactele fără a le elimina din listă. +* XEP-0198: Stream Management permite XMPP să supraviețuiască unor mici întreruperi de rețea și schimbărilor conexiunii TCP de bază. +* XEP-0280: Message Carbons, care sincronizează automat mesajele pe care le trimiteți în clientul desktop și vă permite astfel să treceți fără probleme de la clientul mobil la clientul desktop și înapoi în cadrul unei singure conversații. +* XEP-0237: Roster Versioning în principal pentru a economisi lățimea de bandă în cazul conexiunilor mobile slabe +* XEP-0313: Gestionarea arhivei de mesaje sincronizează istoricul mesajelor cu serverul. Recuperați mesajele care au fost trimise în timp ce Conversations era deconectat. +* XEP-0352: Client State Indication permite serverului să știe dacă Conversations este sau nu în fundal. Permite serverului să economisească lățimea de bandă prin reținerea pachetelor neimportante. +* XEP-0363: HTTP File Upload vă permite să partajați fișiere în cadrul conferințelor și cu contactele deconectate. Necesită o componentă suplimentară pe serverul dumneavoastră. diff --git a/src/conversations/fastlane/metadata/android/ro/short_description.txt b/src/conversations/fastlane/metadata/android/ro/short_description.txt new file mode 100644 index 0000000000..143f7cb553 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/ro/short_description.txt @@ -0,0 +1 @@ +Client de mesagerie XMPP ușor de folosit, criptat, și optimizat pentru mobile diff --git a/src/conversations/fastlane/metadata/android/ru-RU/full_description.txt b/src/conversations/fastlane/metadata/android/ru-RU/full_description.txt new file mode 100644 index 0000000000..77c8edbb9a --- /dev/null +++ b/src/conversations/fastlane/metadata/android/ru-RU/full_description.txt @@ -0,0 +1,39 @@ +Простой в использовании, надежный, экономный для батареи. Со встроенной поддержкой изображений, групповых чатов и сквозным шифрованием. + +Принципы дизайна: + +* Быть максимально красивым и простым в использовании, не жертвуя при этом безопасностью и конфиденциальностью. +* Полагаться на существующие, хорошо зарекомендовавшие себя протоколы. +* Не требовать учетную запись Google или, в частности, Google Cloud Messaging (GCM). +* Требовать как можно меньше разрешений. + +Функции: + +* Сквозное шифрование с помощью OMEMO или OpenPGP. +* Отправка и получение изображений +* Зашифрованные аудио и видео звонки (DTLS-SRTP) +* Интуитивно понятный пользовательский интерфейс, соответствующий Рекомендациям по дизайну Android +* Картинки / аватары для ваших контактов +* Синхронизация с настольным клиентом +* Конференции (с поддержкой закладок) +* Интеграция с адресной книгой +* Несколько учетных записей / единый почтовый ящик +* Очень низкое влияние на время работы от батареи + +Conversations позволяет очень легко создать учетную запись на бесплатном сервере conversations.im. Однако Conversations также будет работать с любым другим сервером XMPP. Многие XMPP серверы управляются добровольцами и предоставляются бесплатно. + +Возможности XMPP: + +Conversations работает со всеми существующими XMPP-серверами. Однако XMPP - это расширяемый протокол. Эти расширения также стандартизированы в так называемых XEP-протоколах. Conversations поддерживает несколько из них, чтобы улучшить общее взаимодействие с пользователем. Есть вероятность, что ваш текущий XMPP-сервер не поддерживает какие либо расширения. Поэтому, чтобы получить максимальную отдачу от Conversations, вам следует либо перейти на XMPP-сервер который поддерживает эти расширения, либо, что еще лучше, запустить свой собственный XMPP-сервер для вас и ваших друзей. + +На данный момент эти XEP: + +* XEP-0065: SOCKS5 Bytestreams SOCKS5 (или mod_proxy65): будет использоваться для передачи файлов если обе стороны находятся за брандмауэром (или NAT). +* XEP-0163: Personal Eventing Protocol: для аватаров. +* XEP-0191: Blocking command: позволяет вносить спамеров в черный список или блокировать контакты, не удаляя их из своего списка. +* XEP-0198: Stream Management: позволяет XMPP справляться с небольшими перебоями в сети и изменениями нижележащего TCP-соединения. +* XEP-0280: Message Carbons: автоматически синхронизирует отправляемые вами сообщения с вашим клиентом на настольном компьютере и таким образом позволяет вам плавно переключаться с мобильного клиента на настольный клиент и обратно в рамках одного разговора. +* XEP-0237: Roster Versioning: в основном, для экономии полосы пропускания при плохом мобильном соединении. +* XEP-0313: Message Archive Management: синхронизирует историю сообщений с сервером. Отслеживание сообщений, отправленных во время разговоров в автономном режиме. +* XEP-0352: Client State Indication: позволяет серверу узнать ведутся ли разговоры в фоновом режиме. Позволяет серверу экономить пропускную способность, удерживая неважные пакеты. +* XEP-0363: HTTP File Upload: позволяет обмениваться файлами в конференциях и с контактами в автономном режиме. Требует дополнительный компонент на вашем сервере. diff --git a/src/conversations/fastlane/metadata/android/ru-RU/short_description.txt b/src/conversations/fastlane/metadata/android/ru-RU/short_description.txt new file mode 100644 index 0000000000..059ec9eb73 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/ru-RU/short_description.txt @@ -0,0 +1 @@ +Зашифрованный и простой в использовании XMPP мессенджер для вашего мобильного diff --git a/src/conversations/fastlane/metadata/android/sq/full_description.txt b/src/conversations/fastlane/metadata/android/sq/full_description.txt new file mode 100644 index 0000000000..f6f03b1513 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/sq/full_description.txt @@ -0,0 +1,39 @@ +I kollajtë për t’u përdorur, i qëndrueshëm, dashamirës ndaj baterisë. Me mbulim së brendshmi për figura, fjalosje në grup dhe fshehtëzim e2e. + +Parime konceptuale: + +* Të qenët aq i bukur dhe i lehtë për përdorim sa mundet, pa sakrifikuar sigurinë ose privatësinë +* Bazim në protokolle ekzistues, të mirënjohur +* Mospasje nevojë për një Google Account, ose, posaçërisht Google Cloud Messaging (GCM) +* Kërkim i sa më pak lejesh që të jetë e mundur + +Veçori: + +* Fshehtëzim skaj-më-skaj me OMEMO, ose OpenPGP +* Dërgim dhe marrje mesazhesh +* Thirrje të fshehtëzuara audio dhe video (DTLS-SRTP) +* UI intuitive që ndjek udhëzimet Android Design +* Foto / Avatarë të Kontakteve tuaja +* Njëkohësim me klient desktop +* Konferenca (me mbulim për faqerojtës) +* Integrim libri adresash +* Llogari të shumta / kuti e unifikuar të marrësh +* Ndikim shumë i pakët në jetëgjatësinë e baterisë + +Conversations e bën shumë të lehtë krijimin e një llogarie te shërbyesi falas conversations.im. Megjithatë, Conversations do të funksionojë me çfarëdo shërbyesi tjetër XMPP. Plot shërbyes XMPP mbahen në punë nga vullnetarë dhe janë pa pagesë + +Veçori të XMPP-së: + +Conversations funksionon me çdo shërbyes XMPP në qarkullim. Megjithatë, XMPP është një protokoll i zgjerueshëm. Edhe këto zgjerime janë të standardizuara në të ashtuquajturit XEP-e. Conversations mbulon një a dy prej tyre, për ta bërë punën e përdoruesit më të mirë në përgjithësi. Ka një mundësi që shërbyesi juaj aktual XMPP të mos i mbulojë këto zgjerime. Ndaj, që të përfitoni maksimumin nga Conversations, duhet të shihni mundësi ose të kaloni te një shërbyes XMPP që i mbulon, ose - akoma më mirë - të vini në punë shërbyesin tuaj XMPP për ju dhe shokët tuaj. + +Këto XEP-e janë - deri sot: + +* XEP-0065: SOCKS5 Bytestreams (ose mod_proxy65). Do të përdoret për të shpërngulur kartela, nëse të dy palët gjenden pas një firewall-i (NAT). +* XEP-0163: Personal Eventing Protocol, për avatarë +* XEP-0191: Urdhri i bllokimeve ju lejon të kaloni në listë bllokimesh llogari që dërgojnë mesazhe të padëshiruar, ose të bllokoni kontakte pa i hequr nga lista juaj. +* XEP-0198: Stream Management i lejon XMPP-së të mbijetojë ndërprerje të vockla rrjeti dhe ndryshime te lidhja përkatëse TCP. +* XEP-0280: Message Carbons do të njëkohësojë automatikisht te klienti juaj desktop mesazhet që dërgoni dhe, pra, ju lejon të kaloni pa një cen nga klienti juaj për celular në atë për desktop dhe anasjelltas, brenda një bisede. +* XEP-0237: Roster Versioning kryesisht për të kursyer sasi trafiku në lidhje celulare të dobëta +* XEP-0313: Message Archive Management njëkohëson historik mesazhesh me shërbyesin. Ndiqni mesazhet që qenë dërguar ndërkohë që Conversations s’qe në linjë. +* XEP-0352: Client State Indication i lejon shërbyesit të dijë nëse është apo jo në prapaskenë Conversations. I lejon shërbyesit të kursejë sasi trafiku, duke mbajtur paketa pa rëndësi. +* XEP-0363: HTTP File Upload ju lejon të ndani me të tjerë kartela në konferenca dhe me kontakte jo në linjë. Lyp një përbërë shtesë në shërbyesin tuaj. diff --git a/src/conversations/fastlane/metadata/android/sq/short_description.txt b/src/conversations/fastlane/metadata/android/sq/short_description.txt new file mode 100644 index 0000000000..bec029626c --- /dev/null +++ b/src/conversations/fastlane/metadata/android/sq/short_description.txt @@ -0,0 +1 @@ +Shkëmbyes XMPP mesazhesh aty për aty, i fshehtëzuar, i kollajtë, për celular diff --git a/src/conversations/fastlane/metadata/android/sv-SE/full_description.txt b/src/conversations/fastlane/metadata/android/sv-SE/full_description.txt new file mode 100644 index 0000000000..c02bd4912c --- /dev/null +++ b/src/conversations/fastlane/metadata/android/sv-SE/full_description.txt @@ -0,0 +1,39 @@ +Lättanvänd, pålitlig och batterivänlig. Med inbyggt stöd för bilder, gruppchatt och totalsträckskryptering (end-to-end-kryptering). + +Designprinciper: + +* Vara så snygg och lättanvänd som möjligt utan att offra säkerhet eller personlig integritet +* Bygga på väletablerade existerande protokoll +* Inte kräva ett Google-konto eller specifikt Google Cloud Messaging (GCM) +* Kräva så få behörigheter som möjligt + +Funktioner: + +* Totalsträckskryptering (end-to-end-kryptering) med antingen OMEMO eller OpenPGP +* Skicka och ta emot bilder +* Krypterade ljud- och bildsamtal (DTLS-SRTP) +* Intuitivt användargränssnitt som följder Androids designriktlinjer +* Bilder eller avatarer för dina kontakter +* Synkroniserar med din skrivbordsklient +* Konferenser (med stöd för bokmärken) +* Integration med adressboken +* Stöd för flera konton, med delan inkorg +* Väldigt liten påverkan på batteriets livstid + +Med Conversations kan du lätt skapa ett konto på den fria servern conversations.im. Men Conversations fungerar med vilken annan XMPP-server som helst. Många XMPP-servrar drivs av volontärer och är gratis att använda. + +XMPP-funktioner: + +Conversations fungerar med alla XMPP-servrar. Men XMPP är ett utbyggbart protokoll. Dessa tillägg är också standardiserade i så kallade XEP’s. Conversations stödjer vissa av dessa tillägg för att göra den övergripande användarupplevelsen bättre. Det kan hända att din XMPP-server inte har stöd för dessa tillägg. För att få ut det mesta av Conversations bör du överväga att antingen byta till en XMPP-server som har stöd, eller - ännu bättre - kör din egen XMPP-server för dig och dina vänner! + +De XEP-tillägg som stöds är: + +* XEP-0065: SOCKS5 Bytestreams (or mod_proxy65). Används för filöverföring om båda parter är bakom en brandvägg (NAT). +* XEP-0163: Personal Eventing Protocol för avatarer +* XEP-0191: Blocking command låter dig svartlista spammare eller blocka kontakter utan att ta bort dem +* XEP-0198: Stream Management låter XMPP att klara av mindre nätverksavbrott och förändringar i den underliggande TCP-anslutningen +* XEP-0280: Message Carbons som automatiskt synkar meddelanden till din skrivbordsklient och på så viss gör det möjligt att växla sömlöst från din mobil till skrivbordsklient och tillbaka inom en och samma konversation +* XEP-0237: Roster Versioning för att spara bandbredd vid dåliga mobilanslutningar +* XEP-0313: Message Archive Management synkronisera meddelandehistorik med server. Läs meddelanden som sänts medan Conversations var off line. +* XEP-0352: Client State Indication låter servern veta om Conversations är körs i bakgrunden eller inte. Det gör att servern kan spara bandbredd genom att inte skicka oviktiga paket. +* XEP-0363: HTTP File Upload låter dig dela filer i konferenser med offline-kontakter. Det kräver ett tillägg på din server. diff --git a/src/conversations/fastlane/metadata/android/sv-SE/short_description.txt b/src/conversations/fastlane/metadata/android/sv-SE/short_description.txt new file mode 100644 index 0000000000..0177c6fe26 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/sv-SE/short_description.txt @@ -0,0 +1 @@ +Krypterad lättanvänd XMPP-meddelandeapp för din mobil diff --git a/src/conversations/fastlane/metadata/android/tr-TR/full_description.txt b/src/conversations/fastlane/metadata/android/tr-TR/full_description.txt new file mode 100644 index 0000000000..889d502e08 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/tr-TR/full_description.txt @@ -0,0 +1,39 @@ +Kullanımı kolay, güvenilir, pil ömrü dostu. Resimler, gruplar ve uçtan uca şifreleme için yerleşik destek. + +Tasarım ilkeleri: + +* Gizlilik ve güvenlikten tasarruf etmeden olabildiğince iyi görünümlü ve kolay kullanımlı olmak +* Halihazırda var olan, köklü protokollere dayanmak +* Bir Google hesabına, özellikle Google Bulut Mesajlaşması (GCM)'e, gerek duymamak +* Olabildiğince az izine gerek duymak + +Özellikler: + +* OMEMO veya OpenPGP ile uçtan uca şifreleme +* Fotoğraf gönderme ve alma +* Şifrelenmiş görüntülü ve sesli aramalar (DTLS-SRTP) +* Android tasarım standartlarına uyan öğrenmesi kolay arayüz +* Kişileriniz için profil fotoğrafları / Avatarlar +* Masaüstü uygulamasıyla senkronizasyon +* Konferanslar (yer imi desteği ile) +* Kişiler listesiyle entegrasyon +* Birden fazla hesap / Birleşik gelen kutusu +* Pil ömrüne çok düşük etki + +Conversations, kolayca ve ücretsiz olarak conversations.im sunucusunda hesap oluşturmanıza olanak tanır. Conversations başka herhangi bir XMPP sunucusuyla da çalışır. Çoğu XMPP sunucusu gönüllüler tarafından işletilir ve ücretsizdir. + +XMPP Özellikleri: + +Conversations var olan bütün XMPP sunucularıyla kullanılabilir. Ancak XMPP, eklentiler ile genişletilebilen bir protokoldür. Bu eklentiler XEP'ler olarak standardize edilmiştir. Conversations kullanıcı deneyimini iyileştirmek için bu eklentilerden birkaçını destekler. Kullandığınız XMPP sunucusu bu eklentileri desteklemiyor olabilir. Bu yüzden Conversations'tan en iyi şekilde faydalanmak için bu eklentileri destekleyen bir sunucuya geçmeli veya, daha da iyisi, siz ve arkadaşlarınız için kendi XMPP sunucunuzu kurmalısınız. + +Şimdilik bu XEP'ler: + +* XEP-0065: SOCKS5 Bytestreams (mod_proxy65). İki taraf da bir güvenlik duvarı (NAT) arkasında ise dosya aktarımı için kullanılacaktır. +* XEP-0163: Avatarlar için Kişisel Olay Protokolü (Personal Eventing Protocol) +* XEP-0191: Engelleme komutu - Spam atanları ve kişilerinizi listenizden kaldırmadan engellemenizi sağlar. +* XEP-0198: Akış Kontrolü (Stream Management) - XMPP'yi ve altındaki TCP bağlantısını küçük çaplı bağlantı kopmalarına karşı korur. +* XEP-0280: Mesaj Karbonları - Mesajlarınızı masaüstü uygulamasıyla senkronize ederek cihazlarınız arasında kesintisiz geçiş yapmanızı sağlar. +* XEP-0237: Roster Versioning (Liste Sürüm Takibi) - Zayıf mobil ağlarda bant aralığından tasarruf etmek amacıyla. +* XEP-0313: Mesaj Arşivi Yönetimi - Çevrimdışı olduğunuzda bile mesaj almaya devam edebilmeniz için mesajlarınızı sunucuyla senkronize eder. +* XEP-0352: İstemci Durum Bildirimi - Conversations'un arkaplanda çalıştığını sunucuya bildir. Sunucunun önemsiz paketleri saklayarak veriden tasarruf etmesini sağlar. +* XEP-0363: HTTP Dosya Yükleme - Konferanslarla ve çevrimdışı kişilerle dosya paylaşabilmenizi sağlar. Sunucunuzda ek bileşen gerektirir. diff --git a/src/conversations/fastlane/metadata/android/tr-TR/short_description.txt b/src/conversations/fastlane/metadata/android/tr-TR/short_description.txt new file mode 100644 index 0000000000..1eb74ef8f8 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/tr-TR/short_description.txt @@ -0,0 +1 @@ +Mobil cihazınız için şifrelenmiş, kullanımı kolay bir XMPP mesajlaşma uygulaması diff --git a/src/conversations/fastlane/metadata/android/uk/full_description.txt b/src/conversations/fastlane/metadata/android/uk/full_description.txt new file mode 100644 index 0000000000..39971ed557 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/uk/full_description.txt @@ -0,0 +1,39 @@ +Надійний, простий у використанні, ощадливо витрачає заряд акумулятора. Має вбудовану підтримку зображень, групових чатів і наскрізного шифрування. + +Принципи проєктування: + +* Бути максимально красивим та простим у використанні, не жертвуючи безпекою чи конфіденційністю +* Покладатися на існуючі, добре встановлені протоколи +* Не вимагати облікового запису Google, зокрема Google Cloud Messaging (GCM) +* Вимагати якомога менше дозволів + +Функції: + +* Наскрізне шифрування (від відправника до одержувача) за допомогою OMEMO або OpenPGP +* Надсилання та отримання зображень +* Зашифровані голосові та відеодзвінки (DTLS-SRTP) +* Інтуїтивно зрозумілий інтерфейс користувача, який відповідає вказівкам Android Design +* Зображення / Аватари для Ваших контактів +* Синхронізація з настільним клієнтом +* Конференції (з підтримкою закладок) +* Інтеграція адресної книги +* Кілька облікових записів / єдина папка вхідних +* Дуже низький вплив на термін служби акумулятора + +Conversations дозволяє легко створити обліковий запис на безкоштовному сервері conversations.im. Однак Conversations працюватиме також із будь-яким іншим XMPP-сервером. Чимало серверів XMPP обслуговуються волонтерами і є безкоштовними. + +Функції XMPP: + +Conversations працює з будь-яким сервером XMPP. Проте XMPP — розширюваний протокол. Розширення також стандартизовані в так званих XEP. Conversations підтримує кілька з них, щоб покращити загальний досвід користування. Може виявитися, що Ваш поточний сервер XMPP не підтримує цих розширень. Тому, щоб отримати максимум від Conversations, розгляньте перехід на XMPP-сервер з підтримкою цих розширень або — ще краще — запускайте власний сервер XMPP для себе і своїх друзів. + +На даний час підтримуються такі XEP: + +* XEP-0065: SOCKS5 Bytestreams (або mod_proxy65). Використовується для передачі файлів, якщо обидві сторони знаходяться за брандмауером (NAT). +* XEP-0163: персональний протокол подій для аватарів +* XEP-0191: команда блокування дозволяє Вам заносити спамерів у чорний список або блокувати контакти, не видаляючи їх зі свого списку. +* XEP-0198: керування потоками дозволяє XMPP витримувати невеликі перебої в мережі та зміни основного TCP-з'єднання. +* XEP-0280: Message Carbons, який автоматично синхронізує повідомлення, які Ви надсилаєте, на настільний клієнт і, таким чином, дозволяє плавно переключатися з мобільного клієнта на клієнт для настільного ПК і назад протягом однієї розмови. +* XEP-0237: версія списку в основному для економії пропускної здатності при поганих мобільних з'єднаннях +* XEP-0313: керування архівом повідомлень синхронізує історію повідомлень із сервером. Дізнавайтеся про повідомлення, надіслані, поки Conversations був офлайн. +* XEP-0352: індикація стану клієнта повідомляє серверу, чи працює Conversations у фоновому режимі. Дозволяє серверу заощаджувати пропускну здатність, утримуючи неважливі пакети. +* XEP-0363: завантаження файлів HTTP дозволяє обмінюватися файлами в конференціях і з офлайн-контактами. Потрібен додатковий компонент на Вашому сервері. diff --git a/src/conversations/fastlane/metadata/android/uk/short_description.txt b/src/conversations/fastlane/metadata/android/uk/short_description.txt new file mode 100644 index 0000000000..300b89277d --- /dev/null +++ b/src/conversations/fastlane/metadata/android/uk/short_description.txt @@ -0,0 +1 @@ +Простий у використанні XMPP-клієнт з підтримкою шифрування для Вашого телефона diff --git a/src/conversations/fastlane/metadata/android/zh-CN/full_description.txt b/src/conversations/fastlane/metadata/android/zh-CN/full_description.txt new file mode 100644 index 0000000000..87d4ecea0a --- /dev/null +++ b/src/conversations/fastlane/metadata/android/zh-CN/full_description.txt @@ -0,0 +1,39 @@ +易用、可靠、省电。内置支持图片、群聊和端到端加密功能。 + +设计原则: + +* 在不牺牲安全性和隐私性的前提下,尽可能美观易用 +* 依赖现有的、完善的协议 +* 不需要 Google 账号或特定的 Google 云通讯服务(GCM) +* 要求尽可能少的权限 + +特点: + +* 使用 OMEMOOpenPGP 进行端到端加密 +* 发送和接收图片 +* 加密音视频通话(DTLS-SRTP) +* 直观的用户界面,遵循 Android 设计准则 +* 为您的联系人添加图片/头像 +* 与桌面客户端同步 +* 群聊(支持书签功能) +* 通讯录集成 +* 多账号/统一消息栏 +* 对电池寿命的影响非常小 + +Conversations 使在免费的 conversations.im 服务器上创建账号变得非常简单。不过,Conversations 也适用于任何其他 XMPP 服务器。许多 XMPP 服务器都是由志愿者免费运行的。 + +XMPP 功能: + +Conversations 适用于所有 XMPP 服务器。然而,XMPP 是一种可扩展的协议。这些扩展在所谓的 XMPP 扩展协议中也是标准化的。Conversations 支持其中的一些扩展,以使整体用户体验更好。有一种可能是您当前的 XMPP 服务器不支持这些扩展。因此,要想充分使用 Conversations 的功能,您应该考虑切换到支持这些扩展的 XMPP 服务器,甚至有更好的方式,或者为您和您的朋友运行自己的 XMPP 服务器。 + +到目前为止,这些 XMPP 扩展协议是: + +* XEP-0065:SOCKS5 字节流(或 mod_proxy65)。如果双方都在防火墙(NAT)后面,将用于传输文件。 +* XEP-0163:个人事件协议(头像) +* XEP-0191:屏蔽命令可让您将垃圾消息发送者列入黑名单或屏蔽的联系人中,而不会将其从花名册中删除。 +* XEP-0198:流管理允许 XMPP 在小规模网络中断和底层 TCP 连接发生变化时继续运行。 +* XEP-0280:消息抄送,可自动将您发送的消息同步到桌面客户端,因此您可以在一次对话中从手机客户端无缝切换到桌面客户端,然后再返回。 +* XEP-0237:花名册版本控制主要是为了在移动连接不佳的情况下节省带宽 +* XEP-0313:消息存档管理与服务器同步消息历史记录。补发 Conversations 离线时发送的消息。 +* XEP-0352:客户端状态指示让服务器知道 Conversations 是否在后台。允许服务器保留不重要的数据包,从而节省带宽。 +* XEP-0363:通过 HTTP 文件上传功能,您可以在群聊中与离线联系人分享文件。需要在服务器上安装额外组件。 diff --git a/src/conversations/fastlane/metadata/android/zh-CN/short_description.txt b/src/conversations/fastlane/metadata/android/zh-CN/short_description.txt new file mode 100644 index 0000000000..40275beb39 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/zh-CN/short_description.txt @@ -0,0 +1 @@ +为您的移动设备提供加密、易用的 XMPP 即时通讯软件 diff --git a/src/conversations/fastlane/metadata/android/zh-TW/full_description.txt b/src/conversations/fastlane/metadata/android/zh-TW/full_description.txt new file mode 100644 index 0000000000..0e9114c98b --- /dev/null +++ b/src/conversations/fastlane/metadata/android/zh-TW/full_description.txt @@ -0,0 +1,39 @@ +易於使用、可靠、省電,且帶有內建圖像支援、群組聊天和端對端加密的 XMPP 用戶端。 + +設計原則: + +* 在不犧牲安全或隱私權的前提下,盡可能地保持美觀性和易用性 +* 仰賴現存的、已建立的通訊協定 +* 不需要 Google 帳戶或特別的 Google 雲端訊息 (GCM) +* 需要少量可能的權限 + +功能: + +* OMEMOOpenPGP 端對端加密 +* 傳送並接收圖像 +* 加密的音訊和視訊通話 (DTLS-SRTP) +* 依循 Android 設計指南的直覺化 UI +* 為您的聯絡人顯示圖片/ 頭像 +* 與桌面用戶端同步 +* 會議 (書籤支援) +* 通訊錄整合 +* 多個帳戶/整合收件匣 +* 對電池壽命的極低影響 + +Conversations 使在免費的 conversations.im 伺服器上建立一個帳戶變得極為輕易。然而 Conversations 也可在其他 XMPP 伺服器上運作,很多 XMPP 伺服器是由志工驅動的,並且完全免費。 + +XMPP 功能: + +Conversations 可以在所有 XMPP 伺服器上運作。然而,XMPP 是一個可以擴充的通訊協定,這些擴充功能在所謂的 XEP 中也是標準化的。Conversations 支援其中的幾個,已使使用者體驗更佳。有可能您目前的 XMPP 伺服器並不支援這些擴充功能,因此,為了最大限度的發揮 Conversations 的作用,您應該考慮切換到一個支援這些擴充功能的 XMPP 伺服器,或者甚至更好——為您和您的朋友驅動您自己的 XMPP 伺服器。 + +如下 XEP - 截止目前: + +* XEP-0065:SOCKS5 位元資料流 (或 mod_proxy65),將被用於傳輸檔案,如果雙方都在防火牆之後 (NAT)。 +* XEP-0163:用於虛擬化身的私人活動通訊協定 +* XEP-0191:封鎖命令可讓您將濫發垃圾郵件者列入黑名單,或封鎖聯絡人而不把他們從名冊中移除。 +* XEP-0198:串流管理允許 XMPP 在小型網路中斷和基礎 TCP 連線的變更中生存。 +* XEP-0280:訊息副本,自動將您傳送的訊息同步至桌面用戶端,從而允許您在一次會話中從您的行動用戶端無縫切換到您的桌面用戶端。 +* XEP-0237:名冊版本管理,主要是為了節省行動連線不佳時的頻寬。 +* XEP-0313:訊息封存管理將訊息記錄與伺服器同步,隨時掌握離線傳送的訊息。 +* XEP-0352:用戶端狀態指示可讓伺服器知道 Conversations 是否在背景,允許伺服器透過扣留不必要的封裝來節省頻寬。 +* XEP-0363:HTTP 檔案上傳允許您在會議中或與離線聯絡人分享檔案,需要在您的伺服器上有一個額外的元件。 diff --git a/src/conversations/fastlane/metadata/android/zh-TW/short_description.txt b/src/conversations/fastlane/metadata/android/zh-TW/short_description.txt new file mode 100644 index 0000000000..06e14ddbe9 --- /dev/null +++ b/src/conversations/fastlane/metadata/android/zh-TW/short_description.txt @@ -0,0 +1 @@ +可加密、易於使用的 XMPP 即時訊息,為您的行動裝置設計 diff --git a/src/main/java/eu/siacs/conversations/entities/AccountConfiguration.java b/src/conversations/java/eu/siacs/conversations/entities/AccountConfiguration.java similarity index 100% rename from src/main/java/eu/siacs/conversations/entities/AccountConfiguration.java rename to src/conversations/java/eu/siacs/conversations/entities/AccountConfiguration.java diff --git a/src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java b/src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java new file mode 100644 index 0000000000..dd96468ee8 --- /dev/null +++ b/src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java @@ -0,0 +1,508 @@ +package eu.siacs.conversations.services; + +import static eu.siacs.conversations.utils.Compatibility.s; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; +import android.os.Binder; +import android.os.IBinder; +import android.provider.OpenableColumns; +import android.util.Log; + +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; + +import com.google.common.base.Charsets; +import com.google.common.base.Stopwatch; +import com.google.common.io.CountingInputStream; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.crypto.axolotl.SQLiteAxolotlStore; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.persistance.DatabaseBackend; +import eu.siacs.conversations.persistance.FileBackend; +import eu.siacs.conversations.ui.ManageAccountActivity; +import eu.siacs.conversations.utils.BackupFileHeader; +import eu.siacs.conversations.utils.SerialSingleThreadExecutor; +import eu.siacs.conversations.worker.ExportBackupWorker; +import eu.siacs.conversations.xmpp.Jid; + +import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.io.CipherInputStream; +import org.bouncycastle.crypto.modes.AEADBlockCipher; +import org.bouncycastle.crypto.modes.GCMBlockCipher; +import org.bouncycastle.crypto.params.AEADParameters; +import org.bouncycastle.crypto.params.KeyParameter; + +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Pattern; +import java.util.zip.GZIPInputStream; +import java.util.zip.ZipException; + +import javax.crypto.BadPaddingException; + +public class ImportBackupService extends Service { + + private static final ExecutorService BACKUP_FILE_READER_EXECUTOR = + Executors.newSingleThreadExecutor(); + + private static final int NOTIFICATION_ID = 21; + private static final AtomicBoolean running = new AtomicBoolean(false); + private final ImportBackupServiceBinder binder = new ImportBackupServiceBinder(); + private final SerialSingleThreadExecutor executor = + new SerialSingleThreadExecutor(getClass().getSimpleName()); + private final Set mOnBackupProcessedListeners = + Collections.newSetFromMap(new WeakHashMap<>()); + private DatabaseBackend mDatabaseBackend; + private NotificationManager notificationManager; + + private static final Collection TABLE_ALLOW_LIST = + Arrays.asList( + Account.TABLENAME, + Conversation.TABLENAME, + Message.TABLENAME, + SQLiteAxolotlStore.PREKEY_TABLENAME, + SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME, + SQLiteAxolotlStore.SESSION_TABLENAME, + SQLiteAxolotlStore.IDENTITIES_TABLENAME); + private static final Pattern COLUMN_PATTERN = Pattern.compile("^[a-zA-Z_]+$"); + + @Override + public void onCreate() { + mDatabaseBackend = DatabaseBackend.getInstance(getBaseContext()); + notificationManager = + (android.app.NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (intent == null) { + return START_NOT_STICKY; + } + final String password = intent.getStringExtra("password"); + final Uri data = intent.getData(); + final Uri uri; + if (data == null) { + final String file = intent.getStringExtra("file"); + uri = file == null ? null : Uri.fromFile(new File(file)); + } else { + uri = data; + } + + if (password == null || password.isEmpty() || uri == null) { + return START_NOT_STICKY; + } + if (running.compareAndSet(false, true)) { + executor.execute( + () -> { + startForegroundService(); + final boolean success = importBackup(uri, password); + stopForeground(true); + running.set(false); + if (success) { + notifySuccess(); + } + stopSelf(); + }); + } else { + Log.d(Config.LOGTAG, "backup already running"); + } + return START_NOT_STICKY; + } + + public boolean getLoadingState() { + return running.get(); + } + + public void loadBackupFiles(final OnBackupFilesLoaded onBackupFilesLoaded) { + executor.execute( + () -> { + final List accounts = mDatabaseBackend.getAccountJids(false); + final ArrayList backupFiles = new ArrayList<>(); + final Set apps = + new HashSet<>( + Arrays.asList( + "Conversations", + "Quicksy", + getString(R.string.app_name))); + final List directories = new ArrayList<>(); + for (final String app : apps) { + directories.add(FileBackend.getLegacyBackupDirectory(app)); + } + directories.add(FileBackend.getBackupDirectory(this)); + for (final File directory : directories) { + if (!directory.exists() || !directory.isDirectory()) { + Log.d( + Config.LOGTAG, + "directory not found: " + directory.getAbsolutePath()); + continue; + } + final File[] files = directory.listFiles(); + if (files == null) { + continue; + } + Log.d(Config.LOGTAG, "looking for backups in " + directory); + for (final File file : files) { + if (file.isFile() && file.getName().endsWith(".ceb")) { + try { + final BackupFile backupFile = BackupFile.read(file); + if (accounts.contains(backupFile.getHeader().getJid())) { + Log.d( + Config.LOGTAG, + "skipping backup for " + + backupFile.getHeader().getJid()); + } else { + backupFiles.add(backupFile); + } + } catch (final IOException + | IllegalArgumentException + | BackupFileHeader.OutdatedBackupFileVersion e) { + Log.d(Config.LOGTAG, "unable to read backup file ", e); + } + } + } + } + Collections.sort( + backupFiles, Comparator.comparing(a -> a.header.getJid().toString())); + onBackupFilesLoaded.onBackupFilesLoaded(backupFiles); + }); + } + + private void startForegroundService() { + startForeground(NOTIFICATION_ID, createImportBackupNotification(1, 0)); + } + + private void updateImportBackupNotification(final long total, final long current) { + final int max; + final int progress; + if (total == 0) { + max = 1; + progress = 0; + } else { + max = 100; + progress = (int) (current * 100 / total); + } + final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); + try { + notificationManager.notify( + NOTIFICATION_ID, createImportBackupNotification(max, progress)); + } catch (final RuntimeException e) { + Log.d(Config.LOGTAG, "unable to make notification", e); + } + } + + private Notification createImportBackupNotification(final int max, final int progress) { + NotificationCompat.Builder mBuilder = + new NotificationCompat.Builder(getBaseContext(), "backup"); + mBuilder.setContentTitle(getString(R.string.restoring_backup)) + .setSmallIcon(R.drawable.ic_unarchive_24dp) + .setProgress(max, progress, max == 1 && progress == 0); + return mBuilder.build(); + } + + private boolean importBackup(final Uri uri, final String password) { + Log.d(Config.LOGTAG, "importing backup from " + uri); + final Stopwatch stopwatch = Stopwatch.createStarted(); + try { + final SQLiteDatabase db = mDatabaseBackend.getWritableDatabase(); + final InputStream inputStream; + final String path = uri.getPath(); + final long fileSize; + if ("file".equals(uri.getScheme()) && path != null) { + final File file = new File(path); + inputStream = new FileInputStream(file); + fileSize = file.length(); + } else { + final Cursor returnCursor = getContentResolver().query(uri, null, null, null, null); + if (returnCursor == null) { + fileSize = 0; + } else { + returnCursor.moveToFirst(); + fileSize = + returnCursor.getLong( + returnCursor.getColumnIndexOrThrow(OpenableColumns.SIZE)); + returnCursor.close(); + } + inputStream = getContentResolver().openInputStream(uri); + } + if (inputStream == null) { + synchronized (mOnBackupProcessedListeners) { + for (final OnBackupProcessed l : mOnBackupProcessedListeners) { + l.onBackupRestoreFailed(); + } + } + return false; + } + final CountingInputStream countingInputStream = new CountingInputStream(inputStream); + final DataInputStream dataInputStream = new DataInputStream(countingInputStream); + final BackupFileHeader backupFileHeader = BackupFileHeader.read(dataInputStream); + Log.d(Config.LOGTAG, backupFileHeader.toString()); + + if (mDatabaseBackend.getAccountJids(false).contains(backupFileHeader.getJid())) { + synchronized (mOnBackupProcessedListeners) { + for (OnBackupProcessed l : mOnBackupProcessedListeners) { + l.onAccountAlreadySetup(); + } + } + return false; + } + + final byte[] key = ExportBackupWorker.getKey(password, backupFileHeader.getSalt()); + + final AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine()); + cipher.init( + false, + new AEADParameters(new KeyParameter(key), 128, backupFileHeader.getIv())); + final CipherInputStream cipherInputStream = + new CipherInputStream(countingInputStream, cipher); + + final GZIPInputStream gzipInputStream = new GZIPInputStream(cipherInputStream); + final BufferedReader reader = + new BufferedReader(new InputStreamReader(gzipInputStream, Charsets.UTF_8)); + final JsonReader jsonReader = new JsonReader(reader); + if (jsonReader.peek() == JsonToken.BEGIN_ARRAY) { + jsonReader.beginArray(); + } else { + throw new IllegalStateException("Backup file did not begin with array"); + } + db.beginTransaction(); + while (jsonReader.hasNext()) { + if (jsonReader.peek() == JsonToken.BEGIN_OBJECT) { + importRow(db, jsonReader, backupFileHeader.getJid(), password); + } else if (jsonReader.peek() == JsonToken.END_ARRAY) { + jsonReader.endArray(); + continue; + } + updateImportBackupNotification(fileSize, countingInputStream.getCount()); + } + db.setTransactionSuccessful(); + db.endTransaction(); + final Jid jid = backupFileHeader.getJid(); + final Cursor countCursor = + db.rawQuery( + "select count(messages.uuid) from messages join conversations on conversations.uuid=messages.conversationUuid join accounts on conversations.accountUuid=accounts.uuid where accounts.username=? and accounts.server=?", + new String[] { + jid.getEscapedLocal(), jid.getDomain().toEscapedString() + }); + countCursor.moveToFirst(); + final int count = countCursor.getInt(0); + Log.d( + Config.LOGTAG, + String.format( + "restored %d messages in %s", count, stopwatch.stop().toString())); + countCursor.close(); + stopBackgroundService(); + synchronized (mOnBackupProcessedListeners) { + for (OnBackupProcessed l : mOnBackupProcessedListeners) { + l.onBackupRestored(); + } + } + return true; + } catch (final Exception e) { + final Throwable throwable = e.getCause(); + final boolean reasonWasCrypto = + throwable instanceof BadPaddingException || e instanceof ZipException; + synchronized (mOnBackupProcessedListeners) { + for (OnBackupProcessed l : mOnBackupProcessedListeners) { + if (reasonWasCrypto) { + l.onBackupDecryptionFailed(); + } else { + l.onBackupRestoreFailed(); + } + } + } + Log.d(Config.LOGTAG, "error restoring backup " + uri, e); + return false; + } + } + + private void importRow( + final SQLiteDatabase db, + final JsonReader jsonReader, + final Jid account, + final String passphrase) + throws IOException { + jsonReader.beginObject(); + final String firstParameter = jsonReader.nextName(); + if (!firstParameter.equals("table")) { + throw new IllegalStateException("Expected key 'table'"); + } + final String table = jsonReader.nextString(); + if (!TABLE_ALLOW_LIST.contains(table)) { + throw new IOException(String.format("%s is not recognized for import", table)); + } + final ContentValues contentValues = new ContentValues(); + final String secondParameter = jsonReader.nextName(); + if (!secondParameter.equals("values")) { + throw new IllegalStateException("Expected key 'values'"); + } + jsonReader.beginObject(); + while (jsonReader.peek() != JsonToken.END_OBJECT) { + final String name = jsonReader.nextName(); + if (COLUMN_PATTERN.matcher(name).matches()) { + if (jsonReader.peek() == JsonToken.NULL) { + jsonReader.nextNull(); + contentValues.putNull(name); + } else if (jsonReader.peek() == JsonToken.NUMBER) { + contentValues.put(name, jsonReader.nextLong()); + } else { + contentValues.put(name, jsonReader.nextString()); + } + } else { + throw new IOException(String.format("Unexpected column name %s", name)); + } + } + jsonReader.endObject(); + jsonReader.endObject(); + if (Account.TABLENAME.equals(table)) { + final Jid jid = + Jid.of( + contentValues.getAsString(Account.USERNAME), + contentValues.getAsString(Account.SERVER), + null); + final String password = contentValues.getAsString(Account.PASSWORD); + if (jid.equals(account) && passphrase.equals(password)) { + Log.d(Config.LOGTAG, "jid and password from backup header had matching row"); + } else { + throw new IOException("jid or password in table did not match backup"); + } + } + db.insert(table, null, contentValues); + } + + private void notifySuccess() { + NotificationCompat.Builder mBuilder = + new NotificationCompat.Builder(getBaseContext(), "backup"); + mBuilder.setContentTitle(getString(R.string.notification_restored_backup_title)) + .setContentText(getString(R.string.notification_restored_backup_subtitle)) + .setAutoCancel(true) + .setContentIntent( + PendingIntent.getActivity( + this, + 145, + new Intent(this, ManageAccountActivity.class), + s() + ? PendingIntent.FLAG_IMMUTABLE + | PendingIntent.FLAG_UPDATE_CURRENT + : PendingIntent.FLAG_UPDATE_CURRENT)) + .setSmallIcon(R.drawable.ic_unarchive_24dp); + notificationManager.notify(NOTIFICATION_ID, mBuilder.build()); + } + + private void stopBackgroundService() { + Intent intent = new Intent(this, XmppConnectionService.class); + stopService(intent); + } + + public void removeOnBackupProcessedListener(OnBackupProcessed listener) { + synchronized (mOnBackupProcessedListeners) { + mOnBackupProcessedListeners.remove(listener); + } + } + + public void addOnBackupProcessedListener(OnBackupProcessed listener) { + synchronized (mOnBackupProcessedListeners) { + mOnBackupProcessedListeners.add(listener); + } + } + + public static ListenableFuture read(final Context context, final Uri uri) { + return Futures.submit(() -> BackupFile.read(context, uri), BACKUP_FILE_READER_EXECUTOR); + } + + @Override + public IBinder onBind(Intent intent) { + return this.binder; + } + + public interface OnBackupFilesLoaded { + void onBackupFilesLoaded(List files); + } + + public interface OnBackupProcessed { + void onBackupRestored(); + + void onBackupDecryptionFailed(); + + void onBackupRestoreFailed(); + + void onAccountAlreadySetup(); + } + + public static class BackupFile { + private final Uri uri; + private final BackupFileHeader header; + + private BackupFile(Uri uri, BackupFileHeader header) { + this.uri = uri; + this.header = header; + } + + private static BackupFile read(File file) throws IOException { + final FileInputStream fileInputStream = new FileInputStream(file); + final DataInputStream dataInputStream = new DataInputStream(fileInputStream); + BackupFileHeader backupFileHeader = BackupFileHeader.read(dataInputStream); + fileInputStream.close(); + return new BackupFile(Uri.fromFile(file), backupFileHeader); + } + + public static BackupFile read(final Context context, final Uri uri) throws IOException { + final InputStream inputStream = context.getContentResolver().openInputStream(uri); + if (inputStream == null) { + throw new FileNotFoundException(); + } + final DataInputStream dataInputStream = new DataInputStream(inputStream); + final BackupFileHeader backupFileHeader = BackupFileHeader.read(dataInputStream); + inputStream.close(); + return new BackupFile(uri, backupFileHeader); + } + + public BackupFileHeader getHeader() { + return header; + } + + public Uri getUri() { + return uri; + } + } + + public class ImportBackupServiceBinder extends Binder { + public ImportBackupService getService() { + return ImportBackupService.this; + } + } +} diff --git a/src/conversations/java/eu/siacs/conversations/services/QuickConversationsService.java b/src/conversations/java/eu/siacs/conversations/services/QuickConversationsService.java new file mode 100644 index 0000000000..b2a0d17f4a --- /dev/null +++ b/src/conversations/java/eu/siacs/conversations/services/QuickConversationsService.java @@ -0,0 +1,38 @@ +package eu.siacs.conversations.services; + +import android.content.Intent; +import android.util.Log; + +import eu.siacs.conversations.Config; + +public class QuickConversationsService extends AbstractQuickConversationsService { + + QuickConversationsService(XmppConnectionService xmppConnectionService) { + super(xmppConnectionService); + } + + @Override + public void considerSync() { + + } + + @Override + public void signalAccountStateChange() { + + } + + @Override + public boolean isSynchronizing() { + return false; + } + + @Override + public void considerSyncBackground(boolean force) { + + } + + @Override + public void handleSmsReceived(Intent intent) { + Log.d(Config.LOGTAG,"ignoring received SMS"); + } +} \ No newline at end of file diff --git a/src/conversations/java/eu/siacs/conversations/ui/EasyOnboardingInviteActivity.java b/src/conversations/java/eu/siacs/conversations/ui/EasyOnboardingInviteActivity.java new file mode 100644 index 0000000000..9228a5170a --- /dev/null +++ b/src/conversations/java/eu/siacs/conversations/ui/EasyOnboardingInviteActivity.java @@ -0,0 +1,187 @@ +package eu.siacs.conversations.ui; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.Point; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.databinding.DataBindingUtil; + +import com.google.android.material.color.MaterialColors; +import com.google.common.base.Strings; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.databinding.ActivityEasyInviteBinding; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.services.BarcodeProvider; +import eu.siacs.conversations.utils.EasyOnboardingInvite; +import eu.siacs.conversations.xmpp.Jid; + +public class EasyOnboardingInviteActivity extends XmppActivity + implements EasyOnboardingInvite.OnInviteRequested { + + private ActivityEasyInviteBinding binding; + + private EasyOnboardingInvite easyOnboardingInvite; + + @Override + public void onCreate(final Bundle bundle) { + super.onCreate(bundle); + this.binding = DataBindingUtil.setContentView(this, R.layout.activity_easy_invite); + setSupportActionBar(binding.toolbar); + configureActionBar(getSupportActionBar(), true); + Activities.setStatusAndNavigationBarColors(this, binding.getRoot()); + this.binding.shareButton.setOnClickListener(v -> share()); + if (bundle != null && bundle.containsKey("invite")) { + this.easyOnboardingInvite = bundle.getParcelable("invite"); + if (this.easyOnboardingInvite != null) { + showInvite(this.easyOnboardingInvite); + return; + } + } + this.showLoading(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.easy_onboarding_invite, menu); + final MenuItem share = menu.findItem(R.id.action_share); + share.setVisible(easyOnboardingInvite != null); + return super.onCreateOptionsMenu(menu); + } + + public boolean onOptionsItemSelected(MenuItem menuItem) { + if (menuItem.getItemId() == R.id.action_share) { + share(); + return true; + } else { + return super.onOptionsItemSelected(menuItem); + } + } + + private void share() { + final String shareText = + getString( + R.string.easy_invite_share_text, + easyOnboardingInvite.getDomain(), + easyOnboardingInvite.getShareableLink()); + final Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, shareText); + sendIntent.setType("text/plain"); + startActivity(Intent.createChooser(sendIntent, getString(R.string.share_invite_with))); + } + + @Override + protected void refreshUiReal() { + invalidateOptionsMenu(); + if (easyOnboardingInvite != null) { + showInvite(easyOnboardingInvite); + } else { + showLoading(); + } + } + + private void showLoading() { + this.binding.inProgress.setVisibility(View.VISIBLE); + this.binding.invite.setVisibility(View.GONE); + } + + private void showInvite(final EasyOnboardingInvite invite) { + this.binding.inProgress.setVisibility(View.GONE); + this.binding.invite.setVisibility(View.VISIBLE); + this.binding.tapToShare.setText( + getString(R.string.tap_share_button_send_invite, invite.getDomain())); + final Point size = new Point(); + getWindowManager().getDefaultDisplay().getSize(size); + final int width = Math.min(size.x, size.y); + final boolean nightMode = + (this.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) + == Configuration.UI_MODE_NIGHT_YES; + final int black; + final int white; + if (nightMode) { + black = + MaterialColors.getColor( + this, + com.google.android.material.R.attr.colorSurface, + "No surface color configured"); + white = + MaterialColors.getColor( + this, + com.google.android.material.R.attr.colorSurfaceInverse, + "No inverse surface color configured"); + } else { + black = + MaterialColors.getColor( + this, + com.google.android.material.R.attr.colorSurfaceInverse, + "No inverse surface color configured"); + white = + MaterialColors.getColor( + this, + com.google.android.material.R.attr.colorSurface, + "No surface color configured"); + } + final Bitmap bitmap = + BarcodeProvider.create2dBarcodeBitmap( + invite.getShareableLink(), width, black, white); + binding.qrCode.setImageBitmap(bitmap); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle bundle) { + super.onSaveInstanceState(bundle); + if (easyOnboardingInvite != null) { + bundle.putParcelable("invite", easyOnboardingInvite); + } + } + + @Override + protected void onBackendConnected() { + if (easyOnboardingInvite != null) { + return; + } + final Intent launchIntent = getIntent(); + final String accountExtra = launchIntent.getStringExtra(EXTRA_ACCOUNT); + final Jid jid = accountExtra == null ? null : Jid.ofEscaped(accountExtra); + if (jid == null) { + return; + } + final Account account = xmppConnectionService.findAccountByJid(jid); + xmppConnectionService.requestEasyOnboardingInvite(account, this); + } + + public static void launch(final Account account, final Activity context) { + final Intent intent = new Intent(context, EasyOnboardingInviteActivity.class); + intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString()); + context.startActivity(intent); + } + + @Override + public void inviteRequested(EasyOnboardingInvite invite) { + this.easyOnboardingInvite = invite; + Log.d(Config.LOGTAG, "invite requested"); + refreshUi(); + } + + @Override + public void inviteRequestFailed(final String message) { + runOnUiThread( + () -> { + if (!Strings.isNullOrEmpty(message)) { + Toast.makeText(this, message, Toast.LENGTH_LONG).show(); + } + finish(); + }); + } +} diff --git a/src/conversations/java/eu/siacs/conversations/ui/ImportBackupActivity.java b/src/conversations/java/eu/siacs/conversations/ui/ImportBackupActivity.java new file mode 100644 index 0000000000..331857e29f --- /dev/null +++ b/src/conversations/java/eu/siacs/conversations/ui/ImportBackupActivity.java @@ -0,0 +1,379 @@ +package eu.siacs.conversations.ui; + +import android.Manifest; +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.core.content.ContextCompat; +import androidx.databinding.DataBindingUtil; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.snackbar.Snackbar; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.databinding.ActivityImportBackupBinding; +import eu.siacs.conversations.databinding.DialogEnterPasswordBinding; +import eu.siacs.conversations.services.ImportBackupService; +import eu.siacs.conversations.ui.adapter.BackupFileAdapter; +import eu.siacs.conversations.ui.util.MainThreadExecutor; +import eu.siacs.conversations.utils.BackupFileHeader; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +public class ImportBackupActivity extends ActionBarActivity + implements ServiceConnection, + ImportBackupService.OnBackupFilesLoaded, + BackupFileAdapter.OnItemClickedListener, + ImportBackupService.OnBackupProcessed { + + private ActivityImportBackupBinding binding; + + private BackupFileAdapter backupFileAdapter; + private ImportBackupService service; + + private boolean mLoadingState = false; + private final ActivityResultLauncher requestPermissions = + registerForActivityResult( + new ActivityResultContracts.RequestMultiplePermissions(), + results -> { + if (results.containsValue(Boolean.TRUE)) { + final var service = this.service; + if (service == null) { + return; + } + service.loadBackupFiles(this); + } + }); + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + binding = DataBindingUtil.setContentView(this, R.layout.activity_import_backup); + Activities.setStatusAndNavigationBarColors(this, binding.getRoot()); + setSupportActionBar(binding.toolbar); + setLoadingState( + savedInstanceState != null + && savedInstanceState.getBoolean("loading_state", false)); + this.backupFileAdapter = new BackupFileAdapter(); + this.binding.list.setAdapter(this.backupFileAdapter); + this.backupFileAdapter.setOnItemClickedListener(this); + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.import_backup, menu); + final MenuItem openBackup = menu.findItem(R.id.action_open_backup_file); + openBackup.setVisible(!this.mLoadingState); + return true; + } + + @Override + public void onSaveInstanceState(Bundle bundle) { + bundle.putBoolean("loading_state", this.mLoadingState); + super.onSaveInstanceState(bundle); + } + + @Override + public void onStart() { + + super.onStart(); + bindService(new Intent(this, ImportBackupService.class), this, Context.BIND_AUTO_CREATE); + final Intent intent = getIntent(); + if (intent != null + && Intent.ACTION_VIEW.equals(intent.getAction()) + && !this.mLoadingState) { + Uri uri = intent.getData(); + if (uri != null) { + openBackupFileFromUri(uri, true); + return; + } + } + final List desiredPermission; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + desiredPermission = + ImmutableList.of( + Manifest.permission.READ_MEDIA_IMAGES, + Manifest.permission.READ_MEDIA_VIDEO, + Manifest.permission.READ_MEDIA_AUDIO, + Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED); + } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.TIRAMISU) { + desiredPermission = + ImmutableList.of( + Manifest.permission.READ_MEDIA_IMAGES, + Manifest.permission.READ_MEDIA_VIDEO, + Manifest.permission.READ_MEDIA_AUDIO); + } else { + desiredPermission = ImmutableList.of(Manifest.permission.READ_EXTERNAL_STORAGE); + } + final Set declaredPermission = getDeclaredPermission(); + if (declaredPermission.containsAll(desiredPermission)) { + requestPermissions.launch(desiredPermission.toArray(new String[0])); + } else { + Log.d(Config.LOGTAG, "Manifest is lacking some desired permission. not requesting"); + } + } + + private Set getDeclaredPermission() { + final String[] permissions; + try { + permissions = + getPackageManager() + .getPackageInfo(getPackageName(), PackageManager.GET_PERMISSIONS) + .requestedPermissions; + } catch (final PackageManager.NameNotFoundException e) { + return Collections.emptySet(); + } + return ImmutableSet.copyOf(permissions); + } + + @Override + public void onStop() { + super.onStop(); + if (this.service != null) { + this.service.removeOnBackupProcessedListener(this); + } + unbindService(this); + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + ImportBackupService.ImportBackupServiceBinder binder = + (ImportBackupService.ImportBackupServiceBinder) service; + this.service = binder.getService(); + this.service.addOnBackupProcessedListener(this); + setLoadingState(this.service.getLoadingState()); + this.service.loadBackupFiles(this); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + this.service = null; + } + + @Override + public void onBackupFilesLoaded(final List files) { + runOnUiThread(() -> backupFileAdapter.setFiles(files)); + } + + @Override + public void onClick(final ImportBackupService.BackupFile backupFile) { + showEnterPasswordDialog(backupFile, false); + } + + private void openBackupFileFromUri(final Uri uri, final boolean finishOnCancel) { + final var backupFileFuture = ImportBackupService.read(this, uri); + Futures.addCallback( + backupFileFuture, + new FutureCallback<>() { + @Override + public void onSuccess(final ImportBackupService.BackupFile backupFile) { + showEnterPasswordDialog(backupFile, finishOnCancel); + } + + @Override + public void onFailure(@NonNull final Throwable throwable) { + Log.d(Config.LOGTAG, "could not open backup file " + uri, throwable); + showBackupThrowable(throwable); + } + }, + MainThreadExecutor.getInstance()); + } + + private void showBackupThrowable(final Throwable throwable) { + if (throwable instanceof BackupFileHeader.OutdatedBackupFileVersion) { + Snackbar.make( + binding.coordinator, + R.string.outdated_backup_file_format, + Snackbar.LENGTH_LONG) + .show(); + } else if (throwable instanceof IOException + || throwable instanceof IllegalArgumentException) { + Snackbar.make(binding.coordinator, R.string.not_a_backup_file, Snackbar.LENGTH_LONG) + .show(); + } else if (throwable instanceof SecurityException e) { + Snackbar.make( + binding.coordinator, + R.string.sharing_application_not_grant_permission, + Snackbar.LENGTH_LONG) + .show(); + } + } + + private void showEnterPasswordDialog( + final ImportBackupService.BackupFile backupFile, final boolean finishOnCancel) { + final DialogEnterPasswordBinding enterPasswordBinding = + DataBindingUtil.inflate( + LayoutInflater.from(this), R.layout.dialog_enter_password, null, false); + Log.d(Config.LOGTAG, "attempting to import " + backupFile.getUri()); + enterPasswordBinding.explain.setText( + getString( + R.string.enter_password_to_restore, + backupFile.getHeader().getJid().toString())); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); + builder.setView(enterPasswordBinding.getRoot()); + builder.setTitle(R.string.enter_password); + builder.setNegativeButton( + R.string.cancel, + (dialog, which) -> { + if (finishOnCancel) { + finish(); + } + }); + builder.setPositiveButton(R.string.restore, null); + builder.setCancelable(false); + final AlertDialog dialog = builder.create(); + dialog.setOnShowListener( + (d) -> { + dialog.getButton(DialogInterface.BUTTON_POSITIVE) + .setOnClickListener( + v -> { + final String password = + enterPasswordBinding + .accountPassword + .getEditableText() + .toString(); + if (password.isEmpty()) { + enterPasswordBinding.accountPasswordLayout.setError( + getString(R.string.please_enter_password)); + return; + } + final Intent intent = getIntent(backupFile, password); + setLoadingState(true); + ContextCompat.startForegroundService(this, intent); + d.dismiss(); + }); + }); + dialog.show(); + } + + @NonNull + private Intent getIntent(ImportBackupService.BackupFile backupFile, String password) { + final Uri uri = backupFile.getUri(); + Intent intent = new Intent(this, ImportBackupService.class); + intent.setAction(Intent.ACTION_SEND); + intent.putExtra("password", password); + if ("file".equals(uri.getScheme())) { + intent.putExtra("file", uri.getPath()); + } else { + intent.setData(uri); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + return intent; + } + + private void setLoadingState(final boolean loadingState) { + binding.coordinator.setVisibility(loadingState ? View.GONE : View.VISIBLE); + binding.inProgress.setVisibility(loadingState ? View.VISIBLE : View.GONE); + setTitle(loadingState ? R.string.restoring_backup : R.string.restore_backup); + Activities.setStatusAndNavigationBarColors(this, binding.getRoot()); + configureActionBar(getSupportActionBar(), !loadingState); + this.mLoadingState = loadingState; + invalidateOptionsMenu(); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent intent) { + super.onActivityResult(requestCode, resultCode, intent); + if (resultCode == RESULT_OK) { + if (requestCode == 0xbac) { + openBackupFileFromUri(intent.getData(), false); + } + } + } + + @Override + public void onAccountAlreadySetup() { + runOnUiThread( + () -> { + setLoadingState(false); + Snackbar.make( + binding.coordinator, + R.string.account_already_setup, + Snackbar.LENGTH_LONG) + .show(); + }); + } + + @Override + public void onBackupRestored() { + runOnUiThread( + () -> { + Intent intent = new Intent(this, ConversationActivity.class); + intent.addFlags( + Intent.FLAG_ACTIVITY_CLEAR_TOP + | Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(intent); + finish(); + }); + } + + @Override + public void onBackupDecryptionFailed() { + runOnUiThread( + () -> { + setLoadingState(false); + Snackbar.make( + binding.coordinator, + R.string.unable_to_decrypt_backup, + Snackbar.LENGTH_LONG) + .show(); + }); + } + + @Override + public void onBackupRestoreFailed() { + runOnUiThread( + () -> { + setLoadingState(false); + Snackbar.make( + binding.coordinator, + R.string.unable_to_restore_backup, + Snackbar.LENGTH_LONG) + .show(); + }); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.action_open_backup_file) { + openBackupFile(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void openBackupFile() { + final Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("*/*"); + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); + intent.addCategory(Intent.CATEGORY_OPENABLE); + startActivityForResult( + Intent.createChooser(intent, getString(R.string.open_backup)), 0xbac); + } +} diff --git a/src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java b/src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java new file mode 100644 index 0000000000..b6d4d452ee --- /dev/null +++ b/src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java @@ -0,0 +1,161 @@ +package eu.siacs.conversations.ui; + +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; +import android.widget.Toast; + +import androidx.databinding.DataBindingUtil; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.databinding.ActivityMagicCreateBinding; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.utils.CryptoHelper; +import eu.siacs.conversations.utils.InstallReferrerUtils; +import eu.siacs.conversations.xmpp.Jid; + +import java.security.SecureRandom; + +public class MagicCreateActivity extends XmppActivity implements TextWatcher { + + public static final String EXTRA_DOMAIN = "domain"; + public static final String EXTRA_PRE_AUTH = "pre_auth"; + public static final String EXTRA_USERNAME = "username"; + + private ActivityMagicCreateBinding binding; + private String domain; + private String username; + private String preAuth; + + @Override + protected void refreshUiReal() {} + + @Override + protected void onBackendConnected() {} + + @Override + protected void onCreate(final Bundle savedInstanceState) { + final Intent data = getIntent(); + this.domain = data == null ? null : data.getStringExtra(EXTRA_DOMAIN); + this.preAuth = data == null ? null : data.getStringExtra(EXTRA_PRE_AUTH); + this.username = data == null ? null : data.getStringExtra(EXTRA_USERNAME); + if (getResources().getBoolean(R.bool.portrait_only)) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + super.onCreate(savedInstanceState); + this.binding = DataBindingUtil.setContentView(this, R.layout.activity_magic_create); + Activities.setStatusAndNavigationBarColors(this, binding.getRoot()); + setSupportActionBar(this.binding.toolbar); + configureActionBar(getSupportActionBar(), this.domain == null); + if (username != null && domain != null) { + binding.title.setText(R.string.your_server_invitation); + binding.instructions.setText(getString(R.string.magic_create_text_fixed, domain)); + binding.username.setEnabled(false); + binding.username.setText(this.username); + updateFullJidInformation(this.username); + } else if (domain != null) { + binding.instructions.setText(getString(R.string.magic_create_text_on_x, domain)); + } + binding.createAccount.setOnClickListener( + v -> { + try { + final String username = binding.username.getText().toString(); + final Jid jid; + final boolean fixedUsername; + if (this.domain != null && this.username != null) { + fixedUsername = true; + jid = Jid.ofLocalAndDomainEscaped(this.username, this.domain); + } else if (this.domain != null) { + fixedUsername = false; + jid = Jid.ofLocalAndDomainEscaped(username, this.domain); + } else { + fixedUsername = false; + jid = Jid.ofLocalAndDomainEscaped(username, Config.MAGIC_CREATE_DOMAIN); + } + if (!jid.getEscapedLocal().equals(jid.getLocal()) + || (this.username == null && username.length() < 3)) { + binding.usernameLayout.setError(getString(R.string.invalid_username)); + binding.username.requestFocus(); + } else { + binding.usernameLayout.setError(null); + Account account = xmppConnectionService.findAccountByJid(jid); + if (account == null) { + account = + new Account( + jid, + CryptoHelper.createPassword(new SecureRandom())); + account.setOption(Account.OPTION_REGISTER, true); + account.setOption(Account.OPTION_DISABLED, true); + account.setOption(Account.OPTION_MAGIC_CREATE, true); + account.setOption(Account.OPTION_FIXED_USERNAME, fixedUsername); + if (this.preAuth != null) { + account.setKey( + Account.KEY_PRE_AUTH_REGISTRATION_TOKEN, this.preAuth); + } + xmppConnectionService.createAccount(account); + } + Intent intent = + new Intent(MagicCreateActivity.this, EditAccountActivity.class); + intent.putExtra("jid", account.getJid().asBareJid().toString()); + intent.putExtra("init", true); + intent.setFlags( + Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK); + Toast.makeText( + MagicCreateActivity.this, + R.string.secure_password_generated, + Toast.LENGTH_SHORT) + .show(); + StartConversationActivity.addInviteUri(intent, getIntent()); + startActivity(intent); + } + } catch (final IllegalArgumentException e) { + binding.usernameLayout.setError(getString(R.string.invalid_username)); + binding.username.requestFocus(); + } + }); + binding.username.addTextChangedListener(this); + } + + @Override + public void onDestroy() { + InstallReferrerUtils.markInstallReferrerExecuted(this); + super.onDestroy(); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(final Editable s) { + updateFullJidInformation(s.toString()); + } + + private void updateFullJidInformation(final String username) { + if (username.trim().isEmpty()) { + binding.fullJid.setVisibility(View.INVISIBLE); + } else { + try { + binding.fullJid.setVisibility(View.VISIBLE); + final Jid jid; + if (this.domain == null) { + jid = Jid.ofLocalAndDomainEscaped(username, Config.MAGIC_CREATE_DOMAIN); + } else { + jid = Jid.ofLocalAndDomainEscaped(username, this.domain); + } + binding.fullJid.setText( + getString(R.string.your_full_jid_will_be, jid.toEscapedString())); + binding.usernameLayout.setError(null); + } catch (final IllegalArgumentException e) { + binding.fullJid.setVisibility(View.INVISIBLE); + } + } + } +} diff --git a/src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java new file mode 100644 index 0000000000..2f4c81671c --- /dev/null +++ b/src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java @@ -0,0 +1,433 @@ +package eu.siacs.conversations.ui; + +import static eu.siacs.conversations.utils.PermissionUtils.allGranted; +import static eu.siacs.conversations.utils.PermissionUtils.writeGranted; + +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.os.Bundle; +import android.security.KeyChain; +import android.security.KeyChainAliasCallback; +import android.util.Log; +import android.util.Pair; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.databinding.DataBindingUtil; + +import com.google.common.base.Strings; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.databinding.ActivityManageAccountsBinding; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; +import eu.siacs.conversations.ui.adapter.AccountAdapter; +import eu.siacs.conversations.ui.util.MenuDoubleTabUtil; +import eu.siacs.conversations.xmpp.Jid; +import eu.siacs.conversations.xmpp.XmppConnection; + +import org.openintents.openpgp.util.OpenPgpApi; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +public class ManageAccountActivity extends XmppActivity + implements OnAccountUpdate, + KeyChainAliasCallback, + XmppConnectionService.OnAccountCreated, + AccountAdapter.OnTglAccountState { + + private final String STATE_SELECTED_ACCOUNT = "selected_account"; + + private static final int REQUEST_IMPORT_BACKUP = 0x63fb; + + protected Account selectedAccount = null; + protected Jid selectedAccountJid = null; + + protected final List accountList = new ArrayList<>(); + protected AccountAdapter mAccountAdapter; + protected AtomicBoolean mInvokedAddAccount = new AtomicBoolean(false); + + protected Pair mPostponedActivityResult = null; + + @Override + public void onAccountUpdate() { + refreshUi(); + } + + @Override + protected void refreshUiReal() { + synchronized (this.accountList) { + accountList.clear(); + accountList.addAll(xmppConnectionService.getAccounts()); + } + final ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setHomeButtonEnabled(this.accountList.size() > 0); + actionBar.setDisplayHomeAsUpEnabled(this.accountList.size() > 0); + } + invalidateOptionsMenu(); + mAccountAdapter.notifyDataSetChanged(); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + + ActivityManageAccountsBinding binding = + DataBindingUtil.setContentView(this, R.layout.activity_manage_accounts); + + Activities.setStatusAndNavigationBarColors(this, binding.getRoot()); + setSupportActionBar(binding.toolbar); + configureActionBar(getSupportActionBar()); + if (savedInstanceState != null) { + String jid = savedInstanceState.getString(STATE_SELECTED_ACCOUNT); + if (jid != null) { + try { + this.selectedAccountJid = Jid.ofEscaped(jid); + } catch (IllegalArgumentException e) { + this.selectedAccountJid = null; + } + } + } + + this.mAccountAdapter = new AccountAdapter(this, accountList); + binding.accountList.setAdapter(this.mAccountAdapter); + binding.accountList.setOnItemClickListener( + (arg0, view, position, arg3) -> switchToAccount(accountList.get(position))); + registerForContextMenu(binding.accountList); + } + + + @Override + public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) { + if (selectedAccount != null) { + savedInstanceState.putString( + STATE_SELECTED_ACCOUNT, selectedAccount.getJid().asBareJid().toEscapedString()); + } + super.onSaveInstanceState(savedInstanceState); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + ManageAccountActivity.this.getMenuInflater().inflate(R.menu.manageaccounts_context, menu); + AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; + this.selectedAccount = accountList.get(acmi.position); + if (this.selectedAccount.isEnabled()) { + menu.findItem(R.id.mgmt_account_enable).setVisible(false); + menu.findItem(R.id.mgmt_account_announce_pgp).setVisible(Config.supportOpenPgp()); + } else { + menu.findItem(R.id.mgmt_account_disable).setVisible(false); + menu.findItem(R.id.mgmt_account_announce_pgp).setVisible(false); + menu.findItem(R.id.mgmt_account_publish_avatar).setVisible(false); + } + menu.setHeaderTitle(this.selectedAccount.getJid().asBareJid().toEscapedString()); + } + + @Override + protected void onBackendConnected() { + if (selectedAccountJid != null) { + this.selectedAccount = xmppConnectionService.findAccountByJid(selectedAccountJid); + } + refreshUiReal(); + if (this.mPostponedActivityResult != null) { + this.onActivityResult( + mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second); + } + if (Config.X509_VERIFICATION && this.accountList.isEmpty()) { + if (mInvokedAddAccount.compareAndSet(false, true)) { + addAccountFromKey(); + } + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.manageaccounts, menu); + MenuItem enableAll = menu.findItem(R.id.action_enable_all); + MenuItem addAccount = menu.findItem(R.id.action_add_account); + MenuItem addAccountWithCertificate = menu.findItem(R.id.action_add_account_with_cert); + + if (Config.X509_VERIFICATION) { + addAccount.setVisible(false); + addAccountWithCertificate.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + } + + if (!accountsLeftToEnable()) { + enableAll.setVisible(false); + } + MenuItem disableAll = menu.findItem(R.id.action_disable_all); + if (!accountsLeftToDisable()) { + disableAll.setVisible(false); + } + return true; + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.mgmt_account_publish_avatar: + publishAvatar(selectedAccount); + return true; + case R.id.mgmt_account_disable: + disableAccount(selectedAccount); + return true; + case R.id.mgmt_account_enable: + enableAccount(selectedAccount); + return true; + case R.id.mgmt_account_delete: + deleteAccount(selectedAccount); + return true; + case R.id.mgmt_account_announce_pgp: + publishOpenPGPPublicKey(selectedAccount); + return true; + default: + return super.onContextItemSelected(item); + } + } + + @Override + protected void deleteAccount(final Account account) { + super.deleteAccount(account); + this.selectedAccount = null; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (MenuDoubleTabUtil.shouldIgnoreTap()) { + return false; + } + switch (item.getItemId()) { + case R.id.action_add_account: + startActivity(new Intent(this, EditAccountActivity.class)); + break; + case R.id.action_import_backup: + if (hasStoragePermission(REQUEST_IMPORT_BACKUP)) { + startActivity(new Intent(this, ImportBackupActivity.class)); + } + break; + case R.id.action_disable_all: + disableAllAccounts(); + break; + case R.id.action_enable_all: + enableAllAccounts(); + break; + case R.id.action_add_account_with_cert: + addAccountFromKey(); + break; + default: + break; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onRequestPermissionsResult( + int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (grantResults.length > 0) { + if (allGranted(grantResults)) { + switch (requestCode) { + case REQUEST_IMPORT_BACKUP: + startActivity(new Intent(this, ImportBackupActivity.class)); + break; + } + } else { + Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); + } + } + if (writeGranted(grantResults, permissions)) { + if (xmppConnectionService != null) { + xmppConnectionService.restartFileObserver(); + } + } + } + + @Override + public boolean onNavigateUp() { + if (xmppConnectionService.getConversations().size() == 0) { + Intent contactsIntent = new Intent(this, StartConversationActivity.class); + contactsIntent.setFlags( + // if activity exists in stack, pop the stack and go back to it + Intent.FLAG_ACTIVITY_CLEAR_TOP + | + // otherwise, make a new task for it + Intent.FLAG_ACTIVITY_NEW_TASK + | + // don't use the new activity animation; finish + // animation runs instead + Intent.FLAG_ACTIVITY_NO_ANIMATION); + startActivity(contactsIntent); + finish(); + return true; + } else { + return super.onNavigateUp(); + } + } + + @Override + public void onClickTglAccountState(Account account, boolean enable) { + if (enable) { + enableAccount(account); + } else { + disableAccount(account); + } + } + + private void addAccountFromKey() { + Log.d(Config.LOGTAG, "add account from key"); + try { + KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null); + } catch (final ActivityNotFoundException e) { + Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG) + .show(); + } + } + + private void publishAvatar(Account account) { + Intent intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class); + intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString()); + startActivity(intent); + } + + private void disableAllAccounts() { + List list = new ArrayList<>(); + synchronized (this.accountList) { + for (Account account : this.accountList) { + if (account.isEnabled()) { + list.add(account); + } + } + } + for (Account account : list) { + disableAccount(account); + } + } + + private boolean accountsLeftToDisable() { + synchronized (this.accountList) { + for (Account account : this.accountList) { + if (account.isEnabled()) { + return true; + } + } + return false; + } + } + + private boolean accountsLeftToEnable() { + synchronized (this.accountList) { + for (Account account : this.accountList) { + if (!account.isEnabled()) { + return true; + } + } + return false; + } + } + + private void enableAllAccounts() { + List list = new ArrayList<>(); + synchronized (this.accountList) { + for (Account account : this.accountList) { + if (!account.isEnabled()) { + list.add(account); + } + } + } + for (Account account : list) { + enableAccount(account); + } + } + + private void disableAccount(Account account) { + account.setOption(Account.OPTION_DISABLED, true); + if (!xmppConnectionService.updateAccount(account)) { + Toast.makeText(this, R.string.unable_to_update_account, Toast.LENGTH_SHORT).show(); + } + } + + private void enableAccount(Account account) { + account.setOption(Account.OPTION_DISABLED, false); + account.setOption(Account.OPTION_SOFT_DISABLED, false); + final XmppConnection connection = account.getXmppConnection(); + if (connection != null) { + connection.resetEverything(); + } + if (!xmppConnectionService.updateAccount(account)) { + Toast.makeText(this, R.string.unable_to_update_account, Toast.LENGTH_SHORT).show(); + } + } + + private void publishOpenPGPPublicKey(Account account) { + if (ManageAccountActivity.this.hasPgp()) { + announcePgp(selectedAccount, null, null, onOpenPGPKeyPublished); + } else { + this.showInstallPgpDialog(); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK) { + if (xmppConnectionServiceBound) { + if (requestCode == REQUEST_CHOOSE_PGP_ID) { + if (data.getExtras().containsKey(OpenPgpApi.EXTRA_SIGN_KEY_ID)) { + selectedAccount.setPgpSignId( + data.getExtras().getLong(OpenPgpApi.EXTRA_SIGN_KEY_ID)); + announcePgp(selectedAccount, null, null, onOpenPGPKeyPublished); + } else { + choosePgpSignId(selectedAccount); + } + } else if (requestCode == REQUEST_ANNOUNCE_PGP) { + announcePgp(selectedAccount, null, data, onOpenPGPKeyPublished); + } + this.mPostponedActivityResult = null; + } else { + this.mPostponedActivityResult = new Pair<>(requestCode, data); + } + } + } + + @Override + public void alias(final String alias) { + if (Strings.isNullOrEmpty(alias)) { + runOnUiThread( + () -> + Toast.makeText( + this, + R.string.no_certificate_selected, + Toast.LENGTH_LONG) + .show()); + return; + } + xmppConnectionService.createAccountFromKey(alias, this); + } + + @Override + public void onAccountCreated(final Account account) { + final Intent intent = new Intent(this, EditAccountActivity.class); + intent.putExtra("jid", account.getJid().asBareJid().toString()); + intent.putExtra("init", true); + startActivity(intent); + } + + @Override + public void informUser(final int r) { + runOnUiThread( + () -> Toast.makeText(ManageAccountActivity.this, r, Toast.LENGTH_LONG).show()); + } +} diff --git a/src/conversations/java/eu/siacs/conversations/ui/PickServerActivity.java b/src/conversations/java/eu/siacs/conversations/ui/PickServerActivity.java new file mode 100644 index 0000000000..f96a17ffce --- /dev/null +++ b/src/conversations/java/eu/siacs/conversations/ui/PickServerActivity.java @@ -0,0 +1,97 @@ +package eu.siacs.conversations.ui; + +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.os.Bundle; +import android.view.MenuItem; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.databinding.DataBindingUtil; + +import java.util.List; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.databinding.ActivityPickServerBinding; +import eu.siacs.conversations.entities.Account; + +public class PickServerActivity extends XmppActivity { + + @Override + protected void refreshUiReal() { + + } + + @Override + protected void onBackendConnected() { + + } + + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + if (item.getItemId() == android.R.id.home) { + startActivity(new Intent(this, WelcomeActivity.class)); + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onBackPressed() { + startActivity(new Intent(this, WelcomeActivity.class)); + super.onBackPressed(); + } + + @Override + public void onNewIntent(final Intent intent) { + super.onNewIntent(intent); + if (intent != null) { + setIntent(intent); + } + } + + @Override + protected void onCreate(final Bundle savedInstanceState) { + if (getResources().getBoolean(R.bool.portrait_only)) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + super.onCreate(savedInstanceState); + ActivityPickServerBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_pick_server); + Activities.setStatusAndNavigationBarColors(this, binding.getRoot()); + setSupportActionBar(binding.toolbar); + configureActionBar(getSupportActionBar()); + binding.useCim.setOnClickListener(v -> { + final Intent intent = new Intent(this, MagicCreateActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + addInviteUri(intent); + startActivity(intent); + }); + binding.useOwnProvider.setOnClickListener(v -> { + List accounts = xmppConnectionService.getAccounts(); + Intent intent = new Intent(this, EditAccountActivity.class); + intent.putExtra(EditAccountActivity.EXTRA_FORCE_REGISTER, true); + if (accounts.size() == 1) { + intent.putExtra("jid", accounts.get(0).getJid().asBareJid().toString()); + intent.putExtra("init", true); + } else if (!accounts.isEmpty()) { + intent = new Intent(this, ManageAccountActivity.class); + } + addInviteUri(intent); + startActivity(intent); + }); + + } + + public void addInviteUri(Intent intent) { + StartConversationActivity.addInviteUri(intent, getIntent()); + } + + public static void launch(AppCompatActivity activity) { + Intent intent = new Intent(activity, PickServerActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + activity.startActivity(intent); + activity.overridePendingTransition(0, 0); + } + +} diff --git a/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java b/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java new file mode 100644 index 0000000000..0b20e26c58 --- /dev/null +++ b/src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java @@ -0,0 +1,81 @@ +package eu.siacs.conversations.ui; + +import android.os.Bundle; +import android.widget.ListView; + +import java.util.ArrayList; +import java.util.List; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.ui.adapter.AccountAdapter; +import eu.siacs.conversations.xmpp.Jid; + +public class ShareViaAccountActivity extends XmppActivity { + public static final String EXTRA_CONTACT = "contact"; + public static final String EXTRA_BODY = "body"; + + protected final List accountList = new ArrayList<>(); + protected ListView accountListView; + protected AccountAdapter mAccountAdapter; + + @Override + protected void refreshUiReal() { + synchronized (this.accountList) { + accountList.clear(); + accountList.addAll(xmppConnectionService.getAccounts()); + } + mAccountAdapter.notifyDataSetChanged(); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_manage_accounts); + setSupportActionBar(findViewById(R.id.toolbar)); + configureActionBar(getSupportActionBar()); + accountListView = findViewById(R.id.account_list); + this.mAccountAdapter = new AccountAdapter(this, accountList, false); + accountListView.setAdapter(this.mAccountAdapter); + accountListView.setOnItemClickListener((arg0, view, position, arg3) -> { + final Account account = accountList.get(position); + final String body = getIntent().getStringExtra(EXTRA_BODY); + + try { + final Jid contact = Jid.of(getIntent().getStringExtra(EXTRA_CONTACT)); + final Conversation conversation = xmppConnectionService.findOrCreateConversation( + account, contact, false, false); + switchToConversation(conversation, body); + } catch (IllegalArgumentException e) { + // ignore error + } + + finish(); + }); + } + + @Override + protected void onBackendConnected() { + final int numAccounts = xmppConnectionService.getAccounts().size(); + + if (numAccounts == 1) { + final String body = getIntent().getStringExtra(EXTRA_BODY); + final Account account = xmppConnectionService.getAccounts().get(0); + + try { + final Jid contact = Jid.of(getIntent().getStringExtra(EXTRA_CONTACT)); + final Conversation conversation = xmppConnectionService.findOrCreateConversation( + account, contact, false, false); + switchToConversation(conversation, body); + } catch (IllegalArgumentException e) { + // ignore error + } + + finish(); + } else { + refreshUiReal(); + } + } +} diff --git a/src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java b/src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java new file mode 100644 index 0000000000..b2a40976c5 --- /dev/null +++ b/src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java @@ -0,0 +1,244 @@ +package eu.siacs.conversations.ui; + +import android.Manifest; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.net.Uri; +import android.os.Bundle; +import android.security.KeyChain; +import android.security.KeyChainAliasCallback; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.databinding.DataBindingUtil; + +import java.util.Arrays; +import java.util.List; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.databinding.ActivityWelcomeBinding; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.utils.Compatibility; +import eu.siacs.conversations.utils.InstallReferrerUtils; +import eu.siacs.conversations.utils.SignupUtils; +import eu.siacs.conversations.utils.XmppUri; +import eu.siacs.conversations.xmpp.Jid; + +import static eu.siacs.conversations.utils.PermissionUtils.allGranted; +import static eu.siacs.conversations.utils.PermissionUtils.writeGranted; + +import com.google.common.base.Strings; + +public class WelcomeActivity extends XmppActivity + implements XmppConnectionService.OnAccountCreated, KeyChainAliasCallback { + + private static final int REQUEST_IMPORT_BACKUP = 0x63fb; + + private XmppUri inviteUri; + + public static void launch(AppCompatActivity activity) { + Intent intent = new Intent(activity, WelcomeActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + activity.startActivity(intent); + activity.overridePendingTransition(0, 0); + } + + public void onInstallReferrerDiscovered(final Uri referrer) { + Log.d(Config.LOGTAG, "welcome activity: on install referrer discovered " + referrer); + if ("xmpp".equalsIgnoreCase(referrer.getScheme())) { + final XmppUri xmppUri = new XmppUri(referrer); + runOnUiThread(() -> processXmppUri(xmppUri)); + } else { + Log.i(Config.LOGTAG, "install referrer was not an XMPP uri"); + } + } + + private void processXmppUri(final XmppUri xmppUri) { + if (!xmppUri.isValidJid()) { + return; + } + final String preAuth = xmppUri.getParameter(XmppUri.PARAMETER_PRE_AUTH); + final Jid jid = xmppUri.getJid(); + final Intent intent; + if (xmppUri.isAction(XmppUri.ACTION_REGISTER)) { + intent = SignupUtils.getTokenRegistrationIntent(this, jid, preAuth); + } else if (xmppUri.isAction(XmppUri.ACTION_ROSTER) + && "y".equals(xmppUri.getParameter(XmppUri.PARAMETER_IBR))) { + intent = SignupUtils.getTokenRegistrationIntent(this, jid.getDomain(), preAuth); + intent.putExtra(StartConversationActivity.EXTRA_INVITE_URI, xmppUri.toString()); + } else { + intent = null; + } + if (intent != null) { + startActivity(intent); + finish(); + return; + } + this.inviteUri = xmppUri; + } + + @Override + protected void refreshUiReal() {} + + @Override + protected void onBackendConnected() {} + + @Override + public void onStart() { + super.onStart(); + new InstallReferrerUtils(this); + } + + @Override + public void onStop() { + super.onStop(); + } + + @Override + public void onNewIntent(final Intent intent) { + super.onNewIntent(intent); + if (intent != null) { + setIntent(intent); + } + } + + @Override + protected void onCreate(final Bundle savedInstanceState) { + if (getResources().getBoolean(R.bool.portrait_only)) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + super.onCreate(savedInstanceState); + ActivityWelcomeBinding binding = + DataBindingUtil.setContentView(this, R.layout.activity_welcome); + Activities.setStatusAndNavigationBarColors(this, binding.getRoot()); + setSupportActionBar(binding.toolbar); + configureActionBar(getSupportActionBar(), false); + setTitle(null); + binding.registerNewAccount.setOnClickListener( + v -> { + final Intent intent = new Intent(this, PickServerActivity.class); + addInviteUri(intent); + startActivity(intent); + }); + binding.useExisting.setOnClickListener( + v -> { + final List accounts = xmppConnectionService.getAccounts(); + Intent intent = new Intent(this, EditAccountActivity.class); + intent.putExtra(EditAccountActivity.EXTRA_FORCE_REGISTER, false); + if (accounts.size() == 1) { + intent.putExtra("jid", accounts.get(0).getJid().asBareJid().toString()); + intent.putExtra("init", true); + } else if (!accounts.isEmpty()) { + intent = new Intent(this, ManageAccountActivity.class); + } + addInviteUri(intent); + startActivity(intent); + }); + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.welcome_menu, menu); + final MenuItem scan = menu.findItem(R.id.action_scan_qr_code); + scan.setVisible(Compatibility.hasFeatureCamera(this)); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case R.id.action_import_backup: + if (hasStoragePermission(REQUEST_IMPORT_BACKUP)) { + startActivity(new Intent(this, ImportBackupActivity.class)); + } + break; + case R.id.action_scan_qr_code: + UriHandlerActivity.scan(this, true); + break; + case R.id.action_add_account_with_cert: + addAccountFromKey(); + break; + } + return super.onOptionsItemSelected(item); + } + + private void addAccountFromKey() { + try { + KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null); + } catch (final ActivityNotFoundException e) { + Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG) + .show(); + } + } + + @Override + public void alias(final String alias) { + if (Strings.isNullOrEmpty(alias)) { + runOnUiThread( + () -> + Toast.makeText( + this, + R.string.no_certificate_selected, + Toast.LENGTH_LONG) + .show()); + return; + } + xmppConnectionService.createAccountFromKey(alias, this); + } + + @Override + public void onAccountCreated(final Account account) { + final Intent intent = new Intent(this, EditAccountActivity.class); + intent.putExtra("jid", account.getJid().asBareJid().toEscapedString()); + intent.putExtra("init", true); + addInviteUri(intent); + startActivity(intent); + } + + @Override + public void informUser(final int r) { + runOnUiThread(() -> Toast.makeText(this, r, Toast.LENGTH_LONG).show()); + } + + @Override + public void onRequestPermissionsResult( + int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + UriHandlerActivity.onRequestPermissionResult(this, requestCode, grantResults); + if (grantResults.length > 0) { + if (allGranted(grantResults)) { + switch (requestCode) { + case REQUEST_IMPORT_BACKUP: + startActivity(new Intent(this, ImportBackupActivity.class)); + break; + } + } else if (Arrays.asList(permissions) + .contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show(); + } + } + if (writeGranted(grantResults, permissions)) { + if (xmppConnectionService != null) { + xmppConnectionService.restartFileObserver(); + } + } + } + + public void addInviteUri(Intent to) { + final Intent from = getIntent(); + if (from != null && from.hasExtra(StartConversationActivity.EXTRA_INVITE_URI)) { + final String invite = from.getStringExtra(StartConversationActivity.EXTRA_INVITE_URI); + to.putExtra(StartConversationActivity.EXTRA_INVITE_URI, invite); + } else if (this.inviteUri != null) { + Log.d(Config.LOGTAG, "injecting referrer uri into on-boarding flow"); + to.putExtra(StartConversationActivity.EXTRA_INVITE_URI, this.inviteUri.toString()); + } + } +} diff --git a/src/conversations/java/eu/siacs/conversations/ui/adapter/BackupFileAdapter.java b/src/conversations/java/eu/siacs/conversations/ui/adapter/BackupFileAdapter.java new file mode 100644 index 0000000000..9f32352eed --- /dev/null +++ b/src/conversations/java/eu/siacs/conversations/ui/adapter/BackupFileAdapter.java @@ -0,0 +1,169 @@ +package eu.siacs.conversations.ui.adapter; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.text.format.DateUtils; +import android.util.DisplayMetrics; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.databinding.DataBindingUtil; +import androidx.recyclerview.widget.RecyclerView; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.RejectedExecutionException; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.databinding.ItemAccountBinding; +import eu.siacs.conversations.services.AvatarService; +import eu.siacs.conversations.services.ImportBackupService; +import eu.siacs.conversations.utils.BackupFileHeader; +import eu.siacs.conversations.utils.UIHelper; +import eu.siacs.conversations.xmpp.Jid; + +public class BackupFileAdapter extends RecyclerView.Adapter { + + private OnItemClickedListener listener; + + private final List files = new ArrayList<>(); + + + @NonNull + @Override + public BackupFileViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + return new BackupFileViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.item_account, viewGroup, false)); + } + + @Override + public void onBindViewHolder(@NonNull BackupFileViewHolder backupFileViewHolder, int position) { + final ImportBackupService.BackupFile backupFile = files.get(position); + final BackupFileHeader header = backupFile.getHeader(); + backupFileViewHolder.binding.accountJid.setText(header.getJid().asBareJid().toString()); + backupFileViewHolder.binding.accountStatus.setText(String.format("%s · %s",header.getApp(), DateUtils.formatDateTime(backupFileViewHolder.binding.getRoot().getContext(), header.getTimestamp(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR))); + backupFileViewHolder.binding.tglAccountStatus.setVisibility(View.GONE); + backupFileViewHolder.binding.getRoot().setOnClickListener(v -> { + if (listener != null) { + listener.onClick(backupFile); + } + }); + loadAvatar(header.getJid(), backupFileViewHolder.binding.accountImage); + } + + @Override + public int getItemCount() { + return files.size(); + } + + public void setFiles(List files) { + this.files.clear(); + this.files.addAll(files); + notifyDataSetChanged(); + } + + public void setOnItemClickedListener(OnItemClickedListener listener) { + this.listener = listener; + } + + static class BackupFileViewHolder extends RecyclerView.ViewHolder { + private final ItemAccountBinding binding; + + BackupFileViewHolder(ItemAccountBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + + } + + public interface OnItemClickedListener { + void onClick(ImportBackupService.BackupFile backupFile); + } + + static class BitmapWorkerTask extends AsyncTask { + private final WeakReference imageViewReference; + private Jid jid = null; + private final int size; + + BitmapWorkerTask(final ImageView imageView) { + imageViewReference = new WeakReference<>(imageView); + DisplayMetrics metrics = imageView.getContext().getResources().getDisplayMetrics(); + this.size = ((int) (48 * metrics.density)); + } + + @Override + protected Bitmap doInBackground(Jid... params) { + this.jid = params[0]; + return AvatarService.get(this.jid, size); + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (bitmap != null && !isCancelled()) { + final ImageView imageView = imageViewReference.get(); + if (imageView != null) { + imageView.setImageBitmap(bitmap); + imageView.setBackgroundColor(0x00000000); + } + } + } + } + + private void loadAvatar(Jid jid, ImageView imageView) { + if (cancelPotentialWork(jid, imageView)) { + imageView.setBackgroundColor(UIHelper.getColorForName(jid.asBareJid().toString())); + imageView.setImageDrawable(null); + final BitmapWorkerTask task = new BitmapWorkerTask(imageView); + final AsyncDrawable asyncDrawable = new AsyncDrawable(imageView.getContext().getResources(), null, task); + imageView.setImageDrawable(asyncDrawable); + try { + task.execute(jid); + } catch (final RejectedExecutionException ignored) { + } + } + } + + private static boolean cancelPotentialWork(Jid jid, ImageView imageView) { + final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); + + if (bitmapWorkerTask != null) { + final Jid oldJid = bitmapWorkerTask.jid; + if (oldJid == null || jid != oldJid) { + bitmapWorkerTask.cancel(true); + } else { + return false; + } + } + return true; + } + + private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { + if (imageView != null) { + final Drawable drawable = imageView.getDrawable(); + if (drawable instanceof AsyncDrawable asyncDrawable) { + return asyncDrawable.getBitmapWorkerTask(); + } + } + return null; + } + + static class AsyncDrawable extends BitmapDrawable { + private final WeakReference bitmapWorkerTaskReference; + + AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) { + super(res, bitmap); + bitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask); + } + + BitmapWorkerTask getBitmapWorkerTask() { + return bitmapWorkerTaskReference.get(); + } + } + +} \ No newline at end of file diff --git a/src/conversations/java/eu/siacs/conversations/utils/PhoneNumberUtilWrapper.java b/src/conversations/java/eu/siacs/conversations/utils/PhoneNumberUtilWrapper.java new file mode 100644 index 0000000000..2f7963cf69 --- /dev/null +++ b/src/conversations/java/eu/siacs/conversations/utils/PhoneNumberUtilWrapper.java @@ -0,0 +1,11 @@ +package eu.siacs.conversations.utils; + +import android.content.Context; + +import eu.siacs.conversations.xmpp.Jid; + +public class PhoneNumberUtilWrapper { + public static String toFormattedPhoneNumber(Context context, Jid jid) { + throw new AssertionError("This method is not implemented in Conversations"); + } +} diff --git a/src/conversations/java/eu/siacs/conversations/utils/ProvisioningUtils.java b/src/conversations/java/eu/siacs/conversations/utils/ProvisioningUtils.java index 3d639d2f78..593291d953 100644 --- a/src/conversations/java/eu/siacs/conversations/utils/ProvisioningUtils.java +++ b/src/conversations/java/eu/siacs/conversations/utils/ProvisioningUtils.java @@ -2,6 +2,7 @@ package eu.siacs.conversations.utils; import android.app.Activity; import android.content.Intent; +import android.widget.Toast; import java.util.List; @@ -19,13 +20,13 @@ public class ProvisioningUtils { try { accountConfiguration = AccountConfiguration.parse(json); } catch (final IllegalArgumentException e) { - ToastCompat.makeText(activity, R.string.improperly_formatted_provisioning, ToastCompat.LENGTH_LONG).show(); + Toast.makeText(activity, R.string.improperly_formatted_provisioning, Toast.LENGTH_LONG).show(); return; } final Jid jid = accountConfiguration.getJid(); final List accounts = DatabaseBackend.getInstance(activity).getAccountJids(true); if (accounts.contains(jid)) { - ToastCompat.makeText(activity, R.string.account_already_exists, ToastCompat.LENGTH_LONG).show(); + Toast.makeText(activity, R.string.account_already_exists, Toast.LENGTH_LONG).show(); return; } final Intent serviceIntent = new Intent(activity, XmppConnectionService.class); diff --git a/src/conversations/java/eu/siacs/conversations/utils/SignupUtils.java b/src/conversations/java/eu/siacs/conversations/utils/SignupUtils.java new file mode 100644 index 0000000000..fb088234a2 --- /dev/null +++ b/src/conversations/java/eu/siacs/conversations/utils/SignupUtils.java @@ -0,0 +1,77 @@ +package eu.siacs.conversations.utils; + +import android.app.Activity; +import android.content.Intent; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.ui.ConversationsActivity; +import eu.siacs.conversations.ui.EditAccountActivity; +import eu.siacs.conversations.ui.MagicCreateActivity; +import eu.siacs.conversations.ui.ManageAccountActivity; +import eu.siacs.conversations.ui.PickServerActivity; +import eu.siacs.conversations.ui.StartConversationActivity; +import eu.siacs.conversations.ui.WelcomeActivity; +import eu.siacs.conversations.xmpp.Jid; + +public class SignupUtils { + + public static boolean isSupportTokenRegistry() { + return true; + } + + public static Intent getTokenRegistrationIntent(final Activity activity, Jid jid, String preAuth) { + final Intent intent = new Intent(activity, MagicCreateActivity.class); + if (jid.isDomainJid()) { + intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain().toEscapedString()); + } else { + intent.putExtra(MagicCreateActivity.EXTRA_DOMAIN, jid.getDomain().toEscapedString()); + intent.putExtra(MagicCreateActivity.EXTRA_USERNAME, jid.getEscapedLocal()); + } + intent.putExtra(MagicCreateActivity.EXTRA_PRE_AUTH, preAuth); + return intent; + } + + public static Intent getSignUpIntent(final Activity activity) { + return getSignUpIntent(activity, false); + } + + public static Intent getSignUpIntent(final Activity activity, final boolean toServerChooser) { + final Intent intent; + if (toServerChooser) { + intent = new Intent(activity, PickServerActivity.class); + } else { + intent = new Intent(activity, WelcomeActivity.class); + } + return intent; + } + + public static Intent getRedirectionIntent(final ConversationsActivity activity) { + final XmppConnectionService service = activity.xmppConnectionService; + Account pendingAccount = AccountUtils.getPendingAccount(service); + Intent intent; + if (pendingAccount != null) { + intent = new Intent(activity, EditAccountActivity.class); + intent.putExtra("jid", pendingAccount.getJid().asBareJid().toString()); + if (!pendingAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) { + intent.putExtra(EditAccountActivity.EXTRA_FORCE_REGISTER, pendingAccount.isOptionSet(Account.OPTION_REGISTER)); + } + } else { + if (service.getAccounts().size() == 0) { + if (Config.X509_VERIFICATION) { + intent = new Intent(activity, ManageAccountActivity.class); + } else if (Config.MAGIC_CREATE_DOMAIN != null) { + intent = getSignUpIntent(activity); + } else { + intent = new Intent(activity, EditAccountActivity.class); + } + } else { + intent = new Intent(activity, StartConversationActivity.class); + } + } + intent.putExtra("init", true); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + return intent; + } +} \ No newline at end of file diff --git a/src/conversations/new_launcher-web.png b/src/conversations/new_launcher-web.png new file mode 100644 index 0000000000..76057f9fea Binary files /dev/null and b/src/conversations/new_launcher-web.png differ diff --git a/src/conversations/res/drawable-hdpi/main_logo.png b/src/conversations/res/drawable-hdpi/main_logo.png new file mode 100644 index 0000000000..42d553dd75 Binary files /dev/null and b/src/conversations/res/drawable-hdpi/main_logo.png differ diff --git a/src/conversations/res/drawable-hdpi/splash_logo.png b/src/conversations/res/drawable-hdpi/splash_logo.png new file mode 100644 index 0000000000..d8efc71af8 Binary files /dev/null and b/src/conversations/res/drawable-hdpi/splash_logo.png differ diff --git a/src/conversations/res/drawable-mdpi/main_logo.png b/src/conversations/res/drawable-mdpi/main_logo.png new file mode 100644 index 0000000000..d81b736389 Binary files /dev/null and b/src/conversations/res/drawable-mdpi/main_logo.png differ diff --git a/src/conversations/res/drawable-mdpi/splash_logo.png b/src/conversations/res/drawable-mdpi/splash_logo.png new file mode 100644 index 0000000000..1b10d1f919 Binary files /dev/null and b/src/conversations/res/drawable-mdpi/splash_logo.png differ diff --git a/src/conversations/res/drawable-xhdpi/main_logo.png b/src/conversations/res/drawable-xhdpi/main_logo.png new file mode 100644 index 0000000000..19fbe70b8d Binary files /dev/null and b/src/conversations/res/drawable-xhdpi/main_logo.png differ diff --git a/src/conversations/res/drawable-xhdpi/splash_logo.png b/src/conversations/res/drawable-xhdpi/splash_logo.png new file mode 100644 index 0000000000..9458b791c2 Binary files /dev/null and b/src/conversations/res/drawable-xhdpi/splash_logo.png differ diff --git a/src/conversations/res/drawable-xxhdpi/main_logo.png b/src/conversations/res/drawable-xxhdpi/main_logo.png new file mode 100644 index 0000000000..cc091c437a Binary files /dev/null and b/src/conversations/res/drawable-xxhdpi/main_logo.png differ diff --git a/src/conversations/res/drawable-xxhdpi/splash_logo.png b/src/conversations/res/drawable-xxhdpi/splash_logo.png new file mode 100644 index 0000000000..83c2abe6a7 Binary files /dev/null and b/src/conversations/res/drawable-xxhdpi/splash_logo.png differ diff --git a/src/conversations/res/drawable-xxxhdpi/main_logo.png b/src/conversations/res/drawable-xxxhdpi/main_logo.png new file mode 100644 index 0000000000..3e6ddd877c Binary files /dev/null and b/src/conversations/res/drawable-xxxhdpi/main_logo.png differ diff --git a/src/conversations/res/drawable-xxxhdpi/splash_logo.png b/src/conversations/res/drawable-xxxhdpi/splash_logo.png new file mode 100644 index 0000000000..349070ba26 Binary files /dev/null and b/src/conversations/res/drawable-xxxhdpi/splash_logo.png differ diff --git a/src/conversations/res/drawable/ic_app_icon_notification.xml b/src/conversations/res/drawable/ic_app_icon_notification.xml new file mode 100644 index 0000000000..51ccc1fae5 --- /dev/null +++ b/src/conversations/res/drawable/ic_app_icon_notification.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/src/conversations/res/drawable/ic_launcher_foreground.xml b/src/conversations/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000000..5851e5f2c0 --- /dev/null +++ b/src/conversations/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/src/conversations/res/drawable/ic_launcher_monochrome.xml b/src/conversations/res/drawable/ic_launcher_monochrome.xml new file mode 100644 index 0000000000..56895d6051 --- /dev/null +++ b/src/conversations/res/drawable/ic_launcher_monochrome.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/src/conversations/res/layout/activity_easy_invite.xml b/src/conversations/res/layout/activity_easy_invite.xml new file mode 100644 index 0000000000..6f1c8fc57d --- /dev/null +++ b/src/conversations/res/layout/activity_easy_invite.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +