mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 11:39:42 +01:00
Merge remote-tracking branch 'origin/master' into feature/edit_messages
This commit is contained in:
commit
9a4bf14e09
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
||||
with:
|
||||
swap-size-gb: 10
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 # v3.24.0
|
||||
uses: github/codeql-action/init@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Set up JDK 17
|
||||
@ -46,4 +46,4 @@ jobs:
|
||||
echo "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties"
|
||||
./gradlew assembleDebug
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 # v3.24.0
|
||||
uses: github/codeql-action/analyze@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3
|
||||
|
@ -19,4 +19,4 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: gradle/wrapper-validation-action@27152f6fa06a6b8062ef7195c795692e51fc2c81 # v2.0.0
|
||||
- uses: gradle/wrapper-validation-action@699bb18358f12c5b78b37bb0111d3a0e2276e0e2 # v2.1.1
|
||||
|
2
.github/workflows/scorecard.yml
vendored
2
.github/workflows/scorecard.yml
vendored
@ -37,6 +37,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 # v3.24.0
|
||||
uses: github/codeql-action/upload-sarif@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
2
.github/workflows/unit-tests.yml
vendored
2
.github/workflows/unit-tests.yml
vendored
@ -25,7 +25,7 @@ jobs:
|
||||
distribution: "temurin"
|
||||
java-version: 17
|
||||
- name: Run unit tests with coverage
|
||||
uses: gradle/gradle-build-action@3b1b3b9a2104c2b47fbae53f3938079c00c9bb87 # v3.0.0
|
||||
uses: gradle/gradle-build-action@29c0906b64b8fc82467890bfb7a0a7ef34bda89e # v3.1.0
|
||||
with:
|
||||
arguments: testGplayDebugUnit
|
||||
- name: Upload test artifacts
|
||||
|
@ -48,8 +48,8 @@ android {
|
||||
|
||||
// mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable)
|
||||
// xx .xxx .xx .xx
|
||||
versionCode 180010010
|
||||
versionName "18.1.0 Alpha 10"
|
||||
versionCode 190000001
|
||||
versionName "19.0.0 Alpha 01"
|
||||
|
||||
flavorDimensions "default"
|
||||
renderscriptTargetApi 19
|
||||
@ -247,7 +247,7 @@ dependencies {
|
||||
implementation 'com.github.wooplr:Spotlight:1.3'
|
||||
implementation 'com.google.code.findbugs:jsr305:3.0.2'
|
||||
implementation 'com.github.nextcloud-deps:ChatKit:0.4.2'
|
||||
implementation 'joda-time:joda-time:2.12.6'
|
||||
implementation 'joda-time:joda-time:2.12.7'
|
||||
implementation "io.coil-kt:coil:${coilKtVersion}"
|
||||
implementation "io.coil-kt:coil-gif:${coilKtVersion}"
|
||||
implementation "io.coil-kt:coil-svg:${coilKtVersion}"
|
||||
@ -308,11 +308,11 @@ dependencies {
|
||||
spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.4'
|
||||
|
||||
gplayImplementation 'com.google.android.gms:play-services-base:18.3.0'
|
||||
gplayImplementation "com.google.firebase:firebase-messaging:23.4.0"
|
||||
gplayImplementation "com.google.firebase:firebase-messaging:23.4.1"
|
||||
|
||||
implementation 'androidx.activity:activity-ktx:1.8.2'
|
||||
|
||||
implementation 'com.github.nextcloud.android-common:ui:0.14.0'
|
||||
implementation 'com.github.nextcloud.android-common:ui:0.15.0'
|
||||
|
||||
implementation 'com.github.nextcloud-deps:android-talk-webrtc:110.5481.0'
|
||||
}
|
||||
|
@ -23,8 +23,6 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" />
|
||||
|
||||
<application
|
||||
android:name=".application.NextcloudTalkApplication"
|
||||
android:allowBackup="true"
|
||||
|
@ -1117,7 +1117,7 @@ class CallActivity : CallBaseActivity() {
|
||||
micInputAudioRecorder.read(byteArr, 0, byteArr.size)
|
||||
val isCurrentlySpeaking = abs(byteArr[0].toDouble()) > MICROPHONE_VALUE_THRESHOLD
|
||||
|
||||
if (isCurrentlySpeaking && !isSpeakingLongTerm) {
|
||||
if (microphoneOn && isCurrentlySpeaking && !isSpeakingLongTerm) {
|
||||
isSpeakingLongTerm = true
|
||||
sendIsSpeakingMessage(true)
|
||||
} else if (!isCurrentlySpeaking && isSpeakingLongTerm) {
|
||||
|
@ -31,10 +31,12 @@ package com.nextcloud.talk.chat
|
||||
import android.Manifest
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.AssetFileDescriptor
|
||||
import android.content.res.Resources
|
||||
@ -42,7 +44,9 @@ import android.database.Cursor
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.media.AudioFocusRequest
|
||||
import android.media.AudioFormat
|
||||
import android.media.AudioManager
|
||||
import android.media.AudioRecord
|
||||
import android.media.MediaPlayer
|
||||
import android.media.MediaRecorder
|
||||
@ -389,6 +393,20 @@ class ChatActivity :
|
||||
private var lastRecordMediaPosition: Int = 0
|
||||
private var lastRecordedSeeked: Boolean = false
|
||||
|
||||
private val audioFocusChangeListener = getAudioFocusChangeListener()
|
||||
|
||||
private val noisyAudioStreamReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
chatViewModel.isPausedDueToBecomingNoisy = true
|
||||
if (isVoicePreviewPlaying) {
|
||||
pausePreviewVoicePlaying()
|
||||
}
|
||||
if (currentlyPlayedVoiceMessage != null) {
|
||||
pausePlayback(currentlyPlayedVoiceMessage!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var participantPermissions: ParticipantPermissions
|
||||
|
||||
private var videoURI: Uri? = null
|
||||
@ -1217,7 +1235,9 @@ class ChatActivity :
|
||||
|
||||
binding.messageInputView.micInputCloud.setOnClickListener {
|
||||
if (mediaRecorderState == MediaRecorderState.RECORDING) {
|
||||
recorder?.stop()
|
||||
audioFocusRequest(false) {
|
||||
recorder?.stop()
|
||||
}
|
||||
mediaRecorderState = MediaRecorderState.INITIAL
|
||||
stopMicInputRecordingAnimation()
|
||||
showPreviewVoiceRecording(true)
|
||||
@ -1446,8 +1466,11 @@ class ChatActivity :
|
||||
duration = it.duration.toLong()
|
||||
interpolator = LinearInterpolator()
|
||||
}
|
||||
voicePreviewMediaPlayer!!.start()
|
||||
voicePreviewObjectAnimator!!.start()
|
||||
audioFocusRequest(true) {
|
||||
voicePreviewMediaPlayer!!.start()
|
||||
voicePreviewObjectAnimator!!.start()
|
||||
handleBecomingNoisyBroadcast(register = true)
|
||||
}
|
||||
}
|
||||
|
||||
setOnCompletionListener {
|
||||
@ -1461,15 +1484,21 @@ class ChatActivity :
|
||||
if (voicePreviewMediaPlayer == null) {
|
||||
initPreviewVoiceRecording()
|
||||
} else {
|
||||
voicePreviewMediaPlayer!!.start()
|
||||
voicePreviewObjectAnimator!!.resume()
|
||||
audioFocusRequest(true) {
|
||||
voicePreviewMediaPlayer!!.start()
|
||||
voicePreviewObjectAnimator!!.resume()
|
||||
handleBecomingNoisyBroadcast(register = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun pausePreviewVoicePlaying() {
|
||||
Log.d(TAG, "paused preview voice recording")
|
||||
voicePreviewMediaPlayer!!.pause()
|
||||
voicePreviewObjectAnimator!!.pause()
|
||||
audioFocusRequest(false) {
|
||||
voicePreviewMediaPlayer!!.pause()
|
||||
voicePreviewObjectAnimator!!.pause()
|
||||
handleBecomingNoisyBroadcast(register = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopPreviewVoicePlaying() {
|
||||
@ -1479,9 +1508,12 @@ class ChatActivity :
|
||||
voicePreviewObjectAnimator!!.end()
|
||||
voicePreviewObjectAnimator = null
|
||||
binding.messageInputView.seekBar.clearAnimation()
|
||||
voicePreviewMediaPlayer!!.stop()
|
||||
voicePreviewMediaPlayer!!.release()
|
||||
voicePreviewMediaPlayer = null
|
||||
audioFocusRequest(false) {
|
||||
voicePreviewMediaPlayer!!.stop()
|
||||
voicePreviewMediaPlayer!!.release()
|
||||
voicePreviewMediaPlayer = null
|
||||
handleBecomingNoisyBroadcast(register = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1935,6 +1967,73 @@ class ChatActivity :
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAudioFocusChangeListener(): AudioManager.OnAudioFocusChangeListener {
|
||||
return AudioManager.OnAudioFocusChangeListener { flag ->
|
||||
when (flag) {
|
||||
AudioManager.AUDIOFOCUS_LOSS -> {
|
||||
chatViewModel.isPausedDueToBecomingNoisy = false
|
||||
if (isVoicePreviewPlaying) {
|
||||
stopPreviewVoicePlaying()
|
||||
}
|
||||
if (currentlyPlayedVoiceMessage != null) {
|
||||
stopMediaPlayer(currentlyPlayedVoiceMessage!!)
|
||||
}
|
||||
}
|
||||
|
||||
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
|
||||
chatViewModel.isPausedDueToBecomingNoisy = false
|
||||
if (isVoicePreviewPlaying) {
|
||||
pausePreviewVoicePlaying()
|
||||
}
|
||||
if (currentlyPlayedVoiceMessage != null) {
|
||||
pausePlayback(currentlyPlayedVoiceMessage!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun audioFocusRequest(shouldRequestFocus: Boolean, onGranted: () -> Unit) {
|
||||
if (chatViewModel.isPausedDueToBecomingNoisy) {
|
||||
onGranted()
|
||||
return
|
||||
}
|
||||
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
val duration = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
|
||||
|
||||
val isGranted: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val focusRequest = AudioFocusRequest.Builder(duration)
|
||||
.setOnAudioFocusChangeListener(audioFocusChangeListener)
|
||||
.build()
|
||||
if (shouldRequestFocus) {
|
||||
audioManager.requestAudioFocus(focusRequest)
|
||||
} else {
|
||||
audioManager.abandonAudioFocusRequest(focusRequest)
|
||||
}
|
||||
} else {
|
||||
@Deprecated("This method was deprecated in API level 26.")
|
||||
if (shouldRequestFocus) {
|
||||
audioManager.requestAudioFocus(audioFocusChangeListener, AudioManager.STREAM_MUSIC, duration)
|
||||
} else {
|
||||
audioManager.abandonAudioFocus(audioFocusChangeListener)
|
||||
}
|
||||
}
|
||||
if (isGranted == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||
onGranted()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleBecomingNoisyBroadcast(register: Boolean) {
|
||||
if (register && !chatViewModel.receiverRegistered) {
|
||||
registerReceiver(noisyAudioStreamReceiver, IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY))
|
||||
chatViewModel.receiverRegistered = true
|
||||
} else if (!chatViewModel.receiverUnregistered) {
|
||||
unregisterReceiver(noisyAudioStreamReceiver)
|
||||
chatViewModel.receiverUnregistered = true
|
||||
chatViewModel.receiverRegistered = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun startPlayback(message: ChatMessage) {
|
||||
if (!active) {
|
||||
// don't begin to play voice message if screen is not visible anymore.
|
||||
@ -1948,8 +2047,10 @@ class ChatActivity :
|
||||
|
||||
mediaPlayer?.let {
|
||||
if (!it.isPlaying) {
|
||||
it.start()
|
||||
Log.d(TAG, "MediaPlayer has Started")
|
||||
audioFocusRequest(true) {
|
||||
it.start()
|
||||
handleBecomingNoisyBroadcast(register = true)
|
||||
}
|
||||
}
|
||||
|
||||
mediaPlayerHandler = Handler()
|
||||
@ -1984,8 +2085,10 @@ class ChatActivity :
|
||||
|
||||
private fun pausePlayback(message: ChatMessage) {
|
||||
if (mediaPlayer!!.isPlaying) {
|
||||
mediaPlayer!!.pause()
|
||||
Log.d(TAG, "MediaPlayer is paused")
|
||||
audioFocusRequest(false) {
|
||||
mediaPlayer!!.pause()
|
||||
handleBecomingNoisyBroadcast(register = false)
|
||||
}
|
||||
}
|
||||
|
||||
message.isPlayingVoiceMessage = false
|
||||
@ -2043,7 +2146,10 @@ class ChatActivity :
|
||||
mediaPlayer?.let {
|
||||
if (it.isPlaying) {
|
||||
Log.d(TAG, "media player is stopped")
|
||||
it.stop()
|
||||
audioFocusRequest(false) {
|
||||
it.stop()
|
||||
handleBecomingNoisyBroadcast(register = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: IllegalStateException) {
|
||||
@ -2259,8 +2365,10 @@ class ChatActivity :
|
||||
private fun stopMicInputRecordingAnimation() {
|
||||
if (micInputAudioRecordThread != null) {
|
||||
Log.d(TAG, "Mic Animation Ended")
|
||||
micInputAudioRecorder.stop()
|
||||
micInputAudioRecorder.release()
|
||||
audioFocusRequest(false) {
|
||||
micInputAudioRecorder.stop()
|
||||
micInputAudioRecorder.release()
|
||||
}
|
||||
isMicInputAudioThreadRunning = false
|
||||
micInputAudioRecordThread = null
|
||||
}
|
||||
@ -2311,7 +2419,9 @@ class ChatActivity :
|
||||
}
|
||||
|
||||
try {
|
||||
start()
|
||||
audioFocusRequest(true) {
|
||||
start()
|
||||
}
|
||||
mediaRecorderState = MediaRecorderState.RECORDING
|
||||
Log.d(TAG, "recording started")
|
||||
} catch (e: IllegalStateException) {
|
||||
@ -2352,8 +2462,10 @@ class ChatActivity :
|
||||
recorder?.apply {
|
||||
try {
|
||||
if (mediaRecorderState == MediaRecorderState.RECORDING) {
|
||||
stop()
|
||||
reset()
|
||||
audioFocusRequest(false) {
|
||||
stop()
|
||||
reset()
|
||||
}
|
||||
mediaRecorderState = MediaRecorderState.INITIAL
|
||||
Log.d(TAG, "stopped recorder")
|
||||
}
|
||||
|
@ -48,6 +48,11 @@ class ChatViewModel @Inject constructor(private val repository: ChatRepository)
|
||||
open class GetReminderExistState(val reminder: Reminder) : ViewState
|
||||
|
||||
private val _getReminderExistState: MutableLiveData<ViewState> = MutableLiveData(GetReminderStartState)
|
||||
|
||||
var isPausedDueToBecomingNoisy = false
|
||||
var receiverRegistered = false
|
||||
var receiverUnregistered = false
|
||||
|
||||
val getReminderExistState: LiveData<ViewState>
|
||||
get() = _getReminderExistState
|
||||
|
||||
|
@ -44,6 +44,7 @@ import androidx.core.view.marginBottom
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.media3.common.AudioAttributes
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
@ -165,7 +166,10 @@ class FullScreenMediaActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun initializePlayer() {
|
||||
player = ExoPlayer.Builder(applicationContext).build()
|
||||
player = ExoPlayer.Builder(applicationContext)
|
||||
.setAudioAttributes(AudioAttributes.DEFAULT, true)
|
||||
.setHandleAudioBecomingNoisy(true)
|
||||
.build()
|
||||
binding.playerView.player = player
|
||||
}
|
||||
|
||||
@ -202,6 +206,7 @@ class FullScreenMediaActivity : AppCompatActivity() {
|
||||
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
|
||||
supportActionBar?.show()
|
||||
}
|
||||
|
||||
private fun applyWindowInsets() {
|
||||
val playerView = binding.playerView
|
||||
val exoControls = playerView.findViewById<FrameLayout>(R.id.exo_bottom_bar)
|
||||
|
@ -2,7 +2,9 @@
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Marcel Hibbe
|
||||
* @author Parneet Singh
|
||||
* Copyright (C) 2021-2022 Marcel Hibbe <dev@mhibbe.de>
|
||||
* Copyright (C) 2024-2025 Parneet Singh <gurayaparneet@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -22,7 +24,6 @@ package com.nextcloud.talk.jobs
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.app.Notification
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
@ -86,7 +87,6 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
|
||||
|
||||
private var mNotifyManager: NotificationManager? = null
|
||||
private var mBuilder: NotificationCompat.Builder? = null
|
||||
private lateinit var notification: Notification
|
||||
private var notificationId: Int = 0
|
||||
|
||||
lateinit var roomToken: String
|
||||
@ -168,7 +168,7 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
|
||||
}
|
||||
|
||||
if (uploadSuccess) {
|
||||
mNotifyManager?.cancel(notificationId)
|
||||
cancelNotification()
|
||||
return Result.success()
|
||||
} else if (isStopped) {
|
||||
// since work is cancelled the result would be ignored anyways
|
||||
@ -196,12 +196,12 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
|
||||
}
|
||||
|
||||
override fun onTransferProgress(percentage: Int) {
|
||||
notification = mBuilder!!
|
||||
val progressUpdateNotification = mBuilder!!
|
||||
.setProgress(HUNDRED_PERCENT, percentage, false)
|
||||
.setContentText(getNotificationContentText(percentage))
|
||||
.build()
|
||||
|
||||
mNotifyManager!!.notify(notificationId, notification)
|
||||
mNotifyManager!!.notify(notificationId, progressUpdateNotification)
|
||||
}
|
||||
|
||||
override fun onStopped() {
|
||||
@ -223,22 +223,60 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
|
||||
}
|
||||
|
||||
private fun initNotificationWithPercentage() {
|
||||
notification = mBuilder!!
|
||||
.setContentTitle(getResourceString(context, R.string.nc_upload_in_progess))
|
||||
val initNotification = mBuilder!!
|
||||
.setContentTitle(context.resources.getString(R.string.nc_upload_in_progess))
|
||||
.setContentText(getNotificationContentText(ZERO_PERCENT))
|
||||
.setSmallIcon(R.drawable.upload_white)
|
||||
.setOngoing(true)
|
||||
.setProgress(HUNDRED_PERCENT, ZERO_PERCENT, false)
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setGroup(NotificationUtils.KEY_UPLOAD_GROUP)
|
||||
.setContentIntent(getIntentToOpenConversation())
|
||||
.addAction(
|
||||
R.drawable.ic_cancel_white_24dp, getResourceString(context, R.string.nc_cancel),
|
||||
R.drawable.ic_cancel_white_24dp,
|
||||
getResourceString(context, R.string.nc_cancel),
|
||||
getCancelUploadIntent()
|
||||
)
|
||||
.build()
|
||||
|
||||
notificationId = SystemClock.uptimeMillis().toInt()
|
||||
mNotifyManager!!.notify(notificationId, notification)
|
||||
mNotifyManager!!.notify(notificationId, initNotification)
|
||||
// only need one summary notification but multiple upload worker can call it more than once but it is safe
|
||||
// because of the same notification object config and id.
|
||||
makeSummaryNotification()
|
||||
}
|
||||
|
||||
private fun makeSummaryNotification() {
|
||||
// summary notification encapsulating the group of notifications
|
||||
val summaryNotification = NotificationCompat.Builder(
|
||||
context,
|
||||
NotificationUtils.NotificationChannels
|
||||
.NOTIFICATION_CHANNEL_UPLOADS.name
|
||||
).setSmallIcon(R.drawable.upload_white)
|
||||
.setGroup(NotificationUtils.KEY_UPLOAD_GROUP)
|
||||
.setGroupSummary(true)
|
||||
.build()
|
||||
|
||||
mNotifyManager?.notify(NotificationUtils.GROUP_SUMMARY_NOTIFICATION_ID, summaryNotification)
|
||||
}
|
||||
|
||||
private fun getActiveUploadNotifications(): Int? {
|
||||
// filter out active notifications that are upload notifications using group
|
||||
return mNotifyManager?.activeNotifications?.filter {
|
||||
it.notification.group == NotificationUtils
|
||||
.KEY_UPLOAD_GROUP
|
||||
}?.size
|
||||
}
|
||||
|
||||
private fun cancelNotification() {
|
||||
mNotifyManager?.cancel(notificationId)
|
||||
// summary notification would not get dismissed automatically
|
||||
// if child notifications are cancelled programmatically
|
||||
// so check if only 1 notification left if yes
|
||||
// then cancel it (which is summary notification)
|
||||
if (getActiveUploadNotifications() == 1) {
|
||||
mNotifyManager?.cancel(NotificationUtils.GROUP_SUMMARY_NOTIFICATION_ID)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getNotificationContentText(percentage: Int): String {
|
||||
@ -289,17 +327,21 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
|
||||
getResourceString(context, R.string.nc_upload_failed_notification_text),
|
||||
fileName
|
||||
)
|
||||
notification = mBuilder!!
|
||||
val failureNotification = NotificationCompat.Builder(
|
||||
context,
|
||||
NotificationUtils.NotificationChannels
|
||||
.NOTIFICATION_CHANNEL_UPLOADS.name
|
||||
)
|
||||
.setContentTitle(failureTitle)
|
||||
.setContentText(failureText)
|
||||
.setSmallIcon(R.drawable.baseline_error_24)
|
||||
.setGroup(NotificationUtils.KEY_UPLOAD_GROUP)
|
||||
.setOngoing(false)
|
||||
.build()
|
||||
|
||||
// Cancel original notification
|
||||
mNotifyManager?.cancel(notificationId)
|
||||
// Then show information about failure
|
||||
mNotifyManager!!.notify(SystemClock.uptimeMillis().toInt(), notification)
|
||||
// update current notification with failure info
|
||||
mNotifyManager!!.notify(SystemClock.uptimeMillis().toInt(), failureNotification)
|
||||
}
|
||||
|
||||
private fun getResourceString(context: Context, resourceId: Int): String {
|
||||
|
@ -68,6 +68,10 @@ object NotificationUtils {
|
||||
// RemoteInput key - used for replies sent directly from notification
|
||||
const val KEY_DIRECT_REPLY = "key_direct_reply"
|
||||
|
||||
// notification group keys
|
||||
const val KEY_UPLOAD_GROUP = "com.nextcloud.talk.utils.KEY_UPLOAD_GROUP"
|
||||
const val GROUP_SUMMARY_NOTIFICATION_ID = -1
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
private fun createNotificationChannel(
|
||||
context: Context,
|
||||
|
@ -109,6 +109,7 @@
|
||||
<string name="nc_conversations_empty">会話に参加するか、新しいのを開始</string>
|
||||
<string name="nc_conversations_empty_details">友達や同僚に挨拶しましょう!</string>
|
||||
<string name="nc_copy_message">コピー</string>
|
||||
<string name="nc_create_poll">投票を作成</string>
|
||||
<string name="nc_date_header_today">今日</string>
|
||||
<string name="nc_date_header_yesterday">昨日</string>
|
||||
<string name="nc_delete">削除</string>
|
||||
@ -144,6 +145,7 @@
|
||||
<string name="nc_expire_message_one_day">1日</string>
|
||||
<string name="nc_expire_message_one_hour">1時間</string>
|
||||
<string name="nc_expire_message_one_week">1週間</string>
|
||||
<string name="nc_expire_messages_explanation">チャットメッセージは、一定時間経過後に期限切れにすることができます。注意: チャットで共有されたファイルは、ファイル所有者は削除されませんが、会話では共有されなくなります。</string>
|
||||
<string name="nc_external_server_failed">シグナリング設定を取得できませんでした</string>
|
||||
<string name="nc_failed_signaling_settings">ターゲットのサーバーは、モバイル経由での公開の会話への参加をサポートしていません。Webブラウザー経由で会話への参加を試みてください。</string>
|
||||
<string name="nc_failed_to_perform_operation">申し訳ありませんが、何かがおかしいです!</string>
|
||||
@ -330,6 +332,7 @@
|
||||
<string name="nc_settings_theme_key">テーマ</string>
|
||||
<string name="nc_settings_theme_light">ライト</string>
|
||||
<string name="nc_settings_theme_title">テーマ</string>
|
||||
<string name="nc_settings_typing_status_desc">自分のタイピング状況を共有し、他の人のタイピング状況を表示する</string>
|
||||
<string name="nc_settings_use_credentials_title">プロキシは資格情報を必要とします</string>
|
||||
<string name="nc_settings_warning">警告</string>
|
||||
<string name="nc_settings_wrong_account">現在のアカウントのみ再認可できます</string>
|
||||
@ -377,8 +380,11 @@
|
||||
<string name="open_in_files_app">アプリでファイルを開く</string>
|
||||
<string name="play_pause_voice_message">音声メッセージを再生/一時停止</string>
|
||||
<string name="polls_add_option">オプションを追加</string>
|
||||
<string name="polls_end_poll">投票を終了する</string>
|
||||
<string name="polls_multiple_answers">複数の答え</string>
|
||||
<string name="polls_options">オプション</string>
|
||||
<string name="polls_private_poll">プライベート投票</string>
|
||||
<string name="polls_question">質問</string>
|
||||
<string name="polls_results_subtitle">結果</string>
|
||||
<string name="polls_settings">設定</string>
|
||||
<string name="polls_submit_vote">投票</string>
|
||||
@ -386,9 +392,13 @@
|
||||
<string name="reactions_tab_all">すべて</string>
|
||||
<string name="read_storage_no_permission">ストレージからのファイル共有は権限がなければ不可能です</string>
|
||||
<string name="record_cancel_start">録画開始をキャンセル</string>
|
||||
<string name="record_failed_info">レコーディングが失敗しました。あなたの管理者に連絡してください。</string>
|
||||
<string name="record_start_description">録画を開始</string>
|
||||
<string name="record_stop_description">録画を停止</string>
|
||||
<string name="recording_consent_all">全ての通話には録音の同意が必要です。</string>
|
||||
<string name="recording_consent_for_conversation_description">この会話に参加する前に、録音の同意が必要です。</string>
|
||||
<string name="recording_consent_for_conversation_title">レコーディングの同意</string>
|
||||
<string name="recording_consent_title">通話は録音されるかもしれません。</string>
|
||||
<string name="recording_settings_title">記録中</string>
|
||||
<string name="save">保存</string>
|
||||
<string name="scope_federated_description">信頼できるサーバーのみと同期</string>
|
||||
@ -417,6 +427,7 @@
|
||||
<string name="shared_items_file">ファイル</string>
|
||||
<string name="shared_items_media">メディア</string>
|
||||
<string name="shared_items_other">その他</string>
|
||||
<string name="shared_items_poll">投票</string>
|
||||
<string name="shared_items_voice">音声番号</string>
|
||||
<string name="starred">お気に入り</string>
|
||||
<string name="startCallForbidden">通話を開始することが許可されていません</string>
|
||||
@ -436,6 +447,7 @@
|
||||
<string name="today">今日</string>
|
||||
<string name="tomorrow">明日</string>
|
||||
<string name="translate">翻訳</string>
|
||||
<string name="translation_copy_translated_text">翻訳されたテキストをコピー</string>
|
||||
<string name="translation_detect_language">言語を検出する</string>
|
||||
<string name="translation_device_settings">デバイスの設定</string>
|
||||
<string name="translation_error_message">言語を検出できませんでした</string>
|
||||
|
@ -264,7 +264,7 @@
|
||||
<string name="nc_settings">Impostatziones</string>
|
||||
<string name="nc_settings_account_updated">Su contu chi tenias giai est istadu agiornadu, imbetzes de nd\'agiùnghere unu nou</string>
|
||||
<string name="nc_settings_advanced_title">Avantzadu</string>
|
||||
<string name="nc_settings_appearance">Visibilidade</string>
|
||||
<string name="nc_settings_appearance">Aspetu</string>
|
||||
<string name="nc_settings_call_ringtone">Mutidas</string>
|
||||
<string name="nc_settings_incognito_keyboard_desc">Imparat a sa tastiera a disativare s\'imparu personale (chene garantzias)</string>
|
||||
<string name="nc_settings_incognito_keyboard_title">Tastiera in incògnita</string>
|
||||
|
@ -143,7 +143,10 @@
|
||||
<trusted-key id="AFCC4C7594D09E2182C60E0F7A01B0F236E5430F" group="com.google.code.gson"/>
|
||||
<trusted-key id="B02335AA54CCF21E52BBF9ABD9C565AA72BA2FDD" group="io.grpc"/>
|
||||
<trusted-key id="B087A0EB8416563AFE64CEBA4604091C01C3086A" group="com.mebigfatguy.fb-contrib" name="fb-contrib" version="7.6.4"/>
|
||||
<trusted-key id="B41089A2DA79B0FA5810252872385FF0AF338D52" group="joda-time" name="joda-time" version="2.12.6"/>
|
||||
<trusted-key id="B41089A2DA79B0FA5810252872385FF0AF338D52">
|
||||
<trusting group="joda-time" name="joda-time" version="2.12.6"/>
|
||||
<trusting group="joda-time" name="joda-time" version="2.12.7"/>
|
||||
</trusted-key>
|
||||
<trusted-key id="B6E73D84EA4FCC47166087253FAAD2CD5ECBB314" group="org.apache.commons" name="commons-parent" version="52"/>
|
||||
<trusted-key id="B801E2F8EF035068EC1139CC29579F18FA8FD93B" group="com.google.j2objc" name="j2objc-annotations" version="1.3"/>
|
||||
<trusted-key id="BC87A3FD0A54480F0BADBEBD21939FF0CA2A6567" group="commons-codec" name="commons-codec" version="1.15"/>
|
||||
@ -1879,6 +1882,14 @@
|
||||
<sha256 value="89c21ebe5a3aedd8c910bbe0f7c0c6ea6f30dc9dba58d68b39bee3759a7dc52f" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud.android-common" name="core" version="0.15.0">
|
||||
<artifact name="core-0.15.0.aar">
|
||||
<sha256 value="d370010eeae5928f525f31c09e33f9c78ed5e610af4b9f84b1ba68ce0727267b" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="core-0.15.0.module">
|
||||
<sha256 value="609090237e7d6c9745dcb883819e53bb4c9337b89740aa88fd1c56d73ecfa56b" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud.android-common" name="material-color-utilities" version="0.14.0">
|
||||
<artifact name="material-color-utilities-0.14.0.jar">
|
||||
<sha256 value="bfcd5205b056b948bc6ff9a556898188f4a4e92179c723906e10f1164b776eed" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
@ -1887,6 +1898,14 @@
|
||||
<sha256 value="b12eadfbfe39b7fb6e62a13c9aca93b468e66a0cf0a2d841b849fe86ebc2d605" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud.android-common" name="material-color-utilities" version="0.15.0">
|
||||
<artifact name="material-color-utilities-0.15.0.jar">
|
||||
<sha256 value="ced5cd660ebfa6aa7461a2157f67a8e76ae12830f759adec0b51631de4ac5434" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="material-color-utilities-0.15.0.module">
|
||||
<sha256 value="edc221870d47808e96595f11d58dc6f45e50a9d8979658f024ae9a816778ecfb" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud.android-common" name="ui" version="0.14.0">
|
||||
<artifact name="ui-0.14.0.aar">
|
||||
<sha256 value="2ff1b8ca1ce4d4151ce967c4704a4def19a128d3f710491872e007217f3ac84f" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
@ -1895,6 +1914,14 @@
|
||||
<sha256 value="a600ef42a3ffe9a5900893f7f68052272ed8749ae2c5c44471f792f9d1d9d01f" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.nextcloud.android-common" name="ui" version="0.15.0">
|
||||
<artifact name="ui-0.15.0.aar">
|
||||
<sha256 value="7e520034d730a11f5089548a8f15fbdd5d5054f8f0465f711664235b3939b78d" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="ui-0.15.0.module">
|
||||
<sha256 value="ac04b3a93aae2e9e8585d01447210fe0c5c85dec13e241b5e7c8956a3ed8a962" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.github.wooplr" name="Spotlight" version="1.3">
|
||||
<artifact name="Spotlight-1.3.aar">
|
||||
<sha256 value="2216a78710c8626623d3fd8f6519ec49e26d86930757b51288b7889653b7b44e" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
@ -2225,6 +2252,14 @@
|
||||
<sha256 value="f376e72c66dac4215b25d8dcda887ca355c661f630d2d155160e0c6dca7d4ace" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.firebase" name="firebase-messaging" version="23.4.1">
|
||||
<artifact name="firebase-messaging-23.4.1.aar">
|
||||
<sha256 value="15c2637c28fb6895b6a4c998a191b663f3b78ac815f6ac59ab7d673a8d9af202" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
<artifact name="firebase-messaging-23.4.1.pom">
|
||||
<sha256 value="188ee169e2d73488e9b14c7610bf3fd9a834658c0759af51b16b0b255865f7c6" origin="Generated by Gradle" reason="Artifact is not signed"/>
|
||||
</artifact>
|
||||
</component>
|
||||
<component group="com.google.guava" name="failureaccess" version="1.0.1">
|
||||
<artifact name="failureaccess-1.0.1.pom">
|
||||
<sha256 value="e96042ce78fecba0da2be964522947c87b40a291b5fd3cd672a434924103c4b9" origin="Generated by Gradle"/>
|
||||
|
Loading…
Reference in New Issue
Block a user