diff --git a/CHANGES.md b/CHANGES.md index b56cbef37a..20b3b34375 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,9 @@ Improvements 🙌: Bugfix 🐛: - Fix crash when coming from a notification (#1601) - Fix Exception when importing keys (#1576) + - File isn't downloaded when another file with the same name already exists (#1578) + - saved images don't show up in gallery (#1324) + - Fix reply fallback leaking sender locale (#429) Translations 🗣: - @@ -18,7 +21,9 @@ SDK API changes ⚠️: - Build 🧱: - - + - Fix lint false-positive about WorkManger (#1012) + - Upgrade build-tools from 3.5.3 to 3.6.6 + - Upgrade gradle from 5.4.1 to 5.6.4 Other changes: - diff --git a/build.gradle b/build.gradle index 74a62f0d17..5f1fa78620 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.android.tools.build:gradle:3.6.3' classpath 'com.google.gms:google-services:4.3.2' classpath "com.airbnb.okreplay:gradle-plugin:1.5.0" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 51b92600a0..4da2435f42 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Sep 27 10:10:35 CEST 2019 +#Thu Jul 02 12:33:07 CEST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip diff --git a/matrix-sdk-android/src/main/AndroidManifest.xml b/matrix-sdk-android/src/main/AndroidManifest.xml index 94b2db2bf1..c02f34f1c9 100644 --- a/matrix-sdk-android/src/main/AndroidManifest.xml +++ b/matrix-sdk-android/src/main/AndroidManifest.xml @@ -1,5 +1,4 @@ @@ -8,11 +7,6 @@ - Einladung von %s Raumeinladung diff --git a/matrix-sdk-android/src/main/res/values-el/strings.xml b/matrix-sdk-android/src/main/res/values-el/strings.xml index 37eac5351e..9db4e91849 100644 --- a/matrix-sdk-android/src/main/res/values-el/strings.xml +++ b/matrix-sdk-android/src/main/res/values-el/strings.xml @@ -40,8 +40,6 @@ ** Αδυναμία αποκρυπτογράφησης: %s ** Η συσκευή του/της αποστολέα δεν μας έχει στείλει τα κλειδιά για αυτό το μήνυμα. - Προς απάντηση στο - Αποτυχία αποστολής μηνύματος Αποτυχία αναφόρτωσης εικόνας @@ -56,10 +54,6 @@ Η VoIP διάσκεψη έληξε Ο/Η %1$s εισήλθε στο δωμάτιο - έστειλε μία εικόνα. - έστειλε ένα βίντεο. - έστειλε ένα αρχείο ήχου. - έστειλε ένα αρχείο. Πρόσκληση από %s Πρόσκληση στο δωμάτιο diff --git a/matrix-sdk-android/src/main/res/values-eo/strings.xml b/matrix-sdk-android/src/main/res/values-eo/strings.xml index 69600394ac..4a1e2c4c65 100644 --- a/matrix-sdk-android/src/main/res/values-eo/strings.xml +++ b/matrix-sdk-android/src/main/res/values-eo/strings.xml @@ -17,8 +17,6 @@ ** Ne eblas malĉifri: %s ** La aparato de la sendanto ne sendis al ni la ŝlosilojn por tiu mesaĝo. - Responde al - %1$s: %2$s %1$s ŝanĝis sian vidigan nomon al %2$s %1$s ŝanĝis sian vidigan nomon de %2$s al %3$s @@ -62,11 +60,6 @@ Retpoŝtadreso Telefonnumero - sendis bildon. - sendis filmon. - sendis sondosieron. - sendis dosieron. - Invito de %s Ĉambra invito diff --git a/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml b/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml index 56cbe6ace5..35b7bfc829 100644 --- a/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml +++ b/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml @@ -73,13 +73,6 @@ %1$s envió una calcomanía. - En respuesta a - - envió una imagen. - envió un video. - envió un archivo de audio. - envió un archivo. - Invitación de %s Invitación de Sala diff --git a/matrix-sdk-android/src/main/res/values-es/strings.xml b/matrix-sdk-android/src/main/res/values-es/strings.xml index 69f02d2ef4..3c019b3b80 100644 --- a/matrix-sdk-android/src/main/res/values-es/strings.xml +++ b/matrix-sdk-android/src/main/res/values-es/strings.xml @@ -73,13 +73,6 @@ %1$s envió una pegatina. - En respuesta a - - envió una imagen. - envió un vídeo. - envió un archivo de audio. - envió un archivo. - Invitación de %s Invitación a Sala diff --git a/matrix-sdk-android/src/main/res/values-et/strings.xml b/matrix-sdk-android/src/main/res/values-et/strings.xml index 3a5a1ff767..2536500247 100644 --- a/matrix-sdk-android/src/main/res/values-et/strings.xml +++ b/matrix-sdk-android/src/main/res/values-et/strings.xml @@ -50,8 +50,6 @@ ** Ei õnnestu dekrüptida: %s ** Sõnumi saatja seade ei ole selle sõnumi jaoks saatnud dekrüptimisvõtmeid. - Vastuseks kasutajale - Ei saanud muuta sõnumit Sõnumi saatmine ei õnnestunud @@ -67,11 +65,6 @@ E-posti aadress Telefoninumber - saatis pildi. - saatis video. - saatis helifaili. - saatis faili. - Kutse kasutajalt %s Kutse jututuppa diff --git a/matrix-sdk-android/src/main/res/values-eu/strings.xml b/matrix-sdk-android/src/main/res/values-eu/strings.xml index 7938db3cbd..1a5c81fe5e 100644 --- a/matrix-sdk-android/src/main/res/values-eu/strings.xml +++ b/matrix-sdk-android/src/main/res/values-eu/strings.xml @@ -63,13 +63,6 @@ %1$s erabiltzaileak eranskailu bat bidali du. - Honi erantzunez - - irudi bat bidali du. - bideo bat bidali du. - audio fitxategi bat bidali du. - fitxategi bat bidali du. - %s gelarako gonbidapena Gela gonbidapena %1$s eta %2$s diff --git a/matrix-sdk-android/src/main/res/values-fa/strings.xml b/matrix-sdk-android/src/main/res/values-fa/strings.xml index 7addf22ca8..18d8578e54 100644 --- a/matrix-sdk-android/src/main/res/values-fa/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fa/strings.xml @@ -51,8 +51,6 @@ ** ناتوان در رمزگشایی: %s ** دستگاه فرستنده، کلیدهای این پیام را برایمان نفرستاده است. - در پاسخ به - ناتوان در فرستادن پیام شکست در بارگذاری تصویر @@ -67,11 +65,6 @@ نشانی رایانامه شماره تلفن - تصویری فرستاد. - ویدیویی فرستاد. - پرونده‌ای صوتی فرستاد. - پرونده‌ای فرستاد. - دعوت از %s دعوت اتاق diff --git a/matrix-sdk-android/src/main/res/values-fi/strings.xml b/matrix-sdk-android/src/main/res/values-fi/strings.xml index 06820183fd..078769942c 100644 --- a/matrix-sdk-android/src/main/res/values-fi/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fi/strings.xml @@ -70,13 +70,6 @@ %1$s lähetti tarran. - Vastauksena käyttäjälle - - oli lähettänyt kuvan. - lähetti videon. - lähetti äänitiedoston. - lähetti tiedoston. - %1$s ja yksi muu %1$s ja %2$d muuta diff --git a/matrix-sdk-android/src/main/res/values-fr/strings.xml b/matrix-sdk-android/src/main/res/values-fr/strings.xml index a744c35b99..aad3bd1afb 100644 --- a/matrix-sdk-android/src/main/res/values-fr/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fr/strings.xml @@ -63,13 +63,6 @@ %1$s a envoyé un sticker. - En réponse à - - a envoyé une image. - a envoyé une vidéo. - a envoyé un fichier audio. - a envoyé un fichier. - Invitation de %s Invitation au salon Salon vide diff --git a/matrix-sdk-android/src/main/res/values-gl/strings.xml b/matrix-sdk-android/src/main/res/values-gl/strings.xml index 907730f154..77868e7df3 100644 --- a/matrix-sdk-android/src/main/res/values-gl/strings.xml +++ b/matrix-sdk-android/src/main/res/values-gl/strings.xml @@ -50,8 +50,6 @@ ** Imposíbel descifrar: %s ** O dispositivo do que envía non enviou as chaves desta mensaxe. - Respondéndolle a - Non se puido redactar Non foi posíbel enviar a mensaxe @@ -64,11 +62,6 @@ Número de teléfono - Responder a - enviar un vídeo. - enviar un ficheiro de son. - enviar un ficheiro. - %1$s e %2$s diff --git a/matrix-sdk-android/src/main/res/values-hu/strings.xml b/matrix-sdk-android/src/main/res/values-hu/strings.xml index 03d52bef44..35f35eaecd 100644 --- a/matrix-sdk-android/src/main/res/values-hu/strings.xml +++ b/matrix-sdk-android/src/main/res/values-hu/strings.xml @@ -62,13 +62,6 @@ %1$s küldött egy matricát. - Válasz erre: - - képet küldött. - videót küldött. - hangfájlt küldött. - fájlt küldött. - Meghívó tőle: %s Meghívó egy szobába %1$s és %2$s diff --git a/matrix-sdk-android/src/main/res/values-is/strings.xml b/matrix-sdk-android/src/main/res/values-is/strings.xml index 01954ae2b4..ecf19edb8a 100644 --- a/matrix-sdk-android/src/main/res/values-is/strings.xml +++ b/matrix-sdk-android/src/main/res/values-is/strings.xml @@ -24,7 +24,6 @@ (einnig var skipt um auðkennismynd) ** Mistókst að afkóða: %s ** - Sem svar til Gat ekki sent skilaboð diff --git a/matrix-sdk-android/src/main/res/values-it/strings.xml b/matrix-sdk-android/src/main/res/values-it/strings.xml index ec86122313..42328b836f 100644 --- a/matrix-sdk-android/src/main/res/values-it/strings.xml +++ b/matrix-sdk-android/src/main/res/values-it/strings.xml @@ -62,13 +62,6 @@ %1$s ha inviato un adesivo. - In risposta a - - inviata un\'immagine. - inviato un video. - inviato un file audio. - inviato un file. - Invito da %s Invito nella stanza diff --git a/matrix-sdk-android/src/main/res/values-ja/strings.xml b/matrix-sdk-android/src/main/res/values-ja/strings.xml index b72d1a13ca..366c743494 100644 --- a/matrix-sdk-android/src/main/res/values-ja/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ja/strings.xml @@ -56,8 +56,6 @@ ** 解読できません: %s ** 送信者の端末からこのメッセージのキーが送信されていません。 - に返信 - 修正できませんでした メッセージを送信できません @@ -73,9 +71,4 @@ メールアドレス 電話番号 - 画像を送信しました。 - 動画を送りました。 - 音声ファイルを送信しました。 - ファイルを送信しました。 - diff --git a/matrix-sdk-android/src/main/res/values-ko/strings.xml b/matrix-sdk-android/src/main/res/values-ko/strings.xml index 68e94bb641..88c5e7d618 100644 --- a/matrix-sdk-android/src/main/res/values-ko/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ko/strings.xml @@ -52,8 +52,6 @@ ** 암호를 복호화할 수 없음: %s ** 발신인의 기기에서 이 메시지의 키를 보내지 않았습니다. - 관련 대화 - 검열할 수 없습니다 메시지를 보낼 수 없습니다 @@ -69,11 +67,6 @@ 이메일 주소 전화번호 - 사진을 보냈습니다. - 동영상을 보냈습니다. - 오디오 파일을 보냈습니다. - 파일을 보냈습니다. - %s에서 초대함 방 초대 diff --git a/matrix-sdk-android/src/main/res/values-nl/strings.xml b/matrix-sdk-android/src/main/res/values-nl/strings.xml index d08b3c7845..22eb61f109 100644 --- a/matrix-sdk-android/src/main/res/values-nl/strings.xml +++ b/matrix-sdk-android/src/main/res/values-nl/strings.xml @@ -71,13 +71,6 @@ %1$s heeft een sticker gestuurd. - Als antwoord op - - heeft een afbeelding gestuurd. - heeft een video gestuurd. - heeft een audiobestand gestuurd. - heeft een bestand gestuurd. - Uitnodiging van %s Gespreksuitnodiging diff --git a/matrix-sdk-android/src/main/res/values-nn/strings.xml b/matrix-sdk-android/src/main/res/values-nn/strings.xml index edc50a5a0e..601cf4c9df 100644 --- a/matrix-sdk-android/src/main/res/values-nn/strings.xml +++ b/matrix-sdk-android/src/main/res/values-nn/strings.xml @@ -49,8 +49,6 @@ ** Fekk ikkje til å dekryptera: %s ** Avsendareiningi hev ikkje sendt oss nyklane fyr denna meldingi. - Som svar til - Kunde ikkje gjera um Fekk ikkje å senda meldingi @@ -64,11 +62,6 @@ Epostadresse Telefonnummer - sende eit bilæte. - sende ein video. - sende ei ljodfil. - sende ei fil. - Innbjoding frå %s Rominnbjoding %1$s og %2$s diff --git a/matrix-sdk-android/src/main/res/values-pl/strings.xml b/matrix-sdk-android/src/main/res/values-pl/strings.xml index 4e1d256788..dc380516b7 100644 --- a/matrix-sdk-android/src/main/res/values-pl/strings.xml +++ b/matrix-sdk-android/src/main/res/values-pl/strings.xml @@ -42,7 +42,6 @@ %1$s wycofał(a) zaproszenie %2$s %s odebrał(a) połączenie. (awatar też został zmieniony) - W odpowiedzi do Zaproszenie od %s Zaproszenie do pokoju @@ -76,11 +75,6 @@ Nie można zredagować Obecnie nie jest możliwe ponowne dołączenie do pustego pokoju. - wyślij zdjęcie. - wyślij wideo. - wyślij plik audio. - wyślij plik. - Wiadomość usunięta Wiadomość usunięta przez %1$s Wiadomość usunięta [powód: %1$s] diff --git a/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml b/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml index 17e7ae33a1..a573c659a6 100644 --- a/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml +++ b/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml @@ -74,13 +74,6 @@ %1$s enviou um sticker. - Em resposta a - - enviou uma imagem. - enviou um vídeo. - enviou um arquivo de áudio. - enviou um arquivo. - Convite de %s Convite para sala diff --git a/matrix-sdk-android/src/main/res/values-ru/strings.xml b/matrix-sdk-android/src/main/res/values-ru/strings.xml index 3e20353b7d..bd0dcef3dd 100644 --- a/matrix-sdk-android/src/main/res/values-ru/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ru/strings.xml @@ -73,13 +73,6 @@ %1$s отправил стикер. - В ответ на - - отправил изображение. - отправил видео. - отправил аудиофайл. - отправил файл. - Приглашение от %s Приглашение в комнату diff --git a/matrix-sdk-android/src/main/res/values-sk/strings.xml b/matrix-sdk-android/src/main/res/values-sk/strings.xml index c6eb6b896b..8aec8fccf9 100644 --- a/matrix-sdk-android/src/main/res/values-sk/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sk/strings.xml @@ -62,13 +62,6 @@ %1$s poslal nálepku. - Odpoveď na - - odoslal obrázok. - odoslal video. - odoslal zvukový súbor. - Odoslal súbor. - Pozvanie od %s Pozvanie do miestnosti %1$s a %2$s diff --git a/matrix-sdk-android/src/main/res/values-sq/strings.xml b/matrix-sdk-android/src/main/res/values-sq/strings.xml index 853d4729af..e63e28288f 100644 --- a/matrix-sdk-android/src/main/res/values-sq/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sq/strings.xml @@ -34,8 +34,6 @@ ** S’arrihet të shfshehtëzohet: %s ** Pajisja e dërguesit nuk na ka dërguar kyçet për këtë mesazh. - Në përgjigje të - S’u redaktua dot S’arrihet të dërgohet mesazh @@ -51,11 +49,6 @@ Adresë email Numër telefoni - dërgoi një figurë. - dërgoi një video. - dërgoi një kartelë audio. - dërgoi një kartelë. - Ftesë nga %s Ftesë Dhome diff --git a/matrix-sdk-android/src/main/res/values-uk/strings.xml b/matrix-sdk-android/src/main/res/values-uk/strings.xml index bf83e39d72..eb5071f190 100644 --- a/matrix-sdk-android/src/main/res/values-uk/strings.xml +++ b/matrix-sdk-android/src/main/res/values-uk/strings.xml @@ -56,8 +56,6 @@ ** Неможливо розшифрувати: %s ** Пристрій відправника не надіслав нам ключ для цього повідомлення. - У відповідь на - Неможливо відредагувати Не вдалося надіслати повідомлення @@ -71,11 +69,6 @@ Адреса електронної пошти Номер телефону - надіслав зображення. - надіслав відео. - надіслав аудіо файл. - надіслав файл. - %1$s та 1 інший %1$s та %2$d інші diff --git a/matrix-sdk-android/src/main/res/values-vls/strings.xml b/matrix-sdk-android/src/main/res/values-vls/strings.xml index dad88788e4..5c9132ed35 100644 --- a/matrix-sdk-android/src/main/res/values-vls/strings.xml +++ b/matrix-sdk-android/src/main/res/values-vls/strings.xml @@ -50,8 +50,6 @@ ** Kun nie ountsleuteln: %s ** ’t Toestel van den afzender èt geen sleutels vo da bericht hier gesteurd. - Als antwoord ip - Kosteg nie verwyderd wordn Kosteg ’t bericht nie verzendn @@ -67,11 +65,6 @@ E-mailadresse Telefongnumero - èt e fotootje gesteurd. - èt e filmtje gesteurd. - èt e geluudsfragment gesteurd. - èt e bestand gesteurd. - Uutnodigienge van %s Gespreksuutnodigienge diff --git a/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml b/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml index 0c0953c92d..48dbd27a1b 100644 --- a/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml +++ b/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml @@ -63,13 +63,6 @@ %1$s:%2$s %1$s 发送了一张贴纸。 - 发送了一张图片。 - 发送了一个视频。 - 发送了一段音频。 - 发送了一个文件。 - - 回复 - 空聊天室 来自 %s 的邀请 聊天室邀请 diff --git a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml index ca2fd79aa2..f3da62dccc 100644 --- a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml +++ b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml @@ -62,13 +62,6 @@ %1$s 傳送了一張貼圖。 - 回覆 - - 傳送了圖片。 - 傳送了影片。 - 傳送了音訊檔案。 - 傳送了檔案。 - 來自%s 的邀請 聊天室邀請 %1$s 和 %2$s diff --git a/matrix-sdk-android/src/main/res/values/strings.xml b/matrix-sdk-android/src/main/res/values/strings.xml index 9b7fa01eaf..0dc64c1b4b 100644 --- a/matrix-sdk-android/src/main/res/values/strings.xml +++ b/matrix-sdk-android/src/main/res/values/strings.xml @@ -112,7 +112,6 @@ The sender\'s device has not sent us the keys for this message. - In reply to Could not redact @@ -139,12 +138,6 @@ Email address Phone number - - sent an image. - sent a video. - sent an audio file. - sent a file. - Invite from %s Room Invite diff --git a/vector/build.gradle b/vector/build.gradle index e497b156ae..f966f441b2 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -106,6 +106,11 @@ def buildNumber = System.env.BUILDKITE_BUILD_NUMBER as Integer ?: 0 android { compileSdkVersion 29 + + // Due to a bug introduced in Android gradle plugin 3.6.0, we have to specify the ndk version to use + // Ref: https://issuetracker.google.com/issues/144111441 + ndkVersion "21.3.6528147" + defaultConfig { applicationId "im.vector.app" // Set to API 21: see #405 @@ -232,8 +237,7 @@ android { lintOptions { lintConfig file("lint.xml") - // TODO Restore true once pb with WorkManager is fixed - abortOnError false + abortOnError true } compileOptions { diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 3ed0d95b71..f9b78db17c 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -247,6 +247,12 @@ + + + = Build.VERSION_CODES.Q) { - val externalContentUri: Uri - val values = ContentValues() - when { - mediaMimeType?.startsWith("image/") == true -> { - externalContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI - values.put(MediaStore.Images.Media.TITLE, title) - values.put(MediaStore.Images.Media.DISPLAY_NAME, title) - values.put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType) - values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis()) - values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()) - } - mediaMimeType?.startsWith("video/") == true -> { - externalContentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI - values.put(MediaStore.Video.Media.TITLE, title) - values.put(MediaStore.Video.Media.DISPLAY_NAME, title) - values.put(MediaStore.Video.Media.MIME_TYPE, mediaMimeType) - values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis()) - values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis()) - } - mediaMimeType?.startsWith("audio/") == true -> { - externalContentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI - values.put(MediaStore.Audio.Media.TITLE, title) - values.put(MediaStore.Audio.Media.DISPLAY_NAME, title) - values.put(MediaStore.Audio.Media.MIME_TYPE, mediaMimeType) - values.put(MediaStore.Audio.Media.DATE_ADDED, System.currentTimeMillis()) - values.put(MediaStore.Audio.Media.DATE_TAKEN, System.currentTimeMillis()) - } - else -> { - externalContentUri = MediaStore.Downloads.EXTERNAL_CONTENT_URI - values.put(MediaStore.Downloads.TITLE, title) - values.put(MediaStore.Downloads.DISPLAY_NAME, title) - values.put(MediaStore.Downloads.MIME_TYPE, mediaMimeType) - values.put(MediaStore.Downloads.DATE_ADDED, System.currentTimeMillis()) - values.put(MediaStore.Downloads.DATE_TAKEN, System.currentTimeMillis()) - } + val values = ContentValues().apply { + put(MediaStore.Images.Media.TITLE, title) + put(MediaStore.Images.Media.DISPLAY_NAME, title) + put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType) + put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis()) + put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()) } + val externalContentUri = when { + mediaMimeType?.startsWith("image/") == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI + mediaMimeType?.startsWith("video/") == true -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI + mediaMimeType?.startsWith("audio/") == true -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + else -> MediaStore.Downloads.EXTERNAL_CONTENT_URI + } + val uri = context.contentResolver.insert(externalContentUri, values) if (uri == null) { Toast.makeText(context, R.string.error_saving_media_file, Toast.LENGTH_LONG).show() @@ -357,16 +345,70 @@ fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String notificationUtils.showNotificationMessage("DL", uri.hashCode(), notification) } } - // TODO add notification? } else { - @Suppress("DEPRECATION") - Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE).also { mediaScanIntent -> - mediaScanIntent.data = Uri.fromFile(file) - context.sendBroadcast(mediaScanIntent) + saveMediaLegacy(context, mediaMimeType, title, file) + } +} + +@Suppress("DEPRECATION") +private fun saveMediaLegacy(context: Context, mediaMimeType: String?, title: String, file: File) { + val state = Environment.getExternalStorageState() + if (Environment.MEDIA_MOUNTED != state) { + context.toast(context.getString(R.string.error_saving_media_file)) + return + } + + GlobalScope.launch(Dispatchers.IO) { + val dest = when { + mediaMimeType?.startsWith("image/") == true -> Environment.DIRECTORY_PICTURES + mediaMimeType?.startsWith("video/") == true -> Environment.DIRECTORY_MOVIES + mediaMimeType?.startsWith("audio/") == true -> Environment.DIRECTORY_MUSIC + else -> Environment.DIRECTORY_DOWNLOADS + } + val downloadDir = Environment.getExternalStoragePublicDirectory(dest) + try { + val outputFilename = if (title.substringAfterLast('.', "").isEmpty()) { + val extension = mediaMimeType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) } + "$title.$extension" + } else { + title + } + val savedFile = saveFileIntoLegacy(file, downloadDir, outputFilename) + if (savedFile != null) { + val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as? DownloadManager + downloadManager?.addCompletedDownload( + savedFile.name, + title, + true, + mediaMimeType ?: "application/octet-stream", + savedFile.absolutePath, + savedFile.length(), + true) + addToGallery(savedFile, mediaMimeType, context) + } + } catch (error: Throwable) { + GlobalScope.launch(Dispatchers.Main) { + context.toast(context.getString(R.string.error_saving_media_file)) + } } } } +private fun addToGallery(savedFile: File, mediaMimeType: String?, context: Context) { + // MediaScannerConnection provides a way for applications to pass a newly created or downloaded media file to the media scanner service. + var mediaConnection: MediaScannerConnection? = null + val mediaScannerConnectionClient: MediaScannerConnection.MediaScannerConnectionClient = object : MediaScannerConnection.MediaScannerConnectionClient { + override fun onMediaScannerConnected() { + mediaConnection?.scanFile(savedFile.path, mediaMimeType) + } + + override fun onScanCompleted(path: String, uri: Uri?) { + if (path == savedFile.path) mediaConnection?.disconnect() + } + } + mediaConnection = MediaScannerConnection(context, mediaScannerConnectionClient).apply { connect() } +} + /** * Open the play store to the provided application Id, default to this app */ @@ -381,3 +423,76 @@ fun openPlayStore(activity: Activity, appId: String = BuildConfig.APPLICATION_ID } } } + +// ============================================================================================================== +// Media utils +// ============================================================================================================== +/** + * Copy a file into a dstPath directory. + * The output filename can be provided. + * The output file is not overridden if it is already exist. + * + * ~~ This is copied from the old matrix sdk ~~ + * + * @param sourceFile the file source path + * @param dstDirPath the dst path + * @param outputFilename optional the output filename + * @param callback the asynchronous callback + */ +@Suppress("DEPRECATION") +fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: String?): File? { + // defines another name for the external media + val dstFileName: String + + // build a filename is not provided + if (null == outputFilename) { + // extract the file extension from the uri + val dotPos = sourceFile.name.lastIndexOf(".") + var fileExt = "" + if (dotPos > 0) { + fileExt = sourceFile.name.substring(dotPos) + } + dstFileName = "vector_" + System.currentTimeMillis() + fileExt + } else { + dstFileName = outputFilename + } + + var dstFile = File(dstDirPath, dstFileName) + + // if the file already exists, append a marker + if (dstFile.exists()) { + var baseFileName = dstFileName + var fileExt = "" + val lastDotPos = dstFileName.lastIndexOf(".") + if (lastDotPos > 0) { + baseFileName = dstFileName.substring(0, lastDotPos) + fileExt = dstFileName.substring(lastDotPos) + } + var counter = 1 + while (dstFile.exists()) { + dstFile = File(dstDirPath, "$baseFileName($counter)$fileExt") + counter++ + } + } + + // Copy source file to destination + var inputStream: FileInputStream? = null + var outputStream: FileOutputStream? = null + try { + dstFile.createNewFile() + inputStream = FileInputStream(sourceFile) + outputStream = FileOutputStream(dstFile) + val buffer = ByteArray(1024 * 10) + var len: Int + while (inputStream.read(buffer).also { len = it } != -1) { + outputStream.write(buffer, 0, len) + } + return dstFile + } catch (failure: Throwable) { + return null + } finally { + // Close resources + tryThis { inputStream?.close() } + tryThis { outputStream?.close() } + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/form/FormEditTextWithButtonItem.kt b/vector/src/main/java/im/vector/riotx/features/form/FormEditTextWithButtonItem.kt index 0650c0f55c..799f6abe00 100644 --- a/vector/src/main/java/im/vector/riotx/features/form/FormEditTextWithButtonItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/form/FormEditTextWithButtonItem.kt @@ -56,6 +56,7 @@ abstract class FormEditTextWithButtonItem : VectorEpoxyModel, grantResults: IntArray) { if (allGranted(grantResults)) { when (requestCode) { -// PERMISSION_REQUEST_CODE_DOWNLOAD_FILE -> { -// val action = roomDetailViewModel.pendingAction -// if (action != null) { -// (action as? RoomDetailAction.DownloadFile) -// ?.messageFileContent -// ?.getFileName() -// ?.let { showSnackWithMessage(getString(R.string.downloading_file, it)) } -// roomDetailViewModel.pendingAction = null -// roomDetailViewModel.handle(action) -// } -// } + SAVE_ATTACHEMENT_REQUEST_CODE -> { + sharedActionViewModel.pendingAction?.let { + handleActions(it) + sharedActionViewModel.pendingAction = null + } + } PERMISSION_REQUEST_CODE_INCOMING_URI -> { val pendingUri = roomDetailViewModel.pendingUri if (pendingUri != null) { @@ -1357,6 +1354,11 @@ class RoomDetailFragment @Inject constructor( } private fun onSaveActionClicked(action: EventSharedAction.Save) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q + && !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, SAVE_ATTACHEMENT_REQUEST_CODE)) { + sharedActionViewModel.pendingAction = action + return + } session.fileService().downloadFile( downloadMode = FileService.DownloadMode.FOR_EXTERNAL_SHARE, id = action.eventId, diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageSharedActionViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageSharedActionViewModel.kt index 2e041fd2ea..ec5c49f814 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageSharedActionViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageSharedActionViewModel.kt @@ -21,4 +21,6 @@ import javax.inject.Inject /** * Activity shared view model to handle message actions */ -class MessageSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel() +class MessageSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel() { + var pendingAction : EventSharedAction? = null +}