Merge branch 'develop' into bugfix/cmr/extended-character-filename

This commit is contained in:
Christian Rowlands 2024-11-12 10:37:40 -05:00
commit a608bff03b
19 changed files with 5204 additions and 1457 deletions

View File

@ -28,11 +28,11 @@ jobs:
with: with:
# https://github.com/actions/checkout/issues/881 # https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
- name: Use JDK 17 - name: Use JDK 21
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '21'
- name: Configure gradle - name: Configure gradle
uses: gradle/actions/setup-gradle@v3 uses: gradle/actions/setup-gradle@v3
with: with:
@ -57,11 +57,11 @@ jobs:
with: with:
# https://github.com/actions/checkout/issues/881 # https://github.com/actions/checkout/issues/881
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
- name: Use JDK 17 - name: Use JDK 21
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '21'
- name: Configure gradle - name: Configure gradle
uses: gradle/actions/setup-gradle@v3 uses: gradle/actions/setup-gradle@v3
with: with:

View File

@ -20,11 +20,11 @@ jobs:
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: 3.8 python-version: 3.8
- name: Use JDK 17 - name: Use JDK 21
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '21'
- name: Configure gradle - name: Configure gradle
uses: gradle/actions/setup-gradle@v3 uses: gradle/actions/setup-gradle@v3
with: with:

View File

@ -44,11 +44,11 @@ jobs:
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: 3.8 python-version: 3.8
- name: Use JDK 17 - name: Use JDK 21
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '21'
- name: Configure gradle - name: Configure gradle
uses: gradle/actions/setup-gradle@v3 uses: gradle/actions/setup-gradle@v3
with: with:

View File

@ -25,11 +25,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use JDK 17 - name: Use JDK 21
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '21'
- name: Configure gradle - name: Configure gradle
uses: gradle/actions/setup-gradle@v3 uses: gradle/actions/setup-gradle@v3
with: with:
@ -48,11 +48,11 @@ jobs:
cancel-in-progress: true cancel-in-progress: true
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use JDK 17 - name: Use JDK 21
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '21'
- name: Configure gradle - name: Configure gradle
uses: gradle/actions/setup-gradle@v3 uses: gradle/actions/setup-gradle@v3
with: with:
@ -102,11 +102,11 @@ jobs:
cancel-in-progress: true cancel-in-progress: true
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use JDK 17 - name: Use JDK 21
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '21'
- name: Configure gradle - name: Configure gradle
uses: gradle/actions/setup-gradle@v3 uses: gradle/actions/setup-gradle@v3
with: with:

View File

@ -29,11 +29,11 @@ jobs:
with: with:
lfs: true lfs: true
fetch-depth: 0 fetch-depth: 0
- name: Use JDK 17 - name: Use JDK 21
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17' java-version: '21'
- name: Configure gradle - name: Configure gradle
uses: gradle/actions/setup-gradle@v3 uses: gradle/actions/setup-gradle@v3
with: with:
@ -139,11 +139,11 @@ jobs:
# cancel-in-progress: true # cancel-in-progress: true
# steps: # steps:
# - uses: actions/checkout@v4 # - uses: actions/checkout@v4
# - name: Use JDK 17 # - name: Use JDK 21
# uses: actions/setup-java@v4 # uses: actions/setup-java@v4
# with: # with:
# distribution: 'temurin' # See 'Supported distributions' for available options # distribution: 'temurin' # See 'Supported distributions' for available options
# java-version: '17' # java-version: '21'
# - name: Configure gradle # - name: Configure gradle
# uses: gradle/actions/setup-gradle@v3 # uses: gradle/actions/setup-gradle@v3
# with: # with:

View File

@ -43,7 +43,7 @@ plugins {
// ktlint Plugin // ktlint Plugin
id "org.jlleitschuh.gradle.ktlint" version "11.3.2" id "org.jlleitschuh.gradle.ktlint" version "11.3.2"
// Detekt // Detekt
id "io.gitlab.arturbosch.detekt" version "1.22.0" id "io.gitlab.arturbosch.detekt" version "1.23.7"
// Ksp // Ksp
id "com.google.devtools.ksp" version "1.9.24-1.0.20" id "com.google.devtools.ksp" version "1.9.24-1.0.20"

View File

@ -2,9 +2,9 @@ ext.versions = [
'minSdk' : 21, 'minSdk' : 21,
'compileSdk' : 34, 'compileSdk' : 34,
'targetSdk' : 34, 'targetSdk' : 34,
'sourceCompat' : JavaVersion.VERSION_17, 'sourceCompat' : JavaVersion.VERSION_21,
'targetCompat' : JavaVersion.VERSION_17, 'targetCompat' : JavaVersion.VERSION_21,
'jvmTarget' : "17", 'jvmTarget' : "21",
] ]
def gradle = "8.4.2" def gradle = "8.4.2"

View File

@ -203,6 +203,7 @@ ext.groups = [
'org.jacoco', 'org.jacoco',
'org.java-websocket', 'org.java-websocket',
'org.jcodec', 'org.jcodec',
'org.jcommander',
'org.jetbrains', 'org.jetbrains',
'org.jetbrains.dokka', 'org.jetbrains.dokka',
'org.jetbrains.intellij.deps', 'org.jetbrains.intellij.deps',
@ -229,6 +230,7 @@ ext.groups = [
'org.reactivestreams', 'org.reactivestreams',
'org.robolectric', 'org.robolectric',
'org.slf4j', 'org.slf4j',
'org.snakeyaml',
'org.sonatype.oss', 'org.sonatype.oss',
'org.testng', 'org.testng',
'org.threeten', 'org.threeten',

View File

@ -2,7 +2,7 @@ apply plugin: 'kotlin'
apply plugin: 'java' apply plugin: 'java'
sourceCompatibility = versions.sourceCompat sourceCompatibility = versions.sourceCompat
targetCompatibility = versions.sourceCompat targetCompatibility = versions.targetCompat
dependencies { dependencies {
implementation 'com.squareup:javapoet:1.13.0' implementation 'com.squareup:javapoet:1.13.0'

View File

@ -1,7 +1,5 @@
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
apply plugin: 'com.android.library'
android { android {
namespace "com.amulyakhare.textdrawable" namespace "com.amulyakhare.textdrawable"

View File

@ -652,6 +652,8 @@
<string name="call_remove_jitsi_widget_progress">Ending call…</string> <string name="call_remove_jitsi_widget_progress">Ending call…</string>
<string name="microphone_in_use_title">Microphone in use</string>
<!-- permissions Android M --> <!-- permissions Android M -->
<string name="permissions_rationale_popup_title">Information</string> <string name="permissions_rationale_popup_title">Information</string>
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name --> <!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->

View File

@ -25,6 +25,8 @@ style:
active: false active: false
UseCheckOrError: UseCheckOrError:
active: false active: false
UnusedPrivateProperty:
active: false
empty-blocks: empty-blocks:
EmptyFunctionBlock: EmptyFunctionBlock:
@ -75,6 +77,8 @@ naming:
performance: performance:
SpreadOperator: SpreadOperator:
active: false active: false
ForEachOnRange:
active: false
# Note: all rules for `comments` are disabled by default, but I put them here to be aware of their existence # Note: all rules for `comments` are disabled by default, but I put them here to be aware of their existence
comments: comments:
@ -91,7 +95,7 @@ comments:
EndOfSentenceFormat: EndOfSentenceFormat:
active: true active: true
OutdatedDocumentation: OutdatedDocumentation:
active: true active: false
UndocumentedPublicClass: UndocumentedPublicClass:
active: false active: false
UndocumentedPublicFunction: UndocumentedPublicFunction:

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,9 @@
<!-- Jitsi SDK is now API23+ --> <!-- Jitsi SDK is now API23+ -->
<uses-sdk tools:overrideLibrary="com.swmansion.gesturehandler,org.jitsi.meet.sdk,com.oney.WebRTCModule,com.learnium.RNDeviceInfo,com.reactnativecommunity.asyncstorage,com.ocetnik.timer,com.calendarevents,com.reactnativecommunity.netinfo,com.kevinresol.react_native_default_preference,com.rnimmersive,com.rnimmersivemode,com.corbt.keepawake,com.BV.LinearGradient,com.horcrux.svg,com.oblador.performance,com.reactnativecommunity.slider,com.brentvatne.react,com.reactnativecommunity.clipboard,com.swmansion.gesturehandler.react,org.linusu,org.reactnative.maskedview,com.reactnativepagerview,com.swmansion.reanimated,com.th3rdwave.safeareacontext,com.swmansion.rnscreens,org.devio.rn.splashscreen,com.reactnativecommunity.webview,org.wonday.orientation" /> <uses-sdk tools:overrideLibrary="com.swmansion.gesturehandler,org.jitsi.meet.sdk,com.oney.WebRTCModule,com.learnium.RNDeviceInfo,com.reactnativecommunity.asyncstorage,com.ocetnik.timer,com.calendarevents,com.reactnativecommunity.netinfo,com.kevinresol.react_native_default_preference,com.rnimmersive,com.rnimmersivemode,com.corbt.keepawake,com.BV.LinearGradient,com.horcrux.svg,com.oblador.performance,com.reactnativecommunity.slider,com.brentvatne.react,com.reactnativecommunity.clipboard,com.swmansion.gesturehandler.react,org.linusu,org.reactnative.maskedview,com.reactnativepagerview,com.swmansion.reanimated,com.th3rdwave.safeareacontext,com.swmansion.rnscreens,org.devio.rn.splashscreen,com.reactnativecommunity.webview,org.wonday.orientation" />
<!-- For MicrophoneAccessService -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<!-- Adding CAMERA permission prevents Chromebooks to see the application on the PlayStore --> <!-- Adding CAMERA permission prevents Chromebooks to see the application on the PlayStore -->
<!-- Tell that the Camera is not mandatory to install the application --> <!-- Tell that the Camera is not mandatory to install the application -->
<uses-feature <uses-feature
@ -397,6 +400,13 @@
android:foregroundServiceType="mediaProjection" android:foregroundServiceType="mediaProjection"
tools:targetApi="Q" /> tools:targetApi="Q" />
<service
android:name=".features.call.audio.MicrophoneAccessService"
android:exported="false"
android:foregroundServiceType="microphone"
android:permission="android.permission.FOREGROUND_SERVICE_MICROPHONE">
</service>
<!-- Receivers --> <!-- Receivers -->
<receiver <receiver

View File

@ -22,6 +22,7 @@ import im.vector.app.core.extensions.singletonEntryPoint
import im.vector.app.core.extensions.startForegroundCompat import im.vector.app.core.extensions.startForegroundCompat
import im.vector.app.features.call.CallArgs import im.vector.app.features.call.CallArgs
import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.VectorCallActivity
import im.vector.app.features.call.audio.MicrophoneAccessService
import im.vector.app.features.call.telecom.CallConnection import im.vector.app.features.call.telecom.CallConnection
import im.vector.app.features.call.webrtc.WebRtcCall import im.vector.app.features.call.webrtc.WebRtcCall
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
@ -199,6 +200,9 @@ class CallAndroidService : VectorAndroidService() {
stopForegroundCompat() stopForegroundCompat()
mediaSession?.isActive = false mediaSession?.isActive = false
myStopSelf() myStopSelf()
// Also stop the microphone service if it is running
stopService(Intent(this, MicrophoneAccessService::class.java))
} }
val wasConnected = connectedCallIds.remove(callId) val wasConnected = connectedCallIds.remove(callId)
if (!wasConnected && !terminatedCall.isOutgoing && !rejected && endCallReason != EndCallReason.ANSWERED_ELSEWHERE) { if (!wasConnected && !terminatedCall.isOutgoing && !rejected && endCallReason != EndCallReason.ANSWERED_ELSEWHERE) {

View File

@ -7,12 +7,14 @@
package im.vector.app.features.call package im.vector.app.features.call
import android.Manifest
import android.app.Activity import android.app.Activity
import android.app.KeyguardManager import android.app.KeyguardManager
import android.app.PictureInPictureParams import android.app.PictureInPictureParams
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
import android.content.pm.PackageManager
import android.graphics.Color import android.graphics.Color
import android.media.projection.MediaProjection import android.media.projection.MediaProjection
import android.media.projection.MediaProjectionManager import android.media.projection.MediaProjectionManager
@ -31,6 +33,8 @@ import androidx.core.content.getSystemService
import androidx.core.util.Consumer import androidx.core.util.Consumer
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.viewModel
@ -48,6 +52,7 @@ import im.vector.app.core.utils.PERMISSIONS_FOR_VIDEO_IP_CALL
import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.checkPermissions
import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.core.utils.registerForPermissionsResult
import im.vector.app.databinding.ActivityCallBinding import im.vector.app.databinding.ActivityCallBinding
import im.vector.app.features.call.audio.MicrophoneAccessService
import im.vector.app.features.call.dialpad.CallDialPadBottomSheet import im.vector.app.features.call.dialpad.CallDialPadBottomSheet
import im.vector.app.features.call.dialpad.DialPadFragment import im.vector.app.features.call.dialpad.DialPadFragment
import im.vector.app.features.call.transfer.CallTransferActivity import im.vector.app.features.call.transfer.CallTransferActivity
@ -236,6 +241,42 @@ class VectorCallActivity :
} }
} }
private fun startMicrophoneService() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
== PackageManager.PERMISSION_GRANTED) {
// Only start the service if the app is in the foreground
if (isAppInForeground()) {
Timber.tag(loggerTag.value).v("Starting microphone foreground service")
val intent = Intent(this, MicrophoneAccessService::class.java)
ContextCompat.startForegroundService(this, intent)
} else {
Timber.tag(loggerTag.value).v("App is not in foreground; cannot start microphone service")
}
} else {
Timber.tag(loggerTag.value).v("Microphone permission not granted; cannot start service")
}
}
private fun isAppInForeground(): Boolean {
val appProcess = ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)
return appProcess
}
private fun stopMicrophoneService() {
Timber.tag(loggerTag.value).d("Stopping MicrophoneAccessService (if needed).")
val intent = Intent(this, MicrophoneAccessService::class.java)
stopService(intent)
}
override fun onPause() {
super.onPause()
startMicrophoneService()
}
override fun onResume() {
super.onResume()
stopMicrophoneService()
}
override fun onDestroy() { override fun onDestroy() {
detachRenderersIfNeeded() detachRenderersIfNeeded()
turnScreenOffAndKeyguardOn() turnScreenOffAndKeyguardOn()

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.call.audio
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.startForegroundCompat
import im.vector.app.core.services.VectorAndroidService
import im.vector.app.features.notifications.NotificationUtils
import im.vector.lib.core.utils.timer.Clock
import javax.inject.Inject
@AndroidEntryPoint
class MicrophoneAccessService : VectorAndroidService() {
@Inject lateinit var notificationUtils: NotificationUtils
@Inject lateinit var clock: Clock
private val binder = LocalBinder()
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
showMicrophoneAccessNotification()
return START_STICKY
}
private fun showMicrophoneAccessNotification() {
val notificationId = clock.epochMillis().toInt()
val notification = notificationUtils.buildMicrophoneAccessNotification()
startForegroundCompat(notificationId, notification)
}
override fun onBind(intent: Intent?): IBinder {
return binder
}
inner class LocalBinder : Binder() {
fun getService(): MicrophoneAccessService = this@MicrophoneAccessService
}
}

View File

@ -529,6 +529,19 @@ class NotificationUtils @Inject constructor(
.build() .build()
} }
/**
* Creates a notification indicating that the microphone is currently being accessed by the application.
*/
fun buildMicrophoneAccessNotification(): Notification {
return NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID)
.setContentTitle(stringProvider.getString(CommonStrings.microphone_in_use_title))
.setSmallIcon(R.drawable.ic_call_answer)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setColor(ThemeUtils.getColor(context, android.R.attr.colorPrimary))
.setCategory(NotificationCompat.CATEGORY_CALL)
.build()
}
/** /**
* Creates a notification that indicates the application is initializing. * Creates a notification that indicates the application is initializing.
*/ */

File diff suppressed because one or more lines are too long