aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md42
-rw-r--r--README.md172
-rw-r--r--art/ic_read_indicator.svg61
-rw-r--r--art/ic_received_indicator.svg80
-rwxr-xr-xart/render.rb1
-rw-r--r--build.gradle7
-rw-r--r--libs/gson-1.1/build.gradle2
-rw-r--r--libs/gson-1.1/gson-1.1.jarbin0 -> 126300 bytes
-rw-r--r--libs/httpclient-4.0/build.gradle2
-rw-r--r--libs/httpclient-4.0/httpclient-4.0.jarbin0 -> 289954 bytes
-rw-r--r--libs/httpcore-4.0.1/build.gradle2
-rw-r--r--libs/httpcore-4.0.1/httpcore-4.0.1.jarbin0 -> 172888 bytes
-rw-r--r--libs/javax.servlet-5.1.12/build.gradle2
-rw-r--r--libs/javax.servlet-5.1.12/javax.servlet-5.1.12.jarbin0 -> 132336 bytes
-rw-r--r--src/main/AndroidManifest.xml37
-rw-r--r--src/main/java/eu/siacs/conversations/Config.java14
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Contact.java7
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Conversation.java14
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Presences.java15
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Transferable.java55
-rw-r--r--src/main/java/eu/siacs/conversations/services/AvatarService.java12
-rw-r--r--src/main/java/eu/siacs/conversations/services/CheckAppVersionService.java43
-rw-r--r--src/main/java/eu/siacs/conversations/services/NotificationService.java36
-rw-r--r--src/main/java/eu/siacs/conversations/services/UpdaterWebService.java102
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java4
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java2
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationActivity.java2865
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationFragment.java10
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java8
-rw-r--r--src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java4
-rw-r--r--src/main/java/eu/siacs/conversations/ui/UpdaterActivity.java262
-rw-r--r--src/main/java/eu/siacs/conversations/ui/XmppActivity.java3
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java2
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java7
-rw-r--r--src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java2
-rw-r--r--src/main/java/eu/siacs/conversations/utils/GeoHelper.java14
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java0
-rw-r--r--src/main/res/drawable-hdpi/ic_read_indicator.pngbin0 -> 379 bytes
-rw-r--r--src/main/res/drawable-mdpi/ic_read_indicator.pngbin0 -> 292 bytes
-rw-r--r--src/main/res/drawable-xhdpi/ic_read_indicator.pngbin0 -> 526 bytes
-rw-r--r--src/main/res/drawable-xxhdpi/ic_read_indicator.pngbin0 -> 928 bytes
-rw-r--r--src/main/res/drawable-xxxhdpi/ic_read_indicator.pngbin0 -> 931 bytes
-rw-r--r--src/main/res/drawable/message_border.xml15
-rw-r--r--src/main/res/layout/account_row.xml2
-rw-r--r--src/main/res/layout/activity_contact_details.xml37
-rw-r--r--src/main/res/layout/activity_edit_account.xml272
-rw-r--r--src/main/res/layout/activity_muc_details.xml364
-rw-r--r--src/main/res/layout/activity_publish_profile_picture.xml156
-rw-r--r--src/main/res/layout/activity_updater.xml15
-rw-r--r--src/main/res/layout/contact.xml7
-rw-r--r--src/main/res/layout/conversation_list_row.xml4
-rw-r--r--src/main/res/layout/message_received.xml3
-rw-r--r--src/main/res/layout/message_sent.xml18
-rw-r--r--src/main/res/layout/message_status.xml3
-rw-r--r--src/main/res/menu/conversations.xml10
-rw-r--r--src/main/res/menu/menu_updater.xml7
-rw-r--r--src/main/res/menu/muc_details_context.xml2
-rw-r--r--src/main/res/values-bg/strings.xml1
-rw-r--r--src/main/res/values-ca/strings.xml1
-rw-r--r--src/main/res/values-cs/strings.xml1
-rw-r--r--src/main/res/values-de/strings.xml32
-rw-r--r--src/main/res/values-el/strings.xml1
-rw-r--r--src/main/res/values-es/strings.xml1
-rw-r--r--src/main/res/values-eu/strings.xml1
-rw-r--r--src/main/res/values-fr/strings.xml1
-rw-r--r--src/main/res/values-id/strings.xml1
-rw-r--r--src/main/res/values-it/strings.xml1
-rw-r--r--src/main/res/values-ja/strings.xml1
-rw-r--r--src/main/res/values-ko/strings.xml1
-rw-r--r--src/main/res/values-ms/strings.xml2
-rw-r--r--src/main/res/values-nl/strings.xml1
-rw-r--r--src/main/res/values-pl/strings.xml1
-rw-r--r--src/main/res/values-pt/strings.xml1
-rw-r--r--src/main/res/values-ru/strings.xml1
-rw-r--r--src/main/res/values-sk/strings.xml1
-rw-r--r--src/main/res/values-sr/strings.xml1
-rw-r--r--src/main/res/values-sv/strings.xml1
-rw-r--r--src/main/res/values-w820dp/dimens.xml6
-rw-r--r--src/main/res/values-zh-rCN/strings.xml2
-rw-r--r--src/main/res/values/strings.xml21
-rw-r--r--src/main/res/xml/preferences.xml20
81 files changed, 2796 insertions, 2109 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 663079d01..f0b9e13fb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,25 +1,39 @@
###Changelog
####Version 1.7.0
-* CAPTCHA support
-* SASL EXTERNAL (client certifiates)
-* fetching MUC history via MAM
* redownload deleted files from HTTP hosts
-* Expert setting to automatically set presence
* bug fixes
+* show lastseen info as subitle in single chats
-####Version 1.6.11
+####Version 1.6.13
+* bugfixes
+* fetching MUC history via MAM
+* Expert setting to automatically set presence
+* show client-to-client encryption in chatview
+* added changelog to AppUpdater dialog
+* delete old version files in download folder on updating
+* use standard namespace for file transfers
+* CAPTCHA support
+* SASL EXTERNAL (client certifiates)
+
+####Version 1.6.12
+* added blue tick as read indicator
* tab completion for MUC nicks
-* history export
+* history export to SD card
* bug fixes
+####Version 1.6.11
+* optimized app updater and increased app update check period to once a day
+
####Version 1.6.10
* fixed facebook login
* fixed bug with ejabberd mam
-* use official HTTP File Upload namespace
+* run app updater automatically
####Version 1.6.9
* basic keyboard support
+* bug fixes
+* update checker with in app version updates
####Version 1.6.8
* reworked 'enter is send' setting
@@ -51,16 +65,26 @@
####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
+* some bugfixes
+* hard coded pix-art.de as standard server
+
+####Version 1.5.2
+* added new message bubbles
+* added subtitles to chatviews in ActionBar to display typing info in single chats and participant names in conferences
+* some bug fixes
####Version 1.5.1
* fixed rare crashes
* improved otr support
+* moved typing info to ActionBar
####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
+* new file transfer mode to offline contacts and conferences for files smaller than 20 MB: upload files to HTTP host and share them in MUCs. requires new [HttpUploadComponent](https://github.com/siacs/HttpUploadComponent) on server side
+* default image format is JPEG
+* small layout modifications with bigger avatars
+* show contacts name in locations shared in conferences
####Version 1.4.5
* fixes to message parser to not display some ejabberd muc status messages
diff --git a/README.md b/README.md
index 12129a201..bc7c44417 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,9 @@
Conversations: the very last word in instant messaging
-[![Google Play](http://developer.android.com/images/brand/en_generic_rgb_wo_60.png)](https://play.google.com/store/apps/details?id=eu.siacs.conversations&referrer=utm_source%3Dgithub) [![Amazon App Store](https://images-na.ssl-images-amazon.com/images/G/01/AmazonMobileApps/amazon-apps-store-us-black.png)](http://www.amazon.com/dp/B00WD35AAC/)
+This is a fork of the official [Conversations](https://github.com/siacs/Conversations) app with some modifications described under features.
+
+Conversations can be downloaded from github [releases](https://github.com/kriztan/Conversations/releases)
![screenshots](https://raw.githubusercontent.com/siacs/Conversations/master/screenshots.png)
@@ -16,7 +18,7 @@ Conversations: the very last word in instant messaging
## Features
-* End-to-end encryption with [OMEMO](http://conversations.im/omemo/), [OTR](https://otr.cypherpunks.ca/), or [OpenPGP](http://www.openpgp.org/about_openpgp/)
+* End-to-end encryption with either [OTR](https://otr.cypherpunks.ca/) or [OpenPGP](http://www.openpgp.org/about_openpgp/)
* Send and receive images as well as other kind of files
* Share your location via an external [plug-in](https://play.google.com/store/apps/details?id=eu.siacs.conversations.sharelocation&referrer=utm_source%3Dgithub)
* Indication when your contact has read your message
@@ -28,20 +30,28 @@ Conversations: the very last word in instant messaging
* Multiple accounts / unified inbox
* Very low impact on battery life
+our individual changes:
+* accounts are hard linked to pix-art.de
+* increased avatar-sizes in account- and contact-details with prefering XMPP-avatars over addressbook avatars
+* in-app self updater with dayly check for updates
+* moved writing info from chatwindow into actionbar-subtitle
+* show lastseen info in actionbar-subtitle
+* display group chat members in actionbar-subtitle
+* images are transfered as JPEG
+* support more file-types for file-transfer (pdf, doc, docx, txt, m4a, m4b, mp3, mp2, wav, aac, aif, aiff, aifc, mid, midi, 3gpp, avi, mp4, mpeg, mpg, mpe, mov, 3gp, apk, vcf, ics, zip, rar)
+* show contacts name in locations shared in conferences
+* OpenPGP end-to-end encryption methode is disabled
### XMPP Features
-Conversations works with every XMPP server out there. However XMPP is an
+This Conversations works only with `pix-art.de`. However XMPP is an
extensible protocol. These extensions are standardized as well in so called
XEP's. Conversations supports a couple of these to make the overall user
-experience better. There is a chance that your current XMPP server does not
-support these extensions; therefore to get the most out of Conversations you
-should consider either switching to an XMPP server that does or — even better —
-run your own XMPP server for you and your friends. These XEP's are:
+experience better. Our XMPP-Server is prosody and supports all of the listed XEP's:
* [XEP-0065: SOCKS5 Bytestreams](http://xmpp.org/extensions/xep-0065.html) (or mod_proxy65). Will be used to transfer
files if both parties are behind a firewall (NAT).
-* [XEP-0163: Personal Eventing Protocol](http://xmpp.org/extensions/xep-0163.html) for avatars and OMEMO.
+* [XEP-0163: Personal Eventing Protocol](http://xmpp.org/extensions/xep-0163.html) for avatars
* [XEP-0191: Blocking command](http://xmpp.org/extensions/xep-0191.html) lets you blacklist spammers or block contacts
without removing them from your roster.
* [XEP-0198: Stream Management](http://xmpp.org/extensions/xep-0198.html) allows XMPP to survive small network outages and
@@ -58,15 +68,19 @@ run your own XMPP server for you and your friends. These XEP's are:
withholding unimportant packages.
* [XEP-0363: HTTP File Upload](http://xmpp.org/extensions/xep-0363.html) allows you to share files in conferences and with offline
contacts. Requires an [additional component](https://github.com/siacs/HttpUploadComponent)
- on your server. Alternatively, an [Ejabberd contrib-module](https://github.com/processone/ejabberd-contrib/tree/master/mod_http_upload) and a [Prosody module](http://modules.prosody.im/mod_http_upload.html) are available.
+ on your server.
## Team
-#### Head of Development
+#### Head of Development (original Conversations)
+
+* [Daniel Gultsch](https://github.com/inputmice)
+
+#### Head of Development (modified Conversations)
-* [Daniel Gultsch](https://github.com/inputmice)
+* [Christian Schneppe](https://github.com/kriztan)
-#### Code Contributions
+#### Code Contributions (original Conversations)
(In order of appearance)
@@ -84,7 +98,9 @@ run your own XMPP server for you and your friends. These XEP's are:
* [fiaxh](https://github.com/fiaxh) (OMEMO)
#### Translations
-Translations are managed on [Transifex](https://www.transifex.com/projects/p/conversations/)
+Translations are managed on [Transifex](https://www.transifex.com/projects/p/conversations/) for original features
+
+Translations for our own features are managed on github. If you would like to help translation the app create a pull-request.
## FAQ
@@ -93,58 +109,14 @@ Translations are managed on [Transifex](https://www.transifex.com/projects/p/con
#### How do I install Conversations?
Conversations is entirely open source and licensed under GPLv3. So if you are a
-software developer you can check out the sources from GitHub and use Gradle to
+software developer you can check out the sources from GitHub and use ant to
build your apk file.
-The more convenient way — which not only gives you automatic updates but also
-supports the further development of Conversations — is to buy the App in the
-Google [Play Store](https://play.google.com/store/apps/details?id=eu.siacs.conversations&referrer=utm_source%3Dgithub).
-
-Buying the App from the Play Store will also give you access to our [beta test](#beta).
-
-#### I don't have a Google Account but I would still like to make a contribution
-
-I accept donations over PayPal, Bitcoin and Flattr. For donations via PayPal you
-can use the email address `donate@siacs.eu` or the button below.
-
-[![Donate with PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CW3SYT3KG5PDL)
-
-**Disclaimer:** I'm not a huge fan of PayPal and their business policies. For
-larger contributions please get in touch with me beforehand and we can talk
-about bank transfer (SEPA).
-
-My Bitcoin Address is: `1NxSU1YxYzJVDpX1rcESAA3NJki7kRgeeu`
-
-
-[![Flattr this!](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=inputmice&url=http%3A%2F%2Fconversations.siacs.eu&title=Conversations&tags=github&category=software)
+Our modified version of Conversation can be downloaded from github [releases](https://github.com/kriztan/Conversations/releases)
#### How do I create an account?
-XMPP, like email, is a federated protocol which means that there is not one
-company you can create an 'official XMPP account' with. Instead there are
-hundreds, or even thousands, of provider out there. To find one use a web search
-engine of your choice. Or maybe your university has one. Or you can run your
-own. Or ask a friend to run one. Once you've found one, you can use
-Conversations to create an account. Just select 'register new account on server'
-within the create account dialog.
-
-#### Where can I set up a custom hostname / port
-Conversations will automatically look up the SRV records for your domain name
-which can point to any hostname port combination. If your server doesn’t provide
-those please contact your admin and have them read
-[this](http://prosody.im/doc/dns#srv_records)
-
-#### Conversations doesn't work for me. Where can I get help?
-
-You can join our conference room on `conversations@conference.siacs.eu`.
-A lot of people in there are able to answer basic questions about the usage of
-Conversations or can provide you with tips on running your own XMPP server. If
-you found a bug or your app crashes please read the Developer / Report Bugs
-section of this document.
-
-#### I need professional support with Conversations or setting up my server
-
-I'm available for hire. Contact me at `inputmice@siacs.eu`.
+With our Conversations app you can only create and use accounts on `pix-art.de`. You can create your own account for free. You only need a nickname and a password. You don't need to add `@pix-art.de` to your nickname. After creating your own `pix-art.de` account you'll find me in your contact list. If you have any questions about our app or our service feel free to ask me or join our support-conference `support@room.pix-art.de`.
#### How does the address book integration work?
@@ -196,7 +168,7 @@ everybody in your contact list to know that you have been using your computer at
In the past status has been used to judge the likelihood of whether or not your
messages are being read. This is no longer necessary. With Chat Markers
(XEP-0333, supported by Conversations since 0.4) we have the ability to **know**
-whether or not your messages are being read. Similar things can be said for
+whether or not your messages are being read. Similar things can be said for
priorities. In the past priorities have been used (by servers, not by clients!)
to route your messages to one specific client. With carbon messages (XEP-0280,
supported by Conversations since 0.1) this is no longer necessary. Using
@@ -214,27 +186,11 @@ Making these status and priority optional isn't a solution either because
Conversations is trying to get rid of old behaviours and set an example for
other clients.
-#### Conversations is missing a certain feature
-
-I'm open for new feature suggestions. You can use the [issue tracker][issues] on
-GitHub. Please take some time to browse through the issues to see if someone
-else already suggested it. Be assured that I read each and every ticket. If I
-like it I will leave it open until it's implemented. If I don't like it I will
-close it (usually with a short comment). If I don't comment on an feature
-request that's probably a good sign because this means I agree with you.
-Commenting with +1 on either open or closed issues won't change my mind, nor
-will it accelerate the development.
-
-#### You closed my feature request but I want it really really badly
-
-Just write it yourself and send me a pull request. If I like it I will happily
-merge it if I don't at least you and like minded people get to enjoy it.
-
-#### I need a feature and I need it now!
+### Security
-I am available for hire. Contact me via XMPP: `inputmice@siacs.eu`
+#### Encryption methodes
-### Security
+You can choose between different end-to-end encryption methodes, which are explained in the following lines. Our Server only accepts TLS encrypted connections to clients and only allows unencrypted connections to other server, if there is no way to encrypt the connections. If you are chatting with users to other servers, you should use an end-to-end encryption methode or ask me to look if the server-connections are encrypted or not.
#### Why are there three end-to-end encryption methods and which one should I choose?
@@ -253,6 +209,8 @@ downsides: It is vulnerable to replay attacks, it is rather verbose, and
decrypting and encrypting takes longer than OTR. It is however asynchronous and
works well with message carbons.
+In our version, OpenPGP is diabled because of the problems listed above.
+
To use OpenPGP you have to install the open source app
[OpenKeychain](http://www.openkeychain.org) and then long press on the account in
manage accounts and choose renew PGP announcement from the contextual menu.
@@ -272,59 +230,11 @@ feature is regarded experimental. Conversations is the only client that uses
XEP-0027 with conferences. (The XEP neither specifically allows nor disallows
this.)
-### Development
-
-<a name="beta"></a>
-#### Beta testing
-If you bought the App on [Google Play](https://play.google.com/store/apps/details?id=eu.siacs.conversations)
-you can get access to the latest beta version by joining the
-[Conversations Beta Testers](https://plus.google.com/communities/107649347599361240873)
-community on Google+ and then using [this link](https://play.google.com/apps/testing/eu.siacs.conversations)
-to sign up for the beta test.
-
-#### How do I build Conversations
-
-Make sure to have ANDROID_HOME point to your Android SDK
-
- git clone https://github.com/siacs/Conversations.git
- cd Conversations
- ./gradlew build
-
-
-[![Build Status](https://travis-ci.org/siacs/Conversations.svg?branch=development)](https://travis-ci.org/siacs/Conversations)
-
-### How do I update/add external libraries?
-
-If the library you want to update is in Maven Central or JCenter (or has its own
-Maven repo), add it or update its version in `build.gradle`. If the library is
-in the `libs/` directory, you can update it using a subtree merge by doing the
-following (using `minidns` as an example):
-
- git remote add minidns https://github.com/rtreffer/minidns.git
- git fetch minidns
- git merge -s subtree minidns master
-
-To add a new dependency to the `libs/` directory (replacing "name", "branch" and
-"url" as necessary):
-
- git remote add name url
- git merge -s ours --no-commit name/branch
- git read-tree --prefix=libs/name -u name/branch
- git commit -m "Subtree merged in name"
-
-#### How do I debug Conversations
-
-If something goes wrong Conversations usually exposes very little information in
-the UI (other than the fact that something didn't work). However with adb
-(android debug bridge) you squeeze some more information out of Conversations.
-These information are especially useful if you are experiencing trouble with
-your connection or with file transfer.
-
- adb -d logcat -v time -s conversations
-
#### I found a bug
-Please report it to our [issue tracker][issues]. If your app crashes please
+If you have troubles or problems please report them first into our support chat `support@room.pix-art.de`, so we can decide if it's an issue caused by our features or a global issue.
+
+Only global issues should be reported into the Conversations [issue tracker][issues]. If your app crashes please
provide a stack trace. If you are experiencing misbehaviour please provide
detailed steps to reproduce. Always mention whether you are running the latest
Play Store version or the current HEAD. If you are having problems connecting to
diff --git a/art/ic_read_indicator.svg b/art/ic_read_indicator.svg
new file mode 100644
index 000000000..702e97d25
--- /dev/null
+++ b/art/ic_read_indicator.svg
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="586.62292"
+ height="576.55585"
+ id="svg2"
+ inkscape:version="0.48.1 r9760"
+ sodipodi:docname="Check-71-128-204-brightblue.svg">
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="640"
+ inkscape:window-height="480"
+ id="namedview6"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:zoom="0.26226712"
+ inkscape:cx="365.3587"
+ inkscape:cy="62.096819"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg2" />
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <path
+ d="m 1,392.89211 c 0,0 115.16535,129.68765 138.19842,182.66371 l 99.0422,0 C 279.70015,448.87393 440.93164,146.43825 579.13006,40.486115 607.76328,3.6719748 535.83226,-11.524105 477.78456,12.846425 390.29814,49.576415 225.29631,330.01448 194.47779,397.49872 150.71496,409.01526 104.64881,323.7929 104.64881,323.7929 L 1,392.89211 z"
+ id="path4"
+ style="fill:#4780cc;fill-opacity:1;stroke:#000000;stroke-width:2"
+ inkscape:connector-curvature="0" />
+</svg>
diff --git a/art/ic_received_indicator.svg b/art/ic_received_indicator.svg
index 43689c267..a12292f51 100644
--- a/art/ic_received_indicator.svg
+++ b/art/ic_received_indicator.svg
@@ -1,76 +1,4 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- version="1.0"
- width="95"
- height="95"
- id="Yes_check"
- inkscape:version="0.91 r13725"
- sodipodi:docname="ic_received_indicator.svg">
- <metadata
- id="metadata10">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="956"
- inkscape:window-height="1156"
- id="namedview8"
- showgrid="false"
- showguides="true"
- inkscape:guide-bbox="true"
- inkscape:zoom="5.04"
- inkscape:cx="-4.3215257"
- inkscape:cy="37.489149"
- inkscape:window-x="2880"
- inkscape:window-y="20"
- inkscape:window-maximized="0"
- inkscape:current-layer="Yes_check"
- fit-margin-top="0"
- fit-margin-left="0"
- fit-margin-right="0"
- fit-margin-bottom="0" />
- <defs
- id="defs1373">
- <linearGradient
- id="linearGradient2250">
- <stop
- style="stop-color:#008700;stop-opacity:1"
- offset="0"
- id="stop2252" />
- <stop
- style="stop-color:#006f00;stop-opacity:1"
- offset="1"
- id="stop2254" />
- </linearGradient>
- </defs>
- <path
- d="m 2.3894499,61.412131 c 0,0 16.7473651,20.271938 22.3528491,26.154483 3.648598,3.026816 12.878061,3.83429 14.880462,0 1.64903,-2.636163 2.380404,-5.8348 2.991819,-7.931771 C 49.920898,54.575958 72.297563,22.337321 92.321082,10.50894 96.814837,5.2377522 86.327596,3.5063483 77.217442,6.9958109 63.487006,12.254946 34.107717,59.529917 29.270873,69.192545 22.40265,70.841418 12.518762,52.447046 12.518762,52.447046 7.3805037,52.552428 1.8841059,52.071763 2.3894499,61.412131 z"
- style="fill:#259b24;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.29981154;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="check"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccscsccc" />
-</svg>
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600">
+<path d="m7.7,404.6c0,0 115.2,129.7 138.2,182.68l99,0c41.5-126.7 202.7-429.1 340.92-535.1c28.6-36.8-43.3-52-101.35-27.62-87.5,36.7-252.5,317.2-283.3,384.64-43.7,11.5-89.8-73.7-89.84-73.7z" fill="#181"/>
+</svg> \ No newline at end of file
diff --git a/art/render.rb b/art/render.rb
index b4f84769c..c1e57e0f6 100755
--- a/art/render.rb
+++ b/art/render.rb
@@ -14,6 +14,7 @@ images = {
'conversations_baloon.svg' => ['ic_launcher', 48],
'conversations_mono.svg' => ['ic_notification', 24],
'ic_received_indicator.svg' => ['ic_received_indicator', 12],
+ 'ic_read_indicator.svg' => ['ic_read_indicator', 12],
'ic_send_text_offline.svg' => ['ic_send_text_offline', 36],
'ic_send_text_online.svg' => ['ic_send_text_online', 36],
'ic_send_text_away.svg' => ['ic_send_text_away', 36],
diff --git a/build.gradle b/build.gradle
index b36448ec6..c66497894 100644
--- a/build.gradle
+++ b/build.gradle
@@ -40,6 +40,9 @@ dependencies {
compile 'com.kyleduo.switchbutton:library:1.2.8'
compile 'org.whispersystems:axolotl-android:1.3.4'
compile 'com.makeramen:roundedimageview:2.2.0'
+ compile 'jetty:javax.servlet:5.1.12'
+ compile 'com.google.code.gson:gson:2.3.1'
+ compile 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2'
}
android {
@@ -49,8 +52,8 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 21
- versionCode 100
- versionName "1.7.0-beta.2"
+ versionCode 102
+ versionName "1.7.0"
project.ext.set(archivesBaseName, archivesBaseName + "-" + versionName);
}
diff --git a/libs/gson-1.1/build.gradle b/libs/gson-1.1/build.gradle
new file mode 100644
index 000000000..72090a0aa
--- /dev/null
+++ b/libs/gson-1.1/build.gradle
@@ -0,0 +1,2 @@
+configurations.create("default")
+artifacts.add("default", file('gson-1.1.jar')) \ No newline at end of file
diff --git a/libs/gson-1.1/gson-1.1.jar b/libs/gson-1.1/gson-1.1.jar
new file mode 100644
index 000000000..89018e100
--- /dev/null
+++ b/libs/gson-1.1/gson-1.1.jar
Binary files differ
diff --git a/libs/httpclient-4.0/build.gradle b/libs/httpclient-4.0/build.gradle
new file mode 100644
index 000000000..1002f98c2
--- /dev/null
+++ b/libs/httpclient-4.0/build.gradle
@@ -0,0 +1,2 @@
+configurations.create("default")
+artifacts.add("default", file('httpclient-4.0.jar')) \ No newline at end of file
diff --git a/libs/httpclient-4.0/httpclient-4.0.jar b/libs/httpclient-4.0/httpclient-4.0.jar
new file mode 100644
index 000000000..a1d15c41f
--- /dev/null
+++ b/libs/httpclient-4.0/httpclient-4.0.jar
Binary files differ
diff --git a/libs/httpcore-4.0.1/build.gradle b/libs/httpcore-4.0.1/build.gradle
new file mode 100644
index 000000000..8799dfe4b
--- /dev/null
+++ b/libs/httpcore-4.0.1/build.gradle
@@ -0,0 +1,2 @@
+configurations.create("default")
+artifacts.add("default", file('httpcore-4.0.1.jar')) \ No newline at end of file
diff --git a/libs/httpcore-4.0.1/httpcore-4.0.1.jar b/libs/httpcore-4.0.1/httpcore-4.0.1.jar
new file mode 100644
index 000000000..4aef35e2f
--- /dev/null
+++ b/libs/httpcore-4.0.1/httpcore-4.0.1.jar
Binary files differ
diff --git a/libs/javax.servlet-5.1.12/build.gradle b/libs/javax.servlet-5.1.12/build.gradle
new file mode 100644
index 000000000..7ab6d4ff7
--- /dev/null
+++ b/libs/javax.servlet-5.1.12/build.gradle
@@ -0,0 +1,2 @@
+configurations.create("default")
+artifacts.add("default", file('javax.servlet-5.1.12.jar')) \ No newline at end of file
diff --git a/libs/javax.servlet-5.1.12/javax.servlet-5.1.12.jar b/libs/javax.servlet-5.1.12/javax.servlet-5.1.12.jar
new file mode 100644
index 000000000..c1df2b482
--- /dev/null
+++ b/libs/javax.servlet-5.1.12/javax.servlet-5.1.12.jar
Binary files differ
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 117bce928..23273162e 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
-<manifest
- package="eu.siacs.conversations"
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="eu.siacs.conversations" >
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
@@ -29,10 +28,15 @@
<receiver android:name=".services.EventReceiver">
<intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED"/>
- <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
- <action android:name="android.intent.action.ACTION_SHUTDOWN"/>
- <action android:name="android.media.RINGER_MODE_CHANGED"/>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
+ <action android:name="android.intent.action.ACTION_SHUTDOWN" />
+ <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
+ <action android:name="android.media.RINGER_MODE_CHANGED" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.PACKAGE_REPLACED" />
+ <data android:scheme="package" android:path="eu.siacs.conversations" />
</intent-filter>
</receiver>
@@ -51,7 +55,7 @@
android:name=".ui.StartConversationActivity"
android:configChanges="orientation|screenSize"
android:label="@string/title_activity_start_conversation"
- android:launchMode="singleTask">
+ android:launchMode="singleTask" >
<intent-filter>
<action android:name="android.intent.action.SENDTO"/>
@@ -141,11 +145,11 @@
<activity
android:name=".ui.TrustKeysActivity"
android:label="@string/trust_omemo_fingerprints"
- android:windowSoftInputMode="stateAlwaysHidden"/>
+ android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name="de.duenndns.ssl.MemorizingActivity"
android:theme="@style/ConversationsTheme"
- tools:replace="android:theme"/>
+ tools:replace="android:theme" />
<activity
android:name=".ui.AboutActivity"
android:label="@string/title_activity_about"
@@ -154,8 +158,15 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="eu.siacs.conversations.ui.SettingsActivity"/>
</activity>
-
- <service android:name=".services.ExportLogsService"/>
+ <activity
+ android:name=".ui.UpdaterActivity"
+ android:screenOrientation="portrait"
+ android:theme="@style/ConversationsTheme"
+ android:label="@string/title_activity_updater" >
+ </activity>
+ <service android:name=".services.UpdaterWebService" />
+ <service android:name=".services.CheckAppVersionService" />
+ <service android:name=".services.ExportLogsService" />
</application>
</manifest>
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java
index 14605cf09..9361fb0d6 100644
--- a/src/main/java/eu/siacs/conversations/Config.java
+++ b/src/main/java/eu/siacs/conversations/Config.java
@@ -9,11 +9,12 @@ public final class Config {
public static final String LOGTAG = "conversations";
- public static final String DOMAIN_LOCK = null; //only allow account creation for this domain
+ public static final String DOMAIN_LOCK = "pix-art.de"; //only allow account creation for this domain
public static final boolean DISALLOW_REGISTRATION_IN_UI = false; //hide the register checkbox
- public static final boolean HIDE_PGP_IN_UI = false; //some more consumer focused clients might want to disable OpenPGP
+ public static final boolean HIDE_PGP_IN_UI = true; //some more consumer focused clients might want to disable OpenPGP
+ public static final boolean HIDE_ENCRYPTION_IN_UI = false; //completely hide encryption options in menu bar
- public static final boolean LEGACY_NAMESPACE_HTTP_UPLOAD = false;
+ public static final boolean LEGACY_NAMESPACE_HTTP_UPLOAD = false; // true = 'eu:siacs:conversations:http:upload' false = 'urn:xmpp:http:upload'
public static final int PING_MAX_INTERVAL = 300;
public static final int PING_MIN_INTERVAL = 30;
@@ -23,7 +24,7 @@ public final class Config {
public static final int CARBON_GRACE_PERIOD = 90;
public static final int MINI_GRACE_PERIOD = 750;
- public static final int AVATAR_SIZE = 192;
+ public static final int AVATAR_SIZE = 640;
public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP;
public static final int IMAGE_SIZE = 1920;
@@ -57,7 +58,10 @@ public final class Config {
public static final int MAM_MAX_MESSAGES = 500;
public static final ChatState DEFAULT_CHATSTATE = ChatState.ACTIVE;
- public static final int TYPING_TIMEOUT = 8;
+ public static final int TYPING_TIMEOUT = 5;
+
+ public static final String UPDATE_URL = "http://xmpp.pix-art.de/Conversations/update/";
+ public static final long UPDATE_CHECK_TIMER = 24 * 60 * 60; // in seconds
public static final String ENABLED_CIPHERS[] = {
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java
index f924c05a1..f5fa88d7a 100644
--- a/src/main/java/eu/siacs/conversations/entities/Contact.java
+++ b/src/main/java/eu/siacs/conversations/entities/Contact.java
@@ -149,6 +149,9 @@ public class Contact implements ListItem, Blockable {
if (isBlocked()) {
tags.add(new Tag("blocked", 0xff2e2f3b));
}
+ if (!getMostAvailableResource().equals("")){
+ tags.add(new Tag(getMostAvailableResource(), 0xff37b8a9));
+ }
return tags;
}
@@ -239,6 +242,10 @@ public class Contact implements ListItem, Blockable {
return this.presences.getMostAvailableStatus();
}
+ public String getMostAvailableResource() {
+ return this.presences.getMostAvailableResource();
+ }
+
public boolean setPhotoUri(String uri) {
if (uri != null && !uri.equals(this.photoUri)) {
this.photoUri = uri;
diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java
index 5f3f1a6e3..71df60ebf 100644
--- a/src/main/java/eu/siacs/conversations/entities/Conversation.java
+++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java
@@ -20,6 +20,7 @@ import java.util.Iterator;
import java.util.List;
import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
@@ -367,6 +368,19 @@ public class Conversation extends AbstractEntity implements Blockable {
return this.getContact().getDisplayName();
}
}
+
+ public String getParticipants() {
+ if (getMode() == MODE_MULTI) {
+ String generatedName = getMucOptions().createNameFromParticipants();
+ if (generatedName != null) {
+ return generatedName;
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
public String getAccountUuid() {
return this.accountUuid;
diff --git a/src/main/java/eu/siacs/conversations/entities/Presences.java b/src/main/java/eu/siacs/conversations/entities/Presences.java
index bccf31170..f233d015f 100644
--- a/src/main/java/eu/siacs/conversations/entities/Presences.java
+++ b/src/main/java/eu/siacs/conversations/entities/Presences.java
@@ -52,6 +52,21 @@ public class Presences {
return status;
}
+ public String getMostAvailableResource() {
+ int status = OFFLINE;
+ String resource = "";
+ synchronized (this.presences) {
+ Iterator<Entry<String, Integer>> it = presences.entrySet().iterator();
+ while (it.hasNext()) {
+ Entry<String, Integer> entry = it.next();
+ if (entry.getValue() < status)
+ status = entry.getValue();
+ resource = entry.getKey();
+ }
+ }
+ return resource;
+ }
+
public static int parseShow(Element show) {
if ((show == null) || (show.getContent() == null)) {
return Presences.ONLINE;
diff --git a/src/main/java/eu/siacs/conversations/entities/Transferable.java b/src/main/java/eu/siacs/conversations/entities/Transferable.java
index 016c81bdf..859cda658 100644
--- a/src/main/java/eu/siacs/conversations/entities/Transferable.java
+++ b/src/main/java/eu/siacs/conversations/entities/Transferable.java
@@ -2,9 +2,58 @@ package eu.siacs.conversations.entities;
public interface Transferable {
- String[] VALID_IMAGE_EXTENSIONS = {"webp", "jpeg", "jpg", "png", "jpe"};
- String[] VALID_CRYPTO_EXTENSIONS = {"pgp", "gpg", "otr"};
- String[] WELL_KNOWN_EXTENSIONS = {"pdf","m4a","mp4"};
+ String[] VALID_IMAGE_EXTENSIONS = {
+ "webp",
+ "jpeg",
+ "jpg",
+ "png",
+ "jpe",
+ "gif",
+ "tif"
+ };
+ String[] VALID_CRYPTO_EXTENSIONS = {
+ "pgp",
+ "gpg",
+ "otr"
+ };
+ String[] WELL_KNOWN_EXTENSIONS = {
+ //documents
+ "pdf",
+ "doc",
+ "docx",
+ "txt",
+ //audio
+ "m4a",
+ "m4b",
+ "mp3",
+ "mp2",
+ "wav",
+ "aac",
+ "aif",
+ "aiff",
+ "aifc",
+ "mid",
+ "midi",
+ "3gpp",
+ //video
+ "avi",
+ "mp4",
+ "mpeg",
+ "mpg",
+ "mpe",
+ "mov",
+ "3gp",
+ //applications
+ "apk",
+ //contact
+ "vcf",
+ //calendar
+ "ics",
+ //compressed
+ "zip",
+ "rar",
+
+ };
int STATUS_UNKNOWN = 0x200;
int STATUS_CHECKING = 0x201;
diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java
index 7412eb933..e88047f67 100644
--- a/src/main/java/eu/siacs/conversations/services/AvatarService.java
+++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java
@@ -44,12 +44,12 @@ public class AvatarService {
if (avatar != null || cachedOnly) {
return avatar;
}
- if (contact.getProfilePhoto() != null) {
- avatar = mXmppConnectionService.getFileBackend().cropCenterSquare(Uri.parse(contact.getProfilePhoto()), size);
- }
if (avatar == null && contact.getAvatar() != null) {
avatar = mXmppConnectionService.getFileBackend().getAvatar(contact.getAvatar(), size);
}
+ if (avatar == null && contact.getProfilePhoto() != null) {
+ avatar = mXmppConnectionService.getFileBackend().cropCenterSquare(Uri.parse(contact.getProfilePhoto()), size);
+ }
if (avatar == null) {
avatar = get(contact.getDisplayName(), size, cachedOnly);
}
@@ -265,11 +265,11 @@ public class AvatarService {
Contact contact = user.getContact();
if (contact != null) {
Uri uri = null;
- if (contact.getProfilePhoto() != null) {
- uri = Uri.parse(contact.getProfilePhoto());
- } else if (contact.getAvatar() != null) {
+ if (contact.getAvatar() != null) {
uri = mXmppConnectionService.getFileBackend().getAvatarUri(
contact.getAvatar());
+ } else if (contact.getProfilePhoto() != null) {
+ uri = Uri.parse(contact.getProfilePhoto());
}
if (uri != null) {
Bitmap bitmap = mXmppConnectionService.getFileBackend()
diff --git a/src/main/java/eu/siacs/conversations/services/CheckAppVersionService.java b/src/main/java/eu/siacs/conversations/services/CheckAppVersionService.java
new file mode 100644
index 000000000..33faeaeca
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/services/CheckAppVersionService.java
@@ -0,0 +1,43 @@
+package eu.siacs.conversations.services;
+
+import com.google.gson.JsonObject;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class CheckAppVersionService extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+
+ public CheckAppVersionService() {
+ super();
+ }
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ doPost(request,response);
+ }
+
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+
+ PrintWriter out = response.getWriter();
+ response.setContentType("text/html");
+
+ //send a JSON response with the app Version and file URI
+ JsonObject myObj = new JsonObject();
+ myObj.addProperty("success", false);
+ myObj.addProperty("latestVersionCode", 2);
+ myObj.addProperty("latestVersion", "1.0.0");
+ myObj.addProperty("changelog", "");
+ myObj.addProperty("appURI", "");
+ out.println(myObj.toString());
+ out.close();
+
+ }
+
+}
diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java
index e9095020d..515e57c85 100644
--- a/src/main/java/eu/siacs/conversations/services/NotificationService.java
+++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java
@@ -60,12 +60,12 @@ public class NotificationService {
public boolean notify(final Message message) {
return (message.getStatus() == Message.STATUS_RECEIVED)
- && notificationsEnabled()
- && !message.getConversation().isMuted()
- && (message.getConversation().isPnNA()
- || conferenceNotificationsEnabled()
- || wasHighlightedOrPrivate(message)
- );
+ && notificationsEnabled()
+ && !message.getConversation().isMuted()
+ && (message.getConversation().isPnNA()
+ || conferenceNotificationsEnabled()
+ || wasHighlightedOrPrivate(message)
+ );
}
public void notifyPebble(final Message message) {
@@ -179,7 +179,7 @@ public class NotificationService {
private void updateNotification(final boolean notify) {
final NotificationManager notificationManager = (NotificationManager) mXmppConnectionService
- .getSystemService(Context.NOTIFICATION_SERVICE);
+ .getSystemService(Context.NOTIFICATION_SERVICE);
final SharedPreferences preferences = mXmppConnectionService.getPreferences();
final String ringtone = preferences.getString("notification_ringtone", null);
@@ -235,7 +235,7 @@ public class NotificationService {
conversation = messages.get(0).getConversation();
final String name = conversation.getName();
style.addLine(Html.fromHtml("<b>" + name + "</b> "
- + UIHelper.getMessagePreview(mXmppConnectionService,messages.get(0)).first));
+ + UIHelper.getMessagePreview(mXmppConnectionService,messages.get(0)).first));
names.append(name);
names.append(", ");
}
@@ -275,9 +275,9 @@ public class NotificationService {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ?
R.drawable.ic_file_download_white_24dp : R.drawable.ic_action_download,
mXmppConnectionService.getResources().getString(R.string.download_x_file,
- UIHelper.getFileDescriptionString(mXmppConnectionService, message)),
+ UIHelper.getFileDescriptionString(mXmppConnectionService, message)),
createDownloadIntent(message)
- );
+ );
}
if ((message = getFirstLocationMessage(messages)) != null) {
mBuilder.addAction(R.drawable.ic_room_white_24dp,
@@ -290,16 +290,16 @@ public class NotificationService {
}
private void modifyForImage(final Builder builder, final Message message,
- final ArrayList<Message> messages, final boolean notify) {
+ final ArrayList<Message> messages, final boolean notify) {
try {
final Bitmap bitmap = mXmppConnectionService.getFileBackend()
- .getThumbnail(message, getPixel(288), false);
+ .getThumbnail(message, getPixel(200), false);
final ArrayList<Message> tmp = new ArrayList<>();
for (final Message msg : messages) {
if (msg.getType() == Message.TYPE_TEXT
&& msg.getTransferable() == null) {
tmp.add(msg);
- }
+ }
}
final BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle();
bigPictureStyle.bigPicture(bitmap);
@@ -318,7 +318,7 @@ public class NotificationService {
}
private void modifyForTextOnly(final Builder builder,
- final ArrayList<Message> messages, final boolean notify) {
+ final ArrayList<Message> messages, final boolean notify) {
builder.setStyle(new NotificationCompat.BigTextStyle().bigText(getMergedBodies(messages)));
builder.setContentText(UIHelper.getMessagePreview(mXmppConnectionService,messages.get(0)).first);
if (notify) {
@@ -333,7 +333,7 @@ public class NotificationService {
&& message.getEncryption() != Message.ENCRYPTION_PGP
&& message.getFileParams().height > 0) {
return message;
- }
+ }
}
return null;
}
@@ -380,7 +380,7 @@ public class NotificationService {
private PendingIntent createContentIntent(final String conversationUuid, final String downloadMessageUuid) {
final TaskStackBuilder stackBuilder = TaskStackBuilder
- .create(mXmppConnectionService);
+ .create(mXmppConnectionService);
stackBuilder.addParentStack(ConversationActivity.class);
final Intent viewConversationIntent = new Intent(mXmppConnectionService,
@@ -468,7 +468,7 @@ public class NotificationService {
private int getPixel(final int dp) {
final DisplayMetrics metrics = mXmppConnectionService.getResources()
- .getDisplayMetrics();
+ .getDisplayMetrics();
return ((int) (dp * metrics.density));
}
@@ -478,7 +478,7 @@ public class NotificationService {
private boolean inMiniGracePeriod(final Account account) {
final int miniGrace = account.getStatus() == Account.State.ONLINE ? Config.MINI_GRACE_PERIOD
- : Config.MINI_GRACE_PERIOD * 2;
+ : Config.MINI_GRACE_PERIOD * 2;
return SystemClock.elapsedRealtime() < (this.mLastNotification + miniGrace);
}
diff --git a/src/main/java/eu/siacs/conversations/services/UpdaterWebService.java b/src/main/java/eu/siacs/conversations/services/UpdaterWebService.java
new file mode 100644
index 000000000..3ff6641aa
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/services/UpdaterWebService.java
@@ -0,0 +1,102 @@
+package eu.siacs.conversations.services;
+
+import android.app.IntentService;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.StatusLine;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.conn.params.ConnManagerParams;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.ui.UpdaterActivity.UpdateReceiver;
+
+public class UpdaterWebService extends IntentService{
+ public static final String REQUEST_STRING = "";
+ public static final String RESPONSE_MESSAGE = "";
+
+ private String URL = null;
+ public static final int REGISTRATION_TIMEOUT = 3 * 1000;
+ public static final int WAIT_TIMEOUT = 30 * 1000;
+
+ public UpdaterWebService() {
+ super("UpdaterWebService");
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+
+ String requestString = intent.getStringExtra(REQUEST_STRING);
+ Log.d(Config.LOGTAG, "AppUpdater: " + requestString);
+ String responseMessage;
+ PackageInfo pInfo = null;
+ try {
+ pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
+ }
+ catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ //get the app version Name for display
+ final String versionName = pInfo.versionName;
+
+ try {
+
+ URL = requestString;
+ HttpClient httpclient = new DefaultHttpClient();
+ HttpParams params = httpclient.getParams();
+
+ HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT);
+ HttpConnectionParams.setSoTimeout(params, WAIT_TIMEOUT);
+ ConnManagerParams.setTimeout(params, WAIT_TIMEOUT);
+
+ HttpGet httpGet = new HttpGet(URL);
+ httpGet.setHeader("User-Agent", getString(R.string.app_name) + " " + versionName);
+ HttpResponse response = httpclient.execute(httpGet);
+
+ StatusLine statusLine = response.getStatusLine();
+ Log.d(Config.LOGTAG, "AppUpdater: HTTP Status Code: " + statusLine.getStatusCode());
+ if(statusLine.getStatusCode() == HttpStatus.SC_OK){
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ response.getEntity().writeTo(out);
+ out.close();
+ responseMessage = out.toString();
+ } else {
+ Log.e(Config.LOGTAG, "AppUpdater: HTTP1:" + statusLine.getReasonPhrase());
+ response.getEntity().getContent().close();
+ throw new IOException(statusLine.getReasonPhrase());
+ }
+
+ } catch (ClientProtocolException e) {
+ Log.e(Config.LOGTAG, "AppUpdater: HTTP2:" + e);
+ responseMessage = "";
+ } catch (IOException e) {
+ Log.e(Config.LOGTAG, "AppUpdater: HTTP3:" + e);
+ responseMessage = "";
+ }catch (Exception e) {
+ Log.e(Config.LOGTAG, "AppUpdater: HTTP4:" + e);
+ responseMessage = "";
+ }
+
+
+ Intent broadcastIntent = new Intent();
+ broadcastIntent.setAction(UpdateReceiver.PROCESS_RESPONSE);
+ broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
+ broadcastIntent.putExtra(RESPONSE_MESSAGE, responseMessage);
+ sendBroadcast(broadcastIntent);
+
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
index 42ce5349a..0dfeea985 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
@@ -528,11 +528,11 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
Bitmap bm;
Contact contact = user.getContact();
if (contact != null) {
- bm = avatarService().get(contact, getPixel(48));
+ bm = avatarService().get(contact, getPixel(56));
tvDisplayName.setText(contact.getDisplayName());
tvStatus.setText(user.getName() + " \u2022 " + getStatus(user));
} else {
- bm = avatarService().get(user.getName(), getPixel(48));
+ bm = avatarService().get(user.getName(), getPixel(56));
tvDisplayName.setText(user.getName());
tvStatus.setText(getStatus(user));
diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
index 10bdaab16..aff50502c 100644
--- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -367,7 +367,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
account = contact.getAccount().getJid().toBareJid().toString();
}
accountJidTv.setText(getString(R.string.using_account, account));
- badge.setImageBitmap(avatarService().get(contact, getPixel(72)));
+ badge.setImageBitmap(avatarService().get(contact, getPixel(Config.AVATAR_SIZE)));
badge.setOnClickListener(this.onBadgeClick);
keys.removeAllViews();
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
index 8bd512144..0211ffd5d 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
@@ -6,10 +6,12 @@ import android.app.AlertDialog;
import android.app.FragmentTransaction;
import android.app.PendingIntent;
import android.content.ClipData;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
+import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -47,1420 +49,1473 @@ import eu.siacs.conversations.entities.Blockable;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.entities.Presences;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.utils.ExceptionHelper;
+import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
+import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
public class ConversationActivity extends XmppActivity
- implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, XmppConnectionService.OnShowErrorToast {
-
- public static final String ACTION_DOWNLOAD = "eu.siacs.conversations.action.DOWNLOAD";
-
- public static final String VIEW_CONVERSATION = "viewConversation";
- public static final String CONVERSATION = "conversationUuid";
- public static final String MESSAGE = "messageUuid";
- public static final String TEXT = "text";
- public static final String NICK = "nick";
- public static final String PRIVATE_MESSAGE = "pm";
-
- public static final int REQUEST_SEND_MESSAGE = 0x0201;
- public static final int REQUEST_DECRYPT_PGP = 0x0202;
- public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207;
- public static final int REQUEST_TRUST_KEYS_TEXT = 0x0208;
- public static final int REQUEST_TRUST_KEYS_MENU = 0x0209;
- public static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301;
- public static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302;
- public static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303;
- public static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0304;
- public static final int ATTACHMENT_CHOICE_LOCATION = 0x0305;
- public static final int ATTACHMENT_CHOICE_INVALID = 0x0306;
- private static final String STATE_OPEN_CONVERSATION = "state_open_conversation";
- private static final String STATE_PANEL_OPEN = "state_panel_open";
- private static final String STATE_PENDING_URI = "state_pending_uri";
-
- private String mOpenConverstaion = null;
- private boolean mPanelOpen = true;
- final private List<Uri> mPendingImageUris = new ArrayList<>();
- final private List<Uri> mPendingFileUris = new ArrayList<>();
- private Uri mPendingGeoUri = null;
- private boolean forbidProcessingPendings = false;
-
- private boolean conversationWasSelectedByKeyboard = false;
-
- private View mContentView;
-
- private List<Conversation> conversationList = new ArrayList<>();
- private Conversation swipedConversation = null;
- private Conversation mSelectedConversation = null;
- private EnhancedListView listView;
- private ConversationFragment mConversationFragment;
-
- private ArrayAdapter<Conversation> listAdapter;
-
- private Toast prepareFileToast;
-
- private boolean mActivityPaused = false;
- private AtomicBoolean mRedirected = new AtomicBoolean(false);
-
- public Conversation getSelectedConversation() {
- return this.mSelectedConversation;
- }
-
- public void setSelectedConversation(Conversation conversation) {
- this.mSelectedConversation = conversation;
- }
-
- public void showConversationsOverview() {
- if (mContentView instanceof SlidingPaneLayout) {
- SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
- mSlidingPaneLayout.openPane();
- }
- }
-
- @Override
- protected String getShareableUri() {
- Conversation conversation = getSelectedConversation();
- if (conversation != null) {
- return conversation.getAccount().getShareableUri();
- } else {
- return "";
- }
- }
-
- public void hideConversationsOverview() {
- if (mContentView instanceof SlidingPaneLayout) {
- SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
- mSlidingPaneLayout.closePane();
- }
- }
-
- public boolean isConversationsOverviewHideable() {
- if (mContentView instanceof SlidingPaneLayout) {
- SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
- return mSlidingPaneLayout.isSlideable();
- } else {
- return false;
- }
- }
-
- public boolean isConversationsOverviewVisable() {
- if (mContentView instanceof SlidingPaneLayout) {
- SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
- return mSlidingPaneLayout.isOpen();
- } else {
- return true;
- }
- }
-
- @Override
- protected void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (savedInstanceState != null) {
- mOpenConverstaion = savedInstanceState.getString(STATE_OPEN_CONVERSATION, null);
- mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true);
- String pending = savedInstanceState.getString(STATE_PENDING_URI, null);
- if (pending != null) {
- mPendingImageUris.clear();
- mPendingImageUris.add(Uri.parse(pending));
- }
- }
-
- setContentView(R.layout.fragment_conversations_overview);
-
- this.mConversationFragment = new ConversationFragment();
- FragmentTransaction transaction = getFragmentManager().beginTransaction();
- transaction.replace(R.id.selected_conversation, this.mConversationFragment, "conversation");
- transaction.commit();
-
- listView = (EnhancedListView) findViewById(R.id.list);
- this.listAdapter = new ConversationAdapter(this, conversationList);
- listView.setAdapter(this.listAdapter);
-
- if (getActionBar() != null) {
- getActionBar().setDisplayHomeAsUpEnabled(false);
- getActionBar().setHomeButtonEnabled(false);
- }
-
- listView.setOnItemClickListener(new OnItemClickListener() {
-
- @Override
- public void onItemClick(AdapterView<?> arg0, View clickedView,
- int position, long arg3) {
- if (getSelectedConversation() != conversationList.get(position)) {
- setSelectedConversation(conversationList.get(position));
- ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation());
- conversationWasSelectedByKeyboard = false;
- }
- hideConversationsOverview();
- openConversation();
- }
- });
-
- listView.setDismissCallback(new EnhancedListView.OnDismissCallback() {
-
- @Override
- public EnhancedListView.Undoable onDismiss(final EnhancedListView enhancedListView, final int position) {
-
- final int index = listView.getFirstVisiblePosition();
- View v = listView.getChildAt(0);
- final int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop());
-
- try {
- swipedConversation = listAdapter.getItem(position);
- } catch (IndexOutOfBoundsException e) {
- return null;
- }
- listAdapter.remove(swipedConversation);
- xmppConnectionService.markRead(swipedConversation);
-
- final boolean formerlySelected = (getSelectedConversation() == swipedConversation);
- if (position == 0 && listAdapter.getCount() == 0) {
- endConversation(swipedConversation, false, true);
- return null;
- } else if (formerlySelected) {
- setSelectedConversation(listAdapter.getItem(0));
- ConversationActivity.this.mConversationFragment
- .reInit(getSelectedConversation());
- }
-
- return new EnhancedListView.Undoable() {
-
- @Override
- public void undo() {
- listAdapter.insert(swipedConversation, position);
- if (formerlySelected) {
- setSelectedConversation(swipedConversation);
- ConversationActivity.this.mConversationFragment
- .reInit(getSelectedConversation());
- }
- swipedConversation = null;
- listView.setSelectionFromTop(index + (listView.getChildCount() < position ? 1 : 0), top);
- }
-
- @Override
- public void discard() {
- if (!swipedConversation.isRead()
- && swipedConversation.getMode() == Conversation.MODE_SINGLE) {
- swipedConversation = null;
- return;
- }
- endConversation(swipedConversation, false, false);
- swipedConversation = null;
- }
-
- @Override
- public String getTitle() {
- if (swipedConversation.getMode() == Conversation.MODE_MULTI) {
- return getResources().getString(R.string.title_undo_swipe_out_muc);
- } else {
- return getResources().getString(R.string.title_undo_swipe_out_conversation);
- }
- }
- };
- }
- });
- listView.enableSwipeToDismiss();
- listView.setSwipingLayout(R.id.swipeable_item);
- listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP);
- listView.setUndoHideDelay(5000);
- listView.setRequireTouchBeforeDismiss(false);
-
- mContentView = findViewById(R.id.content_view_spl);
- if (mContentView == null) {
- mContentView = findViewById(R.id.content_view_ll);
- }
- if (mContentView instanceof SlidingPaneLayout) {
- SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
- mSlidingPaneLayout.setParallaxDistance(150);
- mSlidingPaneLayout
- .setShadowResource(R.drawable.es_slidingpane_shadow);
- mSlidingPaneLayout.setSliderFadeColor(0);
- mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() {
-
- @Override
- public void onPanelOpened(View arg0) {
- updateActionBarTitle();
- invalidateOptionsMenu();
- hideKeyboard();
- if (xmppConnectionServiceBound) {
- xmppConnectionService.getNotificationService()
- .setOpenConversation(null);
- }
- closeContextMenu();
- }
-
- @Override
- public void onPanelClosed(View arg0) {
- listView.discardUndo();
- openConversation();
- }
-
- @Override
- public void onPanelSlide(View arg0, float arg1) {
- // TODO Auto-generated method stub
-
- }
- });
- }
- }
-
- @Override
- public void switchToConversation(Conversation conversation) {
- setSelectedConversation(conversation);
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation());
- openConversation();
- }
- });
- }
-
- private void updateActionBarTitle() {
- updateActionBarTitle(isConversationsOverviewHideable() && !isConversationsOverviewVisable());
- }
-
- private void updateActionBarTitle(boolean titleShouldBeName) {
- final ActionBar ab = getActionBar();
- final Conversation conversation = getSelectedConversation();
- if (ab != null) {
- if (titleShouldBeName && conversation != null) {
- ab.setDisplayHomeAsUpEnabled(true);
- ab.setHomeButtonEnabled(true);
- if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) {
- ab.setTitle(conversation.getName());
- } else {
- ab.setTitle(conversation.getJid().toBareJid().toString());
- }
- } else {
- ab.setDisplayHomeAsUpEnabled(false);
- ab.setHomeButtonEnabled(false);
- ab.setTitle(R.string.app_name);
- }
- }
- }
-
- private void openConversation() {
- this.updateActionBarTitle();
- this.invalidateOptionsMenu();
- if (xmppConnectionServiceBound) {
- final Conversation conversation = getSelectedConversation();
- xmppConnectionService.getNotificationService().setOpenConversation(conversation);
- sendReadMarkerIfNecessary(conversation);
- }
- listAdapter.notifyDataSetChanged();
- }
-
- public void sendReadMarkerIfNecessary(final Conversation conversation) {
- if (!mActivityPaused && conversation != null) {
- if (!conversation.isRead()) {
- xmppConnectionService.sendReadMarker(conversation);
- } else {
- xmppConnectionService.markRead(conversation);
- }
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.conversations, menu);
- final MenuItem menuSecure = menu.findItem(R.id.action_security);
- final MenuItem menuArchive = menu.findItem(R.id.action_archive);
- final MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details);
- final MenuItem menuContactDetails = menu.findItem(R.id.action_contact_details);
- final MenuItem menuAttach = menu.findItem(R.id.action_attach_file);
- final MenuItem menuClearHistory = menu.findItem(R.id.action_clear_history);
- final MenuItem menuAdd = menu.findItem(R.id.action_add);
- final MenuItem menuInviteContact = menu.findItem(R.id.action_invite);
- final MenuItem menuMute = menu.findItem(R.id.action_mute);
- final MenuItem menuUnmute = menu.findItem(R.id.action_unmute);
-
- if (isConversationsOverviewVisable() && isConversationsOverviewHideable()) {
- menuArchive.setVisible(false);
- menuMucDetails.setVisible(false);
- menuContactDetails.setVisible(false);
- menuSecure.setVisible(false);
- menuInviteContact.setVisible(false);
- menuAttach.setVisible(false);
- menuClearHistory.setVisible(false);
- menuMute.setVisible(false);
- menuUnmute.setVisible(false);
- } else {
- menuAdd.setVisible(!isConversationsOverviewHideable());
- if (this.getSelectedConversation() != null) {
- if (this.getSelectedConversation().getNextEncryption() != Message.ENCRYPTION_NONE) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- menuSecure.setIcon(R.drawable.ic_lock_white_24dp);
- } else {
- menuSecure.setIcon(R.drawable.ic_action_secure);
- }
- }
- if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) {
- menuContactDetails.setVisible(false);
- menuAttach.setVisible(getSelectedConversation().getAccount().httpUploadAvailable() && getSelectedConversation().getMucOptions().participating());
- menuInviteContact.setVisible(getSelectedConversation().getMucOptions().canInvite());
- menuSecure.setVisible(!Config.HIDE_PGP_IN_UI); //if pgp is hidden conferences have no choice of encryption
- } else {
- menuMucDetails.setVisible(false);
- }
- if (this.getSelectedConversation().isMuted()) {
- menuMute.setVisible(false);
- } else {
- menuUnmute.setVisible(false);
- }
- }
- }
- return true;
- }
-
- protected void selectPresenceToAttachFile(final int attachmentChoice, final int encryption) {
- final Conversation conversation = getSelectedConversation();
- final Account account = conversation.getAccount();
- final OnPresenceSelected callback = new OnPresenceSelected() {
-
- @Override
- public void onPresenceSelected() {
- Intent intent = new Intent();
- boolean chooser = false;
- String fallbackPackageId = null;
- switch (attachmentChoice) {
- case ATTACHMENT_CHOICE_CHOOSE_IMAGE:
- intent.setAction(Intent.ACTION_GET_CONTENT);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true);
- }
- intent.setType("image/*");
- chooser = true;
- break;
- case ATTACHMENT_CHOICE_TAKE_PHOTO:
- Uri uri = xmppConnectionService.getFileBackend().getTakePhotoUri();
- intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
- intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
- mPendingImageUris.clear();
- mPendingImageUris.add(uri);
- break;
- case ATTACHMENT_CHOICE_CHOOSE_FILE:
- chooser = true;
- intent.setType("*/*");
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setAction(Intent.ACTION_GET_CONTENT);
- break;
- case ATTACHMENT_CHOICE_RECORD_VOICE:
- intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
- fallbackPackageId = "eu.siacs.conversations.voicerecorder";
- break;
- case ATTACHMENT_CHOICE_LOCATION:
- intent.setAction("eu.siacs.conversations.location.request");
- fallbackPackageId = "eu.siacs.conversations.sharelocation";
- break;
- }
- if (intent.resolveActivity(getPackageManager()) != null) {
- if (chooser) {
- startActivityForResult(
- Intent.createChooser(intent, getString(R.string.perform_action_with)),
- attachmentChoice);
- } else {
- startActivityForResult(intent, attachmentChoice);
- }
- } else if (fallbackPackageId != null) {
- startActivity(getInstallApkIntent(fallbackPackageId));
- }
- }
- };
- if ((account.httpUploadAvailable() || attachmentChoice == ATTACHMENT_CHOICE_LOCATION) && encryption != Message.ENCRYPTION_OTR) {
- conversation.setNextCounterpart(null);
- callback.onPresenceSelected();
- } else {
- selectPresence(conversation, callback);
- }
- }
-
- private Intent getInstallApkIntent(final String packageId) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse("market://details?id=" + packageId));
- if (intent.resolveActivity(getPackageManager()) != null) {
- return intent;
- } else {
- intent.setData(Uri.parse("http://play.google.com/store/apps/details?id=" + packageId));
- return intent;
- }
- }
-
- public void attachFile(final int attachmentChoice) {
- switch (attachmentChoice) {
- case ATTACHMENT_CHOICE_LOCATION:
- getPreferences().edit().putString("recently_used_quick_action","location").apply();
- break;
- case ATTACHMENT_CHOICE_RECORD_VOICE:
- getPreferences().edit().putString("recently_used_quick_action","voice").apply();
- break;
- case ATTACHMENT_CHOICE_TAKE_PHOTO:
- getPreferences().edit().putString("recently_used_quick_action","photo").apply();
- break;
- case ATTACHMENT_CHOICE_CHOOSE_IMAGE:
- getPreferences().edit().putString("recently_used_quick_action","picture").apply();
- break;
- }
- final Conversation conversation = getSelectedConversation();
- final int encryption = conversation.getNextEncryption();
- if (encryption == Message.ENCRYPTION_PGP) {
- if (hasPgp()) {
- if (conversation.getContact().getPgpKeyId() != 0) {
- xmppConnectionService.getPgpEngine().hasKey(
- conversation.getContact(),
- new UiCallback<Contact>() {
-
- @Override
- public void userInputRequried(PendingIntent pi,
- Contact contact) {
- ConversationActivity.this.runIntent(pi,attachmentChoice);
- }
-
- @Override
- public void success(Contact contact) {
- selectPresenceToAttachFile(attachmentChoice,encryption);
- }
-
- @Override
- public void error(int error, Contact contact) {
- displayErrorDialog(error);
- }
- });
- } else {
- final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
- .findFragmentByTag("conversation");
- if (fragment != null) {
- fragment.showNoPGPKeyDialog(false,
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- conversation
- .setNextEncryption(Message.ENCRYPTION_NONE);
- xmppConnectionService.databaseBackend
- .updateConversation(conversation);
- selectPresenceToAttachFile(attachmentChoice,Message.ENCRYPTION_NONE);
- }
- });
- }
- }
- } else {
- showInstallPgpDialog();
- }
- } else {
- if (encryption != Message.ENCRYPTION_AXOLOTL || !trustKeysIfNeeded(REQUEST_TRUST_KEYS_MENU, attachmentChoice)) {
- selectPresenceToAttachFile(attachmentChoice, encryption);
- }
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(final MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- showConversationsOverview();
- return true;
- } else if (item.getItemId() == R.id.action_add) {
- startActivity(new Intent(this, StartConversationActivity.class));
- return true;
- } else if (getSelectedConversation() != null) {
- switch (item.getItemId()) {
- case R.id.action_attach_file:
- attachFileDialog();
- break;
- case R.id.action_archive:
- this.endConversation(getSelectedConversation());
- break;
- case R.id.action_contact_details:
- switchToContactDetails(getSelectedConversation().getContact());
- break;
- case R.id.action_muc_details:
- Intent intent = new Intent(this,
- ConferenceDetailsActivity.class);
- intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
- intent.putExtra("uuid", getSelectedConversation().getUuid());
- startActivity(intent);
- break;
- case R.id.action_invite:
- inviteToConversation(getSelectedConversation());
- break;
- case R.id.action_security:
- selectEncryptionDialog(getSelectedConversation());
- break;
- case R.id.action_clear_history:
- clearHistoryDialog(getSelectedConversation());
- break;
- case R.id.action_mute:
- muteConversationDialog(getSelectedConversation());
- break;
- case R.id.action_unmute:
- unmuteConversation(getSelectedConversation());
- break;
- case R.id.action_block:
- BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation());
- break;
- case R.id.action_unblock:
- BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation());
- break;
- default:
- break;
- }
- return super.onOptionsItemSelected(item);
- } else {
- return super.onOptionsItemSelected(item);
- }
- }
-
- public void endConversation(Conversation conversation) {
- endConversation(conversation, true, true);
- }
-
- public void endConversation(Conversation conversation, boolean showOverview, boolean reinit) {
- if (showOverview) {
- showConversationsOverview();
- }
- xmppConnectionService.archiveConversation(conversation);
- if (reinit) {
- if (conversationList.size() > 0) {
- setSelectedConversation(conversationList.get(0));
- this.mConversationFragment.reInit(getSelectedConversation());
- } else {
- setSelectedConversation(null);
- if (mRedirected.compareAndSet(false,true)) {
- Intent intent = new Intent(this, StartConversationActivity.class);
- intent.putExtra("init",true);
- startActivity(intent);
- finish();
- }
- }
- }
- }
-
- @SuppressLint("InflateParams")
- protected void clearHistoryDialog(final Conversation conversation) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(getString(R.string.clear_conversation_history));
- View dialogView = getLayoutInflater().inflate(
- R.layout.dialog_clear_history, null);
- final CheckBox endConversationCheckBox = (CheckBox) dialogView
- .findViewById(R.id.end_conversation_checkbox);
- builder.setView(dialogView);
- builder.setNegativeButton(getString(R.string.cancel), null);
- builder.setPositiveButton(getString(R.string.delete_messages),
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- ConversationActivity.this.xmppConnectionService.clearConversationHistory(conversation);
- if (endConversationCheckBox.isChecked()) {
- endConversation(conversation);
- } else {
- updateConversationList();
- ConversationActivity.this.mConversationFragment.updateMessages();
- }
- }
- });
- builder.create().show();
- }
-
- protected void attachFileDialog() {
- View menuAttachFile = findViewById(R.id.action_attach_file);
- if (menuAttachFile == null) {
- return;
- }
- PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile);
- attachFilePopup.inflate(R.menu.attachment_choices);
- if (new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION).resolveActivity(getPackageManager()) == null) {
- attachFilePopup.getMenu().findItem(R.id.attach_record_voice).setVisible(false);
- }
- if (new Intent("eu.siacs.conversations.location.request").resolveActivity(getPackageManager()) == null) {
- attachFilePopup.getMenu().findItem(R.id.attach_location).setVisible(false);
- }
- attachFilePopup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
-
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.attach_choose_picture:
- attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE);
- break;
- case R.id.attach_take_picture:
- attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO);
- break;
- case R.id.attach_choose_file:
- attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE);
- break;
- case R.id.attach_record_voice:
- attachFile(ATTACHMENT_CHOICE_RECORD_VOICE);
- break;
- case R.id.attach_location:
- attachFile(ATTACHMENT_CHOICE_LOCATION);
- break;
- }
- return false;
- }
- });
- attachFilePopup.show();
- }
-
- public void verifyOtrSessionDialog(final Conversation conversation, View view) {
- if (!conversation.hasValidOtrSession() || conversation.getOtrSession().getSessionStatus() != SessionStatus.ENCRYPTED) {
- Toast.makeText(this, R.string.otr_session_not_started, Toast.LENGTH_LONG).show();
- return;
- }
- if (view == null) {
- return;
- }
- PopupMenu popup = new PopupMenu(this, view);
- popup.inflate(R.menu.verification_choices);
- popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem menuItem) {
- Intent intent = new Intent(ConversationActivity.this, VerifyOTRActivity.class);
- intent.setAction(VerifyOTRActivity.ACTION_VERIFY_CONTACT);
- intent.putExtra("contact", conversation.getContact().getJid().toBareJid().toString());
- intent.putExtra("account", conversation.getAccount().getJid().toBareJid().toString());
- switch (menuItem.getItemId()) {
- case R.id.scan_fingerprint:
- intent.putExtra("mode", VerifyOTRActivity.MODE_SCAN_FINGERPRINT);
- break;
- case R.id.ask_question:
- intent.putExtra("mode", VerifyOTRActivity.MODE_ASK_QUESTION);
- break;
- case R.id.manual_verification:
- intent.putExtra("mode", VerifyOTRActivity.MODE_MANUAL_VERIFICATION);
- break;
- }
- startActivity(intent);
- return true;
- }
- });
- popup.show();
- }
-
- protected void selectEncryptionDialog(final Conversation conversation) {
- View menuItemView = findViewById(R.id.action_security);
- if (menuItemView == null) {
- return;
- }
- PopupMenu popup = new PopupMenu(this, menuItemView);
- final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
- .findFragmentByTag("conversation");
- if (fragment != null) {
- popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
-
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.encryption_choice_none:
- conversation.setNextEncryption(Message.ENCRYPTION_NONE);
- item.setChecked(true);
- break;
- case R.id.encryption_choice_otr:
- conversation.setNextEncryption(Message.ENCRYPTION_OTR);
- item.setChecked(true);
- break;
- case R.id.encryption_choice_pgp:
- if (hasPgp()) {
- if (conversation.getAccount().getKeys().has("pgp_signature")) {
- conversation.setNextEncryption(Message.ENCRYPTION_PGP);
- item.setChecked(true);
- } else {
- announcePgp(conversation.getAccount(),conversation);
- }
- } else {
- showInstallPgpDialog();
- }
- break;
- case R.id.encryption_choice_axolotl:
- Log.d(Config.LOGTAG, AxolotlService.getLogprefix(conversation.getAccount())
- + "Enabled axolotl for Contact " + conversation.getContact().getJid());
- conversation.setNextEncryption(Message.ENCRYPTION_AXOLOTL);
- item.setChecked(true);
- break;
- default:
- conversation.setNextEncryption(Message.ENCRYPTION_NONE);
- break;
- }
- xmppConnectionService.databaseBackend.updateConversation(conversation);
- fragment.updateChatMsgHint();
- invalidateOptionsMenu();
- refreshUi();
- return true;
- }
- });
- popup.inflate(R.menu.encryption_choices);
- MenuItem otr = popup.getMenu().findItem(R.id.encryption_choice_otr);
- MenuItem none = popup.getMenu().findItem(R.id.encryption_choice_none);
- MenuItem pgp = popup.getMenu().findItem(R.id.encryption_choice_pgp);
- MenuItem axolotl = popup.getMenu().findItem(R.id.encryption_choice_axolotl);
- pgp.setVisible(!Config.HIDE_PGP_IN_UI);
- if (conversation.getMode() == Conversation.MODE_MULTI) {
- otr.setVisible(false);
- axolotl.setVisible(false);
- } else if (!conversation.getAccount().getAxolotlService().isContactAxolotlCapable(conversation.getContact())) {
- axolotl.setEnabled(false);
- }
- switch (conversation.getNextEncryption()) {
- case Message.ENCRYPTION_NONE:
- none.setChecked(true);
- break;
- case Message.ENCRYPTION_OTR:
- otr.setChecked(true);
- break;
- case Message.ENCRYPTION_PGP:
- pgp.setChecked(true);
- break;
- case Message.ENCRYPTION_AXOLOTL:
- axolotl.setChecked(true);
- break;
- default:
- none.setChecked(true);
- break;
- }
- popup.show();
- }
- }
-
- protected void muteConversationDialog(final Conversation conversation) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.disable_notifications);
- final int[] durations = getResources().getIntArray(R.array.mute_options_durations);
- builder.setItems(R.array.mute_options_descriptions,
- new OnClickListener() {
-
- @Override
- public void onClick(final DialogInterface dialog, final int which) {
- final long till;
- if (durations[which] == -1) {
- till = Long.MAX_VALUE;
- } else {
- till = System.currentTimeMillis() + (durations[which] * 1000);
- }
- conversation.setMutedTill(till);
- ConversationActivity.this.xmppConnectionService.databaseBackend
- .updateConversation(conversation);
- updateConversationList();
- ConversationActivity.this.mConversationFragment.updateMessages();
- invalidateOptionsMenu();
- }
- });
- builder.create().show();
- }
-
- public void unmuteConversation(final Conversation conversation) {
- conversation.setMutedTill(0);
- this.xmppConnectionService.databaseBackend.updateConversation(conversation);
- updateConversationList();
- ConversationActivity.this.mConversationFragment.updateMessages();
- invalidateOptionsMenu();
- }
-
- @Override
- public void onBackPressed() {
- if (!isConversationsOverviewVisable()) {
- showConversationsOverview();
- } else {
- moveTaskToBack(true);
- }
- }
-
- @Override
- public boolean onKeyUp(int key, KeyEvent event) {
- int rotation = getWindowManager().getDefaultDisplay().getRotation();
- final int upKey;
- final int downKey;
- switch(rotation) {
- case Surface.ROTATION_90:
- upKey = KeyEvent.KEYCODE_DPAD_LEFT;
- downKey = KeyEvent.KEYCODE_DPAD_RIGHT;
- break;
- case Surface.ROTATION_180:
- upKey = KeyEvent.KEYCODE_DPAD_DOWN;
- downKey = KeyEvent.KEYCODE_DPAD_UP;
- break;
- case Surface.ROTATION_270:
- upKey = KeyEvent.KEYCODE_DPAD_RIGHT;
- downKey = KeyEvent.KEYCODE_DPAD_LEFT;
- break;
- default:
- upKey = KeyEvent.KEYCODE_DPAD_UP;
- downKey = KeyEvent.KEYCODE_DPAD_DOWN;
- }
- final boolean modifier = event.isCtrlPressed() || event.isAltPressed();
- if (modifier && key == KeyEvent.KEYCODE_TAB && isConversationsOverviewHideable()) {
- toggleConversationsOverview();
- return true;
- } else if (modifier && key == downKey) {
- if (isConversationsOverviewHideable() && !isConversationsOverviewVisable()) {
- showConversationsOverview();;
- }
- return selectDownConversation();
- } else if (modifier && key == upKey) {
- if (isConversationsOverviewHideable() && !isConversationsOverviewVisable()) {
- showConversationsOverview();
- }
- return selectUpConversation();
- } else if (modifier && key == KeyEvent.KEYCODE_1) {
- return openConversationByIndex(0);
- } else if (modifier && key == KeyEvent.KEYCODE_2) {
- return openConversationByIndex(1);
- } else if (modifier && key == KeyEvent.KEYCODE_3) {
- return openConversationByIndex(2);
- } else if (modifier && key == KeyEvent.KEYCODE_4) {
- return openConversationByIndex(3);
- } else if (modifier && key == KeyEvent.KEYCODE_5) {
- return openConversationByIndex(4);
- } else if (modifier && key == KeyEvent.KEYCODE_6) {
- return openConversationByIndex(5);
- } else if (modifier && key == KeyEvent.KEYCODE_7) {
- return openConversationByIndex(6);
- } else if (modifier && key == KeyEvent.KEYCODE_8) {
- return openConversationByIndex(7);
- } else if (modifier && key == KeyEvent.KEYCODE_9) {
- return openConversationByIndex(8);
- } else if (modifier && key == KeyEvent.KEYCODE_0) {
- return openConversationByIndex(9);
- } else {
- return super.onKeyUp(key, event);
- }
- }
-
- private void toggleConversationsOverview() {
- if (isConversationsOverviewVisable()) {
- hideConversationsOverview();
- if (mConversationFragment != null) {
- mConversationFragment.setFocusOnInputField();
- }
- } else {
- showConversationsOverview();
- }
- }
-
- private boolean selectUpConversation() {
- if (this.mSelectedConversation != null) {
- int index = this.conversationList.indexOf(this.mSelectedConversation);
- if (index > 0) {
- return openConversationByIndex(index - 1);
- }
- }
- return false;
- }
-
- private boolean selectDownConversation() {
- if (this.mSelectedConversation != null) {
- int index = this.conversationList.indexOf(this.mSelectedConversation);
- if (index != -1 && index < this.conversationList.size() - 1) {
- return openConversationByIndex(index + 1);
- }
- }
- return false;
- }
-
- private boolean openConversationByIndex(int index) {
- try {
- this.conversationWasSelectedByKeyboard = true;
- setSelectedConversation(this.conversationList.get(index));
- this.mConversationFragment.reInit(getSelectedConversation());
- if (index > listView.getLastVisiblePosition() - 1 || index < listView.getFirstVisiblePosition() + 1) {
- this.listView.setSelection(index);
- }
- openConversation();
- return true;
- } catch (IndexOutOfBoundsException e) {
- return false;
- }
- }
-
- @Override
- protected void onNewIntent(final Intent intent) {
- if (xmppConnectionServiceBound) {
- if (intent != null && VIEW_CONVERSATION.equals(intent.getType())) {
- handleViewConversationIntent(intent);
- }
- } else {
- setIntent(intent);
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
- this.mRedirected.set(false);
- if (this.xmppConnectionServiceBound) {
- this.onBackendConnected();
- }
- if (conversationList.size() >= 1) {
- this.onConversationUpdate();
- }
- }
-
- @Override
- public void onPause() {
- listView.discardUndo();
- super.onPause();
- this.mActivityPaused = true;
- if (this.xmppConnectionServiceBound) {
- this.xmppConnectionService.getNotificationService().setIsInForeground(false);
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- final int theme = findTheme();
- final boolean usingEnterKey = usingEnterKey();
- if (this.mTheme != theme || usingEnterKey != mUsingEnterKey) {
- recreate();
- }
- this.mActivityPaused = false;
- if (this.xmppConnectionServiceBound) {
- this.xmppConnectionService.getNotificationService().setIsInForeground(true);
- }
-
- if (!isConversationsOverviewVisable() || !isConversationsOverviewHideable()) {
- sendReadMarkerIfNecessary(getSelectedConversation());
- }
-
- }
-
- @Override
- public void onSaveInstanceState(final Bundle savedInstanceState) {
- Conversation conversation = getSelectedConversation();
- if (conversation != null) {
- savedInstanceState.putString(STATE_OPEN_CONVERSATION,
- conversation.getUuid());
- }
- savedInstanceState.putBoolean(STATE_PANEL_OPEN,
- isConversationsOverviewVisable());
- if (this.mPendingImageUris.size() >= 1) {
- savedInstanceState.putString(STATE_PENDING_URI, this.mPendingImageUris.get(0).toString());
- }
- super.onSaveInstanceState(savedInstanceState);
- }
-
- @Override
- void onBackendConnected() {
- this.xmppConnectionService.getNotificationService().setIsInForeground(true);
- updateConversationList();
-
- if (mPendingConferenceInvite != null) {
- mPendingConferenceInvite.execute(this);
- mPendingConferenceInvite = null;
- }
-
- if (xmppConnectionService.getAccounts().size() == 0) {
- if (mRedirected.compareAndSet(false,true)) {
- if (Config.X509_VERIFICATION) {
- startActivity(new Intent(this, ManageAccountActivity.class));
- } else {
- startActivity(new Intent(this, EditAccountActivity.class));
- }
- finish();
- }
- } else if (conversationList.size() <= 0) {
- if (mRedirected.compareAndSet(false,true)) {
- Intent intent = new Intent(this, StartConversationActivity.class);
- intent.putExtra("init",true);
- startActivity(intent);
- finish();
- }
- } else if (getIntent() != null && VIEW_CONVERSATION.equals(getIntent().getType())) {
- handleViewConversationIntent(getIntent());
- } else if (selectConversationByUuid(mOpenConverstaion)) {
- if (mPanelOpen) {
- showConversationsOverview();
- } else {
- if (isConversationsOverviewHideable()) {
- openConversation();
- }
- }
- this.mConversationFragment.reInit(getSelectedConversation());
- mOpenConverstaion = null;
- } else if (getSelectedConversation() == null) {
- showConversationsOverview();
- mPendingImageUris.clear();
- mPendingFileUris.clear();
- mPendingGeoUri = null;
- setSelectedConversation(conversationList.get(0));
- this.mConversationFragment.reInit(getSelectedConversation());
- } else {
- this.mConversationFragment.messageListAdapter.updatePreferences();
- this.mConversationFragment.messagesView.invalidateViews();
- this.mConversationFragment.setupIme();
- }
-
- if(!forbidProcessingPendings) {
- for (Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
- Uri foo = i.next();
- attachImageToConversation(getSelectedConversation(), foo);
- }
-
- for (Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) {
- attachFileToConversation(getSelectedConversation(), i.next());
- }
-
- if (mPendingGeoUri != null) {
- attachLocationToConversation(getSelectedConversation(), mPendingGeoUri);
- mPendingGeoUri = null;
- }
- }
- forbidProcessingPendings = false;
-
- ExceptionHelper.checkForCrash(this, this.xmppConnectionService);
- setIntent(new Intent());
- }
-
- private void handleViewConversationIntent(final Intent intent) {
- final String uuid = intent.getStringExtra(CONVERSATION);
- final String downloadUuid = intent.getStringExtra(MESSAGE);
- final String text = intent.getStringExtra(TEXT);
- final String nick = intent.getStringExtra(NICK);
- final boolean pm = intent.getBooleanExtra(PRIVATE_MESSAGE,false);
- if (selectConversationByUuid(uuid)) {
- this.mConversationFragment.reInit(getSelectedConversation());
- if (nick != null) {
- if (pm) {
- Jid jid = getSelectedConversation().getJid();
- try {
- Jid next = Jid.fromParts(jid.getLocalpart(),jid.getDomainpart(),nick);
- this.mConversationFragment.privateMessageWith(next);
- } catch (final InvalidJidException ignored) {
- //do nothing
- }
- } else {
- this.mConversationFragment.highlightInConference(nick);
- }
- } else {
- this.mConversationFragment.appendText(text);
- }
- hideConversationsOverview();
- openConversation();
- if (mContentView instanceof SlidingPaneLayout) {
- updateActionBarTitle(true); //fixes bug where slp isn't properly closed yet
- }
- if (downloadUuid != null) {
- final Message message = mSelectedConversation.findMessageWithFileAndUuid(downloadUuid);
- if (message != null) {
- mConversationFragment.messageListAdapter.startDownloadable(message);
- }
- }
- }
- }
-
- private boolean selectConversationByUuid(String uuid) {
- if (uuid == null) {
- return false;
- }
- for (Conversation aConversationList : conversationList) {
- if (aConversationList.getUuid().equals(uuid)) {
- setSelectedConversation(aConversationList);
- return true;
- }
- }
- return false;
- }
-
- @Override
- protected void unregisterListeners() {
- super.unregisterListeners();
- xmppConnectionService.getNotificationService().setOpenConversation(null);
- }
-
- @SuppressLint("NewApi")
- private static List<Uri> extractUriFromIntent(final Intent intent) {
- List<Uri> uris = new ArrayList<>();
- Uri uri = intent.getData();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && uri == null) {
- ClipData clipData = intent.getClipData();
- for(int i = 0; i < clipData.getItemCount(); ++i) {
- uris.add(clipData.getItemAt(i).getUri());
- }
- } else {
- uris.add(uri);
- }
- return uris;
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode,
- final Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (resultCode == RESULT_OK) {
- if (requestCode == REQUEST_DECRYPT_PGP) {
- mConversationFragment.hideSnackbar();
- mConversationFragment.updateMessages();
- } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) {
- mPendingImageUris.clear();
- mPendingImageUris.addAll(extractUriFromIntent(data));
- if (xmppConnectionServiceBound) {
- for(Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
- attachImageToConversation(getSelectedConversation(),i.next());
- }
- }
- } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_FILE || requestCode == ATTACHMENT_CHOICE_RECORD_VOICE) {
- mPendingFileUris.clear();
- mPendingFileUris.addAll(extractUriFromIntent(data));
- if (xmppConnectionServiceBound) {
- for(Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) {
- attachFileToConversation(getSelectedConversation(), i.next());
- }
- }
- } else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) {
- if (mPendingImageUris.size() == 1) {
- Uri uri = mPendingImageUris.get(0);
- if (xmppConnectionServiceBound) {
- attachImageToConversation(getSelectedConversation(), uri);
- mPendingImageUris.clear();
- }
- Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
- intent.setData(uri);
- sendBroadcast(intent);
- } else {
- mPendingImageUris.clear();
- }
- } else if (requestCode == ATTACHMENT_CHOICE_LOCATION) {
- double latitude = data.getDoubleExtra("latitude",0);
- double longitude = data.getDoubleExtra("longitude",0);
- this.mPendingGeoUri = Uri.parse("geo:"+String.valueOf(latitude)+","+String.valueOf(longitude));
- if (xmppConnectionServiceBound) {
- attachLocationToConversation(getSelectedConversation(), mPendingGeoUri);
- this.mPendingGeoUri = null;
- }
- } else if (requestCode == REQUEST_TRUST_KEYS_TEXT || requestCode == REQUEST_TRUST_KEYS_MENU) {
- this.forbidProcessingPendings = !xmppConnectionServiceBound;
- mConversationFragment.onActivityResult(requestCode, resultCode, data);
- }
- } else {
- mPendingImageUris.clear();
- mPendingFileUris.clear();
- }
- }
-
- private void attachLocationToConversation(Conversation conversation, Uri uri) {
- if (conversation == null) {
- return;
- }
- xmppConnectionService.attachLocationToConversation(conversation,uri, new UiCallback<Message>() {
-
- @Override
- public void success(Message message) {
- xmppConnectionService.sendMessage(message);
- }
-
- @Override
- public void error(int errorCode, Message object) {
-
- }
-
- @Override
- public void userInputRequried(PendingIntent pi, Message object) {
-
- }
- });
- }
-
- private void attachFileToConversation(Conversation conversation, Uri uri) {
- if (conversation == null) {
- return;
- }
- prepareFileToast = Toast.makeText(getApplicationContext(),getText(R.string.preparing_file), Toast.LENGTH_LONG);
- prepareFileToast.show();
- xmppConnectionService.attachFileToConversation(conversation, uri, new UiCallback<Message>() {
- @Override
- public void success(Message message) {
- hidePrepareFileToast();
- xmppConnectionService.sendMessage(message);
- }
-
- @Override
- public void error(int errorCode, Message message) {
- displayErrorDialog(errorCode);
- }
-
- @Override
- public void userInputRequried(PendingIntent pi, Message message) {
-
- }
- });
- }
-
- private void attachImageToConversation(Conversation conversation, Uri uri) {
- if (conversation == null) {
- return;
- }
- prepareFileToast = Toast.makeText(getApplicationContext(),getText(R.string.preparing_image), Toast.LENGTH_LONG);
- prepareFileToast.show();
- xmppConnectionService.attachImageToConversation(conversation, uri,
- new UiCallback<Message>() {
-
- @Override
- public void userInputRequried(PendingIntent pi,
- Message object) {
- hidePrepareFileToast();
- }
-
- @Override
- public void success(Message message) {
- xmppConnectionService.sendMessage(message);
- }
-
- @Override
- public void error(int error, Message message) {
- hidePrepareFileToast();
- displayErrorDialog(error);
- }
- });
- }
-
- private void hidePrepareFileToast() {
- if (prepareFileToast != null) {
- runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
- prepareFileToast.cancel();
- }
- });
- }
- }
-
- public void updateConversationList() {
- xmppConnectionService
- .populateWithOrderedConversations(conversationList);
- if (swipedConversation != null) {
- if (swipedConversation.isRead()) {
- conversationList.remove(swipedConversation);
- } else {
- listView.discardUndo();
- }
- }
- listAdapter.notifyDataSetChanged();
- }
-
- public void runIntent(PendingIntent pi, int requestCode) {
- try {
- this.startIntentSenderForResult(pi.getIntentSender(), requestCode,
- null, 0, 0, 0);
- } catch (final SendIntentException ignored) {
- }
- }
-
- public void encryptTextMessage(Message message) {
- xmppConnectionService.getPgpEngine().encrypt(message,
- new UiCallback<Message>() {
-
- @Override
- public void userInputRequried(PendingIntent pi,
- Message message) {
- ConversationActivity.this.runIntent(pi,
- ConversationActivity.REQUEST_SEND_MESSAGE);
- }
-
- @Override
- public void success(Message message) {
- message.setEncryption(Message.ENCRYPTION_DECRYPTED);
- xmppConnectionService.sendMessage(message);
- }
-
- @Override
- public void error(int error, Message message) {
-
- }
- });
- }
-
- public boolean useSendButtonToIndicateStatus() {
- return getPreferences().getBoolean("send_button_status", false);
- }
-
- public boolean indicateReceived() {
- return getPreferences().getBoolean("indicate_received", false);
- }
-
- public boolean useWhiteBackground() {
- return getPreferences().getBoolean("use_white_background",false);
- }
-
- protected boolean trustKeysIfNeeded(int requestCode) {
- return trustKeysIfNeeded(requestCode, ATTACHMENT_CHOICE_INVALID);
- }
-
- protected boolean trustKeysIfNeeded(int requestCode, int attachmentChoice) {
- AxolotlService axolotlService = mSelectedConversation.getAccount().getAxolotlService();
- boolean hasPendingKeys = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED,
- mSelectedConversation.getContact()).isEmpty()
- || !axolotlService.findDevicesWithoutSession(mSelectedConversation).isEmpty();
- boolean hasNoTrustedKeys = axolotlService.getNumTrustedKeys(mSelectedConversation.getContact()) == 0;
- if( hasPendingKeys || hasNoTrustedKeys) {
- axolotlService.createSessionsIfNeeded(mSelectedConversation);
- Intent intent = new Intent(getApplicationContext(), TrustKeysActivity.class);
- intent.putExtra("contact", mSelectedConversation.getContact().getJid().toBareJid().toString());
- intent.putExtra("account", mSelectedConversation.getAccount().getJid().toBareJid().toString());
- intent.putExtra("choice", attachmentChoice);
- intent.putExtra("has_no_trusted", hasNoTrustedKeys);
- startActivityForResult(intent, requestCode);
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- protected void refreshUiReal() {
- updateConversationList();
- if (conversationList.size() > 0) {
- ConversationActivity.this.mConversationFragment.updateMessages();
- updateActionBarTitle();
- invalidateOptionsMenu();
- }
- }
-
- @Override
- public void onAccountUpdate() {
- this.refreshUi();
- }
-
- @Override
- public void onConversationUpdate() {
- this.refreshUi();
- }
-
- @Override
- public void onRosterUpdate() {
- this.refreshUi();
- }
-
- @Override
- public void OnUpdateBlocklist(Status status) {
- this.refreshUi();
- }
-
- public void unblockConversation(final Blockable conversation) {
- xmppConnectionService.sendUnblockRequest(conversation);
- }
-
- public boolean enterIsSend() {
- return getPreferences().getBoolean("enter_is_send",false);
- }
-
- @Override
- public void onShowErrorToast(final int resId) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(ConversationActivity.this,resId,Toast.LENGTH_SHORT).show();
- }
- });
- }
-
- public boolean highlightSelectedConversations() {
- return !isConversationsOverviewHideable() || this.conversationWasSelectedByKeyboard;
- }
+ implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, XmppConnectionService.OnShowErrorToast {
+
+ public static final String ACTION_DOWNLOAD = "eu.siacs.conversations.action.DOWNLOAD";
+
+ public static final String VIEW_CONVERSATION = "viewConversation";
+ public static final String CONVERSATION = "conversationUuid";
+ public static final String MESSAGE = "messageUuid";
+ public static final String TEXT = "text";
+ public static final String NICK = "nick";
+ public static final String PRIVATE_MESSAGE = "pm";
+
+ public static final int REQUEST_SEND_MESSAGE = 0x0201;
+ public static final int REQUEST_DECRYPT_PGP = 0x0202;
+ public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207;
+ public static final int REQUEST_TRUST_KEYS_TEXT = 0x0208;
+ public static final int REQUEST_TRUST_KEYS_MENU = 0x0209;
+ public static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301;
+ public static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302;
+ public static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303;
+ public static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0304;
+ public static final int ATTACHMENT_CHOICE_LOCATION = 0x0305;
+ public static final int ATTACHMENT_CHOICE_INVALID = 0x0306;
+ private static final String STATE_OPEN_CONVERSATION = "state_open_conversation";
+ private static final String STATE_PANEL_OPEN = "state_panel_open";
+ private static final String STATE_PENDING_URI = "state_pending_uri";
+
+ private String mOpenConverstaion = null;
+ private boolean mPanelOpen = true;
+ final private List<Uri> mPendingImageUris = new ArrayList<>();
+ final private List<Uri> mPendingFileUris = new ArrayList<>();
+ private Uri mPendingGeoUri = null;
+ private boolean forbidProcessingPendings = false;
+
+ private boolean conversationWasSelectedByKeyboard = false;
+
+ private View mContentView;
+
+ private List<Conversation> conversationList = new ArrayList<>();
+ private Conversation swipedConversation = null;
+ private Conversation mSelectedConversation = null;
+ private EnhancedListView listView;
+ private ConversationFragment mConversationFragment;
+
+ private ArrayAdapter<Conversation> listAdapter;
+
+ private Toast prepareFileToast;
+
+ private boolean mActivityPaused = false;
+ private AtomicBoolean mRedirected = new AtomicBoolean(false);
+
+ public Conversation getSelectedConversation() {
+ return this.mSelectedConversation;
+ }
+
+ public void setSelectedConversation(Conversation conversation) {
+ this.mSelectedConversation = conversation;
+ }
+
+ public void showConversationsOverview() {
+ if (mContentView instanceof SlidingPaneLayout) {
+ SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
+ mSlidingPaneLayout.openPane();
+ }
+ }
+
+ @Override
+ protected String getShareableUri() {
+ Conversation conversation = getSelectedConversation();
+ if (conversation != null) {
+ return conversation.getAccount().getShareableUri();
+ } else {
+ return "";
+ }
+ }
+
+ public void hideConversationsOverview() {
+ if (mContentView instanceof SlidingPaneLayout) {
+ SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
+ mSlidingPaneLayout.closePane();
+ }
+ }
+
+ public boolean isConversationsOverviewHideable() {
+ if (mContentView instanceof SlidingPaneLayout) {
+ SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
+ return mSlidingPaneLayout.isSlideable();
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isConversationsOverviewVisable() {
+ if (mContentView instanceof SlidingPaneLayout) {
+ SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
+ return mSlidingPaneLayout.isOpen();
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (savedInstanceState != null) {
+ mOpenConverstaion = savedInstanceState.getString(STATE_OPEN_CONVERSATION, null);
+ mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true);
+ String pending = savedInstanceState.getString(STATE_PENDING_URI, null);
+ if (pending != null) {
+ mPendingImageUris.clear();
+ mPendingImageUris.add(Uri.parse(pending));
+ }
+ }
+
+ AppUpdate();
+
+ setContentView(R.layout.fragment_conversations_overview);
+
+ this.mConversationFragment = new ConversationFragment();
+ FragmentTransaction transaction = getFragmentManager().beginTransaction();
+ transaction.replace(R.id.selected_conversation, this.mConversationFragment, "conversation");
+ transaction.commit();
+
+ listView = (EnhancedListView) findViewById(R.id.list);
+ this.listAdapter = new ConversationAdapter(this, conversationList);
+ listView.setAdapter(this.listAdapter);
+
+ if (getActionBar() != null) {
+ getActionBar().setDisplayHomeAsUpEnabled(false);
+ getActionBar().setHomeButtonEnabled(false);
+ }
+
+ listView.setOnItemClickListener(new OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View clickedView,
+ int position, long arg3) {
+ if (getSelectedConversation() != conversationList.get(position)) {
+ setSelectedConversation(conversationList.get(position));
+ ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation());
+ conversationWasSelectedByKeyboard = false;
+ }
+ hideConversationsOverview();
+ openConversation();
+ }
+ });
+
+ listView.setDismissCallback(new EnhancedListView.OnDismissCallback() {
+ @Override
+ public EnhancedListView.Undoable onDismiss(final EnhancedListView enhancedListView, final int position) {
+
+ final int index = listView.getFirstVisiblePosition();
+ View v = listView.getChildAt(0);
+ final int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop());
+
+ try {
+ swipedConversation = listAdapter.getItem(position);
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ listAdapter.remove(swipedConversation);
+ xmppConnectionService.markRead(swipedConversation);
+
+ final boolean formerlySelected = (getSelectedConversation() == swipedConversation);
+ if (position == 0 && listAdapter.getCount() == 0) {
+ endConversation(swipedConversation, false, true);
+ return null;
+ } else if (formerlySelected) {
+ setSelectedConversation(listAdapter.getItem(0));
+ ConversationActivity.this.mConversationFragment
+ .reInit(getSelectedConversation());
+ }
+
+ return new EnhancedListView.Undoable() {
+
+ @Override
+ public void undo() {
+ listAdapter.insert(swipedConversation, position);
+ if (formerlySelected) {
+ setSelectedConversation(swipedConversation);
+ ConversationActivity.this.mConversationFragment
+ .reInit(getSelectedConversation());
+ }
+ swipedConversation = null;
+ listView.setSelectionFromTop(index + (listView.getChildCount() < position ? 1 : 0), top);
+ }
+
+ @Override
+ public void discard() {
+ if (!swipedConversation.isRead()
+ && swipedConversation.getMode() == Conversation.MODE_SINGLE) {
+ swipedConversation = null;
+ return;
+ }
+ endConversation(swipedConversation, false, false);
+ swipedConversation = null;
+ }
+
+ @Override
+ public String getTitle() {
+ if (swipedConversation.getMode() == Conversation.MODE_MULTI) {
+ return getResources().getString(R.string.title_undo_swipe_out_muc);
+ } else {
+ return getResources().getString(R.string.title_undo_swipe_out_conversation);
+ }
+ }
+ };
+ }
+ });
+ listView.enableSwipeToDismiss();
+ listView.setSwipingLayout(R.id.swipeable_item);
+ listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP);
+ listView.setUndoHideDelay(10000);
+ listView.setRequireTouchBeforeDismiss(false);
+ listView.setSwipeDirection(EnhancedListView.SwipeDirection.START); // swipe to left to close conversation
+
+ mContentView = findViewById(R.id.content_view_spl);
+ if (mContentView == null) {
+ mContentView = findViewById(R.id.content_view_ll);
+ }
+ if (mContentView instanceof SlidingPaneLayout) {
+ SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
+ mSlidingPaneLayout.setParallaxDistance(150);
+ mSlidingPaneLayout
+ .setShadowResource(R.drawable.es_slidingpane_shadow);
+ mSlidingPaneLayout.setSliderFadeColor(0);
+ mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() {
+
+ @Override
+ public void onPanelOpened(View arg0) {
+ updateActionBarTitle();
+ invalidateOptionsMenu();
+ hideKeyboard();
+ if (xmppConnectionServiceBound) {
+ xmppConnectionService.getNotificationService()
+ .setOpenConversation(null);
+ }
+ closeContextMenu();
+ }
+
+ @Override
+ public void onPanelClosed(View arg0) {
+ listView.discardUndo();
+ openConversation();
+ }
+
+ @Override
+ public void onPanelSlide(View arg0, float arg1) {
+ // TODO Auto-generated method stub
+
+ }
+ });
+ }
+ }
+
+ protected void AppUpdate() {
+ String PREFS_NAME = "UpdateTimeStamp";
+ SharedPreferences UpdateTimeStamp = getApplicationContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+ long lastUpdateTime = UpdateTimeStamp.getLong("lastUpdateTime", 0);
+
+ Log.d(Config.LOGTAG, "AppUpdater - LastUpdateTime: " + lastUpdateTime);
+
+ if ((lastUpdateTime + (Config.UPDATE_CHECK_TIMER * 1000)) < System.currentTimeMillis()) {
+ lastUpdateTime = System.currentTimeMillis();
+ SharedPreferences.Editor editor = UpdateTimeStamp.edit();
+ editor.putLong("lastUpdateTime", lastUpdateTime);
+ editor.commit();
+
+ // run AppUpdater
+ Log.d(Config.LOGTAG, "AppUpdater - CurrentTime: " + lastUpdateTime);
+ Intent AppUpdater = new Intent(this, UpdaterActivity.class);
+ startActivity(AppUpdater);
+ Log.d(Config.LOGTAG, "AppUpdater started");
+
+ } else {
+
+ Log.d(Config.LOGTAG, "AppUpdater stopped");
+ return;
+ }
+ }
+
+ @Override
+ public void switchToConversation(Conversation conversation) {
+ setSelectedConversation(conversation);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation());
+ openConversation();
+ }
+ });
+ }
+
+ private void updateActionBarTitle() {
+ updateActionBarTitle(isConversationsOverviewHideable() && !isConversationsOverviewVisable());
+ }
+
+ private void updateActionBarTitle(boolean titleShouldBeName) {
+ final ActionBar ab = getActionBar();
+ final Conversation conversation = getSelectedConversation();
+ if (ab != null) {
+ if (titleShouldBeName && conversation != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ ab.setHomeButtonEnabled(true);
+ if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) {
+ ab.setTitle(conversation.getName());
+ if (conversation.getMode() == Conversation.MODE_SINGLE) {
+ if (conversation.getContact().getPresences().getMostAvailableStatus() == Presences.OFFLINE) {
+ ab.setSubtitle(getString(R.string.account_status_offline));
+ } else {
+ ChatState state = conversation.getIncomingChatState();
+ if (state == ChatState.COMPOSING) {
+ ab.setSubtitle(getString(R.string.is_typing));
+ } else if (state == ChatState.PAUSED) {
+ ab.setSubtitle(UIHelper.lastseen(getApplicationContext(), conversation.getContact().lastseen.time));
+ } else {
+ ab.setSubtitle(UIHelper.lastseen(getApplicationContext(), conversation.getContact().lastseen.time));
+ }
+ }
+ } else if (useSubjectToIdentifyConference()) {
+ ab.setSubtitle(conversation.getParticipants());
+ }
+ } else {
+ ab.setTitle(conversation.getJid().toBareJid().toString());
+ ab.setSubtitle(null);
+ }
+ } else {
+ ab.setDisplayHomeAsUpEnabled(false);
+ ab.setHomeButtonEnabled(false);
+ ab.setTitle(R.string.app_name);
+ ab.setSubtitle(null);
+ }
+ }
+ }
+
+ private void openConversation() {
+ this.updateActionBarTitle();
+ this.invalidateOptionsMenu();
+ if (xmppConnectionServiceBound) {
+ final Conversation conversation = getSelectedConversation();
+ xmppConnectionService.getNotificationService().setOpenConversation(conversation);
+ sendReadMarkerIfNecessary(conversation);
+ }
+ listAdapter.notifyDataSetChanged();
+ }
+
+ public void sendReadMarkerIfNecessary(final Conversation conversation) {
+ if (!mActivityPaused && conversation != null) {
+ if (!conversation.isRead()) {
+ xmppConnectionService.sendReadMarker(conversation);
+ } else {
+ xmppConnectionService.markRead(conversation);
+ }
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.conversations, menu);
+ final MenuItem menuSecure = menu.findItem(R.id.action_security);
+ final MenuItem menuArchive = menu.findItem(R.id.action_archive);
+ final MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details);
+ final MenuItem menuContactDetails = menu.findItem(R.id.action_contact_details);
+ final MenuItem menuAttach = menu.findItem(R.id.action_attach_file);
+ final MenuItem menuClearHistory = menu.findItem(R.id.action_clear_history);
+ final MenuItem menuAdd = menu.findItem(R.id.action_add);
+ final MenuItem menuInviteContact = menu.findItem(R.id.action_invite);
+ final MenuItem menuMute = menu.findItem(R.id.action_mute);
+ final MenuItem menuUnmute = menu.findItem(R.id.action_unmute);
+
+ if (isConversationsOverviewVisable() && isConversationsOverviewHideable()) {
+ menuArchive.setVisible(false);
+ menuMucDetails.setVisible(false);
+ menuContactDetails.setVisible(false);
+ menuSecure.setVisible(false);
+ menuInviteContact.setVisible(false);
+ menuAttach.setVisible(false);
+ menuClearHistory.setVisible(false);
+ menuMute.setVisible(false);
+ menuUnmute.setVisible(false);
+ } else {
+ menuAdd.setVisible(!isConversationsOverviewHideable());
+ if (this.getSelectedConversation() != null) {
+ menuSecure.setVisible(!Config.HIDE_ENCRYPTION_IN_UI);
+ if (this.getSelectedConversation().getNextEncryption() != Message.ENCRYPTION_NONE) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ menuSecure.setIcon(R.drawable.ic_lock_white_24dp);
+ } else {
+ menuSecure.setIcon(R.drawable.ic_action_secure);
+ }
+ }
+ if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) {
+ menuContactDetails.setVisible(false);
+ menuAttach.setVisible(getSelectedConversation().getAccount().httpUploadAvailable() && getSelectedConversation().getMucOptions().participating());
+ menuInviteContact.setVisible(getSelectedConversation().getMucOptions().canInvite());
+ menuSecure.setVisible(!Config.HIDE_ENCRYPTION_IN_UI);
+ menuSecure.setVisible(!Config.HIDE_PGP_IN_UI); //if pgp is hidden conferences have no choice of encryption
+ } else {
+ menuMucDetails.setVisible(false);
+ }
+ if (this.getSelectedConversation().isMuted()) {
+ menuMute.setVisible(false);
+ } else {
+ menuUnmute.setVisible(false);
+ }
+ }
+ }
+ return true;
+ }
+
+ protected void selectPresenceToAttachFile(final int attachmentChoice, final int encryption) {
+ final Conversation conversation = getSelectedConversation();
+ final Account account = conversation.getAccount();
+ final OnPresenceSelected callback = new OnPresenceSelected() {
+
+ @Override
+ public void onPresenceSelected() {
+ Intent intent = new Intent();
+ boolean chooser = false;
+ String fallbackPackageId = null;
+ switch (attachmentChoice) {
+ case ATTACHMENT_CHOICE_CHOOSE_IMAGE:
+ intent.setAction(Intent.ACTION_GET_CONTENT);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ }
+ intent.setType("image/*");
+ chooser = true;
+ break;
+ case ATTACHMENT_CHOICE_TAKE_PHOTO:
+ Uri uri = xmppConnectionService.getFileBackend().getTakePhotoUri();
+ intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
+ mPendingImageUris.clear();
+ mPendingImageUris.add(uri);
+ break;
+ case ATTACHMENT_CHOICE_CHOOSE_FILE:
+ chooser = true;
+ intent.setType("*/*");
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setAction(Intent.ACTION_GET_CONTENT);
+ break;
+ case ATTACHMENT_CHOICE_RECORD_VOICE:
+ intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
+ fallbackPackageId = "eu.siacs.conversations.voicerecorder";
+ break;
+ case ATTACHMENT_CHOICE_LOCATION:
+ intent.setAction("eu.siacs.conversations.location.request");
+ fallbackPackageId = "eu.siacs.conversations.sharelocation";
+ break;
+ }
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ if (chooser) {
+ startActivityForResult(
+ Intent.createChooser(intent, getString(R.string.perform_action_with)),
+ attachmentChoice);
+ } else {
+ startActivityForResult(intent, attachmentChoice);
+ }
+ } else if (fallbackPackageId != null) {
+ startActivity(getInstallApkIntent(fallbackPackageId));
+ }
+ }
+ };
+ if ((account.httpUploadAvailable() || attachmentChoice == ATTACHMENT_CHOICE_LOCATION) && encryption != Message.ENCRYPTION_OTR) {
+ conversation.setNextCounterpart(null);
+ callback.onPresenceSelected();
+ } else {
+ selectPresence(conversation, callback);
+ }
+ }
+
+ private Intent getInstallApkIntent(final String packageId) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse("market://details?id=" + packageId));
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ return intent;
+ } else {
+ intent.setData(Uri.parse("http://play.google.com/store/apps/details?id=" + packageId));
+ return intent;
+ }
+ }
+
+ public void attachFile(final int attachmentChoice) {
+ switch (attachmentChoice) {
+ case ATTACHMENT_CHOICE_LOCATION:
+ getPreferences().edit().putString("recently_used_quick_action", "location").apply();
+ break;
+ case ATTACHMENT_CHOICE_RECORD_VOICE:
+ getPreferences().edit().putString("recently_used_quick_action", "voice").apply();
+ break;
+ case ATTACHMENT_CHOICE_TAKE_PHOTO:
+ getPreferences().edit().putString("recently_used_quick_action", "photo").apply();
+ break;
+ case ATTACHMENT_CHOICE_CHOOSE_IMAGE:
+ getPreferences().edit().putString("recently_used_quick_action", "picture").apply();
+ break;
+ }
+ final Conversation conversation = getSelectedConversation();
+ final int encryption = conversation.getNextEncryption();
+ if (encryption == Message.ENCRYPTION_PGP) {
+ if (hasPgp()) {
+ if (conversation.getContact().getPgpKeyId() != 0) {
+ xmppConnectionService.getPgpEngine().hasKey(
+ conversation.getContact(),
+ new UiCallback<Contact>() {
+
+ @Override
+ public void userInputRequried(PendingIntent pi,
+ Contact contact) {
+ ConversationActivity.this.runIntent(pi, attachmentChoice);
+ }
+
+ @Override
+ public void success(Contact contact) {
+ selectPresenceToAttachFile(attachmentChoice, encryption);
+ }
+
+ @Override
+ public void error(int error, Contact contact) {
+ displayErrorDialog(error);
+ }
+ });
+ } else {
+ final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
+ .findFragmentByTag("conversation");
+ if (fragment != null) {
+ fragment.showNoPGPKeyDialog(false,
+ new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ conversation
+ .setNextEncryption(Message.ENCRYPTION_NONE);
+ xmppConnectionService.databaseBackend
+ .updateConversation(conversation);
+ selectPresenceToAttachFile(attachmentChoice, Message.ENCRYPTION_NONE);
+ }
+ });
+ }
+ }
+ } else {
+ showInstallPgpDialog();
+ }
+ } else {
+ if (encryption != Message.ENCRYPTION_AXOLOTL || !trustKeysIfNeeded(REQUEST_TRUST_KEYS_MENU, attachmentChoice)) {
+ selectPresenceToAttachFile(attachmentChoice, encryption);
+ }
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(final MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ showConversationsOverview();
+ return true;
+ } else if (item.getItemId() == R.id.action_add) {
+ startActivity(new Intent(this, StartConversationActivity.class));
+ return true;
+ } else if (getSelectedConversation() != null) {
+ switch (item.getItemId()) {
+ case R.id.action_attach_file:
+ attachFileDialog();
+ break;
+ case R.id.action_archive:
+ this.endConversation(getSelectedConversation());
+ break;
+ case R.id.action_contact_details:
+ switchToContactDetails(getSelectedConversation().getContact());
+ break;
+ case R.id.action_muc_details:
+ Intent intent = new Intent(this,
+ ConferenceDetailsActivity.class);
+ intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
+ intent.putExtra("uuid", getSelectedConversation().getUuid());
+ startActivity(intent);
+ break;
+ case R.id.action_invite:
+ inviteToConversation(getSelectedConversation());
+ break;
+ case R.id.action_security:
+ selectEncryptionDialog(getSelectedConversation());
+ break;
+ case R.id.action_clear_history:
+ clearHistoryDialog(getSelectedConversation());
+ break;
+ case R.id.action_mute:
+ muteConversationDialog(getSelectedConversation());
+ break;
+ case R.id.action_unmute:
+ unmuteConversation(getSelectedConversation());
+ break;
+ case R.id.action_block:
+ BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation());
+ break;
+ case R.id.action_unblock:
+ BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation());
+ break;
+ default:
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ } else {
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ public void endConversation(Conversation conversation) {
+ endConversation(conversation, true, true);
+ }
+
+ public void endConversation(Conversation conversation, boolean showOverview, boolean reinit) {
+ if (showOverview) {
+ showConversationsOverview();
+ }
+ xmppConnectionService.archiveConversation(conversation);
+ if (reinit) {
+ if (conversationList.size() > 0) {
+ setSelectedConversation(conversationList.get(0));
+ this.mConversationFragment.reInit(getSelectedConversation());
+ } else {
+ setSelectedConversation(null);
+ if (mRedirected.compareAndSet(false, true)) {
+ Intent intent = new Intent(this, StartConversationActivity.class);
+ intent.putExtra("init", true);
+ startActivity(intent);
+ finish();
+ }
+ }
+ }
+ }
+
+ @SuppressLint("InflateParams")
+ protected void clearHistoryDialog(final Conversation conversation) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(getString(R.string.clear_conversation_history));
+ View dialogView = getLayoutInflater().inflate(
+ R.layout.dialog_clear_history, null);
+ final CheckBox endConversationCheckBox = (CheckBox) dialogView
+ .findViewById(R.id.end_conversation_checkbox);
+ builder.setView(dialogView);
+ builder.setNegativeButton(getString(R.string.cancel), null);
+ builder.setPositiveButton(getString(R.string.delete_messages),
+ new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ConversationActivity.this.xmppConnectionService.clearConversationHistory(conversation);
+ if (endConversationCheckBox.isChecked()) {
+ endConversation(conversation);
+ } else {
+ updateConversationList();
+ ConversationActivity.this.mConversationFragment.updateMessages();
+ }
+ }
+ });
+ builder.create().show();
+ }
+
+ protected void attachFileDialog() {
+ View menuAttachFile = findViewById(R.id.action_attach_file);
+ if (menuAttachFile == null) {
+ return;
+ }
+ PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile);
+ attachFilePopup.inflate(R.menu.attachment_choices);
+ if (new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION).resolveActivity(getPackageManager()) == null) {
+ attachFilePopup.getMenu().findItem(R.id.attach_record_voice).setVisible(false);
+ }
+ if (new Intent("eu.siacs.conversations.location.request").resolveActivity(getPackageManager()) == null) {
+ attachFilePopup.getMenu().findItem(R.id.attach_location).setVisible(false);
+ }
+ attachFilePopup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.attach_choose_picture:
+ attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE);
+ break;
+ case R.id.attach_take_picture:
+ attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO);
+ break;
+ case R.id.attach_choose_file:
+ attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE);
+ break;
+ case R.id.attach_record_voice:
+ attachFile(ATTACHMENT_CHOICE_RECORD_VOICE);
+ break;
+ case R.id.attach_location:
+ attachFile(ATTACHMENT_CHOICE_LOCATION);
+ break;
+ }
+ return false;
+ }
+ });
+ attachFilePopup.show();
+ }
+
+ public void verifyOtrSessionDialog(final Conversation conversation, View view) {
+ if (!conversation.hasValidOtrSession() || conversation.getOtrSession().getSessionStatus() != SessionStatus.ENCRYPTED) {
+ Toast.makeText(this, R.string.otr_session_not_started, Toast.LENGTH_LONG).show();
+ return;
+ }
+ if (view == null) {
+ return;
+ }
+ PopupMenu popup = new PopupMenu(this, view);
+ popup.inflate(R.menu.verification_choices);
+ popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem menuItem) {
+ Intent intent = new Intent(ConversationActivity.this, VerifyOTRActivity.class);
+ intent.setAction(VerifyOTRActivity.ACTION_VERIFY_CONTACT);
+ intent.putExtra("contact", conversation.getContact().getJid().toBareJid().toString());
+ intent.putExtra("account", conversation.getAccount().getJid().toBareJid().toString());
+ switch (menuItem.getItemId()) {
+ case R.id.scan_fingerprint:
+ intent.putExtra("mode", VerifyOTRActivity.MODE_SCAN_FINGERPRINT);
+ break;
+ case R.id.ask_question:
+ intent.putExtra("mode", VerifyOTRActivity.MODE_ASK_QUESTION);
+ break;
+ case R.id.manual_verification:
+ intent.putExtra("mode", VerifyOTRActivity.MODE_MANUAL_VERIFICATION);
+ break;
+ }
+ startActivity(intent);
+ return true;
+ }
+ });
+ popup.show();
+ }
+
+ protected void selectEncryptionDialog(final Conversation conversation) {
+ View menuItemView = findViewById(R.id.action_security);
+ if (menuItemView == null) {
+ return;
+ }
+ PopupMenu popup = new PopupMenu(this, menuItemView);
+ final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
+ .findFragmentByTag("conversation");
+ if (fragment != null) {
+ popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.encryption_choice_none:
+ conversation.setNextEncryption(Message.ENCRYPTION_NONE);
+ item.setChecked(true);
+ break;
+ case R.id.encryption_choice_otr:
+ conversation.setNextEncryption(Message.ENCRYPTION_OTR);
+ item.setChecked(true);
+ break;
+ case R.id.encryption_choice_pgp:
+ if (hasPgp()) {
+ if (conversation.getAccount().getKeys().has("pgp_signature")) {
+ conversation.setNextEncryption(Message.ENCRYPTION_PGP);
+ item.setChecked(true);
+ } else {
+ announcePgp(conversation.getAccount(), conversation);
+ }
+ } else {
+ showInstallPgpDialog();
+ }
+ break;
+ case R.id.encryption_choice_axolotl:
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(conversation.getAccount())
+ + "Enabled axolotl for Contact " + conversation.getContact().getJid());
+ conversation.setNextEncryption(Message.ENCRYPTION_AXOLOTL);
+ item.setChecked(true);
+ break;
+ default:
+ conversation.setNextEncryption(Message.ENCRYPTION_NONE);
+ break;
+ }
+ xmppConnectionService.databaseBackend.updateConversation(conversation);
+ fragment.updateChatMsgHint();
+ invalidateOptionsMenu();
+ refreshUi();
+ return true;
+ }
+ });
+ popup.inflate(R.menu.encryption_choices);
+ MenuItem otr = popup.getMenu().findItem(R.id.encryption_choice_otr);
+ MenuItem none = popup.getMenu().findItem(R.id.encryption_choice_none);
+ MenuItem pgp = popup.getMenu().findItem(R.id.encryption_choice_pgp);
+ MenuItem axolotl = popup.getMenu().findItem(R.id.encryption_choice_axolotl);
+ pgp.setVisible(!Config.HIDE_PGP_IN_UI);
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ otr.setVisible(false);
+ axolotl.setVisible(false);
+ } else if (!conversation.getAccount().getAxolotlService().isContactAxolotlCapable(conversation.getContact())) {
+ axolotl.setEnabled(false);
+ }
+ switch (conversation.getNextEncryption()) {
+ case Message.ENCRYPTION_NONE:
+ none.setChecked(true);
+ break;
+ case Message.ENCRYPTION_OTR:
+ otr.setChecked(true);
+ break;
+ case Message.ENCRYPTION_PGP:
+ pgp.setChecked(true);
+ break;
+ case Message.ENCRYPTION_AXOLOTL:
+ axolotl.setChecked(true);
+ break;
+ default:
+ none.setChecked(true);
+ break;
+ }
+ popup.show();
+ }
+ }
+
+ protected void muteConversationDialog(final Conversation conversation) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.disable_notifications);
+ final int[] durations = getResources().getIntArray(R.array.mute_options_durations);
+ builder.setItems(R.array.mute_options_descriptions,
+ new OnClickListener() {
+
+ @Override
+ public void onClick(final DialogInterface dialog, final int which) {
+ final long till;
+ if (durations[which] == -1) {
+ till = Long.MAX_VALUE;
+ } else {
+ till = System.currentTimeMillis() + (durations[which] * 1000);
+ }
+ conversation.setMutedTill(till);
+ ConversationActivity.this.xmppConnectionService.databaseBackend
+ .updateConversation(conversation);
+ updateConversationList();
+ ConversationActivity.this.mConversationFragment.updateMessages();
+ invalidateOptionsMenu();
+ }
+ });
+ builder.create().show();
+ }
+
+ public void unmuteConversation(final Conversation conversation) {
+ conversation.setMutedTill(0);
+ this.xmppConnectionService.databaseBackend.updateConversation(conversation);
+ updateConversationList();
+ ConversationActivity.this.mConversationFragment.updateMessages();
+ invalidateOptionsMenu();
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (!isConversationsOverviewVisable()) {
+ showConversationsOverview();
+ } else {
+ moveTaskToBack(true);
+ }
+ }
+
+ @Override
+ public boolean onKeyUp(int key, KeyEvent event) {
+ int rotation = getWindowManager().getDefaultDisplay().getRotation();
+ final int upKey;
+ final int downKey;
+ switch (rotation) {
+ case Surface.ROTATION_90:
+ upKey = KeyEvent.KEYCODE_DPAD_LEFT;
+ downKey = KeyEvent.KEYCODE_DPAD_RIGHT;
+ break;
+ case Surface.ROTATION_180:
+ upKey = KeyEvent.KEYCODE_DPAD_DOWN;
+ downKey = KeyEvent.KEYCODE_DPAD_UP;
+ break;
+ case Surface.ROTATION_270:
+ upKey = KeyEvent.KEYCODE_DPAD_RIGHT;
+ downKey = KeyEvent.KEYCODE_DPAD_LEFT;
+ break;
+ default:
+ upKey = KeyEvent.KEYCODE_DPAD_UP;
+ downKey = KeyEvent.KEYCODE_DPAD_DOWN;
+ }
+ final boolean modifier = event.isCtrlPressed() || event.isAltPressed();
+ if (modifier && key == KeyEvent.KEYCODE_TAB && isConversationsOverviewHideable()) {
+ toggleConversationsOverview();
+ return true;
+ } else if (modifier && key == downKey) {
+ if (isConversationsOverviewHideable() && !isConversationsOverviewVisable()) {
+ showConversationsOverview();
+ ;
+ }
+ return selectDownConversation();
+ } else if (modifier && key == upKey) {
+ if (isConversationsOverviewHideable() && !isConversationsOverviewVisable()) {
+ showConversationsOverview();
+ }
+ return selectUpConversation();
+ } else if (modifier && key == KeyEvent.KEYCODE_1) {
+ return openConversationByIndex(0);
+ } else if (modifier && key == KeyEvent.KEYCODE_2) {
+ return openConversationByIndex(1);
+ } else if (modifier && key == KeyEvent.KEYCODE_3) {
+ return openConversationByIndex(2);
+ } else if (modifier && key == KeyEvent.KEYCODE_4) {
+ return openConversationByIndex(3);
+ } else if (modifier && key == KeyEvent.KEYCODE_5) {
+ return openConversationByIndex(4);
+ } else if (modifier && key == KeyEvent.KEYCODE_6) {
+ return openConversationByIndex(5);
+ } else if (modifier && key == KeyEvent.KEYCODE_7) {
+ return openConversationByIndex(6);
+ } else if (modifier && key == KeyEvent.KEYCODE_8) {
+ return openConversationByIndex(7);
+ } else if (modifier && key == KeyEvent.KEYCODE_9) {
+ return openConversationByIndex(8);
+ } else if (modifier && key == KeyEvent.KEYCODE_0) {
+ return openConversationByIndex(9);
+ } else {
+ return super.onKeyUp(key, event);
+ }
+ }
+
+ private void toggleConversationsOverview() {
+ if (isConversationsOverviewVisable()) {
+ hideConversationsOverview();
+ if (mConversationFragment != null) {
+ mConversationFragment.setFocusOnInputField();
+ }
+ } else {
+ showConversationsOverview();
+ }
+ }
+
+ private boolean selectUpConversation() {
+ if (this.mSelectedConversation != null) {
+ int index = this.conversationList.indexOf(this.mSelectedConversation);
+ if (index > 0) {
+ return openConversationByIndex(index - 1);
+ }
+ }
+ return false;
+ }
+
+ private boolean selectDownConversation() {
+ if (this.mSelectedConversation != null) {
+ int index = this.conversationList.indexOf(this.mSelectedConversation);
+ if (index != -1 && index < this.conversationList.size() - 1) {
+ return openConversationByIndex(index + 1);
+ }
+ }
+ return false;
+ }
+
+ private boolean openConversationByIndex(int index) {
+ try {
+ this.conversationWasSelectedByKeyboard = true;
+ setSelectedConversation(this.conversationList.get(index));
+ this.mConversationFragment.reInit(getSelectedConversation());
+ if (index > listView.getLastVisiblePosition() - 1 || index < listView.getFirstVisiblePosition() + 1) {
+ this.listView.setSelection(index);
+ }
+ openConversation();
+ return true;
+ } catch (IndexOutOfBoundsException e) {
+ return false;
+ }
+ }
+
+ @Override
+ protected void onNewIntent(final Intent intent) {
+ if (xmppConnectionServiceBound) {
+ if (intent != null && VIEW_CONVERSATION.equals(intent.getType())) {
+ handleViewConversationIntent(intent);
+ }
+ } else {
+ setIntent(intent);
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ this.mRedirected.set(false);
+ if (this.xmppConnectionServiceBound) {
+ this.onBackendConnected();
+ }
+ if (conversationList.size() >= 1) {
+ this.onConversationUpdate();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ listView.discardUndo();
+ super.onPause();
+ this.mActivityPaused = true;
+ if (this.xmppConnectionServiceBound) {
+ this.xmppConnectionService.getNotificationService().setIsInForeground(false);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ final int theme = findTheme();
+ final boolean usingEnterKey = usingEnterKey();
+ if (this.mTheme != theme || usingEnterKey != mUsingEnterKey) {
+ recreate();
+ }
+ this.mActivityPaused = false;
+ if (this.xmppConnectionServiceBound) {
+ this.xmppConnectionService.getNotificationService().setIsInForeground(true);
+ }
+
+ if (!isConversationsOverviewVisable() || !isConversationsOverviewHideable()) {
+ sendReadMarkerIfNecessary(getSelectedConversation());
+ }
+
+ AppUpdate();
+ }
+
+ @Override
+ public void onSaveInstanceState(final Bundle savedInstanceState) {
+ Conversation conversation = getSelectedConversation();
+ if (conversation != null) {
+ savedInstanceState.putString(STATE_OPEN_CONVERSATION,
+ conversation.getUuid());
+ }
+ savedInstanceState.putBoolean(STATE_PANEL_OPEN,
+ isConversationsOverviewVisable());
+ if (this.mPendingImageUris.size() >= 1) {
+ savedInstanceState.putString(STATE_PENDING_URI, this.mPendingImageUris.get(0).toString());
+ }
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ @Override
+ void onBackendConnected() {
+ this.xmppConnectionService.getNotificationService().setIsInForeground(true);
+ updateConversationList();
+
+ if (mPendingConferenceInvite != null) {
+ mPendingConferenceInvite.execute(this);
+ mPendingConferenceInvite = null;
+ }
+
+ if (xmppConnectionService.getAccounts().size() == 0) {
+ if (mRedirected.compareAndSet(false, true)) {
+ if (Config.X509_VERIFICATION) {
+ startActivity(new Intent(this, ManageAccountActivity.class));
+ } else {
+ startActivity(new Intent(this, EditAccountActivity.class));
+ }
+ finish();
+ }
+ } else if (conversationList.size() <= 0) {
+ if (mRedirected.compareAndSet(false, true)) {
+ Intent intent = new Intent(this, StartConversationActivity.class);
+ intent.putExtra("init", true);
+ startActivity(intent);
+ finish();
+ }
+ } else if (getIntent() != null && VIEW_CONVERSATION.equals(getIntent().getType())) {
+ handleViewConversationIntent(getIntent());
+ } else if (selectConversationByUuid(mOpenConverstaion)) {
+ if (mPanelOpen) {
+ showConversationsOverview();
+ } else {
+ if (isConversationsOverviewHideable()) {
+ openConversation();
+ }
+ }
+ this.mConversationFragment.reInit(getSelectedConversation());
+ mOpenConverstaion = null;
+ } else if (getSelectedConversation() == null) {
+ showConversationsOverview();
+ mPendingImageUris.clear();
+ mPendingFileUris.clear();
+ mPendingGeoUri = null;
+ setSelectedConversation(conversationList.get(0));
+ this.mConversationFragment.reInit(getSelectedConversation());
+ } else {
+ this.mConversationFragment.messageListAdapter.updatePreferences();
+ this.mConversationFragment.messagesView.invalidateViews();
+ this.mConversationFragment.setupIme();
+ }
+
+ if (!forbidProcessingPendings) {
+ for (Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
+ Uri foo = i.next();
+ attachImageToConversation(getSelectedConversation(), foo);
+ }
+
+ for (Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) {
+ attachFileToConversation(getSelectedConversation(), i.next());
+ }
+
+ if (mPendingGeoUri != null) {
+ attachLocationToConversation(getSelectedConversation(), mPendingGeoUri);
+ mPendingGeoUri = null;
+ }
+ }
+ forbidProcessingPendings = false;
+
+ ExceptionHelper.checkForCrash(this, this.xmppConnectionService);
+ setIntent(new Intent());
+ }
+
+ private void handleViewConversationIntent(final Intent intent) {
+ final String uuid = intent.getStringExtra(CONVERSATION);
+ final String downloadUuid = intent.getStringExtra(MESSAGE);
+ final String text = intent.getStringExtra(TEXT);
+ final String nick = intent.getStringExtra(NICK);
+ final boolean pm = intent.getBooleanExtra(PRIVATE_MESSAGE, false);
+ if (selectConversationByUuid(uuid)) {
+ this.mConversationFragment.reInit(getSelectedConversation());
+ if (nick != null) {
+ if (pm) {
+ Jid jid = getSelectedConversation().getJid();
+ try {
+ Jid next = Jid.fromParts(jid.getLocalpart(), jid.getDomainpart(), nick);
+ this.mConversationFragment.privateMessageWith(next);
+ } catch (final InvalidJidException ignored) {
+ //do nothing
+ }
+ } else {
+ this.mConversationFragment.highlightInConference(nick);
+ }
+ } else {
+ this.mConversationFragment.appendText(text);
+ }
+ hideConversationsOverview();
+ openConversation();
+ if (mContentView instanceof SlidingPaneLayout) {
+ updateActionBarTitle(true); //fixes bug where slp isn't properly closed yet
+ }
+ if (downloadUuid != null) {
+ final Message message = mSelectedConversation.findMessageWithFileAndUuid(downloadUuid);
+ if (message != null) {
+ mConversationFragment.messageListAdapter.startDownloadable(message);
+ }
+ }
+ }
+ }
+
+ private boolean selectConversationByUuid(String uuid) {
+ if (uuid == null) {
+ return false;
+ }
+ for (Conversation aConversationList : conversationList) {
+ if (aConversationList.getUuid().equals(uuid)) {
+ setSelectedConversation(aConversationList);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void unregisterListeners() {
+ super.unregisterListeners();
+ xmppConnectionService.getNotificationService().setOpenConversation(null);
+ }
+
+ @SuppressLint("NewApi")
+ private static List<Uri> extractUriFromIntent(final Intent intent) {
+ List<Uri> uris = new ArrayList<>();
+ Uri uri = intent.getData();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && uri == null) {
+ ClipData clipData = intent.getClipData();
+ for (int i = 0; i < clipData.getItemCount(); ++i) {
+ uris.add(clipData.getItemAt(i).getUri());
+ }
+ } else {
+ uris.add(uri);
+ }
+ return uris;
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode,
+ final Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode == RESULT_OK) {
+ if (requestCode == REQUEST_DECRYPT_PGP) {
+ mConversationFragment.hideSnackbar();
+ mConversationFragment.updateMessages();
+ } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) {
+ mPendingImageUris.clear();
+ mPendingImageUris.addAll(extractUriFromIntent(data));
+ if (xmppConnectionServiceBound) {
+ for (Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
+ attachImageToConversation(getSelectedConversation(), i.next());
+ }
+ }
+ } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_FILE || requestCode == ATTACHMENT_CHOICE_RECORD_VOICE) {
+ mPendingFileUris.clear();
+ mPendingFileUris.addAll(extractUriFromIntent(data));
+ if (xmppConnectionServiceBound) {
+ for (Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) {
+ attachFileToConversation(getSelectedConversation(), i.next());
+ }
+ }
+ } else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) {
+ if (mPendingImageUris.size() == 1) {
+ Uri uri = mPendingImageUris.get(0);
+ if (xmppConnectionServiceBound) {
+ attachImageToConversation(getSelectedConversation(), uri);
+ mPendingImageUris.clear();
+ }
+ Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ intent.setData(uri);
+ sendBroadcast(intent);
+ } else {
+ mPendingImageUris.clear();
+ }
+ } else if (requestCode == ATTACHMENT_CHOICE_LOCATION) {
+ double latitude = data.getDoubleExtra("latitude", 0);
+ double longitude = data.getDoubleExtra("longitude", 0);
+ this.mPendingGeoUri = Uri.parse("geo:" + String.valueOf(latitude) + "," + String.valueOf(longitude));
+ if (xmppConnectionServiceBound) {
+ attachLocationToConversation(getSelectedConversation(), mPendingGeoUri);
+ this.mPendingGeoUri = null;
+ }
+ } else if (requestCode == REQUEST_TRUST_KEYS_TEXT || requestCode == REQUEST_TRUST_KEYS_MENU) {
+ this.forbidProcessingPendings = !xmppConnectionServiceBound;
+ mConversationFragment.onActivityResult(requestCode, resultCode, data);
+ }
+ } else {
+ mPendingImageUris.clear();
+ mPendingFileUris.clear();
+ }
+ }
+
+ private void attachLocationToConversation(Conversation conversation, Uri uri) {
+ if (conversation == null) {
+ return;
+ }
+ xmppConnectionService.attachLocationToConversation(conversation, uri, new UiCallback<Message>() {
+
+ @Override
+ public void success(Message message) {
+ xmppConnectionService.sendMessage(message);
+ }
+
+ @Override
+ public void error(int errorCode, Message object) {
+
+ }
+
+ @Override
+ public void userInputRequried(PendingIntent pi, Message object) {
+
+ }
+ });
+ }
+
+ private void attachFileToConversation(Conversation conversation, Uri uri) {
+ if (conversation == null) {
+ return;
+ }
+ prepareFileToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_file), Toast.LENGTH_LONG);
+ prepareFileToast.show();
+ xmppConnectionService.attachFileToConversation(conversation, uri, new UiCallback<Message>() {
+ @Override
+ public void success(Message message) {
+ hidePrepareFileToast();
+ xmppConnectionService.sendMessage(message);
+ }
+
+ @Override
+ public void error(int errorCode, Message message) {
+ displayErrorDialog(errorCode);
+ }
+
+ @Override
+ public void userInputRequried(PendingIntent pi, Message message) {
+
+ }
+ });
+ }
+
+ private void attachImageToConversation(Conversation conversation, Uri uri) {
+ if (conversation == null) {
+ return;
+ }
+ prepareFileToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_image), Toast.LENGTH_LONG);
+ prepareFileToast.show();
+ xmppConnectionService.attachImageToConversation(conversation, uri,
+ new UiCallback<Message>() {
+
+ @Override
+ public void userInputRequried(PendingIntent pi,
+ Message object) {
+ hidePrepareFileToast();
+ }
+
+ @Override
+ public void success(Message message) {
+ xmppConnectionService.sendMessage(message);
+ }
+
+ @Override
+ public void error(int error, Message message) {
+ hidePrepareFileToast();
+ displayErrorDialog(error);
+ }
+ });
+ }
+
+ private void hidePrepareFileToast() {
+ if (prepareFileToast != null) {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ prepareFileToast.cancel();
+ }
+ });
+ }
+ }
+
+ public void updateConversationList() {
+ xmppConnectionService
+ .populateWithOrderedConversations(conversationList);
+ if (swipedConversation != null) {
+ if (swipedConversation.isRead()) {
+ conversationList.remove(swipedConversation);
+ } else {
+ listView.discardUndo();
+ }
+ }
+ listAdapter.notifyDataSetChanged();
+ }
+
+ public void runIntent(PendingIntent pi, int requestCode) {
+ try {
+ this.startIntentSenderForResult(pi.getIntentSender(), requestCode,
+ null, 0, 0, 0);
+ } catch (final SendIntentException ignored) {
+ }
+ }
+
+ public void encryptTextMessage(Message message) {
+ xmppConnectionService.getPgpEngine().encrypt(message,
+ new UiCallback<Message>() {
+
+ @Override
+ public void userInputRequried(PendingIntent pi,
+ Message message) {
+ ConversationActivity.this.runIntent(pi,
+ ConversationActivity.REQUEST_SEND_MESSAGE);
+ }
+
+ @Override
+ public void success(Message message) {
+ message.setEncryption(Message.ENCRYPTION_DECRYPTED);
+ xmppConnectionService.sendMessage(message);
+ }
+
+ @Override
+ public void error(int error, Message message) {
+
+ }
+ });
+ }
+
+ public boolean useSendButtonToIndicateStatus() {
+ return getPreferences().getBoolean("send_button_status", false);
+ }
+
+ public boolean indicateReceived() {
+ return getPreferences().getBoolean("indicate_received", false);
+ }
+
+ public boolean useWhiteBackground() {
+ return getPreferences().getBoolean("use_white_background", false);
+ }
+
+ protected boolean trustKeysIfNeeded(int requestCode) {
+ return trustKeysIfNeeded(requestCode, ATTACHMENT_CHOICE_INVALID);
+ }
+
+ protected boolean trustKeysIfNeeded(int requestCode, int attachmentChoice) {
+ AxolotlService axolotlService = mSelectedConversation.getAccount().getAxolotlService();
+ boolean hasPendingKeys = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED,
+ mSelectedConversation.getContact()).isEmpty()
+ || !axolotlService.findDevicesWithoutSession(mSelectedConversation).isEmpty();
+ boolean hasNoTrustedKeys = axolotlService.getNumTrustedKeys(mSelectedConversation.getContact()) == 0;
+ if (hasPendingKeys || hasNoTrustedKeys) {
+ axolotlService.createSessionsIfNeeded(mSelectedConversation);
+ Intent intent = new Intent(getApplicationContext(), TrustKeysActivity.class);
+ intent.putExtra("contact", mSelectedConversation.getContact().getJid().toBareJid().toString());
+ intent.putExtra("account", mSelectedConversation.getAccount().getJid().toBareJid().toString());
+ intent.putExtra("choice", attachmentChoice);
+ intent.putExtra("has_no_trusted", hasNoTrustedKeys);
+ startActivityForResult(intent, requestCode);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected void refreshUiReal() {
+ updateConversationList();
+ if (conversationList.size() > 0) {
+ ConversationActivity.this.mConversationFragment.updateMessages();
+ updateActionBarTitle();
+ invalidateOptionsMenu();
+ }
+ }
+
+ @Override
+ public void onAccountUpdate() {
+ this.refreshUi();
+ }
+
+ @Override
+ public void onConversationUpdate() {
+ this.refreshUi();
+ }
+
+ @Override
+ public void onRosterUpdate() {
+ this.refreshUi();
+ }
+
+ @Override
+ public void OnUpdateBlocklist(Status status) {
+ this.refreshUi();
+ }
+
+ public void unblockConversation(final Blockable conversation) {
+ xmppConnectionService.sendUnblockRequest(conversation);
+ }
+
+ public boolean enterIsSend() {
+ return getPreferences().getBoolean("enter_is_send", false);
+ }
+
+ @Override
+ public void onShowErrorToast(final int resId) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(ConversationActivity.this, resId, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ public boolean highlightSelectedConversations() {
+ return !isConversationsOverviewHideable() || this.conversationWasSelectedByKeyboard;
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index 05d6e5ee3..1982781fd 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -1018,18 +1018,18 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
if (conversation.getMode() == Conversation.MODE_SINGLE) {
ChatState state = conversation.getIncomingChatState();
if (state == ChatState.COMPOSING) {
- this.messageList.add(Message.createStatusMessage(conversation, getString(R.string.contact_is_typing, conversation.getName())));
+ //this.messageList.add(Message.createStatusMessage(conversation, getString(R.string.contact_is_typing, conversation.getName())));
} else if (state == ChatState.PAUSED) {
- this.messageList.add(Message.createStatusMessage(conversation, getString(R.string.contact_has_stopped_typing, conversation.getName())));
+ //this.messageList.add(Message.createStatusMessage(conversation, getString(R.string.contact_has_stopped_typing, conversation.getName())));
} else {
for (int i = this.messageList.size() - 1; i >= 0; --i) {
if (this.messageList.get(i).getStatus() == Message.STATUS_RECEIVED) {
return;
} else {
if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) {
- this.messageList.add(i + 1,
- Message.createStatusMessage(conversation, getString(R.string.contact_has_read_up_to_this_point, conversation.getName())));
- return;
+// this.messageList.add(i + 1,
+// Message.createStatusMessage(conversation, getString(R.string.contact_has_read_up_to_this_point, conversation.getName())));
+// return;
}
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index d58f0fc29..1712a717c 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -28,9 +28,9 @@ import android.widget.RelativeLayout;
import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.Toast;
-
+import eu.siacs.conversations.Config;
+import org.whispersystems.libaxolotl.IdentityKey;
import java.util.Set;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
@@ -362,7 +362,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
this.mAxolotlFingerprint = (TextView) findViewById(R.id.axolotl_fingerprint);
this.mAxolotlFingerprintBox = (RelativeLayout) findViewById(R.id.axolotl_fingerprint_box);
this.mAxolotlFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_axolotl_to_clipboard);
- this.mRegenerateAxolotlKeyButton = (ImageButton) findViewById(R.id.action_regenerate_axolotl_key);
+ this.mRegenerateAxolotlKeyButton = (ImageButton) findViewById(R.id.action_regenerate_omemo_key);
this.keysCard = (LinearLayout) findViewById(R.id.other_device_keys_card);
this.keys = (LinearLayout) findViewById(R.id.other_device_keys);
this.mSaveButton = (Button) findViewById(R.id.save_button);
@@ -528,7 +528,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
}
if (!mInitMode) {
this.mAvatar.setVisibility(View.VISIBLE);
- this.mAvatar.setImageBitmap(avatarService().get(this.mAccount, getPixel(72)));
+ this.mAvatar.setImageBitmap(avatarService().get(this.mAccount, getPixel(Config.AVATAR_SIZE)));
}
if (this.mAccount.isOptionSet(Account.OPTION_REGISTER)) {
this.mRegisterNew.setVisibility(View.VISIBLE);
diff --git a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
index e01490f90..9e64a6805 100644
--- a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
@@ -172,7 +172,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
if (this.account.getAvatar() != null
|| this.defaultUri == null) {
this.avatar.setImageBitmap(avatarService().get(account,
- getPixel(194)));
+ getPixel(Config.AVATAR_SIZE)));
if (this.defaultUri != null) {
this.avatar
.setOnLongClickListener(this.backToDefaultListener);
@@ -219,7 +219,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
protected void loadImageIntoPreview(Uri uri) {
Bitmap bm = xmppConnectionService.getFileBackend().cropCenterSquare(
- uri, 384);
+ uri, Config.AVATAR_SIZE);
if (bm == null) {
disablePublishButton();
this.hintOrWarning.setTextColor(getWarningTextColor());
diff --git a/src/main/java/eu/siacs/conversations/ui/UpdaterActivity.java b/src/main/java/eu/siacs/conversations/ui/UpdaterActivity.java
new file mode 100644
index 000000000..4dccdfe5b
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/UpdaterActivity.java
@@ -0,0 +1,262 @@
+package eu.siacs.conversations.ui;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.DownloadManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.util.Log;
+import android.view.WindowManager;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.services.UpdaterWebService;
+
+public class UpdaterActivity extends Activity {
+
+ private UpdateReceiver receiver = null;
+ private int versionCode = 0;
+ String appURI = "";
+
+
+ /*
+ // run AppUpdater
+ Log.d(Config.LOGTAG, "Start automatic AppUpdater");
+ Intent AppUpdater = new Intent(this, UpdaterActivity.class);
+ startActivity(AppUpdater);
+ */
+
+ private DownloadManager downloadManager;
+ private long downloadReference;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ //set activity
+ setContentView(R.layout.activity_updater);
+ TextView textView = (TextView) findViewById(R.id.updater);
+ textView.setText(R.string.update_info);
+
+ //Broadcast receiver for our Web Request
+ IntentFilter filter = new IntentFilter(UpdateReceiver.PROCESS_RESPONSE);
+ filter.addCategory(Intent.CATEGORY_DEFAULT);
+ receiver = new UpdateReceiver();
+ registerReceiver(receiver, filter);
+
+ //Broadcast receiver for the download manager
+ filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
+ registerReceiver(downloadReceiver, filter);
+
+ //check of internet is available before making a web service request
+ if (isNetworkAvailable(this)) {
+ Intent msgIntent = new Intent(this, UpdaterWebService.class);
+ msgIntent.putExtra(UpdaterWebService.REQUEST_STRING, Config.UPDATE_URL);
+
+ Toast.makeText(getApplicationContext(),
+ getText(R.string.checking_for_updates),
+ Toast.LENGTH_SHORT).show();
+ startService(msgIntent);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ //unregister your receivers
+ this.unregisterReceiver(receiver);
+ this.unregisterReceiver(downloadReceiver);
+ super.onDestroy();
+ //enable touch events
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ @Override
+ public void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ }
+
+ //check for internet connection
+ private boolean isNetworkAvailable(Context context) {
+ ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (connectivity != null) {
+ NetworkInfo[] info = connectivity.getAllNetworkInfo();
+ if (info != null) {
+ for (int i = 0; i < info.length; i++) {
+ Log.d(Config.LOGTAG, "AppUpdater: " + String.valueOf(i));
+ if (info[i].getState() == NetworkInfo.State.CONNECTED) {
+ Log.d(Config.LOGTAG, "AppUpdater: connected to update Server!");
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ //broadcast receiver to get notification when the web request finishes
+ public class UpdateReceiver extends BroadcastReceiver {
+
+ public static final String PROCESS_RESPONSE = "eu.siacs.conversations.intent.action.PROCESS_RESPONSE";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ //disable touch events
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+
+ String reponseMessage = intent.getStringExtra(UpdaterWebService.RESPONSE_MESSAGE);
+ Log.d(Config.LOGTAG, "AppUpdater: Reponse: " + reponseMessage);
+
+ if (reponseMessage == "" || reponseMessage.isEmpty() || reponseMessage == null) {
+ Toast.makeText(getApplicationContext(),
+ getText(R.string.failed),
+ Toast.LENGTH_LONG).show();
+ Log.e(Config.LOGTAG, "AppUpdater: error connecting to server");
+ UpdaterActivity.this.finish();
+ } else {
+ Log.d(Config.LOGTAG, "AppUpdater: connecting to server");
+ //parse the JSON reponse
+ JSONObject reponseObj;
+
+ try {
+ //if the reponse was successful check further
+ reponseObj = new JSONObject(reponseMessage);
+ boolean success = reponseObj.getBoolean("success");
+ if (success) {
+ //Overall information about the contents of a package
+ //This correponds to all of the information collected from AndroidManifest.xml.
+ PackageInfo pInfo = null;
+ try {
+ pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ //get the app version Name for display
+ final String versionName = pInfo.versionName;
+ final int versionCode = pInfo.versionCode;
+ //get the latest version from the JSON string
+ int latestVersionCode = reponseObj.getInt("latestVersionCode");
+ String latestVersion = reponseObj.getString("latestVersion");
+ String changelog = reponseObj.getString("changelog");
+ //get the lastest application URI from the JSON string
+ appURI = reponseObj.getString("appURI");
+ //check if we need to upgrade?
+ if (latestVersionCode > versionCode) {
+ Log.d(Config.LOGTAG, "AppUpdater: update available");
+ //delete old downloaded version files
+ File dir = new File(getExternalFilesDir(null), Environment.DIRECTORY_DOWNLOADS);
+ Log.d(Config.LOGTAG, "AppUpdater: delete old update files in: " + dir);
+ if (dir.isDirectory()) {
+ String[] children = dir.list();
+ for (int i = 0; i < children.length; i++) {
+ new File(dir, children[i]).delete();
+ }
+ }
+ //enable touch events
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+
+ //oh yeah we do need an upgrade, let the user know send an alert message
+ AlertDialog.Builder builder = new AlertDialog.Builder(UpdaterActivity.this);
+ builder.setCancelable(false);
+
+ String UpdateMessageInfo = getResources().getString(R.string.update_available);
+ builder.setMessage(String.format(UpdateMessageInfo, latestVersion, changelog, versionName))
+ .setPositiveButton(R.string.update, new DialogInterface.OnClickListener() {
+ //if the user agrees to upgrade
+ public void onClick(DialogInterface dialog, int id) {
+ //disable touch events
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+ //start downloading the file using the download manager
+ downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
+ Uri Download_Uri = Uri.parse(appURI);
+ DownloadManager.Request request = new DownloadManager.Request(Download_Uri);
+ request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
+ request.setAllowedOverRoaming(false);
+ request.setTitle("Conversations Update");
+ request.setDestinationInExternalFilesDir(UpdaterActivity.this, Environment.DIRECTORY_DOWNLOADS, "Conversations" + versionName + ".apk");
+ downloadReference = downloadManager.enqueue(request);
+ Toast.makeText(getApplicationContext(),
+ getText(R.string.download_started),
+ Toast.LENGTH_LONG).show();
+ }
+ })
+ .setNegativeButton(R.string.remind_later, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ // User cancelled the dialog
+ UpdaterActivity.this.finish();
+ }
+ });
+ //show the alert message
+ builder.create().show();
+ } else {
+ Toast.makeText(getApplicationContext(),
+ getText(R.string.no_update_available),
+ Toast.LENGTH_SHORT).show();
+ Log.d(Config.LOGTAG, "AppUpdater: no update available");
+ UpdaterActivity.this.finish();
+ }
+ } else {
+ Toast.makeText(getApplicationContext(),
+ getText(R.string.failed),
+ Toast.LENGTH_LONG).show();
+ Log.e(Config.LOGTAG, "AppUpdater: contact to server not successfull");
+ UpdaterActivity.this.finish();
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ }
+
+ }
+
+ //broadcast receiver to get notification about ongoing downloads
+ private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ //check if the broadcast message is for our Enqueued download
+ long referenceId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
+ if (downloadReference == referenceId) {
+
+ Log.d(Config.LOGTAG, "AppUpdater: Downloading of the new app version complete. Starting installation");
+ //start the installation of the latest version
+ Intent installIntent = new Intent(Intent.ACTION_VIEW);
+ installIntent.setDataAndType(downloadManager.getUriForDownloadedFile(downloadReference),
+ "application/vnd.android.package-archive");
+ installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(installIntent);
+ UpdaterActivity.this.finish();
+ }
+ }
+ };
+
+ //disable back button
+ @Override
+ public void onBackPressed() {
+ }
+}
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index 0cdae2cdc..de4d261c5 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -334,6 +334,9 @@ public abstract class XmppActivity extends Activity {
case R.id.action_settings:
startActivity(new Intent(this, SettingsActivity.class));
break;
+ case R.id.action_check_updates:
+ startActivity(new Intent(this, UpdaterActivity.class));
+ break;
case R.id.action_accounts:
startActivity(new Intent(this, ManageAccountActivity.class));
break;
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
index 98250af94..c1b9cbdf6 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
@@ -43,7 +43,7 @@ public class AccountAdapter extends ArrayAdapter<Account> {
}
TextView statusView = (TextView) view.findViewById(R.id.account_status);
ImageView imageView = (ImageView) view.findViewById(R.id.account_image);
- imageView.setImageBitmap(activity.avatarService().get(account, activity.getPixel(48)));
+ imageView.setImageBitmap(activity.avatarService().get(account, activity.getPixel(56)));
statusView.setText(getContext().getString(account.getStatus().getReadableId()));
switch (account.getStatus()) {
case ONLINE:
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
index d9fea8170..89a15ece3 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -113,6 +113,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
boolean error = false;
if (viewHolder.indicatorReceived != null) {
viewHolder.indicatorReceived.setVisibility(View.GONE);
+ viewHolder.indicatorRead.setVisibility(View.GONE);
}
boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI
&& message.getMergedStatus() <= Message.STATUS_RECEIVED;
@@ -150,6 +151,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
case Message.STATUS_SEND_DISPLAYED:
if (mIndicateReceived) {
viewHolder.indicatorReceived.setVisibility(View.VISIBLE);
+ viewHolder.indicatorRead.setVisibility(View.VISIBLE);
}
break;
case Message.STATUS_SEND_FAILED:
@@ -388,7 +390,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.messageBody.setVisibility(View.GONE);
viewHolder.image.setVisibility(View.VISIBLE);
FileParams params = message.getFileParams();
- double target = metrics.density * 288;
+ double target = metrics.density * 200;
int scalledW;
int scalledH;
if (params.width <= params.height) {
@@ -442,6 +444,8 @@ public class MessageAdapter extends ArrayAdapter<Message> {
.findViewById(R.id.message_time);
viewHolder.indicatorReceived = (ImageView) view
.findViewById(R.id.indicator_received);
+ viewHolder.indicatorRead = (ImageView) view
+ .findViewById(R.id.indicator_read);
break;
case RECEIVED:
view = activity.getLayoutInflater().inflate(
@@ -663,6 +667,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
protected ImageView image;
protected ImageView indicator;
protected ImageView indicatorReceived;
+ protected ImageView indicatorRead;
protected TextView time;
protected TextView messageBody;
protected ImageView contact_picture;
diff --git a/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java b/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java
index 0f1828473..6d1d1074d 100644
--- a/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java
@@ -94,7 +94,7 @@ public class ExceptionHelper {
Conversation conversation = null;
try {
conversation = service.findOrCreateConversation(finalAccount,
- Jid.fromString("bugs@siacs.eu"), false);
+ Jid.fromString("bugs@pix-art.de"), false);
} catch (final InvalidJidException ignored) {
}
Message message = new Message(conversation, report
diff --git a/src/main/java/eu/siacs/conversations/utils/GeoHelper.java b/src/main/java/eu/siacs/conversations/utils/GeoHelper.java
index 74f91a98b..cd97e1105 100644
--- a/src/main/java/eu/siacs/conversations/utils/GeoHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/GeoHelper.java
@@ -9,6 +9,7 @@ import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
@@ -40,6 +41,7 @@ public class GeoHelper {
return intents;
}
final Conversation conversation = message.getConversation();
+ final Contact contact = message.getContact();
String label;
if (conversation.getMode() == Conversation.MODE_SINGLE && message.getStatus() == Message.STATUS_RECEIVED) {
try {
@@ -62,6 +64,16 @@ public class GeoHelper {
else {
locationPluginIntent.putExtra("jid",conversation.getAccount().getJid().toString());
}
+ } else {
+ if (message.getStatus() == Message.STATUS_RECEIVED) {
+ if (contact != null) {
+ locationPluginIntent.putExtra("name",contact.getDisplayName());
+ }
+ locationPluginIntent.putExtra("jid",message.getCounterpart().toString());
+ }
+ else {
+ locationPluginIntent.putExtra("jid",conversation.getAccount().getJid().toString());
+ }
}
intents.add(locationPluginIntent);
@@ -74,4 +86,4 @@ public class GeoHelper {
intents.add(httpIntent);
return intents;
}
-}
+} \ No newline at end of file
diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java b/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java
diff --git a/src/main/res/drawable-hdpi/ic_read_indicator.png b/src/main/res/drawable-hdpi/ic_read_indicator.png
new file mode 100644
index 000000000..21fbf4eb9
--- /dev/null
+++ b/src/main/res/drawable-hdpi/ic_read_indicator.png
Binary files differ
diff --git a/src/main/res/drawable-mdpi/ic_read_indicator.png b/src/main/res/drawable-mdpi/ic_read_indicator.png
new file mode 100644
index 000000000..4cabf6ec2
--- /dev/null
+++ b/src/main/res/drawable-mdpi/ic_read_indicator.png
Binary files differ
diff --git a/src/main/res/drawable-xhdpi/ic_read_indicator.png b/src/main/res/drawable-xhdpi/ic_read_indicator.png
new file mode 100644
index 000000000..216c33128
--- /dev/null
+++ b/src/main/res/drawable-xhdpi/ic_read_indicator.png
Binary files differ
diff --git a/src/main/res/drawable-xxhdpi/ic_read_indicator.png b/src/main/res/drawable-xxhdpi/ic_read_indicator.png
new file mode 100644
index 000000000..66caba6ae
--- /dev/null
+++ b/src/main/res/drawable-xxhdpi/ic_read_indicator.png
Binary files differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_read_indicator.png b/src/main/res/drawable-xxxhdpi/ic_read_indicator.png
new file mode 100644
index 000000000..aef5c7bdc
--- /dev/null
+++ b/src/main/res/drawable-xxxhdpi/ic_read_indicator.png
Binary files differ
diff --git a/src/main/res/drawable/message_border.xml b/src/main/res/drawable/message_border.xml
new file mode 100644
index 000000000..990d02886
--- /dev/null
+++ b/src/main/res/drawable/message_border.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle" >
+
+ <corners android:radius="2dp" />
+
+ <padding
+ android:bottom="1.5dp"
+ android:left="1.5dp"
+ android:right="1.5dp"
+ android:top="1.5dp" />
+
+ <solid android:color="@color/black12" />
+
+</shape> \ No newline at end of file
diff --git a/src/main/res/layout/account_row.xml b/src/main/res/layout/account_row.xml
index cac9a9fa6..f0d0c903d 100644
--- a/src/main/res/layout/account_row.xml
+++ b/src/main/res/layout/account_row.xml
@@ -15,6 +15,8 @@
android:layout_alignParentLeft="true"
android:src="@drawable/ic_profile"
android:contentDescription="@string/account_image_description"
+ android:background="@drawable/message_border"
+ android:padding="1dp"
app:riv_corner_radius="2dp" />
<LinearLayout
diff --git a/src/main/res/layout/activity_contact_details.xml b/src/main/res/layout/activity_contact_details.xml
index 5f6a2dd09..77fb91f2f 100644
--- a/src/main/res/layout/activity_contact_details.xml
+++ b/src/main/res/layout/activity_contact_details.xml
@@ -21,18 +21,28 @@
<QuickContactBadge
android:id="@+id/details_contact_badge"
- android:layout_width="72dp"
- android:layout_height="72dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxHeight="384dp"
+ android:maxWidth="384dp"
+ android:scaleType="centerCrop"
android:layout_alignParentTop="true"
- android:scaleType="centerCrop" />
+ android:layout_centerHorizontal="true"
+ android:background="@drawable/message_border"
+ android:padding="1dp"
+ android:adjustViewBounds="true"/>
<LinearLayout
android:id="@+id/details_jidbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="16dp"
- android:layout_toRightOf="@+id/details_contact_badge"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ android:layout_below="@+id/details_contact_badge"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
+ android:layout_marginTop="16dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true">
<TextView
android:id="@+id/details_contactjid"
@@ -41,12 +51,14 @@
android:text="@string/account_settings_example_jabber_id"
android:textColor="@color/black87"
android:textSize="?attr/TextSizeHeadline"
- android:textStyle="bold" />
+ android:textStyle="bold"
+ android:layout_gravity="center_horizontal" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ android:layout_gravity="center_horizontal">
<LinearLayout
android:id="@+id/tags"
@@ -54,7 +66,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:layout_gravity="center_horizontal">
</LinearLayout>
<TextView
@@ -62,7 +75,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black54"
- android:textSize="?attr/TextSizeBody" />
+ android:textSize="?attr/TextSizeBody"
+ android:layout_gravity="center_horizontal" />
</LinearLayout>
<Button
@@ -70,7 +84,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
- android:text="@string/add_contact"/>
+ android:text="@string/add_contact"
+ android:layout_gravity="center_horizontal" />
<CheckBox
android:id="@+id/details_send_presence"
diff --git a/src/main/res/layout/activity_edit_account.xml b/src/main/res/layout/activity_edit_account.xml
index 0be934a85..bcbe7a7fb 100644
--- a/src/main/res/layout/activity_edit_account.xml
+++ b/src/main/res/layout/activity_edit_account.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/grey200">
+ xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/grey200">
<ScrollView
android:layout_width="fill_parent"
@@ -30,86 +30,92 @@
android:padding="@dimen/infocard_padding">
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/avater"
- android:layout_width="72dp"
- android:layout_height="72dp"
- android:layout_alignParentTop="true"
- android:layout_marginRight="16dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxHeight="384dp"
+ android:maxWidth="384dp"
android:contentDescription="@string/account_image_description"
- app:riv_corner_radius="2dp"/>
+ app:riv_corner_radius="2dp"
+ android:background="@drawable/message_border"
+ android:padding="1dp"
+ android:adjustViewBounds="true"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="16dp" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:layout_toRightOf="@+id/avater">
- <TextView
- android:id="@+id/account_jid_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/account_settings_jabber_id"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody" />
-
- <AutoCompleteTextView
- android:id="@+id/account_jid"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/account_settings_example_jabber_id"
- android:inputType="textEmailAddress"
- android:textColor="@color/black87"
- android:textColorHint="@color/black54"
- android:textSize="?attr/TextSizeBody" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:text="@string/account_settings_password"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody" />
-
- <EditText
- android:id="@+id/account_password"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/password"
- android:inputType="textPassword"
- android:textColor="@color/black87"
- android:textColorHint="@color/black54"
- android:textSize="?attr/TextSizeBody" />
+ android:layout_below="@+id/avater">
+ <TextView
+ android:id="@+id/account_jid_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/account_settings_jabber_id"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
- <CheckBox
- android:id="@+id/account_register_new"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:text="@string/register_account"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody" />
+ <AutoCompleteTextView
+ android:id="@+id/account_jid"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/account_settings_example_jabber_id"
+ android:inputType="textEmailAddress"
+ android:textColor="@color/black87"
+ android:textColorHint="@color/black54"
+ android:textSize="?attr/TextSizeBody" />
- <TextView
- android:id="@+id/account_confirm_password_desc"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/account_settings_confirm_password"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody"
- android:visibility="gone" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/account_settings_password"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
+
+ <EditText
+ android:id="@+id/account_password"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/password"
+ android:inputType="textPassword"
+ android:textColor="@color/black87"
+ android:textColorHint="@color/black54"
+ android:textSize="?attr/TextSizeBody" />
+
+ <CheckBox
+ android:id="@+id/account_register_new"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/register_account"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
- <EditText
- android:id="@+id/account_password_confirm"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:hint="@string/confirm_password"
- android:inputType="textPassword"
- android:visibility="gone"
- android:textColor="@color/black87"
- android:textColorHint="@color/black54"
- android:textSize="?attr/TextSizeBody" />
+ <TextView
+ android:id="@+id/account_confirm_password_desc"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/account_settings_confirm_password"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody"
+ android:visibility="gone" />
+
+ <EditText
+ android:id="@+id/account_password_confirm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:hint="@string/confirm_password"
+ android:inputType="textPassword"
+ android:visibility="gone"
+ android:textColor="@color/black87"
+ android:textColorHint="@color/black54"
+ android:textSize="?attr/TextSizeBody" />
</LinearLayout>
</RelativeLayout>
- <LinearLayout
+ <LinearLayout
android:id="@+id/stats"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
@@ -367,65 +373,65 @@
android:visibility="visible"
android:contentDescription="@string/copy_otr_clipboard_description"/>
</RelativeLayout>
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:id="@+id/axolotl_fingerprint_box"
- android:layout_marginTop="32dp">
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@+id/axolotl_actions"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/axolotl_fingerprint"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody"
- android:typeface="monospace"
- android:fontFamily="monospace"/>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/black54"
- android:textSize="?attr/TextSizeInfo"
- android:text="@string/this_device_omemo_fingerprint"/>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/axolotl_actions"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true"
- android:orientation="vertical">
-
- <ImageButton
- android:id="@+id/action_copy_axolotl_to_clipboard"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="?android:selectableItemBackground"
- android:padding="@dimen/image_button_padding"
- android:src="?attr/icon_copy"
- android:visibility="visible"
- android:contentDescription="@string/copy_omemo_clipboard_description"/>
- <ImageButton
- android:id="@+id/action_regenerate_axolotl_key"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="?android:selectableItemBackground"
- android:padding="@dimen/image_button_padding"
- android:src="?attr/icon_refresh"
- android:visibility="gone"
- android:contentDescription="@string/regenerate_omemo_key"/>
-
- </LinearLayout>
- </RelativeLayout>
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/axolotl_fingerprint_box"
+ android:layout_marginTop="32dp">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_toLeftOf="@+id/axolotl_actions"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/axolotl_fingerprint"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody"
+ android:typeface="monospace"
+ android:fontFamily="monospace"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/black54"
+ android:textSize="?attr/TextSizeInfo"
+ android:text="@string/this_device_omemo_fingerprint"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/axolotl_actions"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:orientation="vertical">
+
+ <ImageButton
+ android:id="@+id/action_copy_axolotl_to_clipboard"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="?android:selectableItemBackground"
+ android:padding="@dimen/image_button_padding"
+ android:src="?attr/icon_copy"
+ android:visibility="visible"
+ android:contentDescription="@string/copy_omemo_clipboard_description"/>
+ <ImageButton
+ android:id="@+id/action_regenerate_omemo_key"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="?android:selectableItemBackground"
+ android:padding="@dimen/image_button_padding"
+ android:src="?attr/icon_refresh"
+ android:visibility="gone"
+ android:contentDescription="@string/regenerate_omemo_key"/>
+
+ </LinearLayout>
+ </RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/other_device_keys_card"
diff --git a/src/main/res/layout/activity_muc_details.xml b/src/main/res/layout/activity_muc_details.xml
index 1a88424e4..3c7027ff3 100644
--- a/src/main/res/layout/activity_muc_details.xml
+++ b/src/main/res/layout/activity_muc_details.xml
@@ -1,184 +1,186 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@color/grey200">
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/activity_horizontal_margin"
- android:layout_marginRight="@dimen/activity_horizontal_margin"
- android:layout_marginTop="@dimen/activity_vertical_margin"
- android:layout_marginBottom="@dimen/activity_vertical_margin"
- android:background="@drawable/infocard_border"
- android:orientation="vertical"
- android:padding="@dimen/infocard_padding">
-
- <TextView
- android:id="@+id/muc_jabberid"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"
- android:text="@string/account_settings_example_jabber_id"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeHeadline"
- android:textStyle="bold"/>
-
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="32dp">
-
- <com.makeramen.roundedimageview.RoundedImageView
- android:id="@+id/your_photo"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_alignParentLeft="true"
- android:src="@drawable/ic_profile"
- app:riv_corner_radius="2dp" />
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_toRightOf="@+id/your_photo"
- android:orientation="vertical"
- android:paddingLeft="8dp">
-
- <TextView
- android:id="@+id/muc_your_nick"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeHeadline"/>
-
- <TextView
- android:id="@+id/muc_role"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody"/>
- </LinearLayout>
-
- <ImageButton
- android:id="@+id/edit_nick_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:background="?android:selectableItemBackground"
- android:padding="@dimen/image_button_padding"
- android:src="?attr/icon_edit_dark"/>
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/muc_conference_type"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/private_conference"
- android:layout_centerVertical="true"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@+id/change_conference_button"
- />
- <ImageButton
- android:id="@+id/change_conference_button"
- style="?android:attr/buttonStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:background="?android:selectableItemBackground"
- android:padding="@dimen/image_button_padding"
- android:src="?attr/icon_settings"/>
- </RelativeLayout>
-
- <TableLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/muc_info_more"
- android:stretchColumns="1"
- android:visibility="gone">
-
- <TableRow
- android:layout_width="fill_parent"
- android:layout_height="match_parent">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/server_info_mam"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody" />
-
- <TextView
- android:id="@+id/muc_info_mam"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="right"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody" />
- </TableRow>
-
- </TableLayout>
-
- <TextView
- android:id="@+id/details_account"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="right"
- android:layout_marginTop="32dp"
- android:text="@string/using_account"
- android:textColor="@color/black54"
- android:textSize="?attr/TextSizeInfo"/>
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/muc_more_details"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/activity_horizontal_margin"
- android:layout_marginRight="@dimen/activity_horizontal_margin"
- android:layout_marginTop="@dimen/activity_vertical_margin"
- android:layout_marginBottom="@dimen/activity_vertical_margin"
- android:background="@drawable/infocard_border"
- android:orientation="vertical"
- android:padding="@dimen/infocard_padding">
-
-
- <LinearLayout
- android:id="@+id/muc_members"
- android:layout_width="fill_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:divider="?android:dividerHorizontal"
- android:orientation="vertical"
- android:showDividers="middle">
- </LinearLayout>
-
- <Button
- android:id="@+id/invite"
- style="?android:attr/buttonStyleSmall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="24dp"
- android:text="@string/invite_contact"/>
- </LinearLayout>
-
- </LinearLayout>
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@color/grey200">
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/activity_vertical_margin"
+ android:layout_marginLeft="@dimen/activity_horizontal_margin"
+ android:layout_marginRight="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin"
+ android:background="@drawable/infocard_border"
+ android:orientation="vertical"
+ android:padding="@dimen/infocard_padding">
+
+ <TextView
+ android:id="@+id/muc_jabberid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:text="@string/account_settings_example_jabber_id"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeHeadline"
+ android:textStyle="bold" />
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="32dp">
+
+ <com.makeramen.roundedimageview.RoundedImageView
+ android:id="@+id/your_photo"
+ android:layout_width="72dp"
+ android:layout_height="72dp"
+ android:layout_alignParentEnd="false"
+ android:layout_alignParentLeft="true"
+ android:background="@drawable/message_border"
+ android:padding="1dp"
+ android:src="@drawable/ic_profile"
+ app:riv_corner_radius="2dp" />
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toRightOf="@+id/your_photo"
+ android:orientation="vertical"
+ android:paddingLeft="8dp">
+
+ <TextView
+ android:id="@+id/muc_your_nick"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeHeadline" />
+
+ <TextView
+ android:id="@+id/muc_role"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
+ </LinearLayout>
+
+ <ImageButton
+ android:id="@+id/edit_nick_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:background="?android:selectableItemBackground"
+ android:padding="@dimen/image_button_padding"
+ android:src="?attr/icon_edit_dark" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/muc_conference_type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_toLeftOf="@+id/change_conference_button"
+ android:text="@string/private_conference"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
+
+ <ImageButton
+ android:id="@+id/change_conference_button"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:layout_gravity="center_horizontal"
+ android:background="?android:selectableItemBackground"
+ android:padding="@dimen/image_button_padding"
+ android:src="?attr/icon_settings" />
+ </RelativeLayout>
+ <TableLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/muc_info_more"
+ android:stretchColumns="1"
+ android:visibility="gone">
+
+ <TableRow
+ android:layout_width="fill_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/server_info_mam"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
+
+ <TextView
+ android:id="@+id/muc_info_mam"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
+ </TableRow>
+
+ </TableLayout>
+
+ <TextView
+ android:id="@+id/details_account"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:layout_marginTop="32dp"
+ android:text="@string/using_account"
+ android:textColor="@color/black54"
+ android:textSize="?attr/TextSizeInfo" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/muc_more_details"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/activity_vertical_margin"
+ android:layout_marginLeft="@dimen/activity_horizontal_margin"
+ android:layout_marginRight="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin"
+ android:background="@drawable/infocard_border"
+ android:orientation="vertical"
+ android:padding="@dimen/infocard_padding">
+
+
+ <LinearLayout
+ android:id="@+id/muc_members"
+ android:layout_width="fill_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:divider="?android:dividerHorizontal"
+ android:orientation="vertical"
+ android:showDividers="middle"></LinearLayout>
+
+ <Button
+ android:id="@+id/invite"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="24dp"
+ android:text="@string/invite_contact" />
+ </LinearLayout>
+
+ </LinearLayout>
</ScrollView> \ No newline at end of file
diff --git a/src/main/res/layout/activity_publish_profile_picture.xml b/src/main/res/layout/activity_publish_profile_picture.xml
index 3b249a665..e5113dab9 100644
--- a/src/main/res/layout/activity_publish_profile_picture.xml
+++ b/src/main/res/layout/activity_publish_profile_picture.xml
@@ -1,43 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/grey50" >
-
+ android:background="@color/grey200">
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_above="@+id/button_bar"
+ android:layout_alignParentTop="true" >
<LinearLayout
- android:id="@+id/account_image_wrapper"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true"
- android:layout_marginBottom="8dp"
- android:layout_marginTop="24dp"
- android:background="@drawable/account_image_border" >
-
- <ImageView
- android:id="@+id/account_image"
- android:layout_width="194dp"
- android:layout_height="194dp" />
- </LinearLayout>
+ android:orientation="vertical"
+ android:gravity="center_horizontal">
- <TextView
- android:id="@+id/hint"
- android:layout_width="wrap_content"
+ <LinearLayout
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/account_image_wrapper"
- android:layout_centerHorizontal="true"
- android:text="@string/touch_to_choose_picture"
- android:textColor="@color/black54" />
+ android:layout_above="@+id/button_bar"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/secondary_hint"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:layout_marginRight="@dimen/activity_horizontal_margin"
+ android:layout_marginLeft="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin"
+ android:layout_marginBottom="@dimen/activity_vertical_margin"
+ android:background="@drawable/infocard_border">
- <TextView
- android:id="@+id/secondary_hint"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/hint"
- android:layout_centerHorizontal="true"
- android:text="@string/or_long_press_for_default"
- android:textColor="@color/black54" />
+ <LinearLayout
+ android:id="@+id/account_image_wrapper"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="8dp"
+ android:layout_marginTop="24dp"
+ android:background="@drawable/account_image_border"
+ android:layout_gravity="center_horizontal">
+
+ <ImageView
+ android:id="@+id/account_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxHeight="384dp"
+ android:maxWidth="384dp"
+ android:adjustViewBounds="true"
+ android:padding="1dp"
+ android:background="@drawable/message_border" />
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/hint"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/account_image_wrapper"
+ android:layout_centerHorizontal="true"
+ android:text="@string/touch_to_choose_picture"
+ android:textColor="@color/black54"
+ android:layout_marginLeft="@dimen/activity_horizontal_margin"
+ android:layout_marginRight="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin"
+ android:layout_marginBottom="@dimen/activity_vertical_margin"
+ android:layout_gravity="center_horizontal" />
+
+ <TextView
+ android:id="@+id/secondary_hint"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/hint"
+ android:layout_centerHorizontal="true"
+ android:text="@string/or_long_press_for_default"
+ android:textColor="@color/black54"
+ android:layout_marginBottom="@dimen/activity_vertical_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin"
+ android:layout_marginLeft="@dimen/activity_horizontal_margin"
+ android:layout_marginRight="@dimen/activity_horizontal_margin"
+ android:layout_gravity="center_horizontal" />
+
+ <TextView
+ android:id="@+id/account"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeHeadline" />
+ <TextView
+ android:id="@+id/hint_or_warning"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:minLines="3"
+ android:text="@string/publish_avatar_explanation"
+ android:textColor="@color/black87"
+ android:textSize="?attr/TextSizeBody" />
+ </LinearLayout>
+</LinearLayout>
+ </ScrollView>
<LinearLayout
android:id="@+id/button_bar"
android:layout_width="wrap_content"
@@ -73,34 +137,4 @@
android:textColor="@color/black54" />
</LinearLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:layout_above="@+id/button_bar"
- android:layout_alignParentLeft="true"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/secondary_hint"
- android:gravity="center_vertical"
- android:orientation="vertical"
- android:paddingLeft="8dp"
- android:paddingRight="8dp" >
-
- <TextView
- android:id="@+id/account"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeHeadline" />
-
- <TextView
- android:id="@+id/hint_or_warning"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:minLines="3"
- android:text="@string/publish_avatar_explanation"
- android:textColor="@color/black87"
- android:textSize="?attr/TextSizeBody" />
- </LinearLayout>
-
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/src/main/res/layout/activity_updater.xml b/src/main/res/layout/activity_updater.xml
new file mode 100644
index 000000000..50bdf0695
--- /dev/null
+++ b/src/main/res/layout/activity_updater.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="eu.siacs.conversations.ui.UpdaterActivity">
+
+ <TextView android:id="@+id/updater" android:layout_width="wrap_content"
+ android:layout_height="wrap_content" android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true" android:layout_marginTop="6dp"
+ android:text="Current" android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="normal"
+ android:layout_marginLeft="4dp"
+ android:layout_marginRight="4dp" />
+
+</RelativeLayout>
diff --git a/src/main/res/layout/contact.xml b/src/main/res/layout/contact.xml
index 56443c346..653bb9176 100644
--- a/src/main/res/layout/contact.xml
+++ b/src/main/res/layout/contact.xml
@@ -8,11 +8,12 @@
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/contact_photo"
- android:layout_width="48dp"
- android:layout_height="48dp"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
android:layout_alignParentLeft="true"
- android:scaleType="centerCrop"
android:src="@drawable/ic_profile"
+ android:background="@drawable/message_border"
+ android:padding="1dp"
app:riv_corner_radius="2dp" />
<LinearLayout
diff --git a/src/main/res/layout/conversation_list_row.xml b/src/main/res/layout/conversation_list_row.xml
index 7321b0f66..575647f0a 100644
--- a/src/main/res/layout/conversation_list_row.xml
+++ b/src/main/res/layout/conversation_list_row.xml
@@ -28,6 +28,8 @@
android:layout_height="56dp"
android:layout_alignParentLeft="true"
android:scaleType="centerCrop"
+ android:background="@drawable/message_border"
+ android:padding="1dp"
app:riv_corner_radius="2dp" />
<RelativeLayout
@@ -68,7 +70,7 @@
<ImageView
android:id="@+id/conversation_lastimage"
android:layout_width="fill_parent"
- android:layout_height="36dp"
+ android:layout_height="14dp"
android:background="@color/black87"
android:scaleType="centerCrop" />
</LinearLayout>
diff --git a/src/main/res/layout/message_received.xml b/src/main/res/layout/message_received.xml
index 76df710bf..07cca2c1e 100644
--- a/src/main/res/layout/message_received.xml
+++ b/src/main/res/layout/message_received.xml
@@ -17,6 +17,8 @@
android:layout_alignParentTop="true"
android:scaleType="fitXY"
android:src="@drawable/ic_profile"
+ android:background="@drawable/message_border"
+ android:padding="1dp"
app:riv_corner_radius="2dp" />
<LinearLayout
@@ -94,5 +96,4 @@
</LinearLayout>
</LinearLayout>
</LinearLayout>
-
</RelativeLayout> \ No newline at end of file
diff --git a/src/main/res/layout/message_sent.xml b/src/main/res/layout/message_sent.xml
index e3b38cd97..aa3aad722 100644
--- a/src/main/res/layout/message_sent.xml
+++ b/src/main/res/layout/message_sent.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="3dp"
android:paddingLeft="8dp"
@@ -14,7 +14,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
- android:paddingBottom="3dp"
+ android:background="@drawable/message_border"
+ android:padding="1dp"
android:src="@drawable/ic_profile"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
@@ -99,11 +100,18 @@
android:layout_height="?attr/TextSizeInfo"
android:layout_gravity="center_vertical"
android:layout_marginLeft="4sp"
- android:alpha="0.54"
android:gravity="center_vertical"
android:src="@drawable/ic_received_indicator" />
+ <ImageView
+ android:id="@+id/indicator_read"
+ android:layout_width="?attr/TextSizeInfo"
+ android:layout_height="?attr/TextSizeInfo"
+ android:layout_gravity="center_vertical"
+ android:gravity="center_vertical"
+ android:src="@drawable/ic_read_indicator"
+ android:layout_marginLeft="-8sp"
+ android:adjustViewBounds="false" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
-
</RelativeLayout> \ No newline at end of file
diff --git a/src/main/res/layout/message_status.xml b/src/main/res/layout/message_status.xml
index ad2579faa..2f14cbf54 100644
--- a/src/main/res/layout/message_status.xml
+++ b/src/main/res/layout/message_status.xml
@@ -16,9 +16,10 @@
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginRight="-1.5dp"
- android:padding="0dp"
+ android:padding="1dp"
android:scaleType="fitXY"
android:src="@drawable/ic_profile"
+ android:background="@drawable/message_border"
app:riv_corner_radius="1dp"/>
<TextView
diff --git a/src/main/res/menu/conversations.xml b/src/main/res/menu/conversations.xml
index 4c724d27d..47214a6b7 100644
--- a/src/main/res/menu/conversations.xml
+++ b/src/main/res/menu/conversations.xml
@@ -20,14 +20,15 @@
android:title="@string/attach_file"/>
<item
android:id="@+id/action_contact_details"
+ android:icon="?attr/icon_group"
android:orderInCategory="40"
- android:showAsAction="never"
+ android:showAsAction="always"
android:title="@string/action_contact_details"/>
<item
android:id="@+id/action_muc_details"
android:icon="?attr/icon_group"
android:orderInCategory="40"
- android:showAsAction="ifRoom"
+ android:showAsAction="always"
android:title="@string/action_muc_details"/>
<item
android:id="@+id/action_invite"
@@ -66,5 +67,10 @@
android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_settings"/>
+ <item
+ android:id="@+id/action_check_updates"
+ android:orderInCategory="100"
+ android:showAsAction="never"
+ android:title="@string/action_check_update"/>
</menu> \ No newline at end of file
diff --git a/src/main/res/menu/menu_updater.xml b/src/main/res/menu/menu_updater.xml
new file mode 100644
index 000000000..f52657372
--- /dev/null
+++ b/src/main/res/menu/menu_updater.xml
@@ -0,0 +1,7 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context="eu.siacs.conversations.ui.UpdaterActivity">
+ <item android:id="@+id/action_settings" android:title="@string/action_settings"
+ android:orderInCategory="100" app:showAsAction="never" />
+</menu>
diff --git a/src/main/res/menu/muc_details_context.xml b/src/main/res/menu/muc_details_context.xml
index af5e691b7..4a8b13d16 100644
--- a/src/main/res/menu/muc_details_context.xml
+++ b/src/main/res/menu/muc_details_context.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item
+ <item
android:id="@+id/start_conversation"
android:title="@string/start_conversation"
android:visible="false"/>
diff --git a/src/main/res/values-bg/strings.xml b/src/main/res/values-bg/strings.xml
index 030432ad6..11c3446b9 100644
--- a/src/main/res/values-bg/strings.xml
+++ b/src/main/res/values-bg/strings.xml
@@ -443,6 +443,7 @@
<string name="hide_offline">Скриване на тези извън линия</string>
<string name="disable_account">Деактивиране на профила</string>
<string name="contact_is_typing">%s пише...</string>
+ <string name="is_typing">пише...</string>
<string name="contact_has_stopped_typing">%s спря да пише</string>
<string name="pref_chat_states">Известия за писането</string>
<string name="pref_chat_states_summary">Позволяване на контакта Ви да вижда, когато пишете ново съобщение</string>
diff --git a/src/main/res/values-ca/strings.xml b/src/main/res/values-ca/strings.xml
index 806ed7a03..43db6f5fb 100644
--- a/src/main/res/values-ca/strings.xml
+++ b/src/main/res/values-ca/strings.xml
@@ -407,6 +407,7 @@
<string name="hide_offline">Amaga el fora de línia</string>
<string name="disable_account">Deshabilita el compte</string>
<string name="contact_is_typing">%s està escrivint...</string>
+ <string name="is_typing">està escrivint...</string>
<string name="contact_has_stopped_typing">%s ha deixat d\'escriure</string>
<string name="pref_chat_states">Notificacions d\'escriptura</string>
<string name="pref_chat_states_summary">Permet el teu contacte saber quan estàs escrivint un missatge nou</string>
diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml
index 0c5dca552..57f93f5cd 100644
--- a/src/main/res/values-cs/strings.xml
+++ b/src/main/res/values-cs/strings.xml
@@ -439,6 +439,7 @@
<string name="hide_offline">Skrýt offline</string>
<string name="disable_account">Vypnout účet</string>
<string name="contact_is_typing">%s píše...</string>
+ <string name="is_typing">píše...</string>
<string name="contact_has_stopped_typing">%s přestal(a) psát</string>
<string name="pref_chat_states">Upozornění při psaní</string>
<string name="pref_chat_states_summary">Oznamovat kontaktům že píšete novou zprávu</string>
diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml
index b7cc4440f..6b8e08657 100644
--- a/src/main/res/values-de/strings.xml
+++ b/src/main/res/values-de/strings.xml
@@ -1,4 +1,4 @@
-<?xml version='1.0' encoding='UTF-8'?>
+<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="action_settings">Einstellungen</string>
<string name="action_add">Neue Unterhaltung</string>
@@ -76,12 +76,12 @@
<string name="delete_messages">Nachrichten löschen</string>
<string name="also_end_conversation">Diese Unterhaltung danach beenden</string>
<string name="choose_presence">Ressource des Kontakts auswählen</string>
- <string name="send_unencrypted_message">Unverschlüsselt schreiben…</string>
+ <string name="send_unencrypted_message">Normal schreiben…</string>
<string name="send_otr_message">OTR-verschlüsselt schreiben…</string>
<string name="send_omemo_message">OMEMO-verschlüsselt schreiben…</string>
<string name="send_pgp_message">OpenPGP-verschlüsselt schreiben…</string>
<string name="your_nick_has_been_changed">Dein Nickname wurde geändert</string>
- <string name="send_unencrypted">Unverschlüsselt senden</string>
+ <string name="send_unencrypted">Normal verschicken</string>
<string name="decryption_failed">Entschlüsselung fehlgeschlagen. Vielleicht hast du nicht den richtigen privaten Schlüssel.</string>
<string name="openkeychain_required">OpenKeychain</string>
<string name="openkeychain_required_long">Conversations benutzt eine Drittanwendung namens <b>OpenKeychain</b>, um Nachrichten zu ver- und entschlüsseln und um deine Schlüssel zu verwalten.\n\nOpenKeychain ist GPLv3-lizenziert und kann über F-Droid oder Google Play bezogen werden.\n\n<small>(Bitte starte Conversations danach neu.)</small></string>
@@ -212,7 +212,7 @@
<string name="this_device_omemo_fingerprint">Eigener OMEMO-Fingerabdruck</string>
<string name="other_devices">Andere Geräte</string>
<string name="trust_omemo_fingerprints">OMEMO-Fingerabdruck vertrauen</string>
- <string name="fetching_keys">Schlüssel abrufen...</string>
+ <string name="fetching_keys">Schlüssel abrufen…</string>
<string name="done">Erledigt</string>
<string name="verify">Überprüfen</string>
<string name="decrypt">Entschlüsseln</string>
@@ -335,12 +335,9 @@
<string name="conversations_foreground_service">Conversations</string>
<string name="pref_keep_foreground_service">Den Dienst im Vordergrund ausführen.</string>
<string name="pref_keep_foreground_service_summary">Verhindert, dass Android Conversations beendet und die Verbindung unterbricht</string>
- <string name="pref_export_logs">Chats exportieren</string>
- <string name="pref_export_logs_summary">Chats auf SD-Karte schreiben</string>
- <string name="notification_export_logs_title">Chats auf SD-Karte schreiben</string>
<string name="choose_file">Datei auswählen</string>
- <string name="receiving_x_file">Empfange %1$s (%2$d%% abgeschlossen)</string>
- <string name="download_x_file">%s wird heruntergeladen</string>
+ <string name="receiving_x_file">Empfange %1$s (%2$d%% abgeschlossen)</string>
+ <string name="download_x_file">%s herunterladen</string>
<string name="file">Datei</string>
<string name="open_x_file">%s öffnen</string>
<string name="sending_file">Senden (%1$d%% abgeschlossen)</string>
@@ -443,6 +440,7 @@
<string name="hide_offline">Offline verstecken</string>
<string name="disable_account">Konto abschalten</string>
<string name="contact_is_typing">%s schreibt…</string>
+ <string name="is_typing">schreibt…</string>
<string name="contact_has_stopped_typing">%s schreibt nicht mehr</string>
<string name="pref_chat_states">Tipp-Benachrichtigung</string>
<string name="pref_chat_states_summary">Informiere deine Kontakte, wenn du eine Nachricht eintippst.</string>
@@ -475,6 +473,7 @@
<string name="recently_used">zuletzt verwendet</string>
<string name="choose_quick_action">wähle Schnell-Taste</string>
<string name="search_for_contacts_or_groups">Nach Kontakten oder Konferenzen suchen</string>
+ <string name="elv_undo">Rückgängig</string>
<string name="send_private_message">Private Nachricht senden</string>
<string name="user_has_left_conference">%s hat die Konferenz verlassen!</string>
<string name="username">Benutzername</string>
@@ -485,8 +484,22 @@
<string name="download_failed_could_not_connect">Download fehlgeschlagen: keine Verbindung zum Host</string>
<string name="pref_use_white_background">Weißen Hintergrund benutzen</string>
<string name="pref_use_white_background_summary">Empfangene Nachrichten als schwarzen Text auf weißem Hintergrund anzeigen</string>
+ <string name="action_check_update">Auf Updates prüfen</string>
+ <string name="current_version">Installierte Version:</string>
+ <string name="new_version">Neue Version: </string>
+ <string name="remind_later">später</string>
+ <string name="checking_for_updates">Auf Conversations Updates prüfen</string>
+ <string name="title_activity_updater">Update Dienst</string>
+ <string name="update">Aktualisieren</string>
+ <string name="update_available">Conversations %1$s mit folgenden Änderungen ist verfügbar:\n\n%2$s\n\nMöchtest Du von Conversations %3$s auf Conversations %1$s aktualisieren?</string>
+ <string name="download_started">Download gestartet</string>
+ <string name="no_update_available">Kein Update verfügbar</string>
<string name="account_status_dns_timeout">Zeitüberschreitung bei der Namensauflösung</string>
<string name="server_info_broken">Fehlerhaft</string>
+ <string name="update_info">Conversation prüft auf eine neuere Version. Wenn ein Update verfügbar ist, wirst du gefragt, ob du deine Version aktualisieren möchtest. Der Update Dienst lädt und installiert die neue Version automatisch.</string>
+ <string name="notification_export_logs_title">Schreibe Chats auf SD Karte</string>
+ <string name="pref_export_logs">Exportiere Chats</string>
+ <string name="pref_export_logs_summary">Schreibe Chats auf SD Karte</string>
<string name="pref_presence_settings">Status Einstellungen</string>
<string name="pref_away_when_screen_off">Abwesend</string>
<string name="pref_away_when_screen_off_summary">Setze deinen Status auf abwesend, wenn dein Bildschirm abgeschaltet ist</string>
@@ -501,4 +514,5 @@
<string name="certificate_chain_is_not_trusted">Zertifikat wird nicht vertraut</string>
<string name="jid_does_not_match_certificate">Jabber-ID stimmt nicht dem Zertifikat überein</string>
<string name="action_renew_certificate">Zertifikat erneuern</string>
+
</resources>
diff --git a/src/main/res/values-el/strings.xml b/src/main/res/values-el/strings.xml
index ed38d0c06..ef1e9532b 100644
--- a/src/main/res/values-el/strings.xml
+++ b/src/main/res/values-el/strings.xml
@@ -407,6 +407,7 @@
<string name="hide_offline">Απόκρυψη των εκτός σύνδεσης</string>
<string name="disable_account">Απενεργοποίηση λογαριασμού</string>
<string name="contact_is_typing">Ο χρήστης %s γράφει...</string>
+ <string name="is_typing">Ο χρήστης γράφει...</string>
<string name="contact_has_stopped_typing">Ο χρήστης %s σταμάτησε να γράφει</string>
<string name="pref_chat_states">Ειδοποιήσεις πληκτρολόγησης</string>
<string name="pref_chat_states_summary">Επιτρέψτε στην επαφή σας να γνωρίζει πότε γράφετε ένα νέο μήνυμα</string>
diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml
index cdddfb164..0494225cd 100644
--- a/src/main/res/values-es/strings.xml
+++ b/src/main/res/values-es/strings.xml
@@ -443,6 +443,7 @@
<string name="hide_offline">Ocultar desconectados</string>
<string name="disable_account">Deshabilitar Cuenta</string>
<string name="contact_is_typing">%s está escribiendo...</string>
+ <string name="is_typing">está escribiendo...</string>
<string name="contact_has_stopped_typing">%s ha dejado de escribir</string>
<string name="pref_chat_states">Notificación de escritura</string>
<string name="pref_chat_states_summary">Permite a tus contactos saber cuando estás escribiendo un nuevo mensaje</string>
diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml
index 86f39b0f6..d3dfa995f 100644
--- a/src/main/res/values-eu/strings.xml
+++ b/src/main/res/values-eu/strings.xml
@@ -439,6 +439,7 @@
<string name="hide_offline">Lineaz kanpokoak ezkutatu</string>
<string name="disable_account">Kontua ezgaitu</string>
<string name="contact_is_typing">%s idazten ari da...</string>
+ <string name="is_typing">idazten ari da...</string>
<string name="contact_has_stopped_typing">%s(e)k idazteari utzi dio</string>
<string name="pref_chat_states">Idazketa jakinarazpenak</string>
<string name="pref_chat_states_summary">Zure kontaktuak mezu berri bat noiz idazten ari zaren jakin dezan baimendu</string>
diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml
index b6c5f0daf..90ce584db 100644
--- a/src/main/res/values-fr/strings.xml
+++ b/src/main/res/values-fr/strings.xml
@@ -439,6 +439,7 @@
<string name="hide_offline">Se cacher hors-ligne</string>
<string name="disable_account">Désactiver le compte</string>
<string name="contact_is_typing">%s écrit un message...</string>
+ <string name="is_typing">écrit un message...</string>
<string name="contact_has_stopped_typing">%s a arrêté d\'écrire</string>
<string name="pref_chat_states">Notifications d\'écriture</string>
<string name="pref_chat_states_summary">Permettre à votre contact de savoir que vous écrivez un message</string>
diff --git a/src/main/res/values-id/strings.xml b/src/main/res/values-id/strings.xml
index 894c18a71..6c22c1323 100644
--- a/src/main/res/values-id/strings.xml
+++ b/src/main/res/values-id/strings.xml
@@ -412,6 +412,7 @@
<string name="hide_offline">Sembunyikan Offline</string>
<string name="disable_account">Nonaktifkan Akun</string>
<string name="contact_is_typing">%s sedang mengetik...</string>
+ <string name="is_typing">sedang mengetik...</string>
<string name="contact_has_stopped_typing">%s telah berhenti mengetik</string>
<string name="pref_chat_states">Notifikasi ketik pesan</string>
<string name="pref_chat_states_summary">Biarkan kontak Anda tahu ketika Anda sedang menulis pesan baru</string>
diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml
index 97311427c..31d4a29ef 100644
--- a/src/main/res/values-it/strings.xml
+++ b/src/main/res/values-it/strings.xml
@@ -408,6 +408,7 @@
<string name="hide_offline">Nascondi i contatti offline</string>
<string name="disable_account">Disabilita l\'account</string>
<string name="contact_is_typing">%s sta digitando...</string>
+ <string name="is_typing">sta digitando...</string>
<string name="contact_has_stopped_typing">%s ha smesso di digitare</string>
<string name="pref_chat_states_summary">Permetti al tuo contatto di vedere quando stai digitando</string>
<string name="send_location">Invia la posizione</string>
diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml
index 45c67940e..c30c87ff2 100644
--- a/src/main/res/values-ja/strings.xml
+++ b/src/main/res/values-ja/strings.xml
@@ -439,6 +439,7 @@
<string name="hide_offline">オフラインを非表示にする</string>
<string name="disable_account">アカウントを無効にする</string>
<string name="contact_is_typing">%s は入力中...</string>
+ <string name="is_typing">は入力中...</string>
<string name="contact_has_stopped_typing">%s は入力を停止しました</string>
<string name="pref_chat_states">入力中通知</string>
<string name="pref_chat_states_summary">あなたが新しいメッセージを書いている時に、連絡先に知らせます</string>
diff --git a/src/main/res/values-ko/strings.xml b/src/main/res/values-ko/strings.xml
index 6f654dcf7..6566724b0 100644
--- a/src/main/res/values-ko/strings.xml
+++ b/src/main/res/values-ko/strings.xml
@@ -407,6 +407,7 @@
<string name="hide_offline">오프라인 숨기기 </string>
<string name="disable_account">계정 해제 </string>
<string name="contact_is_typing">%s 이(가) 입력중입니다... </string>
+ <string name="is_typing">이(가) 입력중입니다... </string>
<string name="contact_has_stopped_typing">%s 이(가) 입력을 중단했습니다 </string>
<string name="pref_chat_states">입력 알림 </string>
<string name="pref_chat_states_summary">새 메세지를 작성할 때 이를 연락처에게 알립니다 </string>
diff --git a/src/main/res/values-ms/strings.xml b/src/main/res/values-ms/strings.xml
new file mode 100644
index 000000000..c757504ac
--- /dev/null
+++ b/src/main/res/values-ms/strings.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources/>
diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml
index 61d57b260..1507865bf 100644
--- a/src/main/res/values-nl/strings.xml
+++ b/src/main/res/values-nl/strings.xml
@@ -439,6 +439,7 @@
<string name="hide_offline">Offline contacten verbergen</string>
<string name="disable_account">Account uitschakelen</string>
<string name="contact_is_typing">%s is aan het typen...</string>
+ <string name="is_typing">is aan het typen...</string>
<string name="contact_has_stopped_typing">%s is gestopt met typen</string>
<string name="pref_chat_states">Aan-het-typen-meldingen</string>
<string name="pref_chat_states_summary">Laat je contacten weten wanneer je een nieuw bericht aan het schrijven bent</string>
diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml
index 408672ca1..16df1b3b3 100644
--- a/src/main/res/values-pl/strings.xml
+++ b/src/main/res/values-pl/strings.xml
@@ -439,6 +439,7 @@
<string name="hide_offline">Ukryj niedostępnych</string>
<string name="disable_account">Wyłącz konto</string>
<string name="contact_is_typing">%s pisze...</string>
+ <string name="is_typing">pisze...</string>
<string name="contact_has_stopped_typing">%s przestał(a) pisać</string>
<string name="pref_chat_states">Powiadomienia pisania</string>
<string name="pref_chat_states_summary">Powiadamiaj rozmówcę, kiedy rozpoczynasz nową wiadomość</string>
diff --git a/src/main/res/values-pt/strings.xml b/src/main/res/values-pt/strings.xml
index 57f9d7c6e..c0614d88f 100644
--- a/src/main/res/values-pt/strings.xml
+++ b/src/main/res/values-pt/strings.xml
@@ -282,6 +282,7 @@
<string name="sending_x_file">Enviando %s</string>
<string name="offering_x_file">Oferecendo %s</string>
<string name="contact_is_typing">%s está digitando...</string>
+ <string name="is_typing">está digitando...</string>
<string name="contact_has_stopped_typing">%s parou de digitar</string>
<string name="pref_chat_states">Notificações de digitação</string>
<string name="send_location">Enviar localização</string>
diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml
index 4c5c205fe..54ea80bc8 100644
--- a/src/main/res/values-ru/strings.xml
+++ b/src/main/res/values-ru/strings.xml
@@ -421,6 +421,7 @@
<string name="hide_offline">Скрыть пользователей вне сети</string>
<string name="disable_account">Отключить учётную запись</string>
<string name="contact_is_typing">%s набирает сообщение...</string>
+ <string name="is_typing">набирает сообщение...</string>
<string name="contact_has_stopped_typing">%s прекратил набор</string>
<string name="pref_chat_states">Оповещения о наборе</string>
<string name="pref_chat_states_summary">Позволяет вашим контактам видеть когда вы пишете новое сообщение</string>
diff --git a/src/main/res/values-sk/strings.xml b/src/main/res/values-sk/strings.xml
index b0f982c20..b8a3993e0 100644
--- a/src/main/res/values-sk/strings.xml
+++ b/src/main/res/values-sk/strings.xml
@@ -409,6 +409,7 @@
<string name="hide_offline">Skryť neprihlásených</string>
<string name="disable_account">Vypnúť účet</string>
<string name="contact_is_typing">%s píše...</string>
+ <string name="is_typing">píše...</string>
<string name="contact_has_stopped_typing">%s prestal písať</string>
<string name="pref_chat_states">Upozornenia pri písaní</string>
<string name="pref_chat_states_summary">Upozorniť kontakt, keď píšete novú správu</string>
diff --git a/src/main/res/values-sr/strings.xml b/src/main/res/values-sr/strings.xml
index 5cf49475f..a251fbcd8 100644
--- a/src/main/res/values-sr/strings.xml
+++ b/src/main/res/values-sr/strings.xml
@@ -439,6 +439,7 @@
<string name="hide_offline">Сакриј неповезане</string>
<string name="disable_account">Онемогући налог</string>
<string name="contact_is_typing">%s куца...</string>
+ <string name="is_typing">куца...</string>
<string name="contact_has_stopped_typing">%s престаде да куца</string>
<string name="pref_chat_states">Обавештења о куцању</string>
<string name="pref_chat_states_summary">Обзнаните контакту кад куцате нову поруку</string>
diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml
index 90a0248ed..34a11698c 100644
--- a/src/main/res/values-sv/strings.xml
+++ b/src/main/res/values-sv/strings.xml
@@ -439,6 +439,7 @@
<string name="hide_offline">Dölj ej anslutna</string>
<string name="disable_account">Deaktivera konton</string>
<string name="contact_is_typing">%s skriver...</string>
+ <string name="is_typing">skriver...</string>
<string name="contact_has_stopped_typing">%s har slutat skriva</string>
<string name="pref_chat_states">Skriv-notifieringar</string>
<string name="pref_chat_states_summary">Låter dina kontakter veta när du skriver ett nytt meddelande</string>
diff --git a/src/main/res/values-w820dp/dimens.xml b/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 000000000..63fc81644
--- /dev/null
+++ b/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+ <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+ (such as screen margins) for screens with more than 820dp of available width. This
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml
index 455d13a8b..8c41f1950 100644
--- a/src/main/res/values-zh-rCN/strings.xml
+++ b/src/main/res/values-zh-rCN/strings.xml
@@ -282,6 +282,8 @@
<string name="conference_members_only">此讨论组只允许成员加入</string>
<string name="conference_kicked">你被从此讨论组踢出</string>
<string name="using_account">用账户 %s</string>
+ <string name="checking_file">正在 HTTP 托管中检查图片</string>
+ <string name="image_file_deleted">此图片已经被删除</string>
<string name="not_connected_try_again">你没有连接。请稍后重试</string>
<string name="message_options">消息选项</string>
<string name="copy_text">拷贝文本</string>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index c4ba759b0..9331bb752 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">Conversations</string>
@@ -214,7 +214,7 @@
<string name="this_device_omemo_fingerprint">Own OMEMO fingerprint</string>
<string name="other_devices">Other devices</string>
<string name="trust_omemo_fingerprints">Trust OMEMO Fingerprints</string>
- <string name="fetching_keys">Fetching keys...</string>
+ <string name="fetching_keys">Fetching keys…</string>
<string name="done">Done</string>
<string name="verify">Verify</string>
<string name="decrypt">Decrypt</string>
@@ -283,7 +283,7 @@
<string name="pref_about_conversations_summary">Build and licensing information</string>
<string name="pref_about_message" translatable="false">
Conversations • the very last word in instant messaging.
- \n\nCopyright © 2014-2015 Daniel Gultsch
+ \n\nCopyright © 2014 Daniel Gultsch
\n\nThis program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -474,7 +474,8 @@
<string name="offering_x_file">Offering %s</string>
<string name="hide_offline">Hide offline</string>
<string name="disable_account">Disable Account</string>
- <string name="contact_is_typing">%s is typing...</string>
+ <string name="contact_is_typing">%s is typing…</string>
+ <string name="is_typing">is typing…</string>
<string name="contact_has_stopped_typing">%s has stopped typing</string>
<string name="pref_chat_states">Typing notifications</string>
<string name="pref_chat_states_summary">Let your contact know when you are writing a new message</string>
@@ -515,15 +516,27 @@
<string name="download_failed_server_not_found">Download failed: Server not found</string>
<string name="download_failed_file_not_found">Download failed: File not found</string>
<string name="download_failed_could_not_connect">Download failed: Could not connect to host</string>
+ <string name="elv_undo">undo</string>
<string name="pref_use_white_background">Use white background</string>
<string name="pref_use_white_background_summary">Show received messages as black text on a white background</string>
<string name="account_status_dns_timeout">Timeout in DNS</string>
+ <string name="action_check_update">Check for Updates</string>
+ <string name="title_activity_updater">Update Service</string>
+ <string name="update_available">Conversations %1$s with the following changes is available:\n\n%2$s\n\nUpdate Conversations %3$s to Conversations %1$s now?</string>
+ <string name="checking_for_updates">Checking for Conversations updates</string>
+ <string name="remind_later">later</string>
+ <string name="update">Update</string>
+ <string name="new_version">New version:</string>
+ <string name="current_version">installed version:</string>
+ <string name="no_update_available">No update available</string>
+ <string name="download_started">Download started</string>
<string name="server_info_broken">Broken</string>
<string name="pref_presence_settings">Presence settings</string>
<string name="pref_away_when_screen_off">Away when screen is off</string>
<string name="pref_away_when_screen_off_summary">Marks your resource as away when the screen is turned off</string>
<string name="pref_xa_on_silent_mode">Not available in silent mode</string>
<string name="pref_xa_on_silent_mode_summary">Marks your resource as not available when phone is in silent mode</string>
+ <string name="update_info">Conversation is checking for an update. If an update is available you will be asked, if you want to update your version. The update process is downloading and installing the new version automatically.</string>
<string name="action_add_account_with_certificate">Add account with certificate</string>
<string name="unable_to_parse_certificate">Unable to parse certificate</string>
<string name="authenticate_with_certificate">Leave empty to authenticate w/ certificate</string>
diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml
index f05738ac5..183e37233 100644
--- a/src/main/res/xml/preferences.xml
+++ b/src/main/res/xml/preferences.xml
@@ -16,7 +16,7 @@
android:summary="@string/pref_xmpp_resource_summary"
android:title="@string/pref_xmpp_resource"/>
<ListPreference
- android:defaultValue="524288"
+ android:defaultValue="1048576"
android:entries="@array/filesizes"
android:entryValues="@array/filesizes_values"
android:key="auto_accept_file_size"
@@ -30,7 +30,7 @@
android:title="@string/pref_confirm_messages"/>
<CheckBoxPreference
- android:defaultValue="false"
+ android:defaultValue="true"
android:key="chat_states"
android:summary="@string/pref_chat_states_summary"
android:title="@string/pref_chat_states"/>
@@ -106,7 +106,7 @@
android:summary="@string/pref_use_larger_font_summary"
android:title="@string/pref_use_larger_font"/>
<CheckBoxPreference
- android:defaultValue="false"
+ android:defaultValue="true"
android:key="send_button_status"
android:summary="@string/pref_use_send_button_to_indicate_status_summary"
android:title="@string/pref_use_send_button_to_indicate_status"/>
@@ -123,6 +123,11 @@
android:key="show_dynamic_tags"
android:summary="@string/pref_show_dynamic_tags_summary"
android:title="@string/pref_show_dynamic_tags"/>
+ <CheckBoxPreference
+ android:defaultValue="true"
+ android:key="indicate_received"
+ android:summary="@string/pref_use_indicate_received_summary"
+ android:title="@string/pref_use_indicate_received"/>
</PreferenceCategory>
<PreferenceCategory
android:key="advanced"
@@ -173,12 +178,7 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/pref_expert_options_other">
<CheckBoxPreference
- android:defaultValue="false"
- android:key="indicate_received"
- android:summary="@string/pref_use_indicate_received_summary"
- android:title="@string/pref_use_indicate_received"/>
- <CheckBoxPreference
- android:defaultValue="false"
+ android:defaultValue="true"
android:key="keep_foreground_service"
android:summary="@string/pref_keep_foreground_service_summary"
android:title="@string/pref_keep_foreground_service"/>
@@ -190,7 +190,7 @@
</PreferenceScreen>
<CheckBoxPreference
- android:defaultValue="false"
+ android:defaultValue="true"
android:key="never_send"
android:summary="@string/pref_never_send_crash_summary"
android:title="@string/pref_never_send_crash"/>