Compare commits

...

63 Commits

Author SHA1 Message Date
adbenitez 7f89ecea5c Merge remote-tracking branch 'upstream/adb/improve-notifications' 2024-11-30 13:17:01 +01:00
adbenitez 30a63dd13b allow to toggle direct mentions notifications in muted chats 2024-11-30 13:16:05 +01:00
adbenitez a5d2642c37 do not notify mentions in muted 1:1 chats 2024-11-30 13:13:50 +01:00
adbenitez 79e5eedab0 Merge remote-tracking branch 'upstream/adb/improve-notifications' 2024-11-30 12:21:20 +01:00
adbenitez 27da217eb7 Merge remote-tracking branch 'upstream/adb/fix-callJavascriptFunction' 2024-11-30 12:20:07 +01:00
adbenitez a0c71a5387 fix WebxdcActivity.callJavaScriptFunction()
now even if internet access is enabled, the index.html is wrapped in
an iframe
2024-11-30 12:03:44 +01:00
adbenitez 4d19a59cb6 improve notifications handling 2024-11-29 20:10:49 +01:00
adbenitez 819a9f415a Merge remote-tracking branch 'upstream/main' 2024-11-29 19:38:43 +01:00
adbenitez dff1ef3778 update CI 2024-11-29 16:49:15 +01:00
B. Petersen 7131f5774e adapt to changed deltachat-pages output folder 2024-11-27 20:36:46 +01:00
adb aa572508dc prepare 1.49.0 (#3453)
* update changelog

* update build.gradle

* update changelog

* update scripts/upload-beta.sh
2024-11-27 20:36:30 +01:00
adb 1f880efb3f Merge pull request #3454 from deltachat/adb/update-link-generation
remove Util.QrDataToInviteURL()
2024-11-27 19:15:41 +01:00
adbenitez 72ace5c156 remove Util.QrDataToInviteURL() 2024-11-27 19:01:49 +01:00
B. Petersen 2f34a6ffa4 do not quote a dedicated message; current android shows them grouped and you do not really know what the message refers to 2024-11-27 18:02:07 +01:00
adbenitez afdfe7bbaa update strings 2024-11-27 14:37:29 +01:00
adbenitez 14f43f2a79 update deltachat-core-rust to 'chore(release): prepare for 1.151.2 (#6267)' of 'v1.151.2' 2024-11-27 14:37:29 +01:00
B. Petersen f3353cf6e9 update local help 2024-11-27 14:36:33 +01:00
adb 722f2cad1e Merge pull request #3449 from deltachat/adb/update-deeplink-api-impl
update to new deep-link API specs
2024-11-26 16:23:09 +01:00
adbenitez b135093628 update to new deep-link API specs 2024-11-26 13:24:35 +01:00
adb be44789b01 Merge pull request #3447 from deltachat/adb/issue-3444
add "show in chat" to webxdc menu
2024-11-26 12:35:22 +01:00
B. Petersen 233197095b remove dead code 2024-11-25 20:42:46 +01:00
adb 494cb728c3 Update src/main/res/menu/webxdc.xml
Co-authored-by: bjoern <r10s@b44t.com>
2024-11-25 19:59:51 +01:00
Hocuri 60e9a9101a Don't always show the sender in notifications (#3441), Always show "~" before overridden sender names (#3442)
* Don't always show the sender in notifications

In 1:1 chats, don't prepend the sender name to every line. The exception is when the display name is not equal to the chat name (i.e. there is an OverwriteSenderDisplayname), in this case we still prepend it.

* Always show the "~" before the sender name if it's overridden

When we introduced this, I assume that we weren't sure whether we should
do it and only showed it in some places. But I think it's nicer to
show the same sender name everywhere, i.e. always add the "~".
2024-11-25 14:44:31 +01:00
adbenitez c23dac6f99 add "show in chat" to webxdc menu 2024-11-25 00:57:45 +01:00
adb 3965319ef4 Merge pull request #3446 from deltachat/adb/deprecate-desc-param-of-sendUpdate
remove 'description' parameter from webxdc's sendUpdate()
2024-11-25 00:56:16 +01:00
adb c4db7c515f Merge pull request #3443 from deltachat/adb/issue-3439
notify DC_EVENT_INCOMING_WEBXDC_NOTIFY
2024-11-24 21:37:15 +01:00
adbenitez fbf88e102b remove 'description' parameter from webxdc's sendUpdate()
the 'description' parameter is about to be deprecated,
see https://github.com/deltachat/deltachat-core-rust/issues/6245
2024-11-24 21:34:22 +01:00
adb d5ea043893 Merge pull request #3440 from deltachat/hoc/reverse-notification-inbox
Reverse order of the tiny inbox in notifications
2024-11-24 21:20:34 +01:00
adbenitez f70c79ba4a fix notifyWebxdc 2024-11-24 03:46:50 +01:00
adb 0b2a26e2f1 Merge pull request #3438 from deltachat/adb/webxdc-deeplink
allow to open deep-link to webxdc
2024-11-24 00:33:59 +01:00
adbenitez b968ba67b3 avoid NullPointerException 2024-11-24 00:33:22 +01:00
adbenitez e234cc864b don't play in-chat sound 2024-11-23 23:11:34 +01:00
adbenitez b47e75eed6 use new selfAddr 2024-11-23 23:11:34 +01:00
adbenitez 6b684bf030 notify DC_EVENT_INCOMING_WEBXDC_NOTIFY 2024-11-23 23:11:34 +01:00
adbenitez ea89d37461 open webxdc when clicking info-message, pass deeplink/href 2024-11-23 23:09:01 +01:00
adbenitez 814af177d1 fix: make getWebxdcHref public 2024-11-23 23:09:01 +01:00
adbenitez 1ccbb7177f add DcMsg.getWebxdcHref() 2024-11-23 23:09:01 +01:00
adbenitez 3118dbd32b allow to open deep-link to webxdc 2024-11-23 23:09:01 +01:00
adb 1a5e062dac Merge pull request #3445 from deltachat/update-core-to-1.151.0
update core to 1.151.0
2024-11-23 23:04:44 +01:00
B. Petersen 0bcaea6f01 update deltachat-core-rust to 'chore(release): prepare for 1.151.0' of 'v1.151.0' 2024-11-23 23:01:56 +01:00
Hocuri 8283a6c4ad Reverse order of the tiny inbox in notifications 2024-11-23 20:01:46 +01:00
adb cd159bac6c Merge pull request #3377 from deltachat/r10s/notify-reactions
notify reactions added
2024-11-23 18:22:49 +01:00
adb 21f917004f Merge pull request #3436 from deltachat/adb/remove-android-4-code
remove android 4 dead code (SDK<21)
2024-11-22 23:07:12 +01:00
adb 0abf2ff00c Merge pull request #3435 from deltachat/adb/allow-to-open-http-link
allow to open in browser http links that look like proxies
2024-11-21 01:31:11 +01:00
adbenitez 0ca92ec6b5 remove android 4 compatibility code 2024-11-21 01:16:20 +01:00
adbenitez e66fa53537 allow to open in browser http links that look like proxies 2024-11-20 19:36:18 +01:00
Hocuri a51013cc00 fix: Show composite emojis enlarged, too (#3427)
fix: Show composite emojis enlarged, too

There are a lot of composite emojis like the flags and the family emojis.
Here, the grapheme starts with an emoji, but then come some other
characters that modify the first emoji (e.g. all flags start with the
flag emoji).

This PR shows those as big, too, by checking whether a grapheme _starts_
with an emoji to determine whether it's an emoji.


---------

Co-authored-by: adb <adb@merlinux.eu>
2024-11-20 13:59:50 +01:00
Hocuri 171500a97d fix: Don't change display name when starting to create a new account and going back (#3434) 2024-11-19 13:24:10 +01:00
link2xt 9a4851961e fix: check draft.isOk() instead of comparing to null
dcContext.getDraft() never returns null.
2024-11-19 10:38:08 +00:00
adbenitez e5ddbacb2e update build.gradle 2024-11-15 22:45:17 +01:00
adbenitez 03c7d78e2b Merge remote-tracking branch 'upstream/main' 2024-11-15 22:45:10 +01:00
adb 00498b02b3 Merge pull request #3424 from deltachat/adb/issue-3423
remove internal font scaling preference
2024-11-15 22:01:51 +01:00
adbenitez ad6e2d1a9f fix typo 2024-11-15 21:20:40 +01:00
adbenitez 5cfa71cd72 add some protection against theoretical 0 value from ViewUtil.pxToSp() 2024-11-15 20:57:33 +01:00
adbenitez 0551044ef9 remove internal font size setting 2024-11-15 18:02:42 +01:00
adb 5126b3eeb2 Merge pull request #3422 from deltachat/adb/issue-3421
change proxy protocol label position
2024-11-15 04:27:31 +01:00
B. Petersen 8d7078f96f fix playing inChatSounds 2024-11-14 14:10:17 +01:00
B. Petersen c446440537 save one database call 2024-11-14 14:10:17 +01:00
B. Petersen 333e4c9eca notify reactions 2024-11-14 14:10:17 +01:00
B. Petersen fb1f5df234 fix ticker line 2024-11-14 14:10:17 +01:00
Hocuri cc419a9f62 perf: Return early in getTextScale() if text is empty or starts with letter (#3426)
Not sure why, but `setText()` seems to be called with an empty string
very often - for this case it's nice if getTextScale() returns early.

If the text starts with a letter, we can also return early.
2024-11-13 20:08:31 +01:00
adbenitez 2469b6efef update originalFontSize on setTextSize() 2024-11-13 17:20:14 +01:00
adbenitez 92bc53b672 change proxy protocol label position 2024-11-12 23:12:37 +01:00
155 changed files with 1833 additions and 1689 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
- uses: nttld/setup-ndk@v1
id: setup-ndk
with:
ndk-version: r23c
ndk-version: r27
- name: Compile core
env:
+28
View File
@@ -1,5 +1,33 @@
# ArcaneChat Android Changelog
## v1.49.0
2024-11
* New emoji picker with support for more emojis
* Webxdc apps can now trigger notifications
* Webxdc apps can now deep-link to internal sections when you click their info-messages in chat
* Add "Show in Chat" to the menu of opened Webxdc apps
* Reverse order of messages in the notification group
* Notify reactions to own messages
* Improve the button to start Webxdc apps
* Make account deletion confirmation dialog faster
* Rename "Back up Chats to External Storage" to "Export Backup"
* Improve compatibility with classic email clients in the outgoing messages
* Removed internal font scaling setting in favor of the better system settings
* Use privacy-preserving webxdc addresses
* Use Rustls for connections with strict TLS
* fix: Trim whitespace from scanned QR codes.
* fix quotes: Line-before-quote may be up to 120 character long instead of 80
* fix: Prevent accidental wrong-password-notifications
* fix: Remove footers from "Show Full Message..."
* fix: Only add "member added/removed" messages if they actually do that
* fix: Update state of message when fully downloading it
* fix: send message: Do not fail if the message does not exist anymore
* fix: Do not percent-encode dot when passing to autoconfig server (so, fix handling of some servers)
* fix displaynames not being updated when intially scanned by a QR code
* several bug fixes
* update to core 1.151.2
## v1.48.3
2024-10
+2 -2
View File
@@ -33,8 +33,8 @@ android {
useLibrary 'org.apache.http.legacy'
defaultConfig {
versionCode 30000696
versionName "1.48.5"
versionCode 30000698
versionName "1.49.0"
applicationId "chat.delta.lite"
multiDexEnabled true
+11 -4
View File
@@ -729,12 +729,10 @@ JNIEXPORT jint Java_com_b44t_messenger_DcContext_sendVideochatInvitation(JNIEnv
}
JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_sendWebxdcStatusUpdate(JNIEnv *env, jobject obj, jint msg_id, jstring payload, jstring descr)
JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_sendWebxdcStatusUpdate(JNIEnv *env, jobject obj, jint msg_id, jstring payload)
{
CHAR_REF(payload);
CHAR_REF(descr);
jboolean ret = dc_send_webxdc_status_update(get_dc_context(env, obj), msg_id, payloadPtr, descrPtr) != 0;
CHAR_UNREF(descr);
jboolean ret = dc_send_webxdc_status_update(get_dc_context(env, obj), msg_id, payloadPtr, NULL) != 0;
CHAR_UNREF(payload);
return ret;
}
@@ -1575,6 +1573,15 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getWebxdcInfoJson(JNIEnv *env, j
}
JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getWebxdcHref(JNIEnv *env, jobject obj)
{
char* temp = dc_msg_get_webxdc_href(get_dc_msg(env, obj));
jstring ret = JSTRING_NEW(temp);
dc_str_unref(temp);
return ret;
}
JNIEXPORT jboolean Java_com_b44t_messenger_DcMsg_isForwarded(JNIEnv *env, jobject obj)
{
return dc_msg_is_forwarded(get_dc_msg(env, obj))!=0;
+1 -1
View File
@@ -1 +1 @@
../deltachat-pages/tools/create-local-help.py ../deltachat-pages/_site src/main/assets/help
../deltachat-pages/tools/create-local-help.py ../deltachat-pages/result src/main/assets/help
+1
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env bash
VERSION=$1
@@ -28,11 +28,6 @@ public class FcmReceiveService extends FirebaseMessagingService {
private static volatile String prefixedToken;
public static void register(Context context) {
if (Build.VERSION.SDK_INT < 19) {
Log.w(TAG, "FCM not available on SDK < 19");
triedRegistering = true;
return;
}
if (FcmReceiveService.prefixedToken != null) {
Log.i(TAG, "FCM already registered");
+38 -2
View File
@@ -99,6 +99,7 @@
<li><a href="#lze-delta-chat-používat-s-protonmail--tutanota--criptext">Lze Delta Chat používat s Protonmail / Tutanota / Criptext?</a></li>
<li><a href="#remove-account">How can I delete my account?</a></li>
<li><a href="#mám-zájem-o-technické-podrobnosti-kde-najdu-víc">Mám zájem o technické podrobnosti. Kde najdu víc?</a></li>
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
<li><a href="#jak-je-financován-vývoj-delta-chatu">Jak je financován vývoj Delta Chatu?</a></li>
</ul>
</li>
@@ -297,8 +298,7 @@ Archived chats remain accessible above the chat list or via search.</p>
</li>
</ul>
<p>To archive or pin a chat, long tap (Android), use the chats menu (Android/Desktop) or swipe to the left (iOS);
to mute a chat, use the chats menu (Android/Desktop) or the chats profile (iOS).</p>
<p>To use the functions, long tap or right click a chat in the chat list.</p>
<h3 id="what-does-the-green-dot-mean">
@@ -1309,6 +1309,12 @@ One device is not needed for the other to work.</p>
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
(after transfer, you can change back to the original value)</p>
</li>
<li>
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
</li>
<li>
<p>On <strong>macOS</strong>, enable “System Settings / Privacy &amp; Security / <strong>Local Network</strong> / Delta Chat”</p>
</li>
<li>
<p>Your system might have a “personal firewall”,
which is known to cause problems (especially on Windows).
@@ -1425,6 +1431,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
<ul>
<li>In general, anyone can share webxdc apps with each
other without restrictions.</li>
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send hi to xstore@testrun.org</a>
to see an experimental webxdc appstore.
All of the apps are open source and for free.</li>
@@ -1874,6 +1881,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
<li>Dobrý začátek je <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Standards used in Delta Chat</a>.</li>
</ul>
<h3 id="where-can-my-friends-find-delta-chat">
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat is available for all major and some minor platforms:</p>
<ul>
<li>
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
</li>
<li>
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
</li>
<li>
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="jak-je-financován-vývoj-delta-chatu">
+37 -1
View File
@@ -99,6 +99,7 @@
<li><a href="#ist-delta-chat-kompatibel-mit-protonmail--tutanota--criptext">Ist Delta Chat kompatibel mit Protonmail / Tutanota / Criptext?</a></li>
<li><a href="#remove-account">Wie kann ich mein Konto löschen?</a></li>
<li><a href="#ich-bin-an-technischen-details-interessiert-gibt-es-hierzu-weitere-infos">Ich bin an technischen Details interessiert. Gibt es hierzu weitere Infos?</a></li>
<li><a href="#wo-können-meine-freunde-delta-chat-finden">Wo können meine Freunde Delta Chat finden?</a></li>
<li><a href="#wie-wird-delta-chat-finanziert">Wie wird Delta Chat finanziert?</a></li>
</ul>
</li>
@@ -286,7 +287,7 @@ unter dem Text Ihrer Nachrichten.</p>
</li>
</ul>
<p>Zum Archivieren oder Anheften, tippen Sie lange auf den Chat (Android), verwenden Sie das Chatmenü (Android/Desktop) oder wischen Sie nach links (iOS); zum Stummschalten, verwenden Sie das Chatmenü (Android/Desktop) oder das Chatprofil (iOS).</p>
<p>Um die Funktionen zu nutzen, lang auf einen Chat in der Chatliste tippen oder den Chat mit der rechten Maustaste anklicken.</p>
<h3 id="was-bedeutet-der-grüne-punkt">
@@ -1215,6 +1216,12 @@ Es wurden keine kritischen Probleme gefunden, aber zwei Probleme mit hohem Schwe
und sicherstellen, dass <strong>Privates Netzwerk</strong> als “Netzwerkprofiltyp” ausgewählt ist.
(nach der Übertragung kann wieder der ursprüngliche Wert verwendet werden)</p>
</li>
<li>
<p>Auf <strong>iOS</strong>, sicherstellen, dass „Systemeinstellungen / Apps / Delta Chat / <strong>Lokales Netzwerk</strong>“ eingeschaltet ist</p>
</li>
<li>
<p>Auf <strong>macOS,</strong> „Systemeinstellungen / Datenschutz &amp; Sicherheit / <strong>Lokales Netzwerk</strong> / Delta Chat“ aktivieren</p>
</li>
<li>
<p>Ihr System verfügt möglicherweise über eine “Personal Firewall”, diese sind dafür bekannt, Probleme zu verursachen (insbesondere bei Windows). <strong>Deaktivieren Sie die Personal Firewall</strong> für Delta Chat auf beiden Seiten und versuchen Sie es erneut</p>
</li>
@@ -1305,6 +1312,7 @@ Verwenden Sie nach Möglichkeit ein Nicht-Gast-Netzwerk. Wenn Sie Zugriff auf de
<ul>
<li>Grundsätzlich kann jeder Webxdc Apps mit anderen ohne Einschränkungen teilen.</li>
<li>Von <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>Sie können <a href="https://delta.chat/en/2023-08-11-xstore">hallo an xstore@testrun.org senden</a>
um einen experimentellen Webxdc Appstore zu sehen.
Alle Apps dort sind Open Source und umsonst.</li>
@@ -1680,6 +1688,34 @@ Andernfalls könnten Sie unverschlüsselte Nachrichten aus diesen Gruppenchats e
<li>Siehe hierzu <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">in Delta Chat genutzte Standards</a>.</li>
</ul>
<h3 id="wo-können-meine-freunde-delta-chat-finden">
Wo können meine Freunde Delta Chat finden? <a href="#wo-können-meine-freunde-delta-chat-finden" class="anchor"></a>
</h3>
<p>Delta Chat ist für alle großen und einige kleinere Plattformen verfügbar:</p>
<ul>
<li>
<p>Die <strong>offizielle Website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> zeigt alle Optionen im Detail</p>
</li>
<li>
<p>Falls nicht verfügbar, verwenden Sie den <strong>Mirror</strong> auf <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Öffnen Sie einen der folgenden <strong>App-Stores und suchen Sie nach „Delta Chat“:</strong> Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS und macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Im <strong>Paketmanager</strong> Ihrer Linux-Distribution nachschauen</p>
</li>
<li>
<p><strong>Android APKs</strong> sind auch auf <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a> verfügbar.</p>
</li>
</ul>
<h3 id="wie-wird-delta-chat-finanziert">
+38 -2
View File
@@ -99,6 +99,7 @@
<li><a href="#is-delta-chat-compatible-with-protonmail--tutanota--criptext">Is Delta Chat compatible with Protonmail / Tutanota / Criptext?</a></li>
<li><a href="#remove-account">How can I delete my account?</a></li>
<li><a href="#im-interested-in-the-technical-details-can-you-tell-me-more">Im interested in the technical details. Can you tell me more?</a></li>
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
<li><a href="#how-are-delta-chat-developments-funded">How are Delta Chat developments funded?</a></li>
</ul>
</li>
@@ -301,8 +302,7 @@ Archived chats remain accessible above the chat list or via search.</p>
</li>
</ul>
<p>To archive or pin a chat, long tap (Android), use the chats menu (Android/Desktop) or swipe to the left (iOS);
to mute a chat, use the chats menu (Android/Desktop) or the chats profile (iOS).</p>
<p>To use the functions, long tap or right click a chat in the chat list.</p>
<h3 id="what-does-the-green-dot-mean">
@@ -1315,6 +1315,12 @@ One device is not needed for the other to work.</p>
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
(after transfer, you can change back to the original value)</p>
</li>
<li>
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
</li>
<li>
<p>On <strong>macOS</strong>, enable “System Settings / Privacy &amp; Security / <strong>Local Network</strong> / Delta Chat”</p>
</li>
<li>
<p>Your system might have a “personal firewall”,
which is known to cause problems (especially on Windows).
@@ -1432,6 +1438,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
<ul>
<li>In general, anyone can share webxdc apps with each
other without restrictions.</li>
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send hi to xstore@testrun.org</a>
to see an experimental webxdc appstore.
All of the apps are open source and for free.</li>
@@ -1883,6 +1890,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
<li>See <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Standards used in Delta Chat</a>.</li>
</ul>
<h3 id="where-can-my-friends-find-delta-chat">
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat is available for all major and some minor platforms:</p>
<ul>
<li>
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
</li>
<li>
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
</li>
<li>
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="how-are-delta-chat-developments-funded">
+37
View File
@@ -99,6 +99,7 @@
<li><a href="#delta-chat-es-compatible-con-protonmail--tutanota--criptext">¿Delta Chat es compatible con Protonmail / Tutanota / Criptext?</a></li>
<li><a href="#remove-account">¿Cómo puedo eliminar mi cuenta?</a></li>
<li><a href="#estoy-interesado-en-los-detalles-técnicos-pueden-decirme-más">Estoy interesado en los detalles técnicos. ¿Pueden decirme más?</a></li>
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
<li><a href="#cómo-se-financia-el-desarrollo-de-delta-chat">¿Cómo se financia el desarrollo de Delta Chat?</a></li>
</ul>
</li>
@@ -1277,6 +1278,12 @@ No es necesario un dispositivo para que el otro funcione.</p>
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
(after transfer, you can change back to the original value)</p>
</li>
<li>
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
</li>
<li>
<p>On <strong>macOS</strong>, enable “System Settings / Privacy &amp; Security / <strong>Local Network</strong> / Delta Chat”</p>
</li>
<li>
<p>Your system might have a “personal firewall”,
which is known to cause problems (especially on Windows).
@@ -1394,6 +1401,7 @@ solo abre archivos adjuntos de remitentes en los que confía y no de spammers.</
<ul>
<li>In general, anyone can share webxdc apps with each
other without restrictions.</li>
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send hi to xstore@testrun.org</a>
to see an experimental webxdc appstore.
All of the apps are open source and for free.</li>
@@ -1827,6 +1835,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
<li>Visita la página <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Estándares usados en Delta Chat</a>.</li>
</ul>
<h3 id="where-can-my-friends-find-delta-chat">
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat is available for all major and some minor platforms:</p>
<ul>
<li>
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
</li>
<li>
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
</li>
<li>
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="cómo-se-financia-el-desarrollo-de-delta-chat">
+37
View File
@@ -99,6 +99,7 @@
<li><a href="#delta-chat-est-il-compatible-avec-protonmail--tutanota--criptext-">Delta Chat est-il compatible avec Protonmail / Tutanota / Criptext ?</a></li>
<li><a href="#remove-account">Comment supprimer mon compte ?</a></li>
<li><a href="#les-détails-techniques-mintéressent-pouvez-vous-men-dire-plus-">Les détails techniques mintéressent. Pouvez-vous men dire plus ?</a></li>
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
<li><a href="#comment-est-financé-le-développement-de-delta-chat-">Comment est financé le développement de Delta Chat ?</a></li>
</ul>
</li>
@@ -1262,6 +1263,12 @@ Lun na pas besoin de lautre pour pouvoir fonctionner.</p>
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
(after transfer, you can change back to the original value)</p>
</li>
<li>
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
</li>
<li>
<p>On <strong>macOS</strong>, enable “System Settings / Privacy &amp; Security / <strong>Local Network</strong> / Delta Chat”</p>
</li>
<li>
<p>Il se peut que votre système dispose dun “pare-feu personnalisé”,
source bien connue de dysfonctionnements (en particulier sur Windows).
@@ -1375,6 +1382,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
<ul>
<li>In general, anyone can share webxdc apps with each
other without restrictions.</li>
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send hi to xstore@testrun.org</a>
to see an experimental webxdc appstore.
All of the apps are open source and for free.</li>
@@ -1789,6 +1797,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
<li>Consultez les <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">standards utilisés dans Delta Chat</a>.</li>
</ul>
<h3 id="where-can-my-friends-find-delta-chat">
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat is available for all major and some minor platforms:</p>
<ul>
<li>
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
</li>
<li>
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
</li>
<li>
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="comment-est-financé-le-développement-de-delta-chat-">
+38 -2
View File
@@ -99,6 +99,7 @@
<li><a href="#is-delta-chat-compatible-with-protonmail--tutanota--criptext">Is Delta Chat compatible with Protonmail / Tutanota / Criptext?</a></li>
<li><a href="#remove-account">How can I delete my account?</a></li>
<li><a href="#im-interested-in-the-technical-details-can-you-tell-me-more">Im interested in the technical details. Can you tell me more?</a></li>
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
<li><a href="#how-are-delta-chat-developments-funded">How are Delta Chat developments funded?</a></li>
</ul>
</li>
@@ -301,8 +302,7 @@ Archived chats remain accessible above the chat list or via search.</p>
</li>
</ul>
<p>To archive or pin a chat, long tap (Android), use the chats menu (Android/Desktop) or swipe to the left (iOS);
to mute a chat, use the chats menu (Android/Desktop) or the chats profile (iOS).</p>
<p>To use the functions, long tap or right click a chat in the chat list.</p>
<h3 id="what-does-the-green-dot-mean">
@@ -1315,6 +1315,12 @@ One device is not needed for the other to work.</p>
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
(after transfer, you can change back to the original value)</p>
</li>
<li>
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
</li>
<li>
<p>On <strong>macOS</strong>, enable “System Settings / Privacy &amp; Security / <strong>Local Network</strong> / Delta Chat”</p>
</li>
<li>
<p>Your system might have a “personal firewall”,
which is known to cause problems (especially on Windows).
@@ -1432,6 +1438,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
<ul>
<li>In general, anyone can share webxdc apps with each
other without restrictions.</li>
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send hi to xstore@testrun.org</a>
to see an experimental webxdc appstore.
All of the apps are open source and for free.</li>
@@ -1883,6 +1890,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
<li>See <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Standards used in Delta Chat</a>.</li>
</ul>
<h3 id="where-can-my-friends-find-delta-chat">
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat is available for all major and some minor platforms:</p>
<ul>
<li>
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
</li>
<li>
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
</li>
<li>
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="how-are-delta-chat-developments-funded">
+36
View File
@@ -99,6 +99,7 @@
<li><a href="#delta-chat-è-compatibile-con-protonmail--tutanota--criptext">Delta Chat è compatibile con Protonmail / Tutanota / Criptext?</a></li>
<li><a href="#remove-account">Come posso eliminare il mio profilo?</a></li>
<li><a href="#sono-interessato-ai-dettagli-tecnici-mi-puoi-dire-di-più">Sono interessato ai dettagli tecnici. Mi puoi dire di più?</a></li>
<li><a href="#dove-possono-trovare-delta-chat-i-miei-amici">Dove possono trovare Delta Chat i miei amici?</a></li>
<li><a href="#come-viene-finanziato-lo-sviluppo-di-delta-chat">Come viene finanziato lo sviluppo di Delta Chat?</a></li>
</ul>
</li>
@@ -1302,6 +1303,12 @@ Un dispositivo non è necessario perché laltro funzioni.</p>
e assicurati che <strong>Rete Privata</strong> sia selezionata come “Tipo di profilo di rete”
(dopo il trasferimento è possibile ripristinare il valore originale)</p>
</li>
<li>
<p>Su <strong>iOS</strong>, assicurati che laccesso a “Impostazioni di Sistema / App / Delta Chat / <strong>Rete locale</strong>” sia concesso</p>
</li>
<li>
<p>Su <strong>macOS</strong>, abilita “Impostazioni di Sistema / Privacy &amp; Sicurezza / <strong>Rete locale</strong> / Delta Chat”</p>
</li>
<li>
<p>Il sistema potrebbe avere un “personal firewall”,
che è noto per causare problemi (soprattutto su Windows).
@@ -1845,6 +1852,35 @@ Altrimenti potresti ricevere messaggi non decifrabili da quelle chat di gruppo.<
<li>Vedi <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Standard usati in Delta Chat</a>.</li>
</ul>
<h3 id="dove-possono-trovare-delta-chat-i-miei-amici">
Dove possono trovare Delta Chat i miei amici? <a href="#dove-possono-trovare-delta-chat-i-miei-amici" class="anchor"></a>
</h3>
<p>Delta Chat è disponibile per tutte le piattaforme principali e alcune minori:</p>
<ul>
<li>
<p>Il <strong>sito ufficiale</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> mostra tutte le opzioni in dettaglio</p>
</li>
<li>
<p>Se non disponibile, utilizzare <strong>mirror</strong> su <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Apri uno dei seguenti <strong>app store e cerca “Delta Chat”:</strong>
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS e macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Controlla il <strong>gestore pacchetti</strong> delle tue distribuzioni Linux</p>
</li>
<li>
<p><strong>APK Android</strong> sono disponibili anche su <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="come-viene-finanziato-lo-sviluppo-di-delta-chat">
+37
View File
@@ -99,6 +99,7 @@
<li><a href="#is-delta-chat-compatibel-met-protonmailtutanotacriptext">Is Delta Chat compatibel met Protonmail/Tutanota/Criptext?</a></li>
<li><a href="#remove-account">Hoe kan ik mijn account verwijderen?</a></li>
<li><a href="#ik-wil-graag-meer-weten-over-de-gebruikte-technieken-waar-kan-ik-meer-informatie-vinden">Ik wil graag meer weten over de gebruikte technieken. Waar kan ik meer informatie vinden?</a></li>
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
<li><a href="#hoe-wordt-de-ontwikkeling-van-delta-chat-gefinancierd">Hoe wordt de ontwikkeling van Delta Chat gefinancierd?</a></li>
</ul>
</li>
@@ -1306,6 +1307,12 @@ op beide apparaten</strong>. Hierdoor hoef je niet het ene apparaat bij de hand
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
(after transfer, you can change back to the original value)</p>
</li>
<li>
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
</li>
<li>
<p>On <strong>macOS</strong>, enable “System Settings / Privacy &amp; Security / <strong>Local Network</strong> / Delta Chat”</p>
</li>
<li>
<p>Wellicht is een firewall actief op je apparaat,
welke problemen kan veroorzaken (met name op Windows).
@@ -1423,6 +1430,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
<ul>
<li>In general, anyone can share webxdc apps with each
other without restrictions.</li>
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send hi to xstore@testrun.org</a>
to see an experimental webxdc appstore.
All of the apps are open source and for free.</li>
@@ -1868,6 +1876,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
<li>Bekijk de pagina <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Door Delta Chat gebruikte standaarden</a>.</li>
</ul>
<h3 id="where-can-my-friends-find-delta-chat">
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat is available for all major and some minor platforms:</p>
<ul>
<li>
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
</li>
<li>
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
</li>
<li>
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="hoe-wordt-de-ontwikkeling-van-delta-chat-gefinancierd">
+37 -2
View File
@@ -99,6 +99,7 @@
<li><a href="#czy-delta-chat-jest-kompatybilny-z-protonmail--tutanota--criptext">Czy Delta Chat jest kompatybilny z Protonmail / Tutanota / Criptext?</a></li>
<li><a href="#remove-account">Jak mogę usunąć swoje konto?</a></li>
<li><a href="#interesują-mnie-szczegóły-techniczne-możesz-powiedzieć-mi-coś-więcej">Interesują mnie szczegóły techniczne. Możesz powiedzieć mi coś więcej?</a></li>
<li><a href="#gdzie-moi-znajomi-mogą-znaleźć-delta-chat">Gdzie moi znajomi mogą znaleźć Delta Chat?</a></li>
<li><a href="#w-jaki-sposób-finansowany-jest-rozwój-delta-chat">W jaki sposób finansowany jest rozwój Delta Chat?</a></li>
</ul>
</li>
@@ -265,8 +266,7 @@
</li>
</ul>
<p>Aby zarchiwizować lub przypiąć czat, dotknij i przytrzymaj (Android), yj menu czatu (Android/Desktop) lub przesuń palcem w lewo (iOS);
aby wyciszyć czat, użyj menu czatu (Android/Desktop) lub profilu czatu (iOS).</p>
<p>Aby skorzystać z tych funkcji, przytrzymaj ej lub kliknij prawym przyciskiem myszy czat na liście czatów.</p>
<h3 id="co-oznacza-zielona-kropka">
@@ -941,6 +941,12 @@ W przypadku innych programów można znaleźć rozwiązanie online.</p>
<p>Na <strong>Windowsie</strong>, przejdź do <strong>Panel sterowania / Sieć i internet</strong> i upewnij się, że <strong>Sieć prywatna</strong> jest wybrana jako “Typ profilu sieci”
(po przeniesieniu możesz wrócić do pierwotnej wartości)</p>
</li>
<li>
<p>W systemie <strong>iOS</strong> upewnij się, że jest przydzielony dostęp do opcji „Ustawienia » Aplikacje » Delta Chat » <strong>Sieć lokalna</strong></p>
</li>
<li>
<p>W systemie <strong>macOS</strong> włącz „Ustawienia systemowe » Prywatność i bezpieczeństwo » <strong>Sieć lokalna</strong> » Delta Chat”</p>
</li>
<li>
<p>Twój system może mieć „zaporę ogniową”, o której wiadomo, że powoduje problemy (szczególnie w systemie Windows).
<strong>Wyłącz zaporę</strong> dla Delta Chat po obu stronach i spróbuj ponownie</p>
@@ -1031,6 +1037,7 @@ W przypadku innych programów można znaleźć rozwiązanie online.</p>
<ul>
<li>Ogólnie rzecz biorąc, każdy może udostępniać sobie aplikacje webxdc bez ograniczeń.</li>
<li>Od <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>Możesz <a href="https://delta.chat/en/2023-08-11-xstore">wysłać „hi” na adres xstore@testrun.org</a>, aby zobaczyć eksperymentalny sklep z aplikacjami webxdc. Wszystkie aplikacje są otwarto źródłowe i są bezpłatne.</li>
<li>Wiele osób pisze własne, aplikacje webxdc i publikuje je na <a href="https://support.delta.chat/c/webxdc/20">forum Delta Chat</a>.</li>
</ul>
@@ -1356,6 +1363,34 @@ jeśli chcesz sprawdzić, czy Twoje poświadczenia są przetwarzane w bezpieczny
<li>Zobacz <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Standardy używane w Delta Chat</a>.</li>
</ul>
<h3 id="gdzie-moi-znajomi-mogą-znaleźć-delta-chat">
Gdzie moi znajomi mogą znaleźć Delta Chat? <a href="#gdzie-moi-znajomi-mogą-znaleźć-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat jest dostępny na wszystkich głównych i niektórych mniejszych platformach:</p>
<ul>
<li>
<p>Oficjalna <strong>strona internetowa</strong> <a href="https://delta.chat/download">https://delta.chat/download</a> pokazuje wszystkie opcje szczegółowo</p>
</li>
<li>
<p>Jeśli nie jest dostępna, użyj <strong>kopii strony</strong> pod adresem <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Otwórz jeden z następujących <strong>sklepów z aplikacjami i wyszukaj „Delta Chat”</strong>: Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS i macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Sprawdź <strong>menedżera pakietów</strong> swoich dystrybucji Linuksa</p>
</li>
<li>
<p><strong>Aplikacje na Androida</strong> są również dostępne na <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="w-jaki-sposób-finansowany-jest-rozwój-delta-chat">
+38 -2
View File
@@ -99,6 +99,7 @@
<li><a href="#o-delta-chat-é-compatível-com-protonmail--tutanota--criptext">O Delta Chat é compatível com Protonmail / Tutanota / Criptext?</a></li>
<li><a href="#remove-account">How can I delete my account?</a></li>
<li><a href="#estou-interessado-nos-detalhes-técnicos-pode-me-dizer-mais">Estou interessado nos detalhes técnicos. Pode me dizer mais?</a></li>
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
<li><a href="#como-são-os-desenvolvimentos-do-delta-chat-financiados">Como são os desenvolvimentos do Delta Chat financiados?</a></li>
</ul>
</li>
@@ -297,8 +298,7 @@ Archived chats remain accessible above the chat list or via search.</p>
</li>
</ul>
<p>To archive or pin a chat, long tap (Android), use the chats menu (Android/Desktop) or swipe to the left (iOS);
to mute a chat, use the chats menu (Android/Desktop) or the chats profile (iOS).</p>
<p>To use the functions, long tap or right click a chat in the chat list.</p>
<h3 id="what-does-the-green-dot-mean">
@@ -1309,6 +1309,12 @@ One device is not needed for the other to work.</p>
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
(after transfer, you can change back to the original value)</p>
</li>
<li>
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
</li>
<li>
<p>On <strong>macOS</strong>, enable “System Settings / Privacy &amp; Security / <strong>Local Network</strong> / Delta Chat”</p>
</li>
<li>
<p>Your system might have a “personal firewall”,
which is known to cause problems (especially on Windows).
@@ -1426,6 +1432,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
<ul>
<li>In general, anyone can share webxdc apps with each
other without restrictions.</li>
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send hi to xstore@testrun.org</a>
to see an experimental webxdc appstore.
All of the apps are open source and for free.</li>
@@ -1869,6 +1876,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
<li>Veja <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">As normas usadas no Delta Chat</a>.</li>
</ul>
<h3 id="where-can-my-friends-find-delta-chat">
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat is available for all major and some minor platforms:</p>
<ul>
<li>
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
</li>
<li>
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
</li>
<li>
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="como-são-os-desenvolvimentos-do-delta-chat-financiados">
+39 -4
View File
@@ -99,6 +99,7 @@
<li><a href="#совместим-ли-delta-chat-с-protonmail--tutanota--criptext">Совместим ли Delta Chat с Protonmail / Tutanota / Criptext?</a></li>
<li><a href="#remove-account">Как я могу удалить свой аккаунт?</a></li>
<li><a href="#меня-интересуют-технические-детали-можете-рассказать-больше">Меня интересуют технические детали. Можете рассказать больше?</a></li>
<li><a href="#где-мои-друзья-могут-найти-delta-chat">Где мои друзья могут найти Delta Chat?</a></li>
<li><a href="#как-финансируются-разработки-delta-chat">Как финансируются разработки Delta Chat?</a></li>
</ul>
</li>
@@ -301,8 +302,7 @@
</li>
</ul>
<p>Чтобы архивировать или закрепить чат, нажмите на него долгим нажатием (Android), воспользуйтесь меню чата (Android/Desktop) или проведите пальцем влево (iOS);
чтобы отключить уведомления, воспользуйтесь меню чата (Android/Desktop) или профиль чата (iOS).</p>
<p>Чтобы использовать функции, нажмите долгим нажатием или щелкните правой кнопкой мыши по чату в списке чатов.</p>
<h3 id="что-означает-зеленая-точка">
@@ -1312,6 +1312,12 @@ Chat <a href="https://github.com/rpgp/rpgp">PGP</a> и
и убедитесь, что в качестве “Типа сетевого профиля” выбрана <strong>Частная сеть</strong>.
(после передачи, вы можете изменить обратно на исходное значение)</p>
</li>
<li>
<p>На <strong>iOS</strong>, убедитесь, что предоставлен доступ “Настройки системы / Приложения / Delta Chat / <strong>Локальная сеть</strong></p>
</li>
<li>
<p>На <strong>macOS</strong>, включите “Системные настройки / Конфиденциальность и безопасность / <strong>Локальная сеть</strong> / Delta Chat”</p>
</li>
<li>
<p>В вашей системе может быть установлен “персональный брандмауэр”,
который может вызвать проблемы (особенно на Windows).
@@ -1430,11 +1436,11 @@ PIN-код разблокировки экрана, графический кл
<ul>
<li>В общем, каждый может поделиться приложениями webxdc
друг с другом без ограничений.</li>
<li>Из <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>Вы можете <a href="https://delta.chat/en/2023-08-11-xstore">отправить hi на xstore@testrun.org</a>
чтобы увидеть экспериментальный магазин приложений webxdc.
Все приложения с открытым исходным кодом и бесплатны.</li>
<li>Многие люди пишут свои собственные приложения webxdc и публикуют их на <a href="https://support.delta.chat/c/webxdc/20">форуме
Delta Chat</a>.</li>
<li>Многие люди создают свои собственные приложения webxdc и публикуют их на <a href="https://support.delta.chat/c/webxdc/20">форуме Delta Chat</a>.</li>
</ul>
<h3 id="как-я-могу-создать-свои-собственные-приложения-webxdc">
@@ -1879,6 +1885,35 @@ Chat.</li>
<li>Смотрите <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Стандарты, используемые в Delta Chat</a>.</li>
</ul>
<h3 id="где-мои-друзья-могут-найти-delta-chat">
Где мои друзья могут найти Delta Chat? <a href="#где-мои-друзья-могут-найти-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat доступен на всех популярных и некоторых менее известных платформах:</p>
<ul>
<li>
<p>На <strong>официальной странице загрузки</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> можно найти подробную информацию о всех вариантах</p>
</li>
<li>
<p>Если основной сайт недоступен, используйте <strong>зеркало</strong> <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Откройте один из следующих <strong>онлайн-магазинов приложений и введите запрос “Delta Chat”:</strong>
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, App Store для iOS и macOS, Microsoft Store</p>
</li>
<li>
<p>Проверьте <strong>менеджер пакетов</strong> вашего дистрибутива Linux</p>
</li>
<li>
<p>Файлы <strong>APK для Android</strong> доступны на <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="как-финансируются-разработки-delta-chat">
+38 -2
View File
@@ -99,6 +99,7 @@
<li><a href="#je-delta-chat-kompatibilný-s-protonmail--tutanota--criptext">Je Delta Chat kompatibilný s Protonmail / Tutanota / Criptext?</a></li>
<li><a href="#remove-account">How can I delete my account?</a></li>
<li><a href="#zaujímajú-ma-technické-detaily-môžete-mi-povedať-viac">Zaujímajú ma technické detaily. Môžete mi povedať viac?</a></li>
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
<li><a href="#ako-sa-financuje-vývoj-delta-chat">Ako sa financuje vývoj Delta Chat?</a></li>
</ul>
</li>
@@ -301,8 +302,7 @@ Archived chats remain accessible above the chat list or via search.</p>
</li>
</ul>
<p>To archive or pin a chat, long tap (Android), use the chats menu (Android/Desktop) or swipe to the left (iOS);
to mute a chat, use the chats menu (Android/Desktop) or the chats profile (iOS).</p>
<p>To use the functions, long tap or right click a chat in the chat list.</p>
<h3 id="what-does-the-green-dot-mean">
@@ -1315,6 +1315,12 @@ One device is not needed for the other to work.</p>
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
(after transfer, you can change back to the original value)</p>
</li>
<li>
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
</li>
<li>
<p>On <strong>macOS</strong>, enable “System Settings / Privacy &amp; Security / <strong>Local Network</strong> / Delta Chat”</p>
</li>
<li>
<p>Your system might have a “personal firewall”,
which is known to cause problems (especially on Windows).
@@ -1432,6 +1438,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
<ul>
<li>In general, anyone can share webxdc apps with each
other without restrictions.</li>
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send hi to xstore@testrun.org</a>
to see an experimental webxdc appstore.
All of the apps are open source and for free.</li>
@@ -1879,6 +1886,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
<li>Pozrite si <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Štandardy používané v Delta Chate</a>.</li>
</ul>
<h3 id="where-can-my-friends-find-delta-chat">
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat is available for all major and some minor platforms:</p>
<ul>
<li>
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
</li>
<li>
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
</li>
<li>
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="ako-sa-financuje-vývoj-delta-chat">
+36
View File
@@ -99,6 +99,7 @@
<li><a href="#a-është-i-përputhshëm-delta-chat-i-me-protonmail-in--tutanota-n--criptext-in">A është i përputhshëm Delta Chat-i me Protonmail-in / Tutanota-n / Criptext-in?</a></li>
<li><a href="#remove-account">Si mund ta fshij llogarinë time?</a></li>
<li><a href="#më-interesojnë-hollësitë-teknike-mund-të-më-tregoni-diçka-më-tepër">Më interesojnë hollësitë teknike. Mund të më tregoni diçka më tepër?</a></li>
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
<li><a href="#si-financohet-zhvillimi-i-delta-chat-it">Si financohet zhvillimi i Delta Chat-it?</a></li>
</ul>
</li>
@@ -1315,6 +1316,12 @@ Njëra pajisja ska nevojë për tjetrën që të funksionojë.</p>
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
(after transfer, you can change back to the original value)</p>
</li>
<li>
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
</li>
<li>
<p>On <strong>macOS</strong>, enable “System Settings / Privacy &amp; Security / <strong>Local Network</strong> / Delta Chat”</p>
</li>
<li>
<p>Sistemi juaj mund të ketë një “firewall personal”,
që dihet se shkakton probleme (veçanërisht në Windows).
@@ -1890,6 +1897,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
<li>Shihni <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Standarde të përdorur në Delta Chat</a>.</li>
</ul>
<h3 id="where-can-my-friends-find-delta-chat">
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat is available for all major and some minor platforms:</p>
<ul>
<li>
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
</li>
<li>
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
</li>
<li>
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="si-financohet-zhvillimi-i-delta-chat-it">
+41 -4
View File
@@ -99,6 +99,7 @@
<li><a href="#чи-сумісний-delta-chat-із-protonmail--tutanota--criptext">Чи сумісний Delta Chat із Protonmail / Tutanota / Criptext?</a></li>
<li><a href="#remove-account">Як мені видалити свій обліковий запис?</a></li>
<li><a href="#мене-цікавлять-технічні-деталі-можете-розповісти-більше">Мене цікавлять технічні деталі. Можете розповісти більше?</a></li>
<li><a href="#де-мої-друзі-можуть-знайти-delta-chat">Де мої друзі можуть знайти Delta Chat?</a></li>
<li><a href="#як-фінансується-розробка-delta-chat">Як фінансується розробка Delta Chat?</a></li>
</ul>
</li>
@@ -267,7 +268,7 @@
</li>
</ul>
<p>Щоб заархівувати або закріпити чат, довго торкніться (Android), скористайтеся меню чату (Android/комп’ютер) або проведіть пальцем ліворуч (iOS); щоб вимкнути звук чату, скористайтеся меню чату (Android/комп’ютер) або профілем чату (iOS).</p>
<p>Щоб скористатися функціями, утримуйте натиснутою клавішу або клацніть правою кнопкою миші на чаті у списку чатів.</p>
<h3 id="що-означає-зелена-точка">
@@ -944,6 +945,12 @@ Look for something like <strong>Start Autocrypt Setup Transfer</strong> in the s
<li>
<p>У <strong>Windows</strong> перейдіть до <strong>Панель керування / Мережа та Інтернет</strong> і переконайтеся, що <strong>Приватна мережа</strong> вибрано як “Тип мережевого профілю” (після перенесення ви можете повернути початкове значення)</p>
</li>
<li>
<p>На <strong>iOS</strong> переконайтеся, що доступ до “Системні налаштування / Програми / Delta Chat / <strong>Локальна мережа</strong>” дозволено</p>
</li>
<li>
<p>У <strong>macOS</strong> увімкніть “Системні налаштування / Конфіденційність і безпека / <strong>Локальна мережа</strong> / Delta Chat”</p>
</li>
<li>
<p>Ваша система може мати “персональний брандмауер”, який, як відомо, викликає проблеми (особливо у Windows). <strong>Вимкніть персональний брандмауер</strong> для Delta Chat на обох кінцях і повторіть спробу</p>
</li>
@@ -1032,9 +1039,11 @@ Look for something like <strong>Start Autocrypt Setup Transfer</strong> in the s
</h3>
<ul>
<li>Загалом, будь-хто може ділитися додатками webxdc один з одним один з одним без обмежень.</li>
<li>Ви можете <a href="https://delta.chat/en/2023-08-11-xstore">надіслати “hi” на xstore@testrun.org</a> щоб побачити експериментальний магазин додатків webxdc. Всі програми мають відкритий вихідний код і є безкоштовними.</li>
<li>Багато людей пишуть власні програми для webxdc і публікують їх на <a href="https://support.delta.chat/c/webxdc/20">форумі Delta Chat</a>.</li>
<li>Загалом, будь-хто може ділитися додатками webxdc один з одним без обмежень.</li>
<li>З <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>Ви можете <a href="https://delta.chat/en/2023-08-11-xstore">надіслати “привіт” на xstore@testrun.org</a> щоб побачити експериментальний магазин додатків webxdc.
Всі програми мають відкритий вихідний код і є безкоштовними.</li>
<li>Багато людей пишуть власні програми webxdc і публікують їх на <a href="https://support.delta.chat/c/webxdc/20">форумі Delta Chat</a>.</li>
</ul>
<h3 id="як-я-можу-створювати-власні-програми-webxdc">
@@ -1374,6 +1383,34 @@ Look for something like <strong>Start Autocrypt Setup Transfer</strong> in the s
<li>Дивіться <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Стандарти, що використовуються у Delta Chat</a>.</li>
</ul>
<h3 id="де-мої-друзі-можуть-знайти-delta-chat">
Де мої друзі можуть знайти Delta Chat? <a href="#де-мої-друзі-можуть-знайти-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat доступний для всіх основних і деяких другорядних платформ:</p>
<ul>
<li>
<p>На <strong>офіційному сайті</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> детально описані всі варіанти</p>
</li>
<li>
<p>Якщо вона недоступна, скористайтеся <strong>дзеркалом</strong> за адресою <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Відкрийте один з наступних <strong>магазинів додатків і введіть у пошук “Delta Chat”:</strong> Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS та macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Перевірте <strong>менеджер пакунків</strong> вашого дистрибутива Linux</p>
</li>
<li>
<p><strong>APK для Android</strong> також доступні на <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="як-фінансується-розробка-delta-chat">
+87 -62
View File
@@ -27,9 +27,9 @@
</li>
<li><a href="#instant-delivery">Instant message delivery and Push Notifications</a>
<ul>
<li><a href="#what-are-push-notifications-how-can-i-get-instant-message-delivery">What are Push Notifications? How can I get instant message delivery?</a></li>
<li><a href="#are-push-notifications-enabled-on-ios-devices-is-there-an-alternative">Are Push Notifications enabled on iOS devices? Is there an alternative?</a></li>
<li><a href="#android-push">Are Push notifications enabled / needed on Android devices?</a></li>
<li><a href="#什么是推送通知如何获得即时消息传递">什么是推送通知?如何获得即时消息传递?</a></li>
<li><a href="#ios-设备上是否启用了推送通知我还有其他的选择吗">iOS 设备上是否启用了推送通知?我还有其他的选择吗?</a></li>
<li><a href="#android-设备上是否启用需要推送通知android-push">Android 设备上是否启用/需要推送通知?{#android-push}</a></li>
<li><a href="#privacy-notifications">How private are Delta Chat Push Notifications?</a></li>
<li><a href="#why-does-delta-chat-integrate-with-centralized-proprietary-applegoogle-push-services">Why does Delta Chat integrate with centralized proprietary Apple/Google push services?</a></li>
</ul>
@@ -44,7 +44,7 @@
<li><a href="#are-attachments-pictures-files-audio-etc-end-to-end-encrypted">Are attachments (pictures, files, audio etc.) end-to-end encrypted?</a></li>
<li><a href="#openpgp-secure">Is OpenPGP secure?</a></li>
<li><a href="#openpgp-alternatives">Did you consider using alternatives to OpenPGP for end-to-end -encryption?</a></li>
<li><a href="#is-delta-chat-vulnerable-to-efail">Is Delta Chat vulnerable to EFAIL?</a></li>
<li><a href="#delta-chat-是否容易受到-efail-攻击">Delta Chat 是否容易受到 EFAIL 攻击?</a></li>
<li><a href="#tls">Is a message exposed in cleartext if end-to-end encryption is not available?</a></li>
<li><a href="#message-metadata">How does Delta Chat protect metadata in messages?</a></li>
<li><a href="#device-seizure">How to protect metadata and contacts when a device is seized?</a></li>
@@ -53,7 +53,7 @@
<li><a href="#why-do-i-see-unencrypted-messages">Why do I see unencrypted messages?</a></li>
<li><a href="#how-can-i-get-an-end-to-end-encrypted-chat-with-a-delta-chat-contact-who-sometimes-uses-webmail-or-another-non-autocrypt-e-mail-app">How can i get an end-to-end encrypted chat with a Delta Chat contact who sometimes uses webmail or another non-Autocrypt e-mail app?</a></li>
<li><a href="#how-can-i-ensure-message-end-to-end-encryption-and-deletion">How can I ensure message end-to-end encryption and deletion?</a></li>
<li><a href="#pfs">Does Delta Chat support Perfect Forward Secrecy?</a></li>
<li><a href="#pfs">Delta Chat 是否支持完美前向保密?</a></li>
<li><a href="#is-end-to-end-encryption-of-delta-chat-as-safe-as-signal">Is end-to-end encryption of Delta Chat as safe as Signal?</a></li>
<li><a href="#importkey">我可以重复使用现有的私钥吗?</a></li>
<li><a href="#我无法将现有的-pgp-密钥导入-delta-chat">我无法将现有的 PGP 密钥导入 Delta Chat。</a></li>
@@ -99,6 +99,7 @@
<li><a href="#delta-chat-与-protonmail--tutanota--criptext-兼容吗">Delta Chat 与 Protonmail / Tutanota / Criptext 兼容吗?</a></li>
<li><a href="#remove-account">如何删除我的账户?</a></li>
<li><a href="#我对技术细节很感兴趣能告诉我更多吗">我对技术细节很感兴趣。能告诉我更多吗?</a></li>
<li><a href="#where-can-my-friends-find-delta-chat">Where can my friends find Delta Chat?</a></li>
<li><a href="#delta-chat-的开发是如何被资助的">Delta Chat 的开发是如何被资助的?</a></li>
</ul>
</li>
@@ -337,10 +338,8 @@ The messages are deleted
both in each email account on the server,
and in the app itself.</p>
<p>Note that you can rely on disappearing messages
only as long as you trust your chat partners;
malicious chat partners can take photos,
or otherwise save, copy or forward messages before deletion.</p>
<p>请注意,只有当您信任您的聊天伙伴时,您才可以依赖“消息定时销毁”;
不怀好意的人可能会拍照,或者在删除之前以其他方式保存、复制或转发消息。</p>
<p>Apart from that,
if one chat partner uninstalls Delta Chat,
@@ -473,64 +472,59 @@ Delta Chat 收到的所有电子邮件都将在此期限后从服务器中删除
</h2>
<h3 id="what-are-push-notifications-how-can-i-get-instant-message-delivery">
<h3 id="什么是推送通知如何获得即时消息传递">
What are Push Notifications? How can I get instant message delivery? <a href="#what-are-push-notifications-how-can-i-get-instant-message-delivery" class="anchor"></a>
什么是推送通知?如何获得即时消息传递? <a href="#什么是推送通知如何获得即时消息传递" class="anchor"></a>
</h3>
<p>Push Notifications are sent by Apple and Google “Push services” to a users device
so that an inactive Delta Chat app can fetch messages in the background
and show notifications on a users phone if needed.</p>
<p>推送通知由 Apple Google 的“推送服务”发送到用户的设备,以便非活动状态的 Delta Chat 应用可以在后台获取消息,并在需要时在用户的手机上显示通知。</p>
<p>Push Notifications work with all <a href="https://delta.chat/chatmail">chatmail</a> servers on</p>
<p>推送通知适用于以下所有 <a href="https://delta.chat/chatmail">chatmail</a> 服务器:</p>
<ul>
<li>
<p>iOS devices, by integrating with Apple Push services.</p>
<p>iOS 设备通过与 Apple Push 服务集成。</p>
</li>
<li>
<p>Android devices, by integrating with the Google FCM Push service,
including on devices that use <a href="https://microg.org">microG</a>
instead of proprietary Google code on the phone.</p>
<p>Android 设备,通过与 Google FCM Push 服务集成,
包括使用 <a href="https://microg.org">microG</a>
而不是手机上专有 Google 代码的设备。</p>
</li>
</ul>
<p>As of May 2024, classic e-mail servers do not support Push Notifications
for Delta Chat users.</p>
<p>自 2024 年 5 月起,传统电子邮件服务器不再支持 Delta Chat 用户的推送通知。</p>
<h3 id="are-push-notifications-enabled-on-ios-devices-is-there-an-alternative">
<h3 id="ios-设备上是否启用了推送通知我还有其他的选择吗">
Are Push Notifications enabled on iOS devices? Is there an alternative? <a href="#are-push-notifications-enabled-on-ios-devices-is-there-an-alternative" class="anchor"></a>
iOS 设备上是否启用了推送通知?我还有其他的选择吗? <a href="#ios-设备上是否启用了推送通知我还有其他的选择吗" class="anchor"></a>
</h3>
<p>Yes, Delta Chat automatically uses Push Notifications for <a href="https://delta.chat/chatmail">chatmail</a> profiles.
And no, there is no alternative on Apples phones to achieve instant message delivery
because Apple devices do not allow Delta Chat to fetch data in the background.
Push notifications are automatically activated for iOS users because
<a href="#privacy-notifications">Delta Chats privacy-preserving Push Notification system</a>
does not expose data to Apple that it doesnt already have.</p>
<p>是的,Delta Chat 会自动使用推送通知来接收 <a href="https://delta.chat/chatmail">chatmail</a> 个人资料。
而且,Apple 手机上没有其他方式可以实现即时消息传递
因为 Apple 设备不允许 Delta Chat 在后台获取数据。
推送通知会自动为 iOS 用户激活,因为
<a href="#privacy-notifications">Delta Chat 的隐私保护推送通知系统</a>
不会向 Apple 泄露其尚未拥有的数据。</p>
<h3 id="android-push">
<h3 id="android-设备上是否启用需要推送通知android-push">
Are Push notifications enabled / needed on Android devices? <a href="#android-push" class="anchor"></a>
Android 设备上是否启用/需要推送通知?{#android-push} <a href="#android-设备上是否启用需要推送通知android-push" class="anchor"></a>
</h3>
<p>If a “Push Service” is available, Delta Chat enables Push Notifications
to achieve instant message delivery for all chatmail users.
If you are using a classic e-mail provider instead of <a href="https://delta.chat/chatmail">chatmail</a> servers,
Push Notifications are not available.</p>
<p>如果有“推送服务”可用,Delta Chat 将启用推送通知,
以实现所有聊天邮件用户的即时消息传递。
如果您使用的是传统电子邮件提供商而不是 <a href="https://delta.chat/chatmail">chatmail</a> 服务器,则无法使用推送通知。</p>
<p>In the Delta Chat “Notifications” settings for “Instant delivery”
you can change the following settings effecting all chat profiles:</p>
<p> Delta Chat“通知”的“推送通知”设置中,您可以更改以下影响所有聊天配置文件的设置:</p>
<ul>
<li>
@@ -710,17 +704,13 @@ both sides will eventually see a (group or direct) chat with a green checkmark
next to the title.</p>
</li>
<li>
<p>If one of the devices is offline, the green checkmarks will only
appear later when the device is internet-connected again
and the Secure-Join network protocol completed.</p>
<p>如果其中一个设备处于离线状态,则只有当设备再次连接互联网且安全加入网络协议完成时,绿色复选标记才会出现。</p>
</li>
</ul>
<p>Congratulations!
You now will automatically use guaranteed end-to-end encryption
with this contact and both of you can add each other to green-checkmarked groups
<img style="vertical-align:middle; width:1.5em; margin:1px" src="../green-checkmark.png" alt="green checkmark" />,
thereby automatically spreading guaranteed end-to-end encryption among its members.</p>
<p>恭喜!
从现在开始您将会自动使用安全的端到端加密与此联系人联系,并且双方都可以将对方添加到绿色复选标记的群组
<img style="vertical-align:middle; width:1.5em; margin:1px" src="../green-checkmark.png" alt="green checkmark" />,从而自动在其成员之间传播有保障的端到端加密。</p>
<h3 id="e2eeguarantee">
@@ -891,19 +881,18 @@ only one part of “user outcomes”,
see also our answers to <a href="#device-seizure">device-seizure</a>
and <a href="#message-metadata">message-metadata</a> questions.</p>
<h3 id="is-delta-chat-vulnerable-to-efail">
<h3 id="delta-chat-是否容易受到-efail-攻击">
Is Delta Chat vulnerable to EFAIL? <a href="#is-delta-chat-vulnerable-to-efail" class="anchor"></a>
Delta Chat 是否容易受到 EFAIL 攻击? <a href="#delta-chat-是否容易受到-efail-攻击" class="anchor"></a>
</h3>
<p>No, <a href="https://delta.chat/en/2018-05-15-delta-chat-not-vulnerable-to-efail">Delta Chat never was vulnerable to EFAIL</a>
because its OpenPGP implementation <a href="https://github.com/rpgp/rpgp">rPGP</a>
uses Modification Detection Code when encrypting messages
and returns <a href="https://docs.rs/pgp/latest/pgp/errors/enum.Error.html#variant.MdcError">an error</a>
if the Modification Detection Code is incorrect.</p>
<p>不,<a href="https://delta.chat/en/2018-05-15-delta-chat-not-vulnerable-to-efail">Delta Chat 从未受到任何 EFAIL 攻击</a>
因为所使用的 OpenPGP 实现了 <a href="https://github.com/rpgp/rpgp">rPGP</a>
在加密消息时“修改检测代码”
并且如果“修改检测代码”不正确则返回 <a href="https://docs.rs/pgp/latest/pgp/errors/enum.Error.html#variant.MdcError">错误</a></p>
<p>Delta Chat also never was vulnerable to the “Direct Exfiltration” EFAIL attack
because it only decrypts <code class="language-plaintext highlighter-rouge">multipart/encrypted</code> messages
@@ -1072,21 +1061,21 @@ you can also turn on <a href="#delold">“delete messages from server automatica
<h3 id="pfs">
Does Delta Chat support Perfect Forward Secrecy? <a href="#pfs" class="anchor"></a>
Delta Chat 是否支持完美前向保密? <a href="#pfs" class="anchor"></a>
</h3>
<p>No, Delta Chat doesnt support Perfect Forward Secrecy (PFS).
This means that if your Delta Chat private decryption key is leaked,
and someone has collected your prior in-transit messages,
they will be able to decrypt and read them using the leaked decryption key.</p>
<p>不,Delta Chat 不支持完美前向保密 (PFS)
这意味着,如果您的 Delta Chat 私人解密密钥泄露,
并且有人收集了您之前传输的消息,
他们将能够使用泄露的解密密钥解密并阅读这些消息。</p>
<p>Note, however, that if anyone obtains to your decryption keys,
they will typically also be able to obtain your messages,
irrespective if Perfect Forward Secrecy is in place or not.
The typical real-world situation for leaked decryption keys is device seizure
which we discuss in our answer <a href="#device-seizure">on metadata and device seizure</a>.</p>
<p>但请注意,如果有人获得您的解密密钥,
他们通常也能够获得您的消息,
无论是否实施了完全前向保密。
泄露解密密钥的典型现实情况是设备扣押,
我们在<a href="#device-seizure">关于元数据和设备扣押</a>的回答中讨论了这一点。</p>
<p>It is possible that Delta Chat evolves to support Perfect Forward Secrecy,
because OpenPGP is just a container for encrypted messages
@@ -1272,6 +1261,12 @@ One device is not needed for the other to work.</p>
and make sure, <strong>Private Network</strong> is selected as “Network profile type”
(after transfer, you can change back to the original value)</p>
</li>
<li>
<p>On <strong>iOS</strong>, make sure “System Settings / Apps / Delta Chat / <strong>Local Network</strong>” access is granted</p>
</li>
<li>
<p>On <strong>macOS</strong>, enable “System Settings / Privacy &amp; Security / <strong>Local Network</strong> / Delta Chat”</p>
</li>
<li>
<p>Your system might have a “personal firewall”,
which is known to cause problems (especially on Windows).
@@ -1384,6 +1379,7 @@ you only open attachments from senders you trust, and not from spammers.</li>
<ul>
<li>In general, anyone can share webxdc apps with each
other without restrictions.</li>
<li>From <a href="https://webxdc.org/apps/">webxdc.org/apps</a>.</li>
<li>You can <a href="https://delta.chat/en/2023-08-11-xstore">send hi to xstore@testrun.org</a>
to see an experimental webxdc appstore.
All of the apps are open source and for free.</li>
@@ -1794,6 +1790,35 @@ Otherwise you might receive undecryptable messages from those group chats.</p>
<li>请参阅 <a href="https://github.com/deltachat/deltachat-core-rust/blob/master/standards.md#standards-used-in-delta-chat">Delta Chat 中使用的标准</a></li>
</ul>
<h3 id="where-can-my-friends-find-delta-chat">
Where can my friends find Delta Chat? <a href="#where-can-my-friends-find-delta-chat" class="anchor"></a>
</h3>
<p>Delta Chat is available for all major and some minor platforms:</p>
<ul>
<li>
<p>The <strong>official website</strong>, <a href="https://delta.chat/download">https://delta.chat/download</a> shows all options in detail</p>
</li>
<li>
<p>If unavailable, use the <strong>mirror</strong> at <a href="https://deltachat.github.io/deltachat-pages">https://deltachat.github.io/deltachat-pages</a></p>
</li>
<li>
<p>Open one of the following <strong>app stores and search for “Delta Chat”:</strong>
Google Play Store, F-Droid, Huawei App Gallery, Amazon App Store, iOS and macOS App Store, Microsoft Store</p>
</li>
<li>
<p>Check the <strong>package manager</strong> of your Linux distributions</p>
</li>
<li>
<p><strong>Android APKs</strong> are also available on <a href="https://github.com/deltachat/deltachat-android/releases">https://github.com/deltachat/deltachat-android/releases</a></p>
</li>
</ul>
<h3 id="delta-chat-的开发是如何被资助的">
@@ -2,16 +2,14 @@ package com.b44t.messenger;
public class DcContext {
public final static int DC_PREF_DEFAULT_MDNS_ENABLED = 1;
public final static int DC_PREF_DEFAULT_TRIM_ENABLED = 0;
public final static int DC_PREF_DEFAULT_TRIM_LENGTH = 500;
public final static int DC_EVENT_INFO = 100;
public final static int DC_EVENT_WARNING = 300;
public final static int DC_EVENT_ERROR = 400;
public final static int DC_EVENT_ERROR_SELF_NOT_IN_GROUP = 410;
public final static int DC_EVENT_MSGS_CHANGED = 2000;
public final static int DC_EVENT_REACTIONS_CHANGED = 2001;
public final static int DC_EVENT_INCOMING_REACTION = 2002;
public final static int DC_EVENT_INCOMING_WEBXDC_NOTIFY = 2003;
public final static int DC_EVENT_INCOMING_MSG = 2005;
public final static int DC_EVENT_MSGS_NOTICED = 2008;
public final static int DC_EVENT_MSG_DELIVERED = 2010;
@@ -82,16 +80,13 @@ public class DcContext {
public final static int DC_MEDIA_QUALITY_BALANCED = 0;
public final static int DC_MEDIA_QUALITY_WORSE = 1;
public final static int DC_DECISION_START_CHAT = 0;
public final static int DC_DECISION_BLOCK = 1;
public final static int DC_DECISION_NOT_NOW = 2;
public final static int DC_CONNECTIVITY_NOT_CONNECTED = 1000;
public final static int DC_CONNECTIVITY_CONNECTING = 2000;
public final static int DC_CONNECTIVITY_WORKING = 3000;
public final static int DC_CONNECTIVITY_CONNECTED = 4000;
private static final String CONFIG_ACCOUNT_ENABLED = "ui.enabled";
private static final String CONFIG_MENTION_NOTIF_ENABLED = "ui.notify_mentions";
// when using DcAccounts, use DcAccounts.addAccount() instead
public DcContext(String osName, String dbfile) {
@@ -204,7 +199,7 @@ public class DcContext {
public native int sendMsg (int chat_id, DcMsg msg);
public native int sendTextMsg (int chat_id, String text);
public native int sendVideochatInvitation(int chat_id);
public native boolean sendWebxdcStatusUpdate(int msg_id, String payload, String descr);
public native boolean sendWebxdcStatusUpdate(int msg_id, String payload);
public native String getWebxdcStatusUpdates(int msg_id, int last_known_serial);
public native void setWebxdcIntegration (String file);
public native int initWebxdcIntegration(int chat_id);
@@ -232,22 +227,12 @@ public class DcContext {
}
}
public String getNameNAddr() {
String displayname = getConfig("displayname");
String addr = getConfig("addr");
String ret = "";
public boolean isMentionsEnabled() {
return !"0".equals(getConfig(CONFIG_MENTION_NOTIF_ENABLED));
}
if (!displayname.isEmpty() && !addr.isEmpty()) {
ret = String.format("%s (%s)", displayname, addr);
} else if (!addr.isEmpty()) {
ret = addr;
}
if (ret.isEmpty() || isConfigured() == 0) {
ret += " (not configured)";
}
return ret.trim();
public void setMentionsEnabled(boolean enabled) {
setConfigInt(CONFIG_MENTION_NOTIF_ENABLED, enabled? 1 : 0);
}
public String getName() {
+3 -2
View File
@@ -148,6 +148,7 @@ public class DcMsg {
return new JSONObject();
}
}
public native String getWebxdcHref ();
public native boolean isForwarded ();
public native boolean isInfo ();
public native boolean isSetupMessage ();
@@ -170,10 +171,10 @@ public class DcMsg {
public native boolean isOutgoing();
public native int getSenderColor();
public String getSenderName(DcContact dcContact, boolean markOverride) {
public String getSenderName(DcContact dcContact) {
String overrideName = getOverrideSenderName();
if (overrideName != null) {
return (markOverride ? "~" : "") + overrideName;
return "~" + overrideName;
} else {
return dcContact.getDisplayName();
}
@@ -36,7 +36,6 @@ import org.thoughtcrime.securesms.connect.KeepAliveService;
import org.thoughtcrime.securesms.connect.NetworkStateReceiver;
import org.thoughtcrime.securesms.crypto.DatabaseSecret;
import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider;
import org.thoughtcrime.securesms.crypto.PRNGFixes;
import org.thoughtcrime.securesms.geolocation.DcLocationManager;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.notifications.FcmReceiveService;
@@ -203,7 +202,6 @@ public class ApplicationContext extends MultiDexApplication {
KeepAliveService.maybeStartSelf(this);
initializeRandomNumberFix();
initializeLogging();
initializeJobManager();
InChatSounds.getInstance(this);
@@ -252,10 +250,6 @@ public class ApplicationContext extends MultiDexApplication {
return jobManager;
}
private void initializeRandomNumberFix() {
PRNGFixes.apply();
}
private void initializeLogging() {
SignalProtocolLoggerProvider.setProvider(new AndroidSignalProtocolLogger());
}
@@ -156,10 +156,6 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
this.findPreference(PREFERENCE_CATEGORY_HELP)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_HELP));
if (VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
tintIcons(getActivity());
}
DcHelper.getEventCenter(getActivity()).addObserver(DcContext.DC_EVENT_CONNECTIVITY_CHANGED, this);
}
@@ -33,9 +33,6 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
onPreCreate();
if (BaseActivity.isMenuWorkaroundRequired()) {
forceOverflowMenu();
}
super.onCreate(savedInstanceState);
}
@@ -46,20 +43,6 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
dynamicTheme.onResume(this);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) {
openOptionsMenu();
return true;
}
return super.onKeyUp(keyCode, event);
}
private void initializeScreenshotSecurity() {
if (Prefs.isScreenSecurityEnabled(this)) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
@@ -1,28 +0,0 @@
package org.thoughtcrime.securesms;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import android.view.KeyEvent;
public abstract class BaseActivity extends FragmentActivity {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return (keyCode == KeyEvent.KEYCODE_MENU && isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && isMenuWorkaroundRequired()) {
openOptionsMenu();
return true;
}
return super.onKeyUp(keyCode, event);
}
public static boolean isMenuWorkaroundRequired() {
return VERSION.SDK_INT < VERSION_CODES.KITKAT && ("LGE".equalsIgnoreCase(Build.MANUFACTURER) || "E6710".equalsIgnoreCase(Build.DEVICE));
}
}
@@ -364,9 +364,7 @@ public abstract class BaseConversationListFragment extends Fragment implements A
mode.setTitle("1");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
requireActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
}
requireActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
return true;
}
@@ -395,11 +393,9 @@ public abstract class BaseConversationListFragment extends Fragment implements A
actionMode = null;
getListAdapter().initializeBatchMode(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
TypedArray color = requireActivity().getTheme().obtainStyledAttributes(new int[] {android.R.attr.statusBarColor});
requireActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
color.recycle();
}
TypedArray color = requireActivity().getTheme().obtainStyledAttributes(new int[]{android.R.attr.statusBarColor});
requireActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
color.recycle();
Context context = getContext();
if (context != null) {
@@ -136,9 +136,7 @@ public class ContactSelectionListFragment extends Fragment
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.contact_list, menu);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
}
getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
setCorrectMenuVisibility(menu);
actionMode.setTitle("1");
return true;
@@ -170,11 +168,9 @@ public class ContactSelectionListFragment extends Fragment
ContactSelectionListFragment.this.actionMode = null;
getContactSelectionListAdapter().resetActionModeSelection();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
TypedArray color = getActivity().getTheme().obtainStyledAttributes(new int[] {android.R.attr.statusBarColor});
getActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
color.recycle();
}
TypedArray color = getActivity().getTheme().obtainStyledAttributes(new int[]{android.R.attr.statusBarColor});
getActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
color.recycle();
}
};
@@ -708,7 +708,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
DcMsg draft = dcContext.getDraft(chatId);
final String sharedText = RelayUtil.getSharedText(this);
if (draft == null) {
if (!draft.isOk()) {
if (TextUtils.isEmpty(sharedText)) {
composeText.setText("");
future.set(false);
@@ -929,12 +929,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
case AttachmentTypeSelector.TAKE_PHOTO:
attachmentManager.capturePhoto(this, TAKE_PHOTO); break;
case AttachmentTypeSelector.RECORD_VIDEO:
if(VideoRecoder.canRecode()) {
attachmentManager.captureVideo(this, RECORD_VIDEO);
}
else {
Toast.makeText(this, "This device does not support video-compression (requires Android 4.4 KitKat)", Toast.LENGTH_LONG).show();
}
attachmentManager.captureVideo(this, RECORD_VIDEO);
break;
}
}
@@ -24,7 +24,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
@@ -442,7 +441,7 @@ public class ConversationFragment extends MessageSelectorFragment
if (msg.getFromId() != prevMsg.getFromId() && !singleMsg) {
DcContact contact = dcContext.getContact(msg.getFromId());
result.append(msg.getSenderName(contact, false)).append(":\n");
result.append(msg.getSenderName(contact)).append(":\n");
}
if (msg.getType() == DcMsg.DC_MSG_TEXT || (singleMsg && !msg.getText().isEmpty())) {
result.append(msg.getText());
@@ -810,7 +809,7 @@ public class ConversationFragment extends MessageSelectorFragment
DozeReminder.dozeReminderTapped(getContext());
}
else if(messageRecord.getInfoType() == DcMsg.DC_INFO_WEBXDC_INFO_MESSAGE) {
scrollMaybeSmoothToMsgId(messageRecord.getParent().getId());
WebxdcActivity.openWebxdcActivity(getContext(), messageRecord.getParent(), messageRecord.getWebxdcHref());
}
else {
String self_mail = dcContext.getConfig("configured_mail_user");
@@ -911,11 +910,9 @@ public class ConversationFragment extends MessageSelectorFragment
mode.setTitle("1");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getActivity().getWindow();
statusBarColor = window.getStatusBarColor();
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
}
Window window = getActivity().getWindow();
statusBarColor = window.getStatusBarColor();
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
setCorrectMenuVisibility(menu);
ConversationAdaptiveActionsToolbar.adjustMenuActions(menu, 10, requireActivity().getWindow().getDecorView().getMeasuredWidth());
@@ -932,9 +929,7 @@ public class ConversationFragment extends MessageSelectorFragment
((ConversationAdapter)list.getAdapter()).clearSelection();
list.getAdapter().notifyDataSetChanged();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getActivity().getWindow().setStatusBarColor(statusBarColor);
}
getActivity().getWindow().setStatusBarColor(statusBarColor);
actionMode = null;
hideAddReactionView();
@@ -22,12 +22,10 @@ import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.os.Build;
import android.text.Spannable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@@ -72,7 +70,6 @@ import org.thoughtcrime.securesms.util.Linkifier;
import org.thoughtcrime.securesms.util.LongClickMovementMethod;
import org.thoughtcrime.securesms.util.MarkdownUtil;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.views.Stub;
@@ -387,7 +384,6 @@ public class ConversationItem extends BaseConversationItem
private void setBodyText(DcMsg messageRecord) {
bodyText.setClickable(false);
bodyText.setFocusable(false);
bodyText.setTextSize(TypedValue.COMPLEX_UNIT_SP, Prefs.getMessageBodyTextSize(context));
String text = messageRecord.getText();
@@ -498,9 +494,7 @@ public class ConversationItem extends BaseConversationItem
audioViewStub.get().setAudio(new AudioSlide(context, messageRecord), duration);
audioViewStub.get().setOnClickListener(passthroughClickListener);
audioViewStub.get().setOnLongClickListener(passthroughClickListener);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
audioViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
audioViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -518,9 +512,7 @@ public class ConversationItem extends BaseConversationItem
documentViewStub.get().setDocument(new DocumentSlide(context, messageRecord));
documentViewStub.get().setDocumentClickListener(new ThumbnailClickListener());
documentViewStub.get().setOnLongClickListener(passthroughClickListener);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
documentViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
documentViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -537,9 +529,7 @@ public class ConversationItem extends BaseConversationItem
webxdcViewStub.get().setWebxdc(messageRecord, context.getString(R.string.webxdc_app));
webxdcViewStub.get().setWebxdcClickListener(new ThumbnailClickListener());
webxdcViewStub.get().setOnLongClickListener(passthroughClickListener);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webxdcViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
webxdcViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -557,9 +547,7 @@ public class ConversationItem extends BaseConversationItem
vcardViewStub.get().setVcardClickListener(new ThumbnailClickListener());
vcardViewStub.get().setOnLongClickListener(passthroughClickListener);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
vcardViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
vcardViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -595,9 +583,7 @@ public class ConversationItem extends BaseConversationItem
mediaThumbnailStub.get().setOnLongClickListener(passthroughClickListener);
mediaThumbnailStub.get().setOnClickListener(passthroughClickListener);
mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getText()));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mediaThumbnailStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
mediaThumbnailStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
setThumbnailOutlineCorners(messageRecord, showSender);
@@ -620,9 +606,7 @@ public class ConversationItem extends BaseConversationItem
stickerStub.get().setThumbnailClickListener(new StickerClickListener());
stickerStub.get().setOnLongClickListener(passthroughClickListener);
stickerStub.get().setOnClickListener(passthroughClickListener);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
stickerStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
}
stickerStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -683,7 +667,7 @@ public class ConversationItem extends BaseConversationItem
contactPhoto.setVisibility(View.GONE);
} else {
int color = messageRecord.getSenderColor();
Recipient recipient = new Recipient(context, dcContact, messageRecord.getSenderName(dcContact, !dcContext.isCommunity()), color);
Recipient recipient = new Recipient(context, dcContact, messageRecord.getSenderName(dcContact), color);
contactPhoto.setAvatar(glideRequests, recipient, true);
contactPhoto.setVisibility(View.VISIBLE);
}
@@ -808,14 +792,14 @@ public class ConversationItem extends BaseConversationItem
if (messageRecord.isForwarded()) {
if (showSender && dcContact !=null) {
this.groupSender.setText(context.getString(R.string.forwarded_by, messageRecord.getSenderName(dcContact, false)));
this.groupSender.setText(context.getString(R.string.forwarded_by, messageRecord.getSenderName(dcContact)));
} else {
this.groupSender.setText(context.getString(R.string.forwarded_message));
}
this.groupSender.setTextColor(context.getResources().getColor(R.color.unknown_sender));
}
else if (showSender && dcContact !=null) {
this.groupSender.setText(messageRecord.getSenderName(dcContact, true));
this.groupSender.setText(messageRecord.getSenderName(dcContact));
int color = messageRecord.getSenderColor();
this.groupSender.setTextColor(Util.rgbToArgbColor(color!=0? color : dcContact.getColor()));
}
@@ -174,9 +174,7 @@ class ConversationItemSwipeCallback extends ItemTouchHelper.SimpleCallback {
vibrate(viewHolder.itemView.getContext());
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
recyclerView.cancelPendingInputEvents();
}
recyclerView.cancelPendingInputEvents();
}
private static void resetProgress(RecyclerView.ViewHolder viewHolder) {
@@ -199,11 +197,7 @@ class ConversationItemSwipeCallback extends ItemTouchHelper.SimpleCallback {
}
private static float getSignFromDirection(@NonNull View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -1f : 1f;
} else {
return 1f;
}
return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -1f : 1f;
}
private static boolean sameSign(float dX, float sign) {
@@ -564,7 +564,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
private void shareInvite() {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
String inviteURL = Util.QrDataToInviteURL(DcHelper.getContext(this).getSecurejoinQr(0));
String inviteURL = DcHelper.getContext(this).getSecurejoinQr(0);
intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.invite_friends_text, inviteURL));
startActivity(Intent.createChooser(intent, getString(R.string.chat_share_with_title)));
}
@@ -29,7 +29,6 @@ public class ConversationListItemInboxZero extends LinearLayout implements Binda
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ConversationListItemInboxZero(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@@ -246,16 +246,22 @@ public class InstantOnboardingActivity extends BaseActionBarActivity implements
protected void onPause() {
super.onPause();
final String displayName = name.getText().toString();
DcHelper.set(this, DcHelper.CONFIG_DISPLAY_NAME, TextUtils.isEmpty(displayName)? null : displayName);
// Save display name and avatar in the unconfigured profile.
// If the currently selected profile is configured, then this means that rollbackAccountCreation()
// was called (see handleOnBackPressed() above), i.e. the newly created profile was removed already
// and we can't save the display name & avatar.
if (DcHelper.getContext(this).isConfigured() == 0) {
final String displayName = name.getText().toString();
DcHelper.set(this, DcHelper.CONFIG_DISPLAY_NAME, TextUtils.isEmpty(displayName) ? null : displayName);
if (avatarChanged) {
try {
AvatarHelper.setSelfAvatar(InstantOnboardingActivity.this, avatarBmp);
Prefs.setProfileAvatarId(InstantOnboardingActivity.this, new SecureRandom().nextInt());
avatarChanged = false;
} catch (IOException e) {
Log.e(TAG, "Failed to save avatar", e);
if (avatarChanged) {
try {
AvatarHelper.setSelfAvatar(InstantOnboardingActivity.this, avatarBmp);
Prefs.setProfileAvatarId(InstantOnboardingActivity.this, new SecureRandom().nextInt());
avatarChanged = false;
} catch (IOException e) {
Log.e(TAG, "Failed to save avatar", e);
}
}
}
}
@@ -197,12 +197,11 @@ public class LogViewFragment extends Fragment {
asMegs(info.maxMemory()));
}
@TargetApi(VERSION_CODES.KITKAT)
public static String getMemoryClass(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
String lowMem = "";
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT && activityManager.isLowRamDevice()) {
if (activityManager.isLowRamDevice()) {
lowMem = ", low-mem device";
}
return activityManager.getMemoryClass() + lowMem;
@@ -252,10 +251,8 @@ public class LogViewFragment extends Fragment {
Locale locale = Util.getLocale();
builder.append("lang=").append(locale.toString()).append("\n");
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
boolean isRtl = Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL;
builder.append("rtl=").append(isRtl).append("\n");
}
boolean isRtl = Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL;
builder.append("rtl=").append(isRtl).append("\n");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
boolean notifPermGranted = PermissionChecker.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) == PermissionChecker.PERMISSION_GRANTED;
@@ -229,11 +229,9 @@ public class ProfileDocumentsFragment
mode.getMenuInflater().inflate(R.menu.profile_context, menu);
mode.setTitle("1");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getActivity().getWindow();
originalStatusBarColor = window.getStatusBarColor();
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
}
Window window = getActivity().getWindow();
originalStatusBarColor = window.getStatusBarColor();
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
setCorrectMenuVisibility(menu);
return true;
}
@@ -283,9 +281,7 @@ public class ProfileDocumentsFragment
actionMode = null;
getListAdapter().clearSelection();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
}
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
}
}
}
@@ -219,11 +219,9 @@ public class ProfileGalleryFragment
mode.getMenuInflater().inflate(R.menu.profile_context, menu);
mode.setTitle("1");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getActivity().getWindow();
originalStatusBarColor = window.getStatusBarColor();
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
}
Window window = getActivity().getWindow();
originalStatusBarColor = window.getStatusBarColor();
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
setCorrectMenuVisibility(menu);
return true;
}
@@ -269,9 +267,7 @@ public class ProfileGalleryFragment
actionMode = null;
getListAdapter().clearSelection();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
}
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
}
}
}
@@ -268,11 +268,9 @@ public class ProfileSettingsFragment extends Fragment
menu.findItem(R.id.menu_select_all).setVisible(false);
mode.setTitle("1");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getActivity().getWindow();
originalStatusBarColor = window.getStatusBarColor();
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
}
Window window = getActivity().getWindow();
originalStatusBarColor = window.getStatusBarColor();
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
return true;
}
@@ -314,9 +312,7 @@ public class ProfileSettingsFragment extends Fragment
public void onDestroyActionMode(ActionMode mode) {
actionMode = null;
adapter.clearSelection();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
}
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
}
}
@@ -40,6 +40,7 @@ import com.b44t.messenger.DcEvent;
import com.b44t.messenger.DcMsg;
import com.b44t.messenger.rpc.Rpc;
import com.b44t.messenger.rpc.RpcException;
import com.google.common.base.Charsets;
import org.json.JSONObject;
import org.thoughtcrime.securesms.connect.AccountManager;
@@ -54,6 +55,8 @@ import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -63,6 +66,7 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
private static final String EXTRA_ACCOUNT_ID = "accountId";
private static final String EXTRA_APP_MSG_ID = "appMessageId";
private static final String EXTRA_HIDE_ACTION_BAR = "hideActionBar";
private static final String EXTRA_HREF = "href";
private static final int REQUEST_CODE_FILE_PICKER = 51426;
private ValueCallback<Uri[]> filePathCallback;
@@ -71,6 +75,7 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
private DcMsg dcAppMsg;
private String baseURL;
private String sourceCodeUrl = "";
private String selfAddr = "";
private boolean internetAccess = false;
private boolean hideActionBar = false;
@@ -92,33 +97,34 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
return;
}
}
openWebxdcActivity(context, msgId, true);
openWebxdcActivity(context, msgId, true, "");
}
public static void openWebxdcActivity(Context context, DcMsg instance) {
openWebxdcActivity(context, instance.getId(), false);
openWebxdcActivity(context, instance, "");
}
public static void openWebxdcActivity(Context context, int msgId, boolean hideActionBar) {
public static void openWebxdcActivity(Context context, DcMsg instance, String href) {
openWebxdcActivity(context, instance.getId(), false, href);
}
public static void openWebxdcActivity(Context context, int msgId, boolean hideActionBar, String href) {
if (!Util.isClickedRecently()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (Prefs.isDeveloperModeEnabled(context)) {
WebView.setWebContentsDebuggingEnabled(true);
}
context.startActivity(getWebxdcIntent(context, msgId, hideActionBar));
} else {
Toast.makeText(context, "At least Android 5.0 (Lollipop) required for Webxdc.", Toast.LENGTH_LONG).show();
if (Prefs.isDeveloperModeEnabled(context)) {
WebView.setWebContentsDebuggingEnabled(true);
}
context.startActivity(getWebxdcIntent(context, msgId, hideActionBar, href));
}
}
private static Intent getWebxdcIntent(Context context, int msgId, boolean hideActionBar) {
private static Intent getWebxdcIntent(Context context, int msgId, boolean hideActionBar, String href) {
DcContext dcContext = DcHelper.getContext(context);
Intent intent = new Intent(context, WebxdcActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(EXTRA_ACCOUNT_ID, dcContext.getAccountId());
intent.putExtra(EXTRA_APP_MSG_ID, msgId);
intent.putExtra(EXTRA_HIDE_ACTION_BAR, hideActionBar);
intent.putExtra(EXTRA_HREF, href);
return intent;
}
@@ -129,7 +135,7 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
.putExtra(ConversationActivity.CHAT_ID_EXTRA, dcContext.getMsg(msgId).getChatId())
.setAction(Intent.ACTION_VIEW);
final Intent webxdcIntent = getWebxdcIntent(context, msgId, false);
final Intent webxdcIntent = getWebxdcIntent(context, msgId, false, "");
return TaskStackBuilder.create(context)
.addNextIntentWithParentStack(chatIntent)
@@ -197,6 +203,7 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
// this is needed here because if the app is opened while already in landscape mode, onConfigurationChanged() is not triggered
setScreenMode(getResources().getConfiguration());
}
selfAddr = JsonUtils.optString(info, "self_addr");
toggleFakeProxy(!internetAccess);
@@ -213,7 +220,15 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
webView.setNetworkAvailable(internetAccess); // this does not block network but sets `window.navigator.isOnline` in js land
webView.addJavascriptInterface(new InternalJSApi(), "InternalJSApi");
webView.loadUrl(this.baseURL + "/index.html");
String href = b.getString(EXTRA_HREF, "");
String encodedHref = "";
try {
encodedHref = URLEncoder.encode(href, Charsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
webView.loadUrl(this.baseURL + "/webxdc_bootstrap324567869.html?i=1&href=" + encodedHref);
Util.runOnAnyBackgroundThread(() -> {
final DcChat chat = dcContext.getChat(dcAppMsg.getChatId());
@@ -223,6 +238,18 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
});
}
@Override
public void onResume() {
super.onResume();
DcHelper.getNotificationCenter(this).updateVisibleWebxdc(dcContext.getAccountId(), dcAppMsg.getId());
}
@Override
protected void onPause() {
super.onPause();
DcHelper.getNotificationCenter(this).clearVisibleWebxdc();
}
@Override
protected void onDestroy() {
DcHelper.getEventCenter(this.getApplicationContext()).removeObservers(this);
@@ -249,6 +276,9 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
case R.id.source_code:
openUrlInBrowser(this, sourceCodeUrl);
return true;
case R.id.show_in_chat:
showInChat();
return true;
}
return false;
}
@@ -334,7 +364,7 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
res = new WebResourceResponse("text/plain", "UTF-8", targetStream);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !internetAccess) {
if (!internetAccess) {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Security-Policy",
"default-src 'self'; "
@@ -353,9 +383,7 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
}
private void callJavaScriptFunction(String func) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript("window." + func + ";", null);
}
webView.evaluateJavascript("document.getElementById('frame').contentWindow." + func + ";", null);
}
@Override
@@ -394,6 +422,13 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
}
}
private void showInChat() {
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.CHAT_ID_EXTRA, dcAppMsg.getChatId());
intent.putExtra(ConversationActivity.STARTING_POSITION_EXTRA, DcMsg.getMessagePosition(dcAppMsg, dcContext));
startActivity(intent);
}
public static void addToHomeScreen(Activity activity, int msgId) {
Context context = activity.getApplicationContext();
try {
@@ -475,7 +510,7 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
int flags = Base64.NO_WRAP | Base64.NO_PADDING | Base64.URL_SAFE;
return Base64.encodeToString(dcContext.getCommunityUser().getBytes(), flags);
}
return dcContext.getConfig("configured_addr");
return WebxdcActivity.this.selfAddr;
}
/** @noinspection unused*/
@@ -493,9 +528,9 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
/** @noinspection unused*/
@JavascriptInterface
public boolean sendStatusUpdate(String payload, String descr) {
public boolean sendStatusUpdate(String payload) {
Log.i(TAG, "sendStatusUpdate");
if (!WebxdcActivity.this.dcContext.sendWebxdcStatusUpdate(WebxdcActivity.this.dcAppMsg.getId(), payload, descr)) {
if (!WebxdcActivity.this.dcContext.sendWebxdcStatusUpdate(WebxdcActivity.this.dcAppMsg.getId(), payload)) {
DcChat dcChat = WebxdcActivity.this.dcContext.getChat(WebxdcActivity.this.dcAppMsg.getChatId());
Toast.makeText(WebxdcActivity.this,
dcChat.isContactRequest() ?
@@ -166,7 +166,7 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
.withPermanentDenialDialog(getString(R.string.perm_explain_access_to_storage_denied))
.onAllGranted(() -> {
File imexDir = DcHelper.getImexDir();
if (Build.VERSION.SDK_INT >= 30) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
AttachmentManager.selectMediaType(this, "application/x-tar", null, PICK_BACKUP, StorageUtil.getDownloadUri());
} else {
final String backupFile = dcContext.imexHasBackup(imexDir.getAbsolutePath());
@@ -130,33 +130,23 @@ public class AttachmentTypeSelector extends PopupWindow {
public void onGlobalLayout() {
getContentView().getViewTreeObserver().removeGlobalOnLayoutListener(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
animateWindowInCircular(anchor, getContentView());
} else {
animateWindowInTranslate(getContentView());
}
animateWindowInCircular(anchor, getContentView());
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//animateButtonIn(cameraButton, ANIMATION_DURATION / 2);
animateButtonIn(videoButton, ANIMATION_DURATION / 2);
animateButtonIn(imageButton, ANIMATION_DURATION / 3);
animateButtonIn(contactButton, ANIMATION_DURATION / 3);
animateButtonIn(locationButton, ANIMATION_DURATION / 4);
animateButtonIn(documentButton, ANIMATION_DURATION / 4);
animateButtonIn(videoChatButton, 0);
animateButtonIn(closeButton, 0);
}
//animateButtonIn(cameraButton, ANIMATION_DURATION / 2);
animateButtonIn(videoButton, ANIMATION_DURATION / 2);
animateButtonIn(imageButton, ANIMATION_DURATION / 3);
animateButtonIn(contactButton, ANIMATION_DURATION / 3);
animateButtonIn(locationButton, ANIMATION_DURATION / 4);
animateButtonIn(documentButton, ANIMATION_DURATION / 4);
animateButtonIn(videoChatButton, 0);
animateButtonIn(closeButton, 0);
}
@Override
public void dismiss() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
animateWindowOutCircular(currentAnchor, getContentView());
} else {
animateWindowOutTranslate(getContentView());
}
animateWindowOutCircular(currentAnchor, getContentView());
}
public void setListener(@Nullable AttachmentClickedListener listener) {
@@ -186,7 +176,6 @@ public class AttachmentTypeSelector extends PopupWindow {
button.startAnimation(animation);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void animateWindowInCircular(@Nullable View anchor, @NonNull View contentView) {
Pair<Integer, Integer> coordinates = getClickOrigin(anchor, contentView);
Animator animator = ViewAnimationUtils.createCircularReveal(contentView,
@@ -205,7 +194,6 @@ public class AttachmentTypeSelector extends PopupWindow {
getContentView().startAnimation(animation);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void animateWindowOutCircular(@Nullable View anchor, @NonNull View contentView) {
Pair<Integer, Integer> coordinates = getClickOrigin(anchor, contentView);
Animator animator = ViewAnimationUtils.createCircularReveal(getContentView(),
@@ -71,12 +71,10 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
this.pauseButton.setOnClickListener(new PauseClickedListener());
this.seekBar.setOnSeekBarChangeListener(new SeekBarModifiedListener());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.playButton.setImageDrawable(context.getDrawable(R.drawable.play_icon));
this.pauseButton.setImageDrawable(context.getDrawable(R.drawable.pause_icon));
this.playButton.setBackground(context.getDrawable(R.drawable.ic_circle_fill_white_48dp));
this.pauseButton.setBackground(context.getDrawable(R.drawable.ic_circle_fill_white_48dp));
}
this.playButton.setImageDrawable(context.getDrawable(R.drawable.play_icon));
this.pauseButton.setImageDrawable(context.getDrawable(R.drawable.pause_icon));
this.playButton.setBackground(context.getDrawable(R.drawable.ic_circle_fill_white_48dp));
this.pauseButton.setBackground(context.getDrawable(R.drawable.ic_circle_fill_white_48dp));
setTint(getContext().getResources().getColor(R.color.audio_icon));
}
@@ -192,13 +190,8 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
}
public void setTint(int foregroundTint) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.playButton.setBackgroundTintList(ColorStateList.valueOf(foregroundTint));
this.pauseButton.setBackgroundTintList(ColorStateList.valueOf(foregroundTint));
} else {
this.playButton.setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
this.pauseButton.setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
}
this.playButton.setBackgroundTintList(ColorStateList.valueOf(foregroundTint));
this.pauseButton.setBackgroundTintList(ColorStateList.valueOf(foregroundTint));
this.seekBar.getProgressDrawable().setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
@@ -220,25 +213,20 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
private void togglePlayToPause() {
controlToggle.displayQuick(pauseButton);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AnimatedVectorDrawable playToPauseDrawable = (AnimatedVectorDrawable)getContext().getDrawable(R.drawable.play_to_pause_animation);
pauseButton.setImageDrawable(playToPauseDrawable);
playToPauseDrawable.start();
}
AnimatedVectorDrawable playToPauseDrawable = (AnimatedVectorDrawable) getContext().getDrawable(R.drawable.play_to_pause_animation);
pauseButton.setImageDrawable(playToPauseDrawable);
playToPauseDrawable.start();
}
private void togglePauseToPlay() {
controlToggle.displayQuick(playButton);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AnimatedVectorDrawable pauseToPlayDrawable = (AnimatedVectorDrawable)getContext().getDrawable(R.drawable.pause_to_play_animation);
playButton.setImageDrawable(pauseToPlayDrawable);
pauseToPlayDrawable.start();
}
AnimatedVectorDrawable pauseToPlayDrawable = (AnimatedVectorDrawable) getContext().getDrawable(R.drawable.pause_to_play_animation);
playButton.setImageDrawable(pauseToPlayDrawable);
pauseToPlayDrawable.start();
}
private class PlayClickedListener implements View.OnClickListener {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onClick(View v) {
try {
@@ -279,7 +267,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
}
private class PauseClickedListener implements View.OnClickListener {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onClick(View v) {
Log.w(TAG, "pausebutton onClick");
@@ -122,7 +122,6 @@ public class ComposeText extends AppCompatEditText {
editorInfo.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
}
if (Build.VERSION.SDK_INT < 21) return inputConnection;
if (mediaListener == null) return inputConnection;
if (inputConnection == null) return null;
@@ -120,15 +120,10 @@ public class ConversationItemThumbnail extends FrameLayout {
@SuppressWarnings("SuspiciousNameCombination")
@Override
protected void dispatchDraw(Canvas canvas) {
if (cornerMask.isLegacy()) {
cornerMask.mask(canvas);
}
super.dispatchDraw(canvas);
if (!cornerMask.isLegacy()) {
cornerMask.mask(canvas);
}
cornerMask.mask(canvas);
final float halfStrokeWidth = outlinePaint.getStrokeWidth() / 2;
@@ -7,7 +7,7 @@ import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.Build;
import androidx.annotation.NonNull;
import android.view.View;
@@ -20,11 +20,7 @@ public class CornerMask {
private final RectF bounds = new RectF();
public CornerMask(@NonNull View view) {
if (isLegacy()) {
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
} else {
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
clearPaint.setColor(Color.BLACK);
clearPaint.setStyle(Paint.Style.FILL);
@@ -44,19 +40,10 @@ public class CornerMask {
// Note: There's a bug in the P beta where most PorterDuff modes aren't working. But CLEAR does.
// So we find and inverse path and use Mode.CLEAR for versions that support Path.op().
// See issue https://issuetracker.google.com/issues/111394085.
if (!isLegacy()) {
outline.reset();
outline.addRect(bounds, Path.Direction.CW);
outline.op(corners, Path.Op.DIFFERENCE);
canvas.drawPath(outline, clearPaint);
} else {
corners.addRoundRect(bounds, radii, Path.Direction.CW);
canvas.clipPath(corners);
}
}
public boolean isLegacy() {
return Build.VERSION.SDK_INT < 19;
outline.reset();
outline.addRect(bounds, Path.Direction.CW);
outline.op(corners, Path.Op.DIFFERENCE);
canvas.drawPath(outline, clearPaint);
}
public void setRadius(int radius) {
@@ -104,7 +104,7 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
}
private void updateKeyboardState() {
if (viewInset == 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) viewInset = getViewInset();
if (viewInset == 0) viewInset = getViewInset();
getWindowVisibleDisplayFrame(rect);
@@ -148,7 +148,6 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
}
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private int getViewInset() {
try {
Field attachInfoField = View.class.getDeclaredField("mAttachInfo");
@@ -219,11 +218,7 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
return Surface.ROTATION_0;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return ServiceUtil.getWindowManager(getContext()).getDefaultDisplay().getRotation();
}
if (Build.VERSION.SDK_INT >= 30) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
getContext().getDisplay().getRealMetrics(displayMetrics);
} else {
ServiceUtil.getWindowManager(getContext()).getDefaultDisplay().getRealMetrics(displayMetrics);
@@ -40,7 +40,6 @@ public class MediaView extends FrameLayout {
initialize();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MediaView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize();
@@ -4,7 +4,6 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.net.Uri;
import android.os.Build;
import android.text.Spannable;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -17,7 +16,6 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.annimon.stream.Stream;
import com.b44t.messenger.DcContact;
@@ -80,7 +78,6 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
initialize(attrs);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public QuoteView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize(attrs);
@@ -158,7 +155,7 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
if (contact == null) {
authorView.setText(getContext().getString(R.string.forwarded_message));
} else {
authorView.setText(getContext().getString(R.string.forwarded_by, quotedMsg.getSenderName(contact, false)));
authorView.setText(getContext().getString(R.string.forwarded_by, quotedMsg.getSenderName(contact)));
}
authorView.setTextColor(getForwardedColor());
quoteBarView.setBackgroundColor(getForwardedColor());
@@ -169,7 +166,7 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
quoteBarView.setBackgroundColor(getForwardedColor());
} else {
authorView.setVisibility(VISIBLE);
authorView.setText(quotedMsg.getSenderName(contact, true));
authorView.setText(quotedMsg.getSenderName(contact));
if (hasSticker) {
authorView.setTextColor(getResources().getColor(R.color.core_dark_05));
quoteBarView.setBackgroundColor(getResources().getColor(R.color.core_dark_05));
@@ -29,7 +29,6 @@ public class RepeatableImageKey extends ImageButton {
init();
}
@TargetApi(VERSION_CODES.LOLLIPOP)
public RepeatableImageKey(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes)
{
@@ -130,15 +130,11 @@ public class SearchToolbar extends LinearLayout {
searchItem.expandActionView();
if (Build.VERSION.SDK_INT >= 21) {
Animator animator = ViewAnimationUtils.createCircularReveal(this, (int)x, (int)y, 0, getWidth());
animator.setDuration(400);
Animator animator = ViewAnimationUtils.createCircularReveal(this, (int) x, (int) y, 0, getWidth());
animator.setDuration(400);
setVisibility(View.VISIBLE);
animator.start();
} else {
setVisibility(View.VISIBLE);
}
setVisibility(View.VISIBLE);
animator.start();
}
}
@@ -153,19 +149,15 @@ public class SearchToolbar extends LinearLayout {
if (listener != null) listener.onSearchClosed();
if (Build.VERSION.SDK_INT >= 21) {
Animator animator = ViewAnimationUtils.createCircularReveal(this, (int)x, (int)y, getWidth(), 0);
animator.setDuration(400);
animator.addListener(new AnimationCompleteListener() {
@Override
public void onAnimationEnd(Animator animation) {
setVisibility(View.INVISIBLE);
}
});
animator.start();
} else {
setVisibility(View.INVISIBLE);
}
Animator animator = ViewAnimationUtils.createCircularReveal(this, (int) x, (int) y, getWidth(), 0);
animator.setDuration(400);
animator.addListener(new AnimationCompleteListener() {
@Override
public void onAnimationEnd(Animator animation) {
setVisibility(View.INVISIBLE);
}
});
animator.start();
}
}
@@ -18,7 +18,6 @@ public class SwitchPreferenceCompat extends CheckBoxPreference {
setLayoutRes();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SwitchPreferenceCompat(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setLayoutRes();
File diff suppressed because one or more lines are too long
@@ -171,7 +171,15 @@ public class DcEventCenter {
switch (id) {
case DcContext.DC_EVENT_INCOMING_MSG:
DcHelper.getNotificationCenter(context).addNotification(accountId, event.getData1Int(), event.getData2Int());
DcHelper.getNotificationCenter(context).notifyMessage(accountId, event.getData1Int(), event.getData2Int());
break;
case DcContext.DC_EVENT_INCOMING_REACTION:
DcHelper.getNotificationCenter(context).notifyReaction(accountId, event.getData1Int(), event.getData2Int(), event.getData2Str());
break;
case DcContext.DC_EVENT_INCOMING_WEBXDC_NOTIFY:
DcHelper.getNotificationCenter(context).notifyWebxdc(accountId, event.getData1Int(), event.getData2Int(), event.getData2Str());
break;
case DcContext.DC_EVENT_MSGS_NOTICED:
@@ -263,9 +263,7 @@ public class DcHelper {
}
public static File getImexDir() {
// DIRECTORY_DOCUMENTS is only available since KitKat;
// as we also support Ice Cream Sandwich and Jellybean (2017: 11% in total), this is no option.
// Moreover, DIRECTORY_DOWNLOADS seems to be easier accessible by the user,
// DIRECTORY_DOCUMENTS could be used but DIRECTORY_DOWNLOADS seems to be easier accessible by the user,
// eg. "Download Managers" are nearly always installed.
// CAVE: do not use DownloadManager to add the file as it is deleted on uninstall then ...
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
@@ -1,345 +0,0 @@
/*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will Google be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, as long as the origin is not misrepresented.
*/
package org.thoughtcrime.securesms.crypto;
import android.os.Build;
import android.os.Process;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.SecureRandomSpi;
import java.security.Security;
/**
* This class is taken directly from the Android blog post announcing this bug:
* http://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html
*
* Since I still don't know exactly what the source of this bug was, I'm using
* this class verbatim under the assumption that the Android team knows what
* they're doing. Although, at this point, that is perhaps a foolish assumption.
*/
/**
* Fixes for the output of the default PRNG having low entropy.
*
* The fixes need to be applied via {@link #apply()} before any use of Java
* Cryptography Architecture primitives. A good place to invoke them is in the
* application's {@code onCreate}.
*/
public final class PRNGFixes {
private static final int VERSION_CODE_JELLY_BEAN = 16;
private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL =
getBuildFingerprintAndDeviceSerial();
/** Hidden constructor to prevent instantiation. */
private PRNGFixes() {}
/**
* Applies all fixes.
*
* @throws SecurityException if a fix is needed but could not be applied.
*/
public static void apply() {
applyOpenSSLFix();
installLinuxPRNGSecureRandom();
}
/**
* Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
* fix is not needed.
*
* @throws SecurityException if the fix is needed but could not be applied.
*/
private static void applyOpenSSLFix() throws SecurityException {
if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN)
|| (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) {
// No need to apply the fix
return;
}
try {
// Mix in the device- and invocation-specific seed.
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
.getMethod("RAND_seed", byte[].class)
.invoke(null, generateSeed());
// Mix output of Linux PRNG into OpenSSL's PRNG
int bytesRead = (Integer) Class.forName(
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
.getMethod("RAND_load_file", String.class, long.class)
.invoke(null, "/dev/urandom", 1024);
if (bytesRead != 1024) {
throw new IOException(
"Unexpected number of bytes read from Linux PRNG: "
+ bytesRead);
}
} catch (Exception e) {
throw new SecurityException("Failed to seed OpenSSL PRNG", e);
}
}
/**
* Installs a Linux PRNG-backed {@code SecureRandom} implementation as the
* default. Does nothing if the implementation is already the default or if
* there is not need to install the implementation.
*
* @throws SecurityException if the fix is needed but could not be applied.
*/
private static void installLinuxPRNGSecureRandom()
throws SecurityException {
if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
// No need to apply the fix
return;
}
// Install a Linux PRNG-based SecureRandom implementation as the
// default, if not yet installed.
Provider[] secureRandomProviders =
Security.getProviders("SecureRandom.SHA1PRNG");
if ((secureRandomProviders == null)
|| (secureRandomProviders.length < 1)
|| (!LinuxPRNGSecureRandomProvider.class.equals(
secureRandomProviders[0].getClass()))) {
Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1);
}
// Assert that new SecureRandom() and
// SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
// by the Linux PRNG-based SecureRandom implementation.
SecureRandom rng1 = new SecureRandom();
if (!LinuxPRNGSecureRandomProvider.class.equals(
rng1.getProvider().getClass())) {
throw new SecurityException(
"new SecureRandom() backed by wrong Provider: "
+ rng1.getProvider().getClass());
}
SecureRandom rng2;
try {
rng2 = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
throw new SecurityException("SHA1PRNG not available", e);
}
if (!LinuxPRNGSecureRandomProvider.class.equals(
rng2.getProvider().getClass())) {
throw new SecurityException(
"SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
+ " Provider: " + rng2.getProvider().getClass());
}
}
/**
* {@code Provider} of {@code SecureRandom} engines which pass through
* all requests to the Linux PRNG.
*/
private static class LinuxPRNGSecureRandomProvider extends Provider {
public LinuxPRNGSecureRandomProvider() {
super("LinuxPRNG",
1.0,
"A Linux-specific random number provider that uses"
+ " /dev/urandom");
// Although /dev/urandom is not a SHA-1 PRNG, some apps
// explicitly request a SHA1PRNG SecureRandom and we thus need to
// prevent them from getting the default implementation whose output
// may have low entropy.
put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName());
put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
}
}
/**
* {@link SecureRandomSpi} which passes all requests to the Linux PRNG
* ({@code /dev/urandom}).
*/
public static class LinuxPRNGSecureRandom extends SecureRandomSpi {
/*
* IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed
* are passed through to the Linux PRNG (/dev/urandom). Instances of
* this class seed themselves by mixing in the current time, PID, UID,
* build fingerprint, and hardware serial number (where available) into
* Linux PRNG.
*
* Concurrency: Read requests to the underlying Linux PRNG are
* serialized (on sLock) to ensure that multiple threads do not get
* duplicated PRNG output.
*/
private static final File URANDOM_FILE = new File("/dev/urandom");
private static final Object sLock = new Object();
/**
* Input stream for reading from Linux PRNG or {@code null} if not yet
* opened.
*
* @GuardedBy("sLock")
*/
private static DataInputStream sUrandomIn;
/**
* Output stream for writing to Linux PRNG or {@code null} if not yet
* opened.
*
* @GuardedBy("sLock")
*/
private static OutputStream sUrandomOut;
/**
* Whether this engine instance has been seeded. This is needed because
* each instance needs to seed itself if the client does not explicitly
* seed it.
*/
private boolean mSeeded;
@Override
protected void engineSetSeed(byte[] bytes) {
try {
OutputStream out;
synchronized (sLock) {
out = getUrandomOutputStream();
}
out.write(bytes);
out.flush();
} catch (IOException e) {
// On a small fraction of devices /dev/urandom is not writable.
// Log and ignore.
Log.w(PRNGFixes.class.getSimpleName(),
"Failed to mix seed into " + URANDOM_FILE);
} finally {
mSeeded = true;
}
}
@Override
protected void engineNextBytes(byte[] bytes) {
if (!mSeeded) {
// Mix in the device- and invocation-specific seed.
engineSetSeed(generateSeed());
}
try {
DataInputStream in;
synchronized (sLock) {
in = getUrandomInputStream();
}
synchronized (in) {
in.readFully(bytes);
}
} catch (IOException e) {
throw new SecurityException(
"Failed to read from " + URANDOM_FILE, e);
}
}
@Override
protected byte[] engineGenerateSeed(int size) {
byte[] seed = new byte[size];
engineNextBytes(seed);
return seed;
}
private DataInputStream getUrandomInputStream() {
synchronized (sLock) {
if (sUrandomIn == null) {
// NOTE: Consider inserting a BufferedInputStream between
// DataInputStream and FileInputStream if you need higher
// PRNG output performance and can live with future PRNG
// output being pulled into this process prematurely.
try {
sUrandomIn = new DataInputStream(
new FileInputStream(URANDOM_FILE));
} catch (IOException e) {
throw new SecurityException("Failed to open "
+ URANDOM_FILE + " for reading", e);
}
}
return sUrandomIn;
}
}
private OutputStream getUrandomOutputStream() throws IOException {
synchronized (sLock) {
if (sUrandomOut == null) {
sUrandomOut = new FileOutputStream(URANDOM_FILE);
}
return sUrandomOut;
}
}
}
/**
* Generates a device- and invocation-specific seed to be mixed into the
* Linux PRNG.
*/
private static byte[] generateSeed() {
try {
ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream();
DataOutputStream seedBufferOut =
new DataOutputStream(seedBuffer);
seedBufferOut.writeLong(System.currentTimeMillis());
seedBufferOut.writeLong(System.nanoTime());
seedBufferOut.writeInt(Process.myPid());
seedBufferOut.writeInt(Process.myUid());
seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL);
seedBufferOut.close();
return seedBuffer.toByteArray();
} catch (IOException e) {
throw new SecurityException("Failed to generate seed", e);
}
}
/**
* Gets the hardware serial number of this device.
*
* @return serial number or {@code null} if not available.
*/
private static String getDeviceSerialNumber() {
// We're using the Reflection API because Build.SERIAL is only available
// since API Level 9 (Gingerbread, Android 2.3).
try {
return (String) Build.class.getField("SERIAL").get(null);
} catch (Exception ignored) {
return null;
}
}
private static byte[] getBuildFingerprintAndDeviceSerial() {
StringBuilder result = new StringBuilder();
String fingerprint = Build.FINGERPRINT;
if (fingerprint != null) {
result.append(fingerprint);
}
String serial = getDeviceSerialNumber();
if (serial != null) {
result.append(serial);
}
try {
return result.toString().getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 encoding not supported");
}
}
}
@@ -584,7 +584,7 @@ public class AttachmentManager {
final Intent intent = new Intent();
intent.setType(type);
if (extraMimeType != null && Build.VERSION.SDK_INT >= 19) {
if (extraMimeType != null) {
intent.putExtra(Intent.EXTRA_MIME_TYPES, extraMimeType);
}
@@ -596,14 +596,12 @@ public class AttachmentManager {
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
try {
activity.startActivityForResult(intent, requestCode);
return;
} catch (ActivityNotFoundException anfe) {
Log.w(TAG, "couldn't complete ACTION_OPEN_DOCUMENT, no activity found. falling back.");
}
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
try {
activity.startActivityForResult(intent, requestCode);
return;
} catch (ActivityNotFoundException anfe) {
Log.w(TAG, "couldn't complete ACTION_OPEN_DOCUMENT, no activity found. falling back.");
}
intent.setAction(Intent.ACTION_GET_CONTENT);
@@ -20,16 +20,19 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.app.RemoteInput;
import androidx.core.app.TaskStackBuilder;
import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcContact;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcMsg;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.json.JSONObject;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.ConversationActivity;
import org.thoughtcrime.securesms.ConversationListActivity;
@@ -40,6 +43,8 @@ import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPrefere
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.IntentUtils;
import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.Pair;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.Util;
@@ -54,6 +59,7 @@ public class NotificationCenter {
private static final String TAG = NotificationCenter.class.getSimpleName();
@NonNull private final ApplicationContext context;
private volatile ChatData visibleChat = null;
private volatile Pair<Integer, Integer> visibleWebxdc = null;
private volatile long lastAudibleNotification = 0;
private static final long MIN_AUDIBLE_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(2);
@@ -331,17 +337,90 @@ public class NotificationCenter {
// add notifications & co.
// --------------------------------------------------------------------------------------------
public void addNotification(int accountId, int chatId, int msgId) {
Util.runOnAnyBackgroundThread(() -> {
public void notifyMessage(int accountId, int chatId, int msgId) {
Util.runOnAnyBackgroundThread(() -> {
DcContext dcContext = context.dcAccounts.getAccount(accountId);
DcChat dcChat = dcContext.getChat(chatId);
DcMsg dcMsg = dcContext.getMsg(msgId);
NotificationPrivacyPreference privacy = Prefs.getNotificationPrivacy(context);
String shortLine = privacy.isDisplayMessage()? dcMsg.getSummarytext(2000) : context.getString(R.string.notify_new_message);
if (dcChat.isMultiUser() && privacy.isDisplayContact()) {
shortLine = dcMsg.getSenderName(dcContext.getContact(dcMsg.getFromId())) + ": " + shortLine;
}
String tickerLine = shortLine;
if (!dcChat.isMultiUser() && privacy.isDisplayContact()) {
tickerLine = dcMsg.getSenderName(dcContext.getContact(dcMsg.getFromId())) + ": " + tickerLine;
if (dcMsg.getOverrideSenderName() != null) {
// There is an "overridden" display name on the message, so, we need to prepend the display name to the message,
// i.e. set the shortLine to be the same as the tickerLine.
shortLine = tickerLine;
}
}
DcMsg quotedMsg = dcMsg.getQuotedMsg();
boolean isMention = dcChat.isMultiUser() && quotedMsg != null && quotedMsg.isOutgoing();
maybeAddNotification(accountId, dcChat, msgId, shortLine, tickerLine, true, isMention);
});
}
public void notifyReaction(int accountId, int contactId, int msgId, String reaction) {
Util.runOnAnyBackgroundThread(() -> {
DcContext dcContext = context.dcAccounts.getAccount(accountId);
DcMsg dcMsg = dcContext.getMsg(msgId);
NotificationPrivacyPreference privacy = Prefs.getNotificationPrivacy(context);
if (!privacy.isDisplayContact() || !privacy.isDisplayMessage()) {
return; // showing "New Message" is wrong and showing "New Reaction" is already content. just do nothing.
}
DcContact sender = dcContext.getContact(contactId);
String shortLine = context.getString(R.string.reaction_by_other, sender.getDisplayName(), reaction, dcMsg.getSummarytext(2000));
DcChat dcChat = dcContext.getChat(dcMsg.getChatId());
maybeAddNotification(accountId, dcChat, msgId, shortLine, shortLine, false, dcChat.isMultiUser());
});
}
public void notifyWebxdc(int accountId, int contactId, int msgId, String text) {
Util.runOnAnyBackgroundThread(() -> {
NotificationPrivacyPreference privacy = Prefs.getNotificationPrivacy(context);
if (!privacy.isDisplayContact() || !privacy.isDisplayMessage()) {
return; // showing "New Message" is wrong, just do nothing.
}
DcContext dcContext = context.dcAccounts.getAccount(accountId);
DcMsg dcMsg = dcContext.getMsg(msgId);
DcMsg parentMsg;
if(dcMsg.getType() == DcMsg.DC_MSG_WEBXDC) {
parentMsg = dcMsg;
} else { // info message, get parent xdc
parentMsg = dcMsg.getParent() != null? dcMsg.getParent() : dcMsg;
}
if (Util.equals(visibleWebxdc, new Pair<>(accountId, parentMsg.getId()))) {
return; // do not notify if the app is already open
}
JSONObject info = parentMsg.getWebxdcInfo();
final String name = JsonUtils.optString(info, "name");
String shortLine = name.isEmpty()? text : (name + ": " + text);
DcChat dcChat = dcContext.getChat(dcMsg.getChatId());
maybeAddNotification(accountId, dcChat, msgId, shortLine, shortLine, false, dcChat.isMultiUser());
});
}
@WorkerThread
private void maybeAddNotification(int accountId, DcChat dcChat, int msgId, String shortLine, String tickerLine, boolean playInChatSound, boolean isMention) {
DcContext dcContext = context.dcAccounts.getAccount(accountId);
DcChat dcChat = dcContext.getChat(chatId);
DcMsg dcMsg = dcContext.getMsg(msgId);
DcMsg quotedMsg = dcMsg.getQuotedMsg();
boolean isGroupMention = quotedMsg != null && dcChat.isMultiUser() && quotedMsg.isOutgoing();
int chatId = dcChat.getId();
ChatData chatData = new ChatData(accountId, chatId);
isMention = isMention && dcContext.isMentionsEnabled();
if (dcContext.isMuted() || (!isGroupMention && dcChat.isMuted())) {
if (dcContext.isMuted() || (!isMention && dcChat.isMuted())) {
return;
}
@@ -351,21 +430,13 @@ public class NotificationCenter {
}
if (Util.equals(visibleChat, chatData)) {
if (Prefs.isInChatNotifications(context)) {
if (playInChatSound && Prefs.isInChatNotifications(context)) {
InChatSounds.getInstance(context).playIncomingSound();
}
return;
}
// get notification text as a single line
NotificationPrivacyPreference privacy = Prefs.getNotificationPrivacy(context);
String line = privacy.isDisplayMessage()? dcMsg.getSummarytext(2000) : context.getString(R.string.notify_new_message);
if (dcChat.isMultiUser() && privacy.isDisplayContact()) {
line = dcMsg.getSenderName(dcContext.getContact(dcMsg.getFromId()), false) + ": " + line;
}
// play signal?
long now = System.currentTimeMillis();
boolean signal = (now - lastAudibleNotification) > MIN_AUDIBLE_PERIOD_MILLIS;
if (signal) {
@@ -383,7 +454,7 @@ public class NotificationCenter {
.setPriority(Prefs.getNotificationPriority(context))
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setOnlyAlertOnce(!signal)
.setContentText(line)
.setContentText(shortLine)
.setDeleteIntent(getMarkAsReadIntent(chatData, msgId, false))
.setContentIntent(getOpenChatIntent(chatData));
@@ -403,12 +474,6 @@ public class NotificationCenter {
}
}
// if privacy allows, for better accessibility,
// prepend the sender in the ticker also for one-to-one chats (for group-chats, this is already done)
String tickerLine = line;
if (!dcChat.isMultiUser() && privacy.isDisplayContact()) {
line = dcMsg.getSenderName(dcContext.getContact(dcMsg.getFromId()), false) + ": " + line;
}
builder.setTicker(tickerLine);
// set sound, vibrate, led for systems that do not have notification channels
@@ -504,9 +569,9 @@ public class NotificationCenter {
lines = new ArrayList<>();
accountInbox.put(chatId, lines);
}
lines.add(line);
lines.add(shortLine);
for (int l = lines.size() - 1; l >= 0; l--) {
for (int l = 0; l < lines.size(); l++) {
inboxStyle.addLine(lines.get(l));
}
}
@@ -552,7 +617,6 @@ public class NotificationCenter {
Log.e(TAG, "cannot add notification summary", e);
}
}
});
}
public void removeNotifications(int accountId, int chatId) {
@@ -610,6 +674,22 @@ public class NotificationCenter {
visibleChat = null;
}
public void updateVisibleWebxdc(int accountId, int msgId) {
Util.runOnAnyBackgroundThread(() -> {
if (accountId != 0 && msgId != 0) {
visibleWebxdc = new Pair<>(accountId, msgId);
} else {
visibleWebxdc = null;
}
});
}
public void clearVisibleWebxdc() {
visibleWebxdc = null;
}
public void maybePlaySendSound(DcChat dcChat) {
if (Prefs.isInChatNotifications(context) && !dcChat.isMuted()) {
InChatSounds.getInstance(context).playSendSound();
@@ -69,7 +69,6 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
DcMsg msg = new DcMsg(dcContext, DcMsg.DC_MSG_TEXT);
msg.setText(responseText.toString());
msg.setQuote(dcContext.getMsg(msgId));
dcContext.sendMsg(chatId, msg);
DcHelper.getNotificationCenter(context).removeNotifications(accountId, chatId);
@@ -136,9 +136,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
Preference developerModeEnabled = this.findPreference("pref_developer_mode_enabled");
developerModeEnabled.setOnPreferenceChangeListener((preference, newValue) -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
WebView.setWebContentsDebuggingEnabled((Boolean) newValue);
}
WebView.setWebContentsDebuggingEnabled((Boolean) newValue);
return true;
});
@@ -23,8 +23,6 @@ public class AppearancePreferenceFragment extends ListSummaryPreferenceFragment
this.findPreference(Prefs.THEME_PREF).setOnPreferenceChangeListener(new ListSummaryListener());
initializeListSummary((ListPreference)findPreference(Prefs.THEME_PREF));
this.findPreference(Prefs.BACKGROUND_PREF).setOnPreferenceClickListener(new BackgroundClickListener());
this.findPreference(Prefs.MESSAGE_BODY_TEXT_SIZE_PREF).setOnPreferenceChangeListener(new ListSummaryListener());
initializeListSummary((ListPreference) findPreference(Prefs.MESSAGE_BODY_TEXT_SIZE_PREF));
}
@Override
@@ -36,6 +36,7 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
private CheckBoxPreference ignoreBattery;
private CheckBoxPreference notificationsEnabled;
private CheckBoxPreference mentionNotifEnabled;
@Override
public void onCreate(Bundle paramBundle) {
@@ -99,6 +100,13 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
dcContext.setMuted(!enabled);
return true;
});
mentionNotifEnabled = this.findPreference("pref_enable_mention_notifications");
mentionNotifEnabled.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
dcContext.setMentionsEnabled(enabled);
return true;
});
}
@Override
@@ -114,6 +122,7 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
// update ignoreBattery in onResume() to reflects changes done in the system settings
ignoreBattery.setChecked(isIgnoringBatteryOptimizations());
notificationsEnabled.setChecked(!dcContext.isMuted());
mentionNotifEnabled.setChecked(dcContext.isMentionsEnabled());
}
@Override
@@ -26,7 +26,6 @@ public class ProfilePreference extends Preference {
private TextView profileNameView;
private TextView profileAddressView;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ProfilePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize();
@@ -63,15 +63,10 @@ public class AvatarHelper {
}
public static void cropAvatar(Activity context, Uri imageUri) {
if (Build.VERSION.SDK_INT >= 19) { // Image editor requires Android 4.4 KitKat or newer.
Intent intent = new Intent(context, ScribbleActivity.class);
intent.setData(imageUri);
intent.putExtra(ScribbleActivity.CROP_AVATAR, true);
context.startActivityForResult(intent, ScribbleActivity.SCRIBBLE_REQUEST_CODE);
} else {
Uri outputFile = Uri.fromFile(new File(context.getCacheDir(), "cropped"));
Crop.of(imageUri, outputFile).asSquare().start(context);
}
Intent intent = new Intent(context, ScribbleActivity.class);
intent.setData(imageUri);
intent.putExtra(ScribbleActivity.CROP_AVATAR, true);
context.startActivityForResult(intent, ScribbleActivity.SCRIBBLE_REQUEST_CODE);
}
}
@@ -98,6 +98,9 @@ public class QrCodeHandler {
dcContext.restartIo();
showDoneToast(activity);
});
if (rawString.toLowerCase().startsWith("http")) {
builder.setNeutralButton(R.string.open, (d, b) -> IntentUtils.showBrowserIntent(activity, rawString));
}
builder.setNegativeButton(R.string.cancel, null);
builder.setCancelable(false);
break;
@@ -119,38 +119,11 @@ public class QrShowFragment extends Fragment implements DcEventCenter.DcEventDel
return svg.replace("y=\"281.136\"", "y=\"296\"");
}
public void shareQr() {
try {
File file = new File(requireActivity().getExternalCacheDir(), "share-qr.png");
file.createNewFile();
file.setReadable(true, false);
FileOutputStream stream = new FileOutputStream(file);
Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawARGB(0,255, 255, 255); // Clear background
SVG svg = SVG.getFromString(fixSVG(dcContext.getSecurejoinQrSvg(chatId)));
svg.renderToCanvas(canvas);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream);
stream.flush();
stream.close();
Uri uri = FileProviderUtil.getUriFor(requireActivity(), file);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/png");
intent.putExtra(Intent.EXTRA_STREAM, uri);
String inviteURL = Util.QrDataToInviteURL(dcContext.getSecurejoinQr(chatId));
intent.putExtra(Intent.EXTRA_TEXT, inviteURL);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(intent, getString(R.string.chat_share_with_title)));
} catch (Exception e) {
Log.e(TAG, "failed to share QR", e);
}
}
public void shareInviteURL() {
try {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
String inviteURL = Util.QrDataToInviteURL(dcContext.getSecurejoinQr(chatId));
String inviteURL = dcContext.getSecurejoinQr(chatId);
intent.putExtra(Intent.EXTRA_TEXT, inviteURL);
startActivity(Intent.createChooser(intent, getString(R.string.chat_share_with_title)));
} catch (Exception e) {
@@ -159,7 +132,7 @@ public class QrShowFragment extends Fragment implements DcEventCenter.DcEventDel
}
public void copyQrData() {
String inviteURL = Util.QrDataToInviteURL(dcContext.getSecurejoinQr(chatId));
String inviteURL = dcContext.getSecurejoinQr(chatId);
Util.writeTextToClipboard(getActivity(), inviteURL);
Toast.makeText(getActivity(), getString(R.string.copied_to_clipboard), Toast.LENGTH_SHORT).show();
}
@@ -179,7 +152,7 @@ public class QrShowFragment extends Fragment implements DcEventCenter.DcEventDel
public void showInviteLinkDialog() {
View view = View.inflate(getActivity(), R.layout.dialog_share_invite_link, null);
String inviteURL = Util.QrDataToInviteURL(dcContext.getSecurejoinQr(chatId));
String inviteURL = dcContext.getSecurejoinQr(chatId);
((TextView)view.findViewById(R.id.invite_link)).setText(inviteURL);
new AlertDialog.Builder(getActivity())
.setView(view)
@@ -59,9 +59,6 @@ public class AddReactionView extends LinearLayout {
}
anyReactionView = findViewById(R.id.reaction_any);
anyReactionView.setOnClickListener(v -> anyReactionClicked());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
anyReactionView.setVisibility(View.GONE); // EmojiPickerView requires SDK 21 or newer
}
}
}
@@ -94,11 +94,7 @@ public final class ImageEditorHud extends LinearLayout {
}
private void initializeVisibilityMap() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
setVisibleViewsWhenInMode(Mode.NONE, drawButton, highlightButton, blurButton, textButton, cropButton, undoButton, saveButton);
} else {
setVisibleViewsWhenInMode(Mode.NONE, drawButton, highlightButton, textButton, cropButton, undoButton, saveButton);
}
setVisibleViewsWhenInMode(Mode.NONE, drawButton, highlightButton, blurButton, textButton, cropButton, undoButton, saveButton);
setVisibleViewsWhenInMode(Mode.DRAW, confirmButton, undoButton, colorPicker, colorPalette);
@@ -117,16 +117,13 @@ final class UriGlideRenderer implements Renderer {
rendererContext.restore();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
renderBlurOverlay(rendererContext);
}
renderBlurOverlay(rendererContext);
} else if (rendererContext.isBlockingLoad()) {
// If failed to load, we draw a black out, in case image was sticker positioned to cover private info.
rendererContext.canvas.drawRect(Bounds.FULL_BOUNDS, paint);
}
}
@RequiresApi(17)
private void renderBlurOverlay(RendererContext rendererContext) {
boolean renderMask = false;
@@ -98,7 +98,6 @@ public class VerticalSlideColorPicker extends View {
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public VerticalSlideColorPicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
@@ -15,10 +15,6 @@ public final class AccessibilityUtil {
Log.e("AccessibilityUtil", "animationsDisabled: context was null");
return false;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return Settings.Global.getFloat(context.getContentResolver(), Settings.Global.ANIMATOR_DURATION_SCALE, 1) == 0f;
} else {
return false;
}
return Settings.Global.getFloat(context.getContentResolver(), Settings.Global.ANIMATOR_DURATION_SCALE, 1) == 0f;
}
}
@@ -110,11 +110,7 @@ public class DateUtils extends android.text.format.DateUtils {
}
private static String getLocalizedPattern(String template) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
return DateFormat.getBestDateTimePattern(Util.getLocale(), template);
} else {
return new SimpleDateFormat(template, Util.getLocale()).toLocalizedPattern();
}
return DateFormat.getBestDateTimePattern(Util.getLocale(), template);
}
public static String getFormatedDuration(long millis) {
@@ -16,8 +16,7 @@ public class FileProviderUtil {
private static final String AUTHORITY = BuildConfig.APPLICATION_ID+".fileprovider";
public static Uri getUriFor(@NonNull Context context, @NonNull File file) throws IllegalStateException, NullPointerException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) return FileProvider.getUriForFile(context, AUTHORITY, file);
else return Uri.fromFile(file);
return FileProvider.getUriForFile(context, AUTHORITY, file);
}
}
@@ -47,7 +47,6 @@ public class Prefs {
public static final String DOZE_ASKED_DIRECTLY = "pref_doze_asked_directly";
public static final String ASKED_FOR_NOTIFICATION_PERMISSION= "pref_asked_for_notification_permission";
private static final String IN_THREAD_NOTIFICATION_PREF = "pref_key_inthread_notifications";
public static final String MESSAGE_BODY_TEXT_SIZE_PREF = "pref_message_body_text_size";
public static final String NOTIFICATION_PRIVACY_PREF = "pref_notification_privacy";
public static final String NOTIFICATION_PRIORITY_PREF = "pref_notification_priority";
@@ -104,10 +103,6 @@ public class Prefs {
return Integer.valueOf(getStringPreference(context, NOTIFICATION_PRIORITY_PREF, String.valueOf(NotificationCompat.PRIORITY_HIGH)));
}
public static int getMessageBodyTextSize(Context context) {
return Integer.valueOf(getStringPreference(context, MESSAGE_BODY_TEXT_SIZE_PREF, "16"));
}
public static void setDirectCaptureCameraId(Context context, int value) {
setIntegerPreference(context, DIRECT_CAPTURE_CAMERA_ID, value);
}
@@ -12,7 +12,7 @@ public class ScreenLockUtil {
public static boolean applyScreenLock(Activity activity, String title, String descr, int requestCode) {
KeyguardManager keyguardManager = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE);
Intent intent;
if (keyguardManager != null && isScreenLockAvailable()) {
if (keyguardManager != null) {
intent = keyguardManager.createConfirmDeviceCredentialIntent(title, descr);
if (intent != null) {
activity.startActivityForResult(intent, requestCode);
@@ -22,7 +22,4 @@ public class ScreenLockUtil {
return false;
}
private static boolean isScreenLockAvailable() {
return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP;
}
}
@@ -20,28 +20,16 @@ public class StorageUtil {
}
public static @NonNull Uri getVideoUri() {
if (Build.VERSION.SDK_INT < 21) {
return getLegacyUri(Environment.DIRECTORY_MOVIES);
} else {
return MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
}
return MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
}
public static @NonNull
Uri getAudioUri() {
if (Build.VERSION.SDK_INT < 21) {
return getLegacyUri(Environment.DIRECTORY_MUSIC);
} else {
return MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
return MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
public static @NonNull Uri getImageUri() {
if (Build.VERSION.SDK_INT < 21) {
return getLegacyUri(Environment.DIRECTORY_PICTURES);
} else {
return MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
return MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
public static @NonNull Uri getDownloadUri() {
@@ -89,10 +89,6 @@ public class Util {
return false;
}
public static String QrDataToInviteURL(String qrData) {
return "https://" + INVITE_DOMAIN + "/#" + qrData.split(":", 2)[1].replaceFirst("#", "&");
}
public static CharSequence getBoldedString(String value) {
SpannableString spanned = new SpannableString(value);
spanned.setSpan(new StyleSpan(Typeface.BOLD), 0,
@@ -261,12 +257,10 @@ public class Util {
return Arrays.hashCode(objects);
}
@TargetApi(VERSION_CODES.KITKAT)
public static boolean isLowMemory(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
return (VERSION.SDK_INT >= VERSION_CODES.KITKAT && activityManager.isLowRamDevice()) ||
activityManager.getLargeMemoryClass() <= 64;
return activityManager.isLowRamDevice() || activityManager.getLargeMemoryClass() <= 64;
}
public static int clamp(int value, int min, int max) {
@@ -390,10 +384,7 @@ public class Util {
}
public static int getLayoutDirection(Context context) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
Configuration configuration = context.getResources().getConfiguration();
return configuration.getLayoutDirection();
}
return ViewCompat.LAYOUT_DIRECTION_LTR;
Configuration configuration = context.getResources().getConfiguration();
return configuration.getLayoutDirection();
}
}
@@ -32,7 +32,9 @@ import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -166,18 +168,15 @@ public class ViewUtil {
@SuppressLint("RtlHardcoded")
public static void setTextViewGravityStart(final @NonNull TextView textView, @NonNull Context context) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
if (Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL) {
textView.setGravity(Gravity.RIGHT);
} else {
textView.setGravity(Gravity.LEFT);
}
if (Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL) {
textView.setGravity(Gravity.RIGHT);
} else {
textView.setGravity(Gravity.LEFT);
}
}
public static void mirrorIfRtl(View view, Context context) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1 &&
Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL) {
if (Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL) {
view.setScaleX(-1.0f);
}
}
@@ -202,6 +201,18 @@ public class ViewUtil {
return (int)((dp * context.getResources().getDisplayMetrics().density) + 0.5);
}
public static float pxToSp(Context context, int px) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
if (VERSION.SDK_INT >= VERSION_CODES.UPSIDE_DOWN_CAKE) {
return TypedValue.deriveDimension(TypedValue.COMPLEX_UNIT_SP, px, metrics);
} else {
if (metrics.scaledDensity == 0) {
return 0;
}
return px / metrics.scaledDensity;
}
}
public static void updateLayoutParams(@NonNull View view, int width, int height) {
view.getLayoutParams().width = width;
view.getLayoutParams().height = height;
@@ -1,14 +1,10 @@
package org.thoughtcrime.securesms.video.recode;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.os.Build;
import android.util.Log;
import androidx.appcompat.app.AlertDialog;
@@ -36,14 +32,7 @@ public class VideoRecoder {
private static final String TAG = VideoRecoder.class.getSimpleName();
private boolean videoConvertFirstWrite = true;
private final static String MIME_TYPE = "video/avc";
private final static int PROCESSOR_TYPE_OTHER = 0;
private final static int PROCESSOR_TYPE_QCOM = 1;
private final static int PROCESSOR_TYPE_INTEL = 2;
private final static int PROCESSOR_TYPE_MTK = 3;
private final static int PROCESSOR_TYPE_SEC = 4;
private final static int PROCESSOR_TYPE_TI = 5;
private final boolean cancelCurrentVideoConversion = false;
private final Object videoConvertSync = new Object();
@@ -57,7 +46,6 @@ public class VideoRecoder {
}
}
@TargetApi(16)
private int selectTrack(MediaExtractor extractor, boolean audio) {
int numTracks = extractor.getTrackCount();
for (int i = 0; i < numTracks; i++) {
@@ -76,60 +64,6 @@ public class VideoRecoder {
return -5;
}
@SuppressLint("NewApi")
private static MediaCodecInfo selectCodec(String mimeType) {
int numCodecs = MediaCodecList.getCodecCount();
MediaCodecInfo lastCodecInfo = null;
for (int i = 0; i < numCodecs; i++) {
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
if (!codecInfo.isEncoder()) {
continue;
}
String[] types = codecInfo.getSupportedTypes();
for (String type : types) {
if (type.equalsIgnoreCase(mimeType)) {
lastCodecInfo = codecInfo;
if (!lastCodecInfo.getName().equals("OMX.SEC.avc.enc")) {
return lastCodecInfo;
} else if (lastCodecInfo.getName().equals("OMX.SEC.AVC.Encoder")) {
return lastCodecInfo;
}
}
}
}
return lastCodecInfo;
}
private static boolean isRecognizedFormat(int colorFormat) {
switch (colorFormat) {
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:
return true;
default:
return false;
}
}
@SuppressLint("NewApi")
private static int selectColorFormat(MediaCodecInfo codecInfo, String mimeType) {
MediaCodecInfo.CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(mimeType);
int lastColorFormat = 0;
for (int i = 0; i < capabilities.colorFormats.length; i++) {
int colorFormat = capabilities.colorFormats[i];
if (isRecognizedFormat(colorFormat)) {
lastColorFormat = colorFormat;
if (!(codecInfo.getName().equals("OMX.SEC.AVC.Encoder") && colorFormat == 19)) {
return colorFormat;
}
}
}
return lastColorFormat;
}
@TargetApi(16)
private long readAndWriteTrack(MediaExtractor extractor, MP4Builder mediaMuxer, MediaCodec.BufferInfo info, long start, long end, File file, boolean isAudio) throws Exception {
int trackIndex = selectTrack(extractor, isAudio);
if (trackIndex >= 0) {
@@ -199,7 +133,6 @@ public class VideoRecoder {
return -1;
}
@TargetApi(16)
private boolean convertVideo(final VideoEditedInfo videoEditedInfo, String destPath) {
long startTime = videoEditedInfo.startTime;
@@ -214,29 +147,21 @@ public class VideoRecoder {
int rotateRender = 0;
File cacheFile = new File(destPath);
if (Build.VERSION.SDK_INT < 18 && resultHeight > resultWidth && resultWidth != originalWidth && resultHeight != originalHeight) {
if (rotationValue == 90) {
int temp = resultHeight;
resultHeight = resultWidth;
resultWidth = temp;
rotationValue = 90;
rotationValue = 0;
rotateRender = 270;
} else if (Build.VERSION.SDK_INT > 20) {
if (rotationValue == 90) {
int temp = resultHeight;
resultHeight = resultWidth;
resultWidth = temp;
rotationValue = 0;
rotateRender = 270;
} else if (rotationValue == 180) {
rotateRender = 180;
rotationValue = 0;
} else if (rotationValue == 270) {
int temp = resultHeight;
resultHeight = resultWidth;
resultWidth = temp;
rotationValue = 0;
rotateRender = 90;
}
} else if (rotationValue == 180) {
rotateRender = 180;
rotationValue = 0;
} else if (rotationValue == 270) {
int temp = resultHeight;
resultHeight = resultWidth;
resultWidth = temp;
rotationValue = 0;
rotateRender = 90;
}
File inputFile = new File(videoEditedInfo.originalPath);
@@ -246,7 +171,6 @@ public class VideoRecoder {
return false;
}
videoConvertFirstWrite = true;
boolean error = false;
long videoStartTime = startTime;
@@ -282,71 +206,12 @@ public class VideoRecoder {
boolean outputDone = false;
boolean inputDone = false;
boolean decoderDone = false;
int swapUV = 0;
int videoTrackIndex = -5;
int colorFormat;
int processorType = PROCESSOR_TYPE_OTHER;
String manufacturer = Build.MANUFACTURER.toLowerCase();
if (Build.VERSION.SDK_INT < 18) {
MediaCodecInfo codecInfo = selectCodec(MIME_TYPE);
colorFormat = selectColorFormat(codecInfo, MIME_TYPE);
if (colorFormat == 0) {
throw new RuntimeException("no supported color format");
}
String codecName = codecInfo.getName();
if (codecName.contains("OMX.qcom.")) {
processorType = PROCESSOR_TYPE_QCOM;
if (Build.VERSION.SDK_INT == 16) {
if (manufacturer.equals("lge") || manufacturer.equals("nokia")) {
swapUV = 1;
}
}
} else if (codecName.contains("OMX.Intel.")) {
processorType = PROCESSOR_TYPE_INTEL;
} else if (codecName.equals("OMX.MTK.VIDEO.ENCODER.AVC")) {
processorType = PROCESSOR_TYPE_MTK;
} else if (codecName.equals("OMX.SEC.AVC.Encoder")) {
processorType = PROCESSOR_TYPE_SEC;
swapUV = 1;
} else if (codecName.equals("OMX.TI.DUCATI1.VIDEO.H264E")) {
processorType = PROCESSOR_TYPE_TI;
}
//Log.i("DeltaChat", "codec = " + codecInfo.getName() + " manufacturer = " + manufacturer + "device = " + Build.MODEL);
} else {
colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
}
colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
//Log.i("DeltaChat", "colorFormat = " + colorFormat);
int resultHeightAligned = resultHeight;
int padding = 0;
int bufferSize = resultWidth * resultHeight * 3 / 2;
if (processorType == PROCESSOR_TYPE_OTHER) {
if (resultHeight % 16 != 0) {
resultHeightAligned += (16 - (resultHeight % 16));
padding = resultWidth * (resultHeightAligned - resultHeight);
bufferSize += padding * 5 / 4;
}
} else if (processorType == PROCESSOR_TYPE_QCOM) {
if (!manufacturer.toLowerCase().equals("lge")) {
int uvoffset = (resultWidth * resultHeight + 2047) & ~2047;
padding = uvoffset - (resultWidth * resultHeight);
bufferSize += padding;
}
} else if (processorType == PROCESSOR_TYPE_TI) {
//resultHeightAligned = 368;
//bufferSize = resultWidth * resultHeightAligned * 3 / 2;
//resultHeightAligned += (16 - (resultHeight % 16));
//padding = resultWidth * (resultHeightAligned - resultHeight);
//bufferSize += padding * 5 / 4;
} else if (processorType == PROCESSOR_TYPE_MTK) {
if (manufacturer.equals("baidu")) {
resultHeightAligned += (16 - (resultHeight % 16));
padding = resultWidth * (resultHeightAligned - resultHeight);
bufferSize += padding * 5 / 4;
}
}
extractor.selectTrack(videoIndex);
if (startTime > 0) {
extractor.seekTo(startTime, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
@@ -360,39 +225,21 @@ public class VideoRecoder {
outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, resultVideoBitrate != 0 ? resultVideoBitrate : 921600);
outputFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 25);
outputFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
if (Build.VERSION.SDK_INT < 18) {
outputFormat.setInteger("stride", resultWidth + 32);
outputFormat.setInteger("slice-height", resultHeight);
}
encoder = MediaCodec.createEncoderByType(MIME_TYPE);
encoder.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
if (Build.VERSION.SDK_INT >= 18) {
inputSurface = new InputSurface(encoder.createInputSurface());
inputSurface.makeCurrent();
}
inputSurface = new InputSurface(encoder.createInputSurface());
inputSurface.makeCurrent();
encoder.start();
decoder = MediaCodec.createDecoderByType(inputFormat.getString(MediaFormat.KEY_MIME));
if (Build.VERSION.SDK_INT >= 18) {
outputSurface = new OutputSurface();
} else {
outputSurface = new OutputSurface(resultWidth, resultHeight, rotateRender);
}
outputSurface = new OutputSurface();
decoder.configure(inputFormat, outputSurface.getSurface(), null, 0);
decoder.start();
final int TIMEOUT_USEC = 2500;
ByteBuffer[] decoderInputBuffers = null;
ByteBuffer[] encoderOutputBuffers = null;
ByteBuffer[] encoderInputBuffers = null;
if (Build.VERSION.SDK_INT < 21) {
decoderInputBuffers = decoder.getInputBuffers();
encoderOutputBuffers = encoder.getOutputBuffers();
if (Build.VERSION.SDK_INT < 18) {
encoderInputBuffers = encoder.getInputBuffers();
}
}
checkConversionCanceled();
@@ -405,11 +252,7 @@ public class VideoRecoder {
int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC);
if (inputBufIndex >= 0) {
ByteBuffer inputBuf;
if (Build.VERSION.SDK_INT < 21) {
inputBuf = decoderInputBuffers[inputBufIndex];
} else {
inputBuf = decoder.getInputBuffer(inputBufIndex);
}
inputBuf = decoder.getInputBuffer(inputBufIndex);
int chunkSize = extractor.readSampleData(inputBuf, 0);
if (chunkSize < 0) {
decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
@@ -439,9 +282,6 @@ public class VideoRecoder {
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
encoderOutputAvailable = false;
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
if (Build.VERSION.SDK_INT < 21) {
encoderOutputBuffers = encoder.getOutputBuffers();
}
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat newFormat = encoder.getOutputFormat();
if (videoTrackIndex == -5) {
@@ -451,11 +291,7 @@ public class VideoRecoder {
throw new RuntimeException("unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);
} else {
ByteBuffer encodedData;
if (Build.VERSION.SDK_INT < 21) {
encodedData = encoderOutputBuffers[encoderStatus];
} else {
encodedData = encoder.getOutputBuffer(encoderStatus);
}
encodedData = encoder.getOutputBuffer(encoderStatus);
if (encodedData == null) {
throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null");
}
@@ -513,11 +349,7 @@ public class VideoRecoder {
throw new RuntimeException("unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus);
} else {
boolean doRender;
if (Build.VERSION.SDK_INT >= 18) {
doRender = info.size != 0;
} else {
doRender = info.size != 0 || info.presentationTimeUs != 0;
}
doRender = info.size != 0;
if (endTime > 0 && info.presentationTimeUs >= endTime) {
inputDone = true;
decoderDone = true;
@@ -542,40 +374,15 @@ public class VideoRecoder {
Log.w(TAG, "error while waiting for recording output surface", e);
}
if (!errorWait) {
if (Build.VERSION.SDK_INT >= 18) {
outputSurface.drawImage(false);
inputSurface.setPresentationTime(info.presentationTimeUs * 1000);
inputSurface.swapBuffers();
} else {
Log.w(TAG, "Cannot proceed with the current SDK version");
return false; // TODO: this should be caught much earlier
/*
int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
if (inputBufIndex >= 0) {
outputSurface.drawImage(true);
ByteBuffer rgbBuf = outputSurface.getFrame();
ByteBuffer yuvBuf = encoderInputBuffers[inputBufIndex];
yuvBuf.clear();
Utilities.convertVideoFrame(rgbBuf, yuvBuf, colorFormat, resultWidth, resultHeight, padding, swapUV);
encoder.queueInputBuffer(inputBufIndex, 0, bufferSize, info.presentationTimeUs, 0);
} else {
//Log.i("DeltaChat", "input buffer not available");
}
*/
}
outputSurface.drawImage(false);
inputSurface.setPresentationTime(info.presentationTimeUs * 1000);
inputSurface.swapBuffers();
}
}
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
decoderOutputAvailable = false;
//Log.i("DeltaChat", "decoder stream end");
if (Build.VERSION.SDK_INT >= 18) {
encoder.signalEndOfInputStream();
} else {
int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
if (inputBufIndex >= 0) {
encoder.queueInputBuffer(inputBufIndex, 0, 1, info.presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
}
}
encoder.signalEndOfInputStream();
}
}
}
@@ -662,45 +469,6 @@ public class VideoRecoder {
int estimatedBytes;
}
public static boolean canRecode()
{
boolean canRecode = true;
if (Build.VERSION.SDK_INT < 16 /*= Jelly Bean 4.1 (before that codecInfo.getName() was not there) */) {
Log.w(TAG, "Cannot recode: API < 16");
canRecode = false;
}
else if (Build.VERSION.SDK_INT < 18 /*= Jelly Bean 4.3*/) {
try {
MediaCodecInfo codecInfo = VideoRecoder.selectCodec(VideoRecoder.MIME_TYPE);
if (codecInfo == null) {
Log.w(TAG, "Cannot recode: cannot select codec");
canRecode = false;
} else {
String name = codecInfo.getName();
if (name.equals("OMX.google.h264.encoder") ||
name.equals("OMX.ST.VFM.H264Enc") ||
name.equals("OMX.Exynos.avc.enc") ||
name.equals("OMX.MARVELL.VIDEO.HW.CODA7542ENCODER") ||
name.equals("OMX.MARVELL.VIDEO.H264ENCODER") ||
name.equals("OMX.k3.video.encoder.avc") ||
name.equals("OMX.TI.DUCATI1.VIDEO.H264E")) {
Log.w(TAG, "Cannot recode: no supported codec found");
canRecode = false;
} else {
if (VideoRecoder.selectColorFormat(codecInfo, VideoRecoder.MIME_TYPE) == 0) {
Log.w(TAG, "Cannot recode: cannot select color format");
canRecode = false;
}
}
}
} catch (Exception e) {
Log.w(TAG, "Cannot recode: Determinating recoding capabilities failed unexpectedly", e);
canRecode = false;
}
}
return canRecode;
}
private static VideoEditedInfo getVideoEditInfoFromFile(String videoPath) {
// load information for the given video
VideoEditedInfo vei = new VideoEditedInfo();
@@ -811,11 +579,6 @@ public class VideoRecoder {
}
msg.setDuration((int)vei.originalDurationMs);
if (!canRecode()) {
alert(context, String.format("Recoding failed for %s: this system cannot recode videos", inPath));
return false;
}
// check if video bitrate is already reasonable
final int MAX_KBPS = 1500000;
final long MAX_BYTES = DcHelper.getInt(context, "sys.msgsize_max_recommended");
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/def_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/def_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/blue_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/blue_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/gray_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/gray_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/green_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/green_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/pink_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/pink_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/purple_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/purple_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/red_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/red_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/def_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/def_primary_alpha33" android:state_pressed="true" />
<item android:drawable="@color/primary_alpha_focus" android:state_focused="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/def_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/def_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/blue_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/blue_primary_alpha33" android:state_pressed="true" />
<item android:drawable="@color/primary_alpha_focus" android:state_focused="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/blue_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/blue_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/gray_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/gray_primary_alpha33" android:state_pressed="true" />
<item android:drawable="@color/primary_alpha_focus" android:state_focused="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/gray_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/gray_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/green_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/green_primary_alpha33" android:state_pressed="true" />
<item android:drawable="@color/primary_alpha_focus" android:state_focused="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/green_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/green_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/pink_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pink_primary_alpha33" android:state_pressed="true" />
<item android:drawable="@color/primary_alpha_focus" android:state_focused="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/pink_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/pink_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/purple_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/purple_primary_alpha33" android:state_pressed="true" />
<item android:drawable="@color/primary_alpha_focus" android:state_focused="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/purple_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/purple_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/red_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/red_primary_alpha33" android:state_pressed="true" />
<item android:drawable="@color/primary_alpha_focus" android:state_focused="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/red_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/red_primary_alpha33" android:state_selected="true" />
<item android:drawable="@color/pinned_bg_dark" />
</selector>
</item>
</ripple>
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/touch_highlight">
<item android:id="@android:id/mask">
<shape android:shape="oval">
<solid android:color="@color/black" />
</shape>
</item>
</ripple>
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/def_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/def_primary_alpha33" android:state_selected="true" />
</selector>
</item>
</ripple>
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/blue_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/blue_primary_alpha33" android:state_selected="true" />
</selector>
</item>
</ripple>
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/gray_primary">
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
<item>
<selector>
<item android:drawable="@color/gray_primary_alpha33" android:state_selected="true" />
</selector>
</item>
</ripple>

Some files were not shown because too many files have changed in this diff Show More