diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 6c785d36f..000000000
--- a/.gitignore
+++ /dev/null
@@ -1,29 +0,0 @@
-*.orig
-*.rej
-.DS_Store
-.gradle
-.idea
-.settings
-adb.pid
-bc-android.keystore
-build
-*.iml
-lint.xml
-local.properties
-res/.DS_Store
-res/raw/lpconfig.xsd
-.d
-.*clang*
-**/*.iml
-**/.classpath
-**/.project
-**/*.kdev4
-**/.vscode
-res/value-hi_IN
-linphone-sdk-android/*.aar
-app/debug
-app/release
-app/releaseAppBundle
-app/releaseWithCrashlytics
-keystore.properties
-app/src/main/res/xml/contacts.xml
diff --git a/.gitlab-ci-files/job-android.yml b/.gitlab-ci-files/job-android.yml
deleted file mode 100644
index a66ce9e9f..000000000
--- a/.gitlab-ci-files/job-android.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-job-android:
-
- stage: build
- tags: [ "docker-android" ]
- image: gitlab.linphone.org:4567/bc/public/linphone-android/bc-dev-android:20230414_bullseye_jdk_17_cleaned
-
- before_script:
- - if ! [ -z ${SCP_PRIVATE_KEY+x} ]; then eval $(ssh-agent -s); fi
- - if ! [ -z ${SCP_PRIVATE_KEY+x} ]; then echo "$SCP_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null; fi
- - if ! [ -z ${ANDROID_SETTINGS_GRADLE+x} ]; then echo "$ANDROID_SETTINGS_GRADLE" > settings.gradle; fi
- - git config --global --add safe.directory /builds/BC/public/linphone-android
-
- script:
- - scp -oStrictHostKeyChecking=no $DEPLOY_SERVER:$ANDROID_KEYSTORE_PATH app/
- - scp -oStrictHostKeyChecking=no $DEPLOY_SERVER:$ANDROID_GOOGLE_SERVICES_PATH app/
- - echo storePassword=$ANDROID_KEYSTORE_PASSWORD > keystore.properties
- - echo keyPassword=$ANDROID_KEYSTORE_KEY_PASSWORD >> keystore.properties
- - echo keyAlias=$ANDROID_KEYSTORE_KEY_ALIAS >> keystore.properties
- - echo storeFile=$ANDROID_KEYSTORE_FILE >> keystore.properties
- - ./gradlew app:dependencies | grep org.linphone
- - ./gradlew assembleDebug
- - ./gradlew assembleRelease
-
- artifacts:
- paths:
- - ./app/build/outputs/apk/debug/linphone-android-debug-*.apk
- - ./app/build/outputs/apk/release/linphone-android-release-*.apk
- when: always
- expire_in: 1 week
-
-
-.scheduled-job-android:
- extends: job-android
- only:
- - schedules
diff --git a/.gitlab-ci-files/job-upload.yml b/.gitlab-ci-files/job-upload.yml
deleted file mode 100644
index 31e1d1a50..000000000
--- a/.gitlab-ci-files/job-upload.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-job-android-upload:
-
- stage: deploy
- tags: [ "deploy" ]
-
- only:
- - schedules
- dependencies:
- - job-android
-
- script:
- - cd app/build/outputs/apk/ && rsync ./debug/*.apk $DEPLOY_SERVER:$ANDROID_DEPLOY_DIRECTORY
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
deleted file mode 100644
index 0e65baf26..000000000
--- a/.gitlab-ci.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-#################################################
-# Base configuration
-#################################################
-
-
-
-#################################################
-# Platforms to test
-#################################################
-
-
-include:
- - '.gitlab-ci-files/job-android.yml'
- - '.gitlab-ci-files/job-upload.yml'
-
-
-stages:
- - build
- - deploy
diff --git a/app/.gitignore b/app/.gitignore
deleted file mode 100644
index 796b96d1c..000000000
--- a/app/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/app/build.gradle b/app/build.gradle
deleted file mode 100644
index 10c35e7a2..000000000
--- a/app/build.gradle
+++ /dev/null
@@ -1,285 +0,0 @@
-plugins {
- id 'com.android.application'
- id 'kotlin-android'
- id 'kotlin-kapt'
- id 'org.jlleitschuh.gradle.ktlint' version '11.3.1'
- id 'org.jetbrains.kotlin.android'
-}
-
-def appVersionName = "5.3.0"
-def appVersionCode = 52000
-
-def packageName = "org.linphone"
-
-def firebaseAvailable = new File(projectDir.absolutePath +'/google-services.json').exists()
-
-def crashlyticsAvailable = new File(projectDir.absolutePath +'/google-services.json').exists() && new File(LinphoneSdkBuildDir + '/libs/').exists() && new File(LinphoneSdkBuildDir + '/libs-debug/').exists()
-
-def extractNativeLibs = false
-
-if (firebaseAvailable) {
- apply plugin: 'com.google.gms.google-services'
-}
-
-def gitBranch = new ByteArrayOutputStream()
-task getGitVersion() {
- def gitVersion = appVersionName
- def gitVersionStream = new ByteArrayOutputStream()
- def gitCommitsCount = new ByteArrayOutputStream()
- def gitCommitHash = new ByteArrayOutputStream()
-
- try {
- exec {
- executable "git" args "describe", "--abbrev=0"
- standardOutput = gitVersionStream
- }
- exec {
- executable "git" args "rev-list", gitVersionStream.toString().trim() + "..HEAD", "--count"
- standardOutput = gitCommitsCount
- }
- exec {
- executable "git" args "rev-parse", "--short", "HEAD"
- standardOutput = gitCommitHash
- }
- exec {
- executable "git" args "name-rev", "--name-only", "HEAD"
- standardOutput = gitBranch
- }
-
- if (gitCommitsCount.toString().toInteger() == 0) {
- gitVersion = gitVersionStream.toString().trim()
- } else {
- gitVersion = gitVersionStream.toString().trim() + "." + gitCommitsCount.toString().trim() + "+" + gitCommitHash.toString().trim()
- }
- println("Git version: " + gitVersion + " (" + appVersionCode + ")")
- } catch (ignored) {
- println("Git not found, using " + gitVersion + " (" + appVersionCode + ")")
- }
- project.version = gitVersion
-}
-
-configurations {
- customImplementation.extendsFrom implementation
-}
-
-task linphoneSdkSource() {
- doLast {
- configurations.customImplementation.getIncoming().each {
- it.getResolutionResult().allComponents.each {
- if (it.id.getDisplayName().contains("linphone-sdk-android")) {
- println 'Linphone SDK used is ' + it.moduleVersion.version + ' from ' + it.properties["repositoryName"]
- }
- }
- }
- }
-}
-
-project.tasks['preBuild'].dependsOn 'getGitVersion'
-project.tasks['preBuild'].dependsOn 'linphoneSdkSource'
-
-android {
- compileOptions {
- sourceCompatibility = 17
- targetCompatibility = 17
- }
-
- compileSdkVersion 34
- defaultConfig {
- minSdkVersion 23
- targetSdkVersion 34
- versionCode appVersionCode
- versionName "${project.version}"
- applicationId packageName
- }
-
- applicationVariants.all { variant ->
- variant.outputs.all {
- outputFileName = "linphone-android-${variant.buildType.name}-${project.version}.apk"
- }
-
- var enableFirebaseService = "false"
- if (firebaseAvailable) {
- enableFirebaseService = "true"
- }
-
- // See https://developer.android.com/studio/releases/gradle-plugin#3-6-0-behavior for why extractNativeLibs is set to true in debug flavor
- if (variant.buildType.name == "release" || variant.buildType.name == "releaseWithCrashlytics") {
- variant.getMergedFlavor().manifestPlaceholders = [linphone_address_mime_type: "vnd.android.cursor.item/vnd." + packageName + ".provider.sip_address",
- linphone_file_provider: packageName + ".fileprovider",
- appLabel: "@string/app_name",
- firebaseServiceEnabled: enableFirebaseService]
- } else {
- variant.getMergedFlavor().manifestPlaceholders = [linphone_address_mime_type: "vnd.android.cursor.item/vnd." + packageName + ".provider.sip_address",
- linphone_file_provider: packageName + ".debug.fileprovider",
- appLabel: "@string/app_name_debug",
- firebaseServiceEnabled: enableFirebaseService]
- extractNativeLibs = true
- }
- }
-
- def keystorePropertiesFile = rootProject.file("keystore.properties")
- def keystoreProperties = new Properties()
- keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
-
- signingConfigs {
- release {
- storeFile file(keystoreProperties['storeFile'])
- storePassword keystoreProperties['storePassword']
- keyAlias keystoreProperties['keyAlias']
- keyPassword keystoreProperties['keyPassword']
- }
- }
-
- buildTypes {
- release {
- minifyEnabled true
- signingConfig signingConfigs.release
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
-
- resValue "string", "linphone_app_branch", gitBranch.toString().trim()
- resValue "string", "sync_account_type", packageName + ".sync"
- resValue "string", "file_provider", packageName + ".fileprovider"
- resValue "string", "linphone_address_mime_type", "vnd.android.cursor.item/vnd." + packageName + ".provider.sip_address"
-
- if (!firebaseAvailable) {
- resValue "string", "gcm_defaultSenderId", "none"
- }
-
- resValue "bool", "crashlytics_enabled", "false"
- }
-
- releaseWithCrashlytics {
- initWith release
-
- resValue "bool", "crashlytics_enabled", crashlyticsAvailable.toString()
-
- if (crashlyticsAvailable) {
- apply plugin: 'com.google.firebase.crashlytics'
-
- firebaseCrashlytics {
- nativeSymbolUploadEnabled true
- unstrippedNativeLibsDir file(LinphoneSdkBuildDir + '/libs-debug/').toString()
- }
- }
- }
-
- debug {
- applicationIdSuffix ".debug"
- debuggable true
- jniDebuggable true
-
- resValue "string", "linphone_app_branch", gitBranch.toString().trim()
- resValue "string", "sync_account_type", packageName + ".sync"
- resValue "string", "file_provider", packageName + ".debug.fileprovider"
- resValue "string", "linphone_address_mime_type", "vnd.android.cursor.item/vnd." + packageName + ".provider.sip_address"
- resValue "bool", "crashlytics_enabled", crashlyticsAvailable.toString()
-
- if (!firebaseAvailable) {
- resValue "string", "gcm_defaultSenderId", "none"
- }
-
- if (crashlyticsAvailable) {
- apply plugin: 'com.google.firebase.crashlytics'
-
- firebaseCrashlytics {
- nativeSymbolUploadEnabled false
- }
- }
- }
- }
-
- buildFeatures {
- dataBinding = true
- }
-
- namespace 'org.linphone'
- packagingOptions {
- jniLibs {
- useLegacyPackaging extractNativeLibs
- }
- }
-}
-
-dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'androidx.appcompat:appcompat:1.6.1'
- implementation 'androidx.core:core-ktx:1.12.0'
- implementation 'androidx.core:core-splashscreen:1.0.1'
- implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
- implementation 'androidx.media:media:1.6.0'
- implementation "androidx.security:security-crypto-ktx:1.1.0-alpha06"
- implementation "androidx.window:window:1.2.0"
-
- def emoji_version = "1.4.0"
- implementation "androidx.emoji2:emoji2:$emoji_version"
- implementation "androidx.emoji2:emoji2-emojipicker:$emoji_version"
-
- def nav_version = "2.7.5"
- implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
- implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
-
- implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0"
- implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
- implementation "androidx.gridlayout:gridlayout:1.0.0"
- implementation 'androidx.recyclerview:recyclerview:1.3.2'
- implementation 'androidx.drawerlayout:drawerlayout:1.2.0'
-
- // https://github.com/material-components/material-components-android/blob/master/LICENSE Apache v2.0
- implementation 'com.google.android.material:material:1.10.0'
- // https://github.com/google/flexbox-layout/blob/main/LICENSE Apache v2.0
- implementation 'com.google.android.flexbox:flexbox:3.0.0'
-
- // https://github.com/coil-kt/coil/blob/main/LICENSE.txt Apache v2.0
- def coil_version = "2.4.0"
- implementation("io.coil-kt:coil:$coil_version")
- implementation("io.coil-kt:coil-gif:$coil_version")
- implementation("io.coil-kt:coil-svg:$coil_version")
- implementation("io.coil-kt:coil-video:$coil_version")
-
- // https://github.com/Baseflow/PhotoView/blob/master/LICENSE Apache v2.0
- implementation 'com.github.chrisbanes:PhotoView:2.3.0'
-
- implementation platform('com.google.firebase:firebase-bom:32.5.0')
- if (crashlyticsAvailable) {
- debugImplementation 'com.google.firebase:firebase-crashlytics-ndk'
- releaseWithCrashlyticsImplementation 'com.google.firebase:firebase-crashlytics-ndk'
- releaseCompileOnly 'com.google.firebase:firebase-crashlytics-ndk'
- } else {
- compileOnly 'com.google.firebase:firebase-crashlytics-ndk'
- }
- if (firebaseAvailable) {
- implementation 'com.google.firebase:firebase-messaging'
- }
-
- implementation 'org.linphone:linphone-sdk-android:5.4+'
-
- // Only enable leak canary prior to release
- // debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10'
-}
-
-task generateContactsXml(type: Copy) {
- from 'contacts.xml'
- into "src/main/res/xml/"
- outputs.upToDateWhen { file('src/main/res/xml/contacts.xml').exists() }
- filter {
- line -> line
- .replaceAll('%%AUTO_GENERATED%%', 'This file has been automatically generated, do not edit or commit !')
- .replaceAll('%%PACKAGE_NAME%%', packageName)
-
- }
-}
-project.tasks['preBuild'].dependsOn 'generateContactsXml'
-
-ktlint {
- android = true
- ignoreFailures = true
-}
-
-project.tasks['preBuild'].dependsOn 'ktlintFormat'
-
-if (crashlyticsAvailable) {
- afterEvaluate {
- assembleReleaseWithCrashlytics.finalizedBy(uploadCrashlyticsSymbolFileReleaseWithCrashlytics)
- packageReleaseWithCrashlytics.finalizedBy(uploadCrashlyticsSymbolFileReleaseWithCrashlytics)
- }
-}
diff --git a/app/contacts.xml b/app/contacts.xml
deleted file mode 100644
index 07ea82c10..000000000
--- a/app/contacts.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
diff --git a/app/google-services.json b/app/google-services.json
deleted file mode 100644
index c26aa7702..000000000
--- a/app/google-services.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
- "project_info": {
- "project_number": "929724111839",
- "firebase_url": "https://linphone-android-8a563.firebaseio.com",
- "project_id": "linphone-android-8a563",
- "storage_bucket": "linphone-android-8a563.appspot.com"
- },
- "client": [
- {
- "client_info": {
- "mobilesdk_app_id": "1:929724111839:android:4662ea9a056188c4",
- "android_client_info": {
- "package_name": "org.linphone"
- }
- },
- "oauth_client": [
- {
- "client_id": "929724111839-co5kffto4j7dets7oolvfv0056cvpfbl.apps.googleusercontent.com",
- "client_type": 1,
- "android_info": {
- "package_name": "org.linphone",
- "certificate_hash": "85463a95603f7b6331899b74b85d53d043dcd500"
- }
- },
- {
- "client_id": "929724111839-v5so1tcd65iil7dd7sde8jgii44h8luf.apps.googleusercontent.com",
- "client_type": 3
- }
- ],
- "api_key": [
- {
- "current_key": "AIzaSyCKrwWhkbA7Iy3wpEI8_ZvKOMp5jf6vV6A"
- }
- ]
- },
- {
- "client_info": {
- "mobilesdk_app_id": "1:929724111839:android:3cf90ee1d2f8fcb6",
- "android_client_info": {
- "package_name": "org.linphone.debug"
- }
- },
- "oauth_client": [
- {
- "client_id": "929724111839-v5so1tcd65iil7dd7sde8jgii44h8luf.apps.googleusercontent.com",
- "client_type": 3
- }
- ],
- "api_key": [
- {
- "current_key": "AIzaSyCKrwWhkbA7Iy3wpEI8_ZvKOMp5jf6vV6A"
- }
- ]
- }
- ],
- "configuration_version": "1"
-}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
deleted file mode 100644
index e70e74af6..000000000
--- a/app/proguard-rules.pro
+++ /dev/null
@@ -1,41 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
-
--keep public class * extends androidx.fragment.app.Fragment { *; }
--dontwarn com.google.errorprone.annotations.Immutable
-
-# To prevent following errors:
-#ERROR: Missing classes detected while running R8. Please add the missing classes or apply additional keep rules that are generated in /builds/BC/public/linphone-android/app/build/outputs/mapping/release/missing_rules.txt.
-#ERROR: R8: Missing class org.bouncycastle.jsse.BCSSLParameters (referenced from: void okhttp3.internal.platform.BouncyCastlePlatform.configureTlsExtensions(javax.net.ssl.SSLSocket, java.lang.String, java.util.List) and 1 other context)
-#Missing class org.bouncycastle.jsse.BCSSLSocket (referenced from: void okhttp3.internal.platform.BouncyCastlePlatform.configureTlsExtensions(javax.net.ssl.SSLSocket, java.lang.String, java.util.List) and 5 other contexts)
-#Missing class org.bouncycastle.jsse.provider.BouncyCastleJsseProvider (referenced from: void okhttp3.internal.platform.BouncyCastlePlatform.())
-#Missing class org.conscrypt.Conscrypt$Version (referenced from: boolean okhttp3.internal.platform.ConscryptPlatform$Companion.atLeastVersion(int, int, int))
-#Missing class org.conscrypt.Conscrypt (referenced from: boolean okhttp3.internal.platform.ConscryptPlatform$Companion.atLeastVersion(int, int, int) and 4 other contexts)
-#Missing class org.conscrypt.ConscryptHostnameVerifier (referenced from: okhttp3.internal.platform.ConscryptPlatform$DisabledHostnameVerifier)
-#Missing class org.openjsse.javax.net.ssl.SSLParameters (referenced from: void okhttp3.internal.platform.OpenJSSEPlatform.configureTlsExtensions(javax.net.ssl.SSLSocket, java.lang.String, java.util.List))
-#Missing class org.openjsse.javax.net.ssl.SSLSocket (referenced from: void okhttp3.internal.platform.OpenJSSEPlatform.configureTlsExtensions(javax.net.ssl.SSLSocket, java.lang.String, java.util.List) and 1 other context)
-#Missing class org.openjsse.net.ssl.OpenJSSE (referenced from: void okhttp3.internal.platform.OpenJSSEPlatform.())
-#> Task :app:lintVitalAnalyzeRelease
-#FAILURE: Build failed with an exception.
--dontwarn org.conscrypt.**
--dontwarn org.bouncycastle.**
--dontwarn org.openjsse.**
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
deleted file mode 100644
index c1b106232..000000000
--- a/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,256 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/assets/assistant_default_values b/app/src/main/assets/assistant_default_values
deleted file mode 100644
index 5800203a4..000000000
--- a/app/src/main/assets/assistant_default_values
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
- 0
- 0
- 0
- -1
-
- 0
- 0
- 3600
-
-
-
- 1
-
-
-
-
- 0
- 0
- 0
-
-
-
-
-
-
- MD5
- -1
- 0
- -1
- 128
- 1
- ^[a-zA-Z0-9+_.\-]*$
-
-
diff --git a/app/src/main/assets/assistant_linphone_default_values b/app/src/main/assets/assistant_linphone_default_values
deleted file mode 100644
index 7a72cd0c8..000000000
--- a/app/src/main/assets/assistant_linphone_default_values
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
- 1
- 0
- 1
- 120
- sip:voip-metrics@sip.linphone.org;transport=tls
- 1
- 180
- 31536000
- sip:?@sip.linphone.org
- <sip:sip.linphone.org;transport=tls>
- <sip:sip.linphone.org;transport=tls>
- 1
- nat_policy_default_values
- sip.linphone.org
- sip:conference-factory@sip.linphone.org
- sip:videoconference-factory@sip.linphone.org
- 1
- 1
- 1
- https://lime.linphone.org/lime-server/lime-server.php
-
-
- stun.linphone.org
- stun,ice
-
-
-
- sip.linphone.org
- SHA-256
- -1
- 1
- -1
- 64
- 1
- ^[a-z0-9+_.\-]*$
-
-
diff --git a/app/src/main/assets/linphonerc_default b/app/src/main/assets/linphonerc_default
deleted file mode 100644
index bad1a1a76..000000000
--- a/app/src/main/assets/linphonerc_default
+++ /dev/null
@@ -1,44 +0,0 @@
-
-## Start of default rc
-
-[sip]
-contact="Linphone Android"
-use_info=0
-use_ipv6=1
-keepalive_period=30000
-sip_port=-1
-sip_tcp_port=-1
-sip_tls_port=-1
-media_encryption=none
-update_presence_model_timestamp_before_publish_expires_refresh=1
-
-[net]
-#Because dynamic bitrate adaption can increase bitrate, we must allow "no limit"
-download_bw=0
-upload_bw=0
-
-[video]
-size=vga
-
-[app]
-tunnel=disabled
-auto_start=1
-record_aware=1
-
-[tunnel]
-host=
-port=443
-
-[misc]
-log_collection_upload_server_url=https://www.linphone.org:444/lft.php
-file_transfer_server_url=https://www.linphone.org:444/lft.php
-version_check_url_root=https://www.linphone.org/releases
-max_calls=10
-history_max_size=100
-conference_layout=1
-
-[in-app-purchase]
-server_url=https://subscribe.linphone.org:444/inapp.php
-purchasable_items_ids=test_account_subscription
-
-## End of default rc
diff --git a/app/src/main/assets/linphonerc_factory b/app/src/main/assets/linphonerc_factory
deleted file mode 100644
index 23e6571e4..000000000
--- a/app/src/main/assets/linphonerc_factory
+++ /dev/null
@@ -1,54 +0,0 @@
-
-## Start of factory rc
-
-# This file shall not contain path referencing package name, in order to be portable when app is renamed.
-# Paths to resources must be set from LinphoneManager, after creating LinphoneCore.
-
-[net]
-mtu=1300
-force_ice_disablement=0
-
-[rtp]
-accept_any_encryption=1
-
-[sip]
-guess_hostname=1
-register_only_when_network_is_up=1
-auto_net_state_mon=1
-auto_answer_replacing_calls=1
-ping_with_options=0
-use_cpim=1
-zrtp_key_agreements_suites=MS_ZRTP_KEY_AGREEMENT_K255_KYB512
-chat_messages_aggregation_delay=1000
-chat_messages_aggregation=1
-
-[sound]
-#remove this property for any application that is not Linphone public version itself
-ec_calibrator_cool_tones=1
-
-[video]
-displaytype=MSAndroidTextureDisplay
-auto_resize_preview_to_keep_ratio=1
-max_conference_size=vga
-
-[misc]
-enable_basic_to_client_group_chat_room_migration=0
-enable_simple_group_chat_message_state=0
-aggregate_imdn=1
-notify_each_friend_individually_when_presence_received=0
-
-[app]
-activation_code_length=4
-prefer_basic_chat_room=1
-record_aware=1
-
-[account_creator]
-backend=1
-# 1 means FlexiAPI, 0 is XMLRPC
-url=https://subscribe.linphone.org/api/
-# replace above URL by https://staging-subscribe.linphone.org/api/ for testing
-
-[lime]
-lime_update_threshold=86400
-
-## End of factory rc
diff --git a/app/src/main/java/org/linphone/LinphoneApplication.kt b/app/src/main/java/org/linphone/LinphoneApplication.kt
deleted file mode 100644
index 2a08ce958..000000000
--- a/app/src/main/java/org/linphone/LinphoneApplication.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone
-
-import android.annotation.SuppressLint
-import android.app.Application
-import android.content.Context
-import coil.ImageLoader
-import coil.ImageLoaderFactory
-import coil.decode.GifDecoder
-import coil.decode.ImageDecoderDecoder
-import coil.decode.SvgDecoder
-import coil.decode.VideoFrameDecoder
-import coil.disk.DiskCache
-import coil.memory.MemoryCache
-import org.linphone.core.*
-import org.linphone.core.tools.Log
-import org.linphone.mediastream.Version
-
-class LinphoneApplication : Application(), ImageLoaderFactory {
- companion object {
- @SuppressLint("StaticFieldLeak")
- lateinit var corePreferences: CorePreferences
-
- @SuppressLint("StaticFieldLeak")
- lateinit var coreContext: CoreContext
-
- private fun createConfig(context: Context) {
- if (::corePreferences.isInitialized) {
- return
- }
-
- Factory.instance().setLogCollectionPath(context.filesDir.absolutePath)
- Factory.instance().enableLogCollection(LogCollectionState.Enabled)
-
- // For VFS
- Factory.instance().setCacheDir(context.cacheDir.absolutePath)
-
- corePreferences = CorePreferences(context)
- corePreferences.copyAssetsFromPackage()
-
- if (corePreferences.vfsEnabled) {
- CoreContext.activateVFS()
- }
-
- val config = Factory.instance().createConfigWithFactory(
- corePreferences.configPath,
- corePreferences.factoryConfigPath
- )
- corePreferences.config = config
-
- val appName = context.getString(R.string.app_name)
- Factory.instance().setLoggerDomain(appName)
- Factory.instance().enableLogcatLogs(corePreferences.logcatLogsOutput)
- if (corePreferences.debugLogs) {
- Factory.instance().loggingService.setLogLevel(LogLevel.Message)
- }
-
- Log.i("[Application] Core config & preferences created")
- }
-
- fun ensureCoreExists(
- context: Context,
- pushReceived: Boolean = false,
- service: CoreService? = null,
- useAutoStartDescription: Boolean = false,
- skipCoreStart: Boolean = false
- ): Boolean {
- if (::coreContext.isInitialized && !coreContext.stopped) {
- Log.d("[Application] Skipping Core creation (push received? $pushReceived)")
- return false
- }
-
- Log.i(
- "[Application] Core context is being created ${if (pushReceived) "from push" else ""}"
- )
- coreContext = CoreContext(
- context,
- corePreferences.config,
- service,
- useAutoStartDescription
- )
- if (!skipCoreStart) {
- coreContext.start()
- }
- return true
- }
-
- fun contextExists(): Boolean {
- return ::coreContext.isInitialized
- }
- }
-
- override fun onCreate() {
- super.onCreate()
- val appName = getString(R.string.app_name)
- android.util.Log.i("[$appName]", "Application is being created")
- createConfig(applicationContext)
- Log.i("[Application] Created")
- }
-
- override fun newImageLoader(): ImageLoader {
- return ImageLoader.Builder(this)
- .components {
- add(VideoFrameDecoder.Factory())
- add(SvgDecoder.Factory())
- if (Version.sdkAboveOrEqual(Version.API28_PIE_90)) {
- add(ImageDecoderDecoder.Factory())
- } else {
- add(GifDecoder.Factory())
- }
- }
- .memoryCache {
- MemoryCache.Builder(this)
- .maxSizePercent(0.25)
- .build()
- }
- .diskCache {
- DiskCache.Builder()
- .directory(cacheDir.resolve("image_cache"))
- .maxSizePercent(0.02)
- .build()
- }
- .build()
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/GenericActivity.kt b/app/src/main/java/org/linphone/activities/GenericActivity.kt
deleted file mode 100644
index 4498c8696..000000000
--- a/app/src/main/java/org/linphone/activities/GenericActivity.kt
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities
-
-import android.annotation.SuppressLint
-import android.content.pm.ActivityInfo
-import android.content.res.Configuration
-import android.os.Bundle
-import android.util.DisplayMetrics
-import android.view.Display
-import androidx.appcompat.app.AppCompatActivity
-import androidx.appcompat.app.AppCompatDelegate
-import androidx.lifecycle.lifecycleScope
-import androidx.navigation.ActivityNavigator
-import androidx.window.layout.FoldingFeature
-import androidx.window.layout.WindowInfoTracker
-import androidx.window.layout.WindowLayoutInfo
-import java.util.*
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.LinphoneApplication.Companion.corePreferences
-import org.linphone.LinphoneApplication.Companion.ensureCoreExists
-import org.linphone.R
-import org.linphone.core.tools.Log
-
-abstract class GenericActivity : AppCompatActivity() {
- private var timer: Timer? = null
- private var _isDestructionPending = false
- val isDestructionPending: Boolean
- get() = _isDestructionPending
-
- open fun onLayoutChanges(foldingFeature: FoldingFeature?) { }
-
- @SuppressLint("SourceLockedOrientationActivity")
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- Log.i("[Generic Activity] Ensuring Core exists")
- ensureCoreExists(applicationContext)
-
- lifecycleScope.launch(Dispatchers.Main) {
- WindowInfoTracker
- .getOrCreate(this@GenericActivity)
- .windowLayoutInfo(this@GenericActivity)
- .collect { newLayoutInfo ->
- updateCurrentLayout(newLayoutInfo)
- }
- }
-
- requestedOrientation = if (corePreferences.forcePortrait) {
- ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
- } else {
- ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
- }
-
- _isDestructionPending = false
- val nightMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
- val darkModeEnabled = corePreferences.darkMode
- when (nightMode) {
- Configuration.UI_MODE_NIGHT_NO, Configuration.UI_MODE_NIGHT_UNDEFINED -> {
- if (darkModeEnabled == 1) {
- // Force dark mode
- Log.w("[Generic Activity] Forcing night mode")
- AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
- _isDestructionPending = true
- }
- }
- Configuration.UI_MODE_NIGHT_YES -> {
- if (darkModeEnabled == 0) {
- // Force light mode
- Log.w("[Generic Activity] Forcing day mode")
- AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
- _isDestructionPending = true
- }
- }
- }
-
- updateScreenSize()
- }
-
- override fun onResume() {
- super.onResume()
-
- // Remove service notification if it has been started by device boot
- coreContext.notificationsManager.stopForegroundNotificationIfPossible()
- }
-
- override fun finish() {
- super.finish()
- ActivityNavigator.applyPopAnimationsToPendingTransition(this)
- }
-
- fun isTablet(): Boolean {
- return resources.getBoolean(R.bool.isTablet)
- }
-
- private fun updateScreenSize() {
- val metrics = DisplayMetrics()
- val display: Display = windowManager.defaultDisplay
- display.getRealMetrics(metrics)
- val screenWidth = metrics.widthPixels.toFloat()
- val screenHeight = metrics.heightPixels.toFloat()
- coreContext.screenWidth = screenWidth
- coreContext.screenHeight = screenHeight
- }
-
- private fun updateCurrentLayout(newLayoutInfo: WindowLayoutInfo) {
- if (newLayoutInfo.displayFeatures.isEmpty()) {
- onLayoutChanges(null)
- } else {
- for (feature in newLayoutInfo.displayFeatures) {
- val foldingFeature = feature as? FoldingFeature
- if (foldingFeature != null) {
- onLayoutChanges(foldingFeature)
- }
- }
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/GenericFragment.kt b/app/src/main/java/org/linphone/activities/GenericFragment.kt
deleted file mode 100644
index ab8db20ef..000000000
--- a/app/src/main/java/org/linphone/activities/GenericFragment.kt
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageView
-import androidx.activity.OnBackPressedCallback
-import androidx.core.view.doOnPreDraw
-import androidx.databinding.DataBindingUtil
-import androidx.databinding.ViewDataBinding
-import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
-import androidx.navigation.fragment.findNavController
-import com.google.android.material.transition.MaterialSharedAxis
-import org.linphone.LinphoneApplication.Companion.corePreferences
-import org.linphone.R
-import org.linphone.activities.main.viewmodels.SharedMainViewModel
-import org.linphone.core.tools.Log
-
-abstract class GenericFragment : Fragment() {
- companion object {
- val emptyFragmentsIds = arrayListOf(
- R.id.emptyChatFragment,
- R.id.emptyContactFragment,
- R.id.emptySettingsFragment,
- R.id.emptyCallHistoryFragment
- )
- }
-
- private var _binding: T? = null
- protected val binding get() = _binding!!
-
- protected var useMaterialSharedAxisXForwardAnimation = true
-
- protected lateinit var sharedViewModel: SharedMainViewModel
-
- protected fun isSharedViewModelInitialized(): Boolean {
- return ::sharedViewModel.isInitialized
- }
-
- protected fun isBindingAvailable(): Boolean {
- return _binding != null
- }
-
- private fun getFragmentRealClassName(): String {
- return this.javaClass.name
- }
-
- private val onBackPressedCallback = object : OnBackPressedCallback(false) {
- override fun handleOnBackPressed() {
- try {
- val navController = findNavController()
- Log.d("[Generic Fragment] ${getFragmentRealClassName()} handleOnBackPressed")
- if (!navController.popBackStack()) {
- Log.d("[Generic Fragment] ${getFragmentRealClassName()} couldn't pop")
- if (!navController.navigateUp()) {
- Log.d(
- "[Generic Fragment] ${getFragmentRealClassName()} couldn't navigate up"
- )
- // Disable this callback & start a new back press event
- isEnabled = false
- goBack()
- }
- }
- } catch (ise: IllegalStateException) {
- Log.e(
- "[Generic Fragment] ${getFragmentRealClassName()}.handleOnBackPressed() Can't go back: $ise"
- )
- }
- }
- }
-
- abstract fun getLayoutId(): Int
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- sharedViewModel = requireActivity().run {
- ViewModelProvider(this)[SharedMainViewModel::class.java]
- }
-
- sharedViewModel.isSlidingPaneSlideable.observe(viewLifecycleOwner) {
- Log.d(
- "[Generic Fragment] ${getFragmentRealClassName()} shared main VM sliding pane has changed"
- )
- onBackPressedCallback.isEnabled = backPressedCallBackEnabled()
- }
-
- _binding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false)
- return _binding!!.root
- }
-
- override fun onStart() {
- super.onStart()
-
- if (useMaterialSharedAxisXForwardAnimation && corePreferences.enableAnimations) {
- enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
- reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
- returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
- exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
-
- postponeEnterTransition()
- binding.root.doOnPreDraw { startPostponedEnterTransition() }
- }
-
- setupBackPressCallback()
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
-
- onBackPressedCallback.remove()
- _binding = null
- }
-
- protected fun goBack() {
- try {
- requireActivity().onBackPressedDispatcher.onBackPressed()
- } catch (ise: IllegalStateException) {
- Log.w("[Generic Fragment] ${getFragmentRealClassName()}.goBack() can't go back: $ise")
- onBackPressedCallback.handleOnBackPressed()
- }
- }
-
- private fun setupBackPressCallback() {
- Log.d("[Generic Fragment] ${getFragmentRealClassName()} setupBackPressCallback")
-
- val backButton = binding.root.findViewById(R.id.back)
- if (backButton != null) {
- Log.d("[Generic Fragment] ${getFragmentRealClassName()} found back button")
- // If popping navigation back stack entry would bring us to an "empty" fragment
- // then don't do it if sliding pane layout isn't "flat"
- onBackPressedCallback.isEnabled = backPressedCallBackEnabled()
- backButton.setOnClickListener { goBack() }
- } else {
- onBackPressedCallback.isEnabled = false
- }
-
- requireActivity().onBackPressedDispatcher.addCallback(
- viewLifecycleOwner,
- onBackPressedCallback
- )
- }
-
- private fun backPressedCallBackEnabled(): Boolean {
- // This allow to navigate a SlidingPane child nav graph.
- // This only concerns fragments for which the nav graph is inside a SlidingPane layout.
- // In our case it's all graphs except the main one.
- if (findNavController().graph.id == R.id.main_nav_graph_xml) return false
-
- val isSlidingPaneFlat = sharedViewModel.isSlidingPaneSlideable.value == false
- Log.d(
- "[Generic Fragment] ${getFragmentRealClassName()} isSlidingPaneFlat ? $isSlidingPaneFlat"
- )
- val isPreviousFragmentEmpty = findNavController().previousBackStackEntry?.destination?.id in emptyFragmentsIds
- Log.d(
- "[Generic Fragment] ${getFragmentRealClassName()} isPreviousFragmentEmpty ? $isPreviousFragmentEmpty"
- )
- val popBackStack = isSlidingPaneFlat || !isPreviousFragmentEmpty
- Log.d("[Generic Fragment] ${getFragmentRealClassName()} popBackStack ? $popBackStack")
- return popBackStack
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/Navigation.kt b/app/src/main/java/org/linphone/activities/Navigation.kt
deleted file mode 100644
index c03d854d1..000000000
--- a/app/src/main/java/org/linphone/activities/Navigation.kt
+++ /dev/null
@@ -1,1222 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities
-
-import android.net.Uri
-import android.os.Bundle
-import androidx.core.os.bundleOf
-import androidx.fragment.app.Fragment
-import androidx.navigation.NavController
-import androidx.navigation.NavOptions
-import androidx.navigation.findNavController
-import androidx.navigation.fragment.NavHostFragment
-import androidx.navigation.fragment.findNavController
-import androidx.slidingpanelayout.widget.SlidingPaneLayout
-import org.linphone.R
-import org.linphone.activities.assistant.fragments.*
-import org.linphone.activities.main.MainActivity
-import org.linphone.activities.main.chat.fragments.ChatRoomCreationFragment
-import org.linphone.activities.main.chat.fragments.DetailChatRoomFragment
-import org.linphone.activities.main.chat.fragments.GroupInfoFragment
-import org.linphone.activities.main.chat.fragments.MasterChatRoomsFragment
-import org.linphone.activities.main.conference.fragments.*
-import org.linphone.activities.main.contact.fragments.ContactEditorFragment
-import org.linphone.activities.main.contact.fragments.DetailContactFragment
-import org.linphone.activities.main.contact.fragments.MasterContactsFragment
-import org.linphone.activities.main.dialer.fragments.DialerFragment
-import org.linphone.activities.main.fragments.TabsFragment
-import org.linphone.activities.main.history.fragments.DetailCallLogFragment
-import org.linphone.activities.main.history.fragments.MasterCallLogsFragment
-import org.linphone.activities.main.settings.fragments.*
-import org.linphone.activities.main.sidemenu.fragments.SideMenuFragment
-import org.linphone.activities.voip.CallActivity
-import org.linphone.activities.voip.fragments.*
-import org.linphone.core.tools.Log
-
-internal fun Fragment.findMasterNavController(): NavController {
- return parentFragment?.parentFragment?.findNavController() ?: findNavController()
-}
-
-fun popupTo(
- popUpTo: Int = -1,
- popUpInclusive: Boolean = false,
- singleTop: Boolean = true
-): NavOptions {
- val builder = NavOptions.Builder()
- builder.setPopUpTo(popUpTo, popUpInclusive).setLaunchSingleTop(singleTop)
- return builder.build()
-}
-
-/* Main activity related */
-
-internal fun MainActivity.navigateToDialer(args: Bundle? = null) {
- findNavController(R.id.nav_host_fragment).navigate(
- R.id.action_global_dialerFragment,
- args,
- popupTo(R.id.dialerFragment, true)
- )
-}
-
-internal fun MainActivity.navigateToChatRooms(args: Bundle? = null) {
- findNavController(R.id.nav_host_fragment).navigate(
- R.id.action_global_masterChatRoomsFragment,
- args,
- popupTo(R.id.masterChatRoomsFragment, true)
- )
-}
-
-internal fun MainActivity.navigateToChatRoom(localAddress: String?, peerAddress: String?) {
- val deepLink = "linphone-android://chat-room/$localAddress/$peerAddress"
- findNavController(R.id.nav_host_fragment).navigate(
- Uri.parse(deepLink),
- popupTo(R.id.masterChatRoomsFragment, true)
- )
-}
-
-internal fun MainActivity.navigateToContacts() {
- findNavController(R.id.nav_host_fragment).navigate(
- R.id.action_global_masterContactsFragment,
- null,
- popupTo(R.id.masterContactsFragment, true)
- )
-}
-
-internal fun MainActivity.navigateToContact(contactId: String?) {
- val deepLink = "linphone-android://contact/view/$contactId"
- findNavController(R.id.nav_host_fragment).navigate(
- Uri.parse(deepLink),
- popupTo(R.id.masterContactsFragment, true)
- )
-}
-
-/* Tabs fragment related */
-
-internal fun TabsFragment.navigateToCallHistory() {
- val action = when (findNavController().currentDestination?.id) {
- R.id.masterContactsFragment -> R.id.action_masterContactsFragment_to_masterCallLogsFragment
- R.id.dialerFragment -> R.id.action_dialerFragment_to_masterCallLogsFragment
- R.id.masterChatRoomsFragment -> R.id.action_masterChatRoomsFragment_to_masterCallLogsFragment
- else -> R.id.action_global_masterCallLogsFragment
- }
- findNavController().navigate(
- action,
- null,
- popupTo(R.id.masterCallLogsFragment, true)
- )
-}
-
-internal fun TabsFragment.navigateToContacts() {
- val action = when (findNavController().currentDestination?.id) {
- R.id.masterCallLogsFragment -> R.id.action_masterCallLogsFragment_to_masterContactsFragment
- R.id.dialerFragment -> R.id.action_dialerFragment_to_masterContactsFragment
- R.id.masterChatRoomsFragment -> R.id.action_masterChatRoomsFragment_to_masterContactsFragment
- else -> R.id.action_global_masterContactsFragment
- }
- findNavController().navigate(
- action,
- null,
- popupTo(R.id.masterContactsFragment, true)
- )
-}
-
-internal fun TabsFragment.navigateToDialer() {
- val action = when (findNavController().currentDestination?.id) {
- R.id.masterCallLogsFragment -> R.id.action_masterCallLogsFragment_to_dialerFragment
- R.id.masterContactsFragment -> R.id.action_masterContactsFragment_to_dialerFragment
- R.id.masterChatRoomsFragment -> R.id.action_masterChatRoomsFragment_to_dialerFragment
- else -> R.id.action_global_dialerFragment
- }
- findNavController().navigate(
- action,
- null,
- popupTo(R.id.dialerFragment, true)
- )
-}
-
-internal fun TabsFragment.navigateToChatRooms() {
- val action = when (findNavController().currentDestination?.id) {
- R.id.masterCallLogsFragment -> R.id.action_masterCallLogsFragment_to_masterChatRoomsFragment
- R.id.masterContactsFragment -> R.id.action_masterContactsFragment_to_masterChatRoomsFragment
- R.id.dialerFragment -> R.id.action_dialerFragment_to_masterChatRoomsFragment
- else -> R.id.action_global_masterChatRoomsFragment
- }
- findNavController().navigate(
- action,
- null,
- popupTo(R.id.masterChatRoomsFragment, true)
- )
-}
-
-/* Dialer related */
-
-internal fun DialerFragment.navigateToContacts(uriToAdd: String?) {
- if (uriToAdd.isNullOrEmpty()) {
- Log.e("[Navigation] SIP URI to add to contact is null or empty!")
- return
- }
-
- val deepLink = "linphone-android://contact/new/$uriToAdd"
- findNavController().navigate(
- Uri.parse(deepLink),
- popupTo(R.id.masterContactsFragment, true)
- )
-}
-
-internal fun DialerFragment.navigateToConfigFileViewer() {
- val bundle = bundleOf("Secure" to true)
- findMasterNavController().navigate(
- R.id.action_global_configViewerFragment,
- bundle,
- popupTo()
- )
-}
-
-internal fun DialerFragment.navigateToConferenceScheduling() {
- findMasterNavController().navigate(
- R.id.action_global_conferenceSchedulingFragment,
- null,
- popupTo()
- )
-}
-
-/* Conference scheduling related */
-
-internal fun ConferenceSchedulingFragment.navigateToParticipantsList() {
- if (findNavController().currentDestination?.id == R.id.conferenceSchedulingFragment) {
- findNavController().navigate(
- R.id.action_conferenceSchedulingFragment_to_conferenceSchedulingParticipantsListFragment,
- null,
- popupTo(R.id.conferenceSchedulingParticipantsListFragment, true)
- )
- }
-}
-
-internal fun ConferenceSchedulingParticipantsListFragment.navigateToSummary() {
- if (findNavController().currentDestination?.id == R.id.conferenceSchedulingParticipantsListFragment) {
- findNavController().navigate(
- R.id.action_conferenceSchedulingParticipantsListFragment_to_conferenceSchedulingSummaryFragment,
- null,
- popupTo(R.id.conferenceSchedulingSummaryFragment, true)
- )
- }
-}
-
-internal fun ConferenceSchedulingSummaryFragment.navigateToScheduledConferences() {
- if (findNavController().currentDestination?.id == R.id.conferenceSchedulingSummaryFragment) {
- findNavController().navigate(
- R.id.action_global_scheduledConferencesFragment,
- null,
- popupTo(R.id.dialerFragment, false)
- )
- }
-}
-
-internal fun ConferenceSchedulingSummaryFragment.navigateToDialer() {
- val bundle = Bundle()
- findMasterNavController().navigate(
- R.id.action_global_dialerFragment,
- bundle,
- popupTo(R.id.dialerFragment, false)
- )
-}
-
-internal fun DetailChatRoomFragment.navigateToConferenceWaitingRoom(
- address: String,
- subject: String?
-) {
- val bundle = Bundle()
- bundle.putString("Address", address)
- bundle.putString("Subject", subject)
- findMasterNavController().navigate(
- R.id.action_global_conferenceWaitingRoomFragment,
- bundle,
- popupTo(R.id.conferenceWaitingRoomFragment, true)
- )
-}
-
-internal fun ScheduledConferencesFragment.navigateToConferenceWaitingRoom(
- address: String,
- subject: String?
-) {
- val bundle = Bundle()
- bundle.putString("Address", address)
- bundle.putString("Subject", subject)
- findMasterNavController().navigate(
- R.id.action_global_conferenceWaitingRoomFragment,
- bundle,
- popupTo(R.id.conferenceWaitingRoomFragment, true)
- )
-}
-
-internal fun ScheduledConferencesFragment.navigateToConferenceScheduling() {
- findMasterNavController().navigate(
- R.id.action_global_conferenceSchedulingFragment,
- null,
- popupTo(R.id.conferenceSchedulingFragment, true)
- )
-}
-
-/* Chat related */
-
-internal fun MasterChatRoomsFragment.navigateToChatRoom(args: Bundle) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.chat_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_detailChatRoomFragment,
- args,
- popupTo(R.id.emptyChatFragment, false)
- )
-}
-
-internal fun MasterChatRoomsFragment.navigateToChatRoomCreation(
- createGroupChatRoom: Boolean = false,
- slidingPane: SlidingPaneLayout
-) {
- val bundle = bundleOf("createGroup" to createGroupChatRoom)
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.chat_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_chatRoomCreationFragment,
- bundle,
- popupTo(R.id.emptyChatFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
-}
-
-internal fun MasterChatRoomsFragment.clearDisplayedChatRoom() {
- if (findNavController().currentDestination?.id == R.id.masterChatRoomsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.chat_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_emptyChatFragment,
- null,
- popupTo(R.id.emptyChatFragment, true)
- )
- }
-}
-
-internal fun DetailChatRoomFragment.navigateToContacts(sipUriToAdd: String) {
- if (sipUriToAdd.isEmpty()) {
- Log.e("[Navigation] SIP URI to add to contact is empty!")
- return
- }
-
- val deepLink = "linphone-android://contact/new/$sipUriToAdd"
- findMasterNavController().navigate(Uri.parse(deepLink))
-}
-
-internal fun DetailChatRoomFragment.navigateToNativeContact(id: String) {
- val deepLink = "linphone-android://contact/view/$id"
- findMasterNavController().navigate(Uri.parse(deepLink))
-}
-
-internal fun DetailChatRoomFragment.navigateToFriend(address: String) {
- val deepLink = "linphone-android://contact/view-friend/$address"
- findMasterNavController().navigate(Uri.parse(deepLink))
-}
-
-internal fun DetailChatRoomFragment.navigateToImdn(args: Bundle?) {
- if (findNavController().currentDestination?.id == R.id.detailChatRoomFragment) {
- findNavController().navigate(
- R.id.action_detailChatRoomFragment_to_imdnFragment,
- args,
- popupTo()
- )
- }
-}
-
-internal fun DetailChatRoomFragment.navigateToDevices() {
- if (findNavController().currentDestination?.id == R.id.detailChatRoomFragment) {
- findNavController().navigate(
- R.id.action_detailChatRoomFragment_to_devicesFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun DetailChatRoomFragment.navigateToGroupInfo() {
- if (findNavController().currentDestination?.id == R.id.detailChatRoomFragment) {
- findNavController().navigate(
- R.id.action_detailChatRoomFragment_to_groupInfoFragment,
- null,
- popupTo(R.id.groupInfoFragment, true)
- )
- }
-}
-
-internal fun DetailChatRoomFragment.navigateToEphemeralInfo() {
- if (findNavController().currentDestination?.id == R.id.detailChatRoomFragment) {
- findNavController().navigate(
- R.id.action_detailChatRoomFragment_to_ephemeralFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun DetailChatRoomFragment.navigateToTextFileViewer(secure: Boolean) {
- val bundle = bundleOf("Secure" to secure)
- findMasterNavController().navigate(
- R.id.action_global_textViewerFragment,
- bundle,
- popupTo()
- )
-}
-
-internal fun DetailChatRoomFragment.navigateToPdfFileViewer(secure: Boolean) {
- val bundle = bundleOf("Secure" to secure)
- findMasterNavController().navigate(
- R.id.action_global_pdfViewerFragment,
- bundle,
- popupTo()
- )
-}
-
-internal fun DetailChatRoomFragment.navigateToImageFileViewer(secure: Boolean) {
- val bundle = bundleOf("Secure" to secure)
- findMasterNavController().navigate(
- R.id.action_global_imageViewerFragment,
- bundle,
- popupTo()
- )
-}
-
-internal fun DetailChatRoomFragment.navigateToVideoFileViewer(secure: Boolean) {
- val bundle = bundleOf("Secure" to secure)
- findMasterNavController().navigate(
- R.id.action_global_videoViewerFragment,
- bundle,
- popupTo()
- )
-}
-
-internal fun DetailChatRoomFragment.navigateToAudioFileViewer(secure: Boolean) {
- val bundle = bundleOf("Secure" to secure)
- findMasterNavController().navigate(
- R.id.action_global_audioViewerFragment,
- bundle,
- popupTo()
- )
-}
-
-internal fun DetailChatRoomFragment.navigateToEmptyChatRoom() {
- findNavController().navigate(
- R.id.action_global_emptyChatFragment,
- null,
- popupTo(R.id.detailChatRoomFragment, true)
- )
-}
-
-internal fun DetailChatRoomFragment.navigateToDialer(args: Bundle?) {
- findMasterNavController().navigate(
- R.id.action_global_dialerFragment,
- args,
- popupTo(R.id.dialerFragment, true)
- )
-}
-
-internal fun DetailChatRoomFragment.navigateToConferenceScheduling() {
- findMasterNavController().navigate(
- R.id.action_global_conferenceSchedulingFragment,
- null,
- popupTo()
- )
-}
-
-internal fun ChatRoomCreationFragment.navigateToGroupInfo() {
- if (findNavController().currentDestination?.id == R.id.chatRoomCreationFragment) {
- findNavController().navigate(
- R.id.action_chatRoomCreationFragment_to_groupInfoFragment,
- null,
- popupTo(R.id.groupInfoFragment, true)
- )
- }
-}
-
-internal fun ChatRoomCreationFragment.navigateToChatRoom(args: Bundle) {
- if (findNavController().currentDestination?.id == R.id.chatRoomCreationFragment) {
- findNavController().navigate(
- R.id.action_chatRoomCreationFragment_to_detailChatRoomFragment,
- args,
- popupTo(R.id.emptyChatFragment, false)
- )
- }
-}
-
-internal fun GroupInfoFragment.navigateToChatRoomCreation(args: Bundle?) {
- if (findNavController().currentDestination?.id == R.id.groupInfoFragment) {
- findNavController().navigate(
- R.id.action_groupInfoFragment_to_chatRoomCreationFragment,
- args,
- popupTo(R.id.chatRoomCreationFragment, true)
- )
- }
-}
-
-internal fun GroupInfoFragment.navigateToChatRoom(args: Bundle?, created: Boolean) {
- if (findNavController().currentDestination?.id == R.id.groupInfoFragment) {
- val popUpToFragmentId = if (created) { // To remove all creation fragments from back stack
- R.id.chatRoomCreationFragment
- } else {
- R.id.detailChatRoomFragment
- }
- findNavController().navigate(
- R.id.action_groupInfoFragment_to_detailChatRoomFragment,
- args,
- popupTo(popUpToFragmentId, true)
- )
- }
-}
-
-/* Contacts related */
-
-internal fun MasterContactsFragment.navigateToContact() {
- if (findNavController().currentDestination?.id == R.id.masterContactsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.contacts_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_detailContactFragment,
- null,
- popupTo(R.id.emptyContactFragment, false)
- )
- }
-}
-
-internal fun MasterContactsFragment.navigateToContactEditor(
- sipUriToAdd: String? = null,
- slidingPane: SlidingPaneLayout
-) {
- if (findNavController().currentDestination?.id == R.id.masterContactsFragment) {
- val bundle = if (sipUriToAdd != null) bundleOf("SipUri" to sipUriToAdd) else Bundle()
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.contacts_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_contactEditorFragment,
- bundle,
- popupTo(R.id.emptyContactFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
- }
-}
-
-internal fun MasterContactsFragment.clearDisplayedContact() {
- if (findNavController().currentDestination?.id == R.id.masterContactsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.contacts_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_emptyContactFragment,
- null,
- popupTo(R.id.emptyContactFragment, true)
- )
- }
-}
-
-internal fun ContactEditorFragment.navigateToContact(id: String) {
- if (findNavController().currentDestination?.id == R.id.contactEditorFragment) {
- val bundle = Bundle()
- bundle.putString("id", id)
- findNavController().navigate(
- R.id.action_contactEditorFragment_to_detailContactFragment,
- bundle,
- popupTo(R.id.contactEditorFragment, true)
- )
- }
-}
-
-internal fun DetailContactFragment.navigateToChatRoom(args: Bundle?) {
- findMasterNavController().navigate(
- R.id.action_global_masterChatRoomsFragment,
- args,
- popupTo(R.id.masterChatRoomsFragment, true)
- )
-}
-
-internal fun DetailContactFragment.navigateToDialer(args: Bundle?) {
- findMasterNavController().navigate(
- R.id.action_global_dialerFragment,
- args,
- popupTo(R.id.dialerFragment, true)
- )
-}
-
-internal fun DetailContactFragment.navigateToContactEditor() {
- if (findNavController().currentDestination?.id == R.id.detailContactFragment) {
- findNavController().navigate(
- R.id.action_detailContactFragment_to_contactEditorFragment,
- null,
- popupTo(R.id.contactEditorFragment, true)
- )
- }
-}
-
-/* History related */
-
-internal fun MasterCallLogsFragment.navigateToCallHistory(slidingPane: SlidingPaneLayout) {
- if (findNavController().currentDestination?.id == R.id.masterCallLogsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.history_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_detailCallLogFragment,
- null,
- popupTo(R.id.emptyCallHistoryFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
- }
-}
-
-internal fun MasterCallLogsFragment.navigateToConferenceCallHistory(slidingPane: SlidingPaneLayout) {
- if (findNavController().currentDestination?.id == R.id.masterCallLogsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.history_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_detailConferenceCallLogFragment,
- null,
- popupTo(R.id.emptyCallHistoryFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
- }
-}
-
-internal fun MasterCallLogsFragment.clearDisplayedCallHistory() {
- if (findNavController().currentDestination?.id == R.id.masterCallLogsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.history_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_emptyFragment,
- null,
- popupTo(R.id.emptyCallHistoryFragment, true)
- )
- }
-}
-
-internal fun MasterCallLogsFragment.navigateToDialer(args: Bundle?) {
- findNavController().navigate(
- R.id.action_global_dialerFragment,
- args,
- popupTo(R.id.dialerFragment, true)
- )
-}
-
-internal fun MasterCallLogsFragment.navigateToConferenceWaitingRoom(
- address: String,
- subject: String?
-) {
- val bundle = Bundle()
- bundle.putString("Address", address)
- bundle.putString("Subject", subject)
- findMasterNavController().navigate(
- R.id.action_global_conferenceWaitingRoomFragment,
- bundle,
- popupTo(R.id.conferenceWaitingRoomFragment, true)
- )
-}
-
-internal fun DetailCallLogFragment.navigateToContacts(sipUriToAdd: String) {
- if (sipUriToAdd.isEmpty()) {
- Log.e("[Navigation] SIP URI to add to contact is empty!")
- return
- }
-
- val deepLink = "linphone-android://contact/new/$sipUriToAdd"
- findMasterNavController().navigate(Uri.parse(deepLink))
-}
-
-internal fun DetailCallLogFragment.navigateToNativeContact(id: String) {
- val deepLink = "linphone-android://contact/view/$id"
- findMasterNavController().navigate(Uri.parse(deepLink))
-}
-
-internal fun DetailCallLogFragment.navigateToFriend(address: String) {
- val deepLink = "linphone-android://contact/view-friend/$address"
- findMasterNavController().navigate(Uri.parse(deepLink))
-}
-
-internal fun DetailCallLogFragment.navigateToChatRoom(args: Bundle?) {
- if (findNavController().currentDestination?.id == R.id.detailCallLogFragment) {
- findMasterNavController().navigate(
- R.id.action_global_masterChatRoomsFragment,
- args,
- popupTo(R.id.masterChatRoomsFragment, true)
- )
- }
-}
-
-internal fun DetailCallLogFragment.navigateToDialer(args: Bundle?) {
- if (findNavController().currentDestination?.id == R.id.detailCallLogFragment) {
- findMasterNavController().navigate(
- R.id.action_global_dialerFragment,
- args,
- popupTo(R.id.dialerFragment, true)
- )
- }
-}
-
-/* Settings related */
-
-internal fun SettingsFragment.navigateToAccountSettings(identity: String) {
- if (findNavController().currentDestination?.id == R.id.settingsFragment) {
- val bundle = bundleOf("Identity" to identity)
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.settings_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_accountSettingsFragment,
- bundle,
- popupTo(R.id.emptySettingsFragment, false)
- )
- }
-}
-
-internal fun SettingsFragment.navigateToTunnelSettings(slidingPane: SlidingPaneLayout) {
- if (findNavController().currentDestination?.id == R.id.settingsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.settings_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_tunnelSettingsFragment,
- null,
- popupTo(R.id.emptySettingsFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
- }
-}
-
-internal fun SettingsFragment.navigateToAudioSettings(slidingPane: SlidingPaneLayout) {
- if (findNavController().currentDestination?.id == R.id.settingsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.settings_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_audioSettingsFragment,
- null,
- popupTo(R.id.emptySettingsFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
- }
-}
-
-internal fun SettingsFragment.navigateToVideoSettings(slidingPane: SlidingPaneLayout) {
- if (findNavController().currentDestination?.id == R.id.settingsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.settings_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_videoSettingsFragment,
- null,
- popupTo(R.id.emptySettingsFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
- }
-}
-
-internal fun SettingsFragment.navigateToCallSettings(slidingPane: SlidingPaneLayout) {
- if (findNavController().currentDestination?.id == R.id.settingsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.settings_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_callSettingsFragment,
- null,
- popupTo(R.id.emptySettingsFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
- }
-}
-
-internal fun SettingsFragment.navigateToChatSettings(slidingPane: SlidingPaneLayout) {
- if (findNavController().currentDestination?.id == R.id.settingsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.settings_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_chatSettingsFragment,
- null,
- popupTo(R.id.emptySettingsFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
- }
-}
-
-internal fun SettingsFragment.navigateToNetworkSettings(slidingPane: SlidingPaneLayout) {
- if (findNavController().currentDestination?.id == R.id.settingsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.settings_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_networkSettingsFragment,
- null,
- popupTo(R.id.emptySettingsFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
- }
-}
-
-internal fun SettingsFragment.navigateToContactsSettings(slidingPane: SlidingPaneLayout) {
- if (findNavController().currentDestination?.id == R.id.settingsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.settings_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_contactsSettingsFragment,
- null,
- popupTo(R.id.emptySettingsFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
- }
-}
-
-internal fun SettingsFragment.navigateToAdvancedSettings(slidingPane: SlidingPaneLayout) {
- if (findNavController().currentDestination?.id == R.id.settingsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.settings_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_advancedSettingsFragment,
- null,
- popupTo(R.id.emptySettingsFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
- }
-}
-
-internal fun SettingsFragment.navigateToConferencesSettings(slidingPane: SlidingPaneLayout) {
- if (findNavController().currentDestination?.id == R.id.settingsFragment) {
- val navHostFragment =
- childFragmentManager.findFragmentById(R.id.settings_nav_container) as NavHostFragment
- navHostFragment.navController.navigate(
- R.id.action_global_conferencesSettingsFragment,
- null,
- popupTo(R.id.emptySettingsFragment, false)
- )
- if (!slidingPane.isOpen) slidingPane.openPane()
- }
-}
-
-internal fun AccountSettingsFragment.navigateToPhoneLinking(args: Bundle?) {
- if (findNavController().currentDestination?.id == R.id.accountSettingsFragment) {
- findNavController().navigate(
- R.id.action_accountSettingsFragment_to_phoneAccountLinkingFragment,
- args,
- popupTo()
- )
- }
-}
-
-internal fun PhoneAccountLinkingFragment.navigateToPhoneAccountValidation(args: Bundle?) {
- if (findNavController().currentDestination?.id == R.id.phoneAccountLinkingFragment) {
- findNavController().navigate(
- R.id.action_phoneAccountLinkingFragment_to_phoneAccountValidationFragment,
- args,
- popupTo()
- )
- }
-}
-
-internal fun navigateToEmptySetting(navController: NavController) {
- navController.navigate(
- R.id.action_global_emptySettingsFragment,
- null,
- popupTo(R.id.emptySettingsFragment, true)
- )
-}
-
-internal fun ContactsSettingsFragment.navigateToLdapSettings(configIndex: Int) {
- if (findNavController().currentDestination?.id == R.id.contactsSettingsFragment) {
- val bundle = bundleOf("LdapConfigIndex" to configIndex)
- findNavController().navigate(
- R.id.action_contactsSettingsFragment_to_ldapSettingsFragment,
- bundle,
- popupTo()
- )
- }
-}
-
-/* Side menu related */
-
-internal fun SideMenuFragment.navigateToAccountSettings(identity: String) {
- val deepLink = "linphone-android://settings/$identity"
- try {
- findNavController().navigate(Uri.parse(deepLink))
- } catch (iae: IllegalArgumentException) {
- Log.e("[Navigation] Failed to navigate to deeplink [$deepLink]")
- }
-}
-
-internal fun SideMenuFragment.navigateToSettings() {
- findNavController().navigate(
- R.id.action_global_settingsFragment,
- null,
- popupTo(R.id.settingsFragment, true)
- )
-}
-
-internal fun SideMenuFragment.navigateToAbout() {
- findNavController().navigate(
- R.id.action_global_aboutFragment,
- null,
- popupTo(R.id.aboutFragment, true)
- )
-}
-
-internal fun SideMenuFragment.navigateToRecordings() {
- findNavController().navigate(
- R.id.action_global_recordingsFragment,
- null,
- popupTo(R.id.recordingsFragment, true)
- )
-}
-
-internal fun SideMenuFragment.navigateToScheduledConferences() {
- findNavController().navigate(
- R.id.action_global_scheduledConferencesFragment,
- null,
- popupTo(R.id.scheduledConferencesFragment, true)
- )
-}
-
-/* Calls related */
-
-internal fun CallActivity.navigateToActiveCall() {
- if (findNavController(R.id.nav_host_fragment).currentDestination?.id != R.id.singleCallFragment) {
- findNavController(R.id.nav_host_fragment).navigate(
- R.id.action_global_singleCallFragment,
- null,
- popupTo(R.id.conferenceCallFragment, true)
- )
- }
-}
-
-internal fun CallActivity.navigateToConferenceCall() {
- if (findNavController(R.id.nav_host_fragment).currentDestination?.id != R.id.conferenceCallFragment) {
- findNavController(R.id.nav_host_fragment).navigate(
- R.id.action_global_conferenceCallFragment,
- null,
- popupTo(R.id.singleCallFragment, true)
- )
- }
-}
-
-internal fun CallActivity.navigateToOutgoingCall() {
- findNavController(R.id.nav_host_fragment).navigate(
- R.id.action_global_outgoingCallFragment,
- null,
- popupTo(R.id.singleCallFragment, true)
- )
-}
-
-internal fun CallActivity.navigateToIncomingCall(earlyMediaVideoEnabled: Boolean) {
- val args = Bundle()
- args.putBoolean("earlyMediaVideo", earlyMediaVideoEnabled)
- findNavController(R.id.nav_host_fragment).navigate(
- R.id.action_global_incomingCallFragment,
- args,
- popupTo(R.id.singleCallFragment, true)
- )
-}
-
-internal fun OutgoingCallFragment.navigateToActiveCall() {
- findNavController().navigate(
- R.id.action_global_singleCallFragment,
- null,
- popupTo(R.id.outgoingCallFragment, true)
- )
-}
-
-internal fun IncomingCallFragment.navigateToActiveCall() {
- findNavController().navigate(
- R.id.action_global_singleCallFragment,
- null,
- popupTo(R.id.incomingCallFragment, true)
- )
-}
-
-internal fun SingleCallFragment.navigateToCallsList() {
- if (findNavController().currentDestination?.id == R.id.singleCallFragment) {
- findNavController().navigate(
- R.id.action_singleCallFragment_to_callsListFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun SingleCallFragment.navigateToConferenceParticipants() {
- if (findNavController().currentDestination?.id == R.id.singleCallFragment) {
- findNavController().navigate(
- R.id.action_singleCallFragment_to_conferenceParticipantsFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun SingleCallFragment.navigateToConferenceLayout() {
- if (findNavController().currentDestination?.id == R.id.singleCallFragment) {
- findNavController().navigate(
- R.id.action_singleCallFragment_to_conferenceLayoutFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun SingleCallFragment.navigateToIncomingCall() {
- if (findNavController().currentDestination?.id == R.id.singleCallFragment) {
- findNavController().navigate(
- R.id.action_global_incomingCallFragment,
- null,
- popupTo(R.id.singleCallFragment, true)
- )
- }
-}
-
-internal fun SingleCallFragment.navigateToOutgoingCall() {
- if (findNavController().currentDestination?.id == R.id.singleCallFragment) {
- findNavController().navigate(
- R.id.action_global_outgoingCallFragment,
- null,
- popupTo(R.id.singleCallFragment, true)
- )
- }
-}
-
-internal fun ConferenceCallFragment.navigateToCallsList() {
- if (findNavController().currentDestination?.id == R.id.conferenceCallFragment) {
- findNavController().navigate(
- R.id.action_conferenceCallFragment_to_callsListFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun ConferenceCallFragment.navigateToConferenceParticipants() {
- if (findNavController().currentDestination?.id == R.id.conferenceCallFragment) {
- findNavController().navigate(
- R.id.action_conferenceCallFragment_to_conferenceParticipantsFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun ConferenceCallFragment.navigateToConferenceLayout() {
- if (findNavController().currentDestination?.id == R.id.conferenceCallFragment) {
- findNavController().navigate(
- R.id.action_conferenceCallFragment_to_conferenceLayoutFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun ConferenceCallFragment.refreshConferenceFragment() {
- if (findNavController().currentDestination?.id == R.id.conferenceCallFragment) {
- findNavController().navigate(
- R.id.action_global_conferenceCallFragment,
- null,
- popupTo(R.id.conferenceCallFragment, true)
- )
- }
-}
-
-internal fun ConferenceParticipantsFragment.navigateToAddParticipants() {
- if (findNavController().currentDestination?.id == R.id.conferenceParticipantsFragment) {
- findNavController().navigate(
- R.id.action_conferenceParticipantsFragment_to_conferenceAddParticipantsFragment,
- null,
- popupTo(R.id.conferenceAddParticipantsFragment, true)
- )
- }
-}
-
-/* Assistant related */
-
-internal fun WelcomeFragment.navigateToEmailAccountCreation() {
- if (findNavController().currentDestination?.id == R.id.welcomeFragment) {
- findNavController().navigate(
- R.id.action_welcomeFragment_to_emailAccountCreationFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun WelcomeFragment.navigateToPhoneAccountCreation() {
- if (findNavController().currentDestination?.id == R.id.welcomeFragment) {
- findNavController().navigate(
- R.id.action_welcomeFragment_to_phoneAccountCreationFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun WelcomeFragment.navigateToNoPushWarning() {
- if (findNavController().currentDestination?.id == R.id.welcomeFragment) {
- findNavController().navigate(
- R.id.action_welcomeFragment_to_noPushWarningFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun WelcomeFragment.navigateToAccountLogin() {
- if (findNavController().currentDestination?.id == R.id.welcomeFragment) {
- findNavController().navigate(
- R.id.action_welcomeFragment_to_accountLoginFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun WelcomeFragment.navigateToGenericLoginWarning() {
- if (findNavController().currentDestination?.id == R.id.welcomeFragment) {
- findNavController().navigate(
- R.id.action_welcomeFragment_to_genericAccountWarningFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun WelcomeFragment.navigateToRemoteProvisioning() {
- if (findNavController().currentDestination?.id == R.id.welcomeFragment) {
- findNavController().navigate(
- R.id.action_welcomeFragment_to_remoteProvisioningFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun AccountLoginFragment.navigateToEchoCancellerCalibration() {
- if (findNavController().currentDestination?.id == R.id.accountLoginFragment) {
- findNavController().navigate(
- R.id.action_accountLoginFragment_to_echoCancellerCalibrationFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun AccountLoginFragment.navigateToPhoneAccountValidation(args: Bundle?) {
- if (findNavController().currentDestination?.id == R.id.accountLoginFragment) {
- findNavController().navigate(
- R.id.action_accountLoginFragment_to_phoneAccountValidationFragment,
- args,
- popupTo()
- )
- }
-}
-
-internal fun GenericAccountWarningFragment.navigateToGenericLogin() {
- if (findNavController().currentDestination?.id == R.id.genericAccountWarningFragment) {
- findNavController().navigate(
- R.id.action_genericAccountWarningFragment_to_genericAccountLoginFragment,
- null,
- popupTo(R.id.welcomeFragment, popUpInclusive = false)
- )
- }
-}
-
-internal fun GenericAccountLoginFragment.navigateToEchoCancellerCalibration() {
- if (findNavController().currentDestination?.id == R.id.genericAccountLoginFragment) {
- findNavController().navigate(
- R.id.action_genericAccountLoginFragment_to_echoCancellerCalibrationFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun RemoteProvisioningFragment.navigateToQrCode() {
- if (findNavController().currentDestination?.id == R.id.remoteProvisioningFragment) {
- findNavController().navigate(
- R.id.action_remoteProvisioningFragment_to_qrCodeFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun RemoteProvisioningFragment.navigateToEchoCancellerCalibration() {
- if (findNavController().currentDestination?.id == R.id.remoteProvisioningFragment) {
- findNavController().navigate(
- R.id.action_remoteProvisioningFragment_to_echoCancellerCalibrationFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun EmailAccountCreationFragment.navigateToEmailAccountValidation() {
- if (findNavController().currentDestination?.id == R.id.emailAccountCreationFragment) {
- findNavController().navigate(
- R.id.action_emailAccountCreationFragment_to_emailAccountValidationFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun EmailAccountValidationFragment.navigateToAccountLinking(args: Bundle?) {
- if (findNavController().currentDestination?.id == R.id.emailAccountValidationFragment) {
- findNavController().navigate(
- R.id.action_emailAccountValidationFragment_to_phoneAccountLinkingFragment,
- args,
- popupTo()
- )
- }
-}
-
-internal fun PhoneAccountCreationFragment.navigateToPhoneAccountValidation(args: Bundle?) {
- if (findNavController().currentDestination?.id == R.id.phoneAccountCreationFragment) {
- findNavController().navigate(
- R.id.action_phoneAccountCreationFragment_to_phoneAccountValidationFragment,
- args,
- popupTo()
- )
- }
-}
-
-internal fun PhoneAccountValidationFragment.navigateToAccountSettings(args: Bundle?) {
- if (findNavController().currentDestination?.id == R.id.phoneAccountValidationFragment) {
- findNavController().navigate(
- R.id.action_phoneAccountValidationFragment_to_accountSettingsFragment,
- args,
- popupTo(R.id.accountSettingsFragment, true)
- )
- }
-}
-
-internal fun PhoneAccountValidationFragment.navigateToEchoCancellerCalibration() {
- if (findNavController().currentDestination?.id == R.id.phoneAccountValidationFragment) {
- findNavController().navigate(
- R.id.action_phoneAccountValidationFragment_to_echoCancellerCalibrationFragment,
- null,
- popupTo()
- )
- }
-}
-
-internal fun PhoneAccountLinkingFragment.navigateToEchoCancellerCalibration() {
- if (findNavController().currentDestination?.id == R.id.phoneAccountLinkingFragment) {
- findNavController().navigate(
- R.id.action_phoneAccountLinkingFragment_to_echoCancellerCalibrationFragment,
- null,
- popupTo()
- )
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/ProximitySensorActivity.kt b/app/src/main/java/org/linphone/activities/ProximitySensorActivity.kt
deleted file mode 100644
index 605af6df8..000000000
--- a/app/src/main/java/org/linphone/activities/ProximitySensorActivity.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities
-
-import android.content.Context
-import android.os.Bundle
-import android.os.PowerManager
-import android.os.PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY
-import org.linphone.core.tools.Log
-
-abstract class ProximitySensorActivity : GenericActivity() {
- private lateinit var proximityWakeLock: PowerManager.WakeLock
- private var proximitySensorEnabled = false
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
- if (!powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) {
- Log.w(
- "[Proximity Sensor Activity] PROXIMITY_SCREEN_OFF_WAKE_LOCK isn't supported on this device!"
- )
- }
-
- proximityWakeLock = powerManager.newWakeLock(
- PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
- "$packageName;proximity_sensor"
- )
- }
-
- override fun onPause() {
- enableProximitySensor(false)
-
- super.onPause()
- }
-
- override fun onDestroy() {
- enableProximitySensor(false)
-
- super.onDestroy()
- }
-
- protected fun enableProximitySensor(enable: Boolean) {
- if (enable) {
- if (!proximitySensorEnabled) {
- Log.i(
- "[Proximity Sensor Activity] Enabling proximity sensor (turning screen OFF when wake lock is acquired)"
- )
- if (!proximityWakeLock.isHeld) {
- Log.i("[Proximity Sensor Activity] Acquiring PROXIMITY_SCREEN_OFF_WAKE_LOCK")
- proximityWakeLock.acquire()
- }
- proximitySensorEnabled = true
- }
- } else {
- if (proximitySensorEnabled) {
- Log.i(
- "[Proximity Sensor Activity] Disabling proximity sensor (turning screen ON when wake lock is released)"
- )
- if (proximityWakeLock.isHeld) {
- Log.i(
- "[Proximity Sensor Activity] Asking to release PROXIMITY_SCREEN_OFF_WAKE_LOCK next time sensor detects no proximity"
- )
- proximityWakeLock.release(RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY)
- }
- proximitySensorEnabled = false
- }
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/SnackBarActivity.kt b/app/src/main/java/org/linphone/activities/SnackBarActivity.kt
deleted file mode 100644
index c9995d68c..000000000
--- a/app/src/main/java/org/linphone/activities/SnackBarActivity.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities
-
-import androidx.annotation.StringRes
-
-interface SnackBarActivity {
- fun showSnackBar(@StringRes resourceId: Int)
- fun showSnackBar(@StringRes resourceId: Int, action: Int, listener: () -> Unit)
- fun showSnackBar(message: String)
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/AssistantActivity.kt b/app/src/main/java/org/linphone/activities/assistant/AssistantActivity.kt
deleted file mode 100644
index 1b1b8321e..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/AssistantActivity.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant
-
-import android.os.Bundle
-import androidx.annotation.StringRes
-import androidx.coordinatorlayout.widget.CoordinatorLayout
-import androidx.lifecycle.ViewModelProvider
-import com.google.android.material.snackbar.Snackbar
-import org.linphone.LinphoneApplication.Companion.corePreferences
-import org.linphone.R
-import org.linphone.activities.GenericActivity
-import org.linphone.activities.SnackBarActivity
-import org.linphone.activities.assistant.viewmodels.SharedAssistantViewModel
-
-class AssistantActivity : GenericActivity(), SnackBarActivity {
- private lateinit var sharedViewModel: SharedAssistantViewModel
- private lateinit var coordinator: CoordinatorLayout
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- setContentView(R.layout.assistant_activity)
-
- sharedViewModel = ViewModelProvider(this)[SharedAssistantViewModel::class.java]
-
- coordinator = findViewById(R.id.coordinator)
-
- corePreferences.firstStart = false
- }
-
- override fun showSnackBar(@StringRes resourceId: Int) {
- Snackbar.make(coordinator, resourceId, Snackbar.LENGTH_LONG).show()
- }
-
- override fun showSnackBar(@StringRes resourceId: Int, action: Int, listener: () -> Unit) {
- Snackbar
- .make(findViewById(R.id.coordinator), resourceId, Snackbar.LENGTH_LONG)
- .setAction(action) {
- listener()
- }
- .show()
- }
-
- override fun showSnackBar(message: String) {
- Snackbar.make(coordinator, message, Snackbar.LENGTH_LONG).show()
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/adapters/CountryPickerAdapter.kt b/app/src/main/java/org/linphone/activities/assistant/adapters/CountryPickerAdapter.kt
deleted file mode 100644
index 47220e0a7..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/adapters/CountryPickerAdapter.kt
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.adapters
-
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.BaseAdapter
-import android.widget.Filter
-import android.widget.Filterable
-import android.widget.TextView
-import kotlin.collections.ArrayList
-import org.linphone.R
-import org.linphone.core.DialPlan
-import org.linphone.core.Factory
-
-class CountryPickerAdapter : BaseAdapter(), Filterable {
- private var countries: ArrayList
-
- init {
- val dialPlans = Factory.instance().dialPlans
- countries = arrayListOf()
- countries.addAll(dialPlans)
- }
-
- override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- val view: View = convertView ?: LayoutInflater.from(parent.context).inflate(
- R.layout.assistant_country_picker_cell,
- parent,
- false
- )
- val dialPlan: DialPlan = countries[position]
-
- val name = view.findViewById(R.id.country_name)
- name.text = dialPlan.country
-
- val dialCode = view.findViewById(R.id.country_prefix)
- dialCode.text = String.format("(%s)", dialPlan.countryCallingCode)
-
- view.tag = dialPlan
- return view
- }
-
- override fun getItem(position: Int): DialPlan {
- return countries[position]
- }
-
- override fun getItemId(position: Int): Long {
- return position.toLong()
- }
-
- override fun getCount(): Int {
- return countries.size
- }
-
- override fun getFilter(): Filter {
- return object : Filter() {
- override fun performFiltering(constraint: CharSequence): FilterResults {
- val filteredCountries = arrayListOf()
- for (dialPlan in Factory.instance().dialPlans) {
- if (dialPlan.country.contains(constraint, ignoreCase = true) ||
- dialPlan.countryCallingCode.contains(constraint)
- ) {
- filteredCountries.add(dialPlan)
- }
- }
- val filterResults = FilterResults()
- filterResults.values = filteredCountries
- return filterResults
- }
-
- @Suppress("UNCHECKED_CAST")
- override fun publishResults(
- constraint: CharSequence,
- results: FilterResults
- ) {
- countries = results.values as ArrayList
- notifyDataSetChanged()
- }
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/AbstractPhoneFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/AbstractPhoneFragment.kt
deleted file mode 100644
index 01c33748a..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/AbstractPhoneFragment.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.linphone.activities.assistant.fragments
-
-import android.content.pm.PackageManager
-import androidx.databinding.ViewDataBinding
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import org.linphone.R
-import org.linphone.activities.GenericFragment
-import org.linphone.activities.assistant.viewmodels.AbstractPhoneViewModel
-import org.linphone.compatibility.Compatibility
-import org.linphone.core.tools.Log
-import org.linphone.utils.LinphoneUtils
-import org.linphone.utils.PermissionHelper
-import org.linphone.utils.PhoneNumberUtils
-
-abstract class AbstractPhoneFragment : GenericFragment() {
- companion object {
- const val READ_PHONE_STATE_PERMISSION_REQUEST_CODE = 0
- }
-
- abstract val viewModel: AbstractPhoneViewModel
-
- @Deprecated("Deprecated in Java")
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- if (requestCode == READ_PHONE_STATE_PERMISSION_REQUEST_CODE) {
- if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- Log.i("[Assistant] READ_PHONE_STATE/READ_PHONE_NUMBERS permission granted")
- updateFromDeviceInfo()
- } else {
- Log.w("[Assistant] READ_PHONE_STATE/READ_PHONE_NUMBERS permission denied")
- }
- }
- }
-
- protected fun checkPermissions() {
- // Only ask for phone number related permission on devices that have TELEPHONY feature && if push notifications are available
- if (requireContext().packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) && LinphoneUtils.isPushNotificationAvailable()) {
- if (!PermissionHelper.get().hasReadPhoneStateOrPhoneNumbersPermission()) {
- Log.i("[Assistant] Asking for READ_PHONE_STATE/READ_PHONE_NUMBERS permission")
- Compatibility.requestReadPhoneStateOrNumbersPermission(
- this,
- READ_PHONE_STATE_PERMISSION_REQUEST_CODE
- )
- } else {
- updateFromDeviceInfo()
- }
- }
- }
-
- private fun updateFromDeviceInfo() {
- val phoneNumber = PhoneNumberUtils.getDevicePhoneNumber(requireContext())
- val dialPlan = PhoneNumberUtils.getDialPlanForCurrentCountry(requireContext())
- viewModel.updateFromPhoneNumberAndOrDialPlan(phoneNumber, dialPlan)
- }
-
- protected fun showPhoneNumberInfoDialog() {
- MaterialAlertDialogBuilder(requireContext())
- .setTitle(getString(R.string.assistant_phone_number_info_title))
- .setMessage(
- getString(R.string.assistant_phone_number_link_info_content) + "\n" +
- getString(
- R.string.assistant_phone_number_link_info_content_already_account
- )
- )
- .setNegativeButton(getString(R.string.dialog_ok), null)
- .show()
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/AccountLoginFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/AccountLoginFragment.kt
deleted file mode 100644
index e9a35b94b..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/AccountLoginFragment.kt
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.app.Dialog
-import android.content.Intent
-import android.net.Uri
-import android.os.Bundle
-import android.view.View
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.R
-import org.linphone.activities.assistant.AssistantActivity
-import org.linphone.activities.assistant.viewmodels.AccountLoginViewModel
-import org.linphone.activities.assistant.viewmodels.AccountLoginViewModelFactory
-import org.linphone.activities.assistant.viewmodels.SharedAssistantViewModel
-import org.linphone.activities.main.viewmodels.DialogViewModel
-import org.linphone.activities.navigateToEchoCancellerCalibration
-import org.linphone.activities.navigateToPhoneAccountValidation
-import org.linphone.databinding.AssistantAccountLoginFragmentBinding
-import org.linphone.utils.DialogUtils
-
-class AccountLoginFragment : AbstractPhoneFragment() {
- override lateinit var viewModel: AccountLoginViewModel
- private lateinit var sharedAssistantViewModel: SharedAssistantViewModel
-
- override fun getLayoutId(): Int = R.layout.assistant_account_login_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- sharedAssistantViewModel = requireActivity().run {
- ViewModelProvider(this)[SharedAssistantViewModel::class.java]
- }
-
- viewModel = ViewModelProvider(
- this,
- AccountLoginViewModelFactory(sharedAssistantViewModel.getAccountCreator())
- )[AccountLoginViewModel::class.java]
- binding.viewModel = viewModel
-
- binding.setInfoClickListener {
- showPhoneNumberInfoDialog()
- }
-
- binding.setSelectCountryClickListener {
- val countryPickerFragment = CountryPickerFragment()
- countryPickerFragment.listener = viewModel
- countryPickerFragment.show(childFragmentManager, "CountryPicker")
- }
-
- binding.setForgotPasswordClickListener {
- val intent = Intent(Intent.ACTION_VIEW)
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- intent.data = Uri.parse(getString(R.string.assistant_forgotten_password_link))
- startActivity(intent)
- }
-
- viewModel.prefix.observe(viewLifecycleOwner) { internationalPrefix ->
- viewModel.getCountryNameFromPrefix(internationalPrefix)
- }
-
- viewModel.goToSmsValidationEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- val args = Bundle()
- args.putBoolean("IsLogin", true)
- args.putString("PhoneNumber", viewModel.accountCreator.phoneNumber)
- navigateToPhoneAccountValidation(args)
- }
- }
-
- viewModel.leaveAssistantEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- coreContext.newAccountConfigured(true)
-
- if (coreContext.core.isEchoCancellerCalibrationRequired) {
- navigateToEchoCancellerCalibration()
- } else {
- requireActivity().finish()
- }
- }
- }
-
- viewModel.invalidCredentialsEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- val dialogViewModel =
- DialogViewModel(getString(R.string.assistant_error_invalid_credentials))
- val dialog: Dialog = DialogUtils.getDialog(requireContext(), dialogViewModel)
-
- dialogViewModel.showCancelButton {
- viewModel.removeInvalidProxyConfig()
- dialog.dismiss()
- }
-
- dialogViewModel.showDeleteButton(
- {
- viewModel.continueEvenIfInvalidCredentials()
- dialog.dismiss()
- },
- getString(R.string.assistant_continue_even_if_credentials_invalid)
- )
-
- dialog.show()
- }
- }
-
- viewModel.onErrorEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume { message ->
- (requireActivity() as AssistantActivity).showSnackBar(message)
- }
- }
-
- checkPermissions()
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/CountryPickerFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/CountryPickerFragment.kt
deleted file mode 100644
index 2e3d4dc72..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/CountryPickerFragment.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.os.Bundle
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.*
-import androidx.fragment.app.DialogFragment
-import org.linphone.R
-import org.linphone.activities.assistant.adapters.CountryPickerAdapter
-import org.linphone.core.DialPlan
-import org.linphone.databinding.AssistantCountryPickerFragmentBinding
-
-class CountryPickerFragment : DialogFragment() {
- private var _binding: AssistantCountryPickerFragmentBinding? = null
- private val binding get() = _binding!!
- private lateinit var adapter: CountryPickerAdapter
-
- var listener: CountryPickedListener? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setStyle(STYLE_NO_TITLE, R.style.assistant_country_dialog_style)
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- _binding = AssistantCountryPickerFragmentBinding.inflate(inflater, container, false)
-
- adapter = CountryPickerAdapter()
- binding.countryList.adapter = adapter
-
- binding.countryList.setOnItemClickListener { _, _, position, _ ->
- if (position >= 0 && position < adapter.count) {
- val dialPlan = adapter.getItem(position)
- listener?.onCountryClicked(dialPlan)
- }
- dismiss()
- }
-
- binding.searchCountry.addTextChangedListener(object : TextWatcher {
- override fun afterTextChanged(s: Editable?) {
- adapter.filter.filter(s)
- }
-
- override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { }
-
- override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { }
- })
-
- binding.setCancelClickListener {
- dismiss()
- }
-
- return binding.root
- }
-
- interface CountryPickedListener {
- fun onCountryClicked(dialPlan: DialPlan)
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/EchoCancellerCalibrationFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/EchoCancellerCalibrationFragment.kt
deleted file mode 100644
index 9c48cb0d0..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/EchoCancellerCalibrationFragment.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.content.pm.PackageManager
-import android.os.Bundle
-import android.view.View
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.R
-import org.linphone.activities.GenericFragment
-import org.linphone.activities.assistant.viewmodels.EchoCancellerCalibrationViewModel
-import org.linphone.core.tools.Log
-import org.linphone.databinding.AssistantEchoCancellerCalibrationFragmentBinding
-import org.linphone.utils.PermissionHelper
-
-class EchoCancellerCalibrationFragment : GenericFragment() {
- companion object {
- const val RECORD_AUDIO_PERMISSION_REQUEST_CODE = 0
- }
-
- private lateinit var viewModel: EchoCancellerCalibrationViewModel
-
- override fun getLayoutId(): Int = R.layout.assistant_echo_canceller_calibration_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- viewModel = ViewModelProvider(this)[EchoCancellerCalibrationViewModel::class.java]
- binding.viewModel = viewModel
-
- viewModel.echoCalibrationTerminated.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- requireActivity().finish()
- }
- }
-
- if (!PermissionHelper.required(requireContext()).hasRecordAudioPermission()) {
- Log.i("[Echo Canceller Calibration] Asking for RECORD_AUDIO permission")
- requestPermissions(
- arrayOf(android.Manifest.permission.RECORD_AUDIO),
- RECORD_AUDIO_PERMISSION_REQUEST_CODE
- )
- } else {
- viewModel.startEchoCancellerCalibration()
- }
- }
-
- @Deprecated("Deprecated in Java")
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- if (requestCode == RECORD_AUDIO_PERMISSION_REQUEST_CODE) {
- val granted =
- grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED
- if (granted) {
- Log.i("[Echo Canceller Calibration] RECORD_AUDIO permission granted")
- viewModel.startEchoCancellerCalibration()
- } else {
- Log.w("[Echo Canceller Calibration] RECORD_AUDIO permission denied")
- requireActivity().finish()
- }
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/EmailAccountCreationFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/EmailAccountCreationFragment.kt
deleted file mode 100644
index 027636460..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/EmailAccountCreationFragment.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.os.Bundle
-import android.view.View
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.R
-import org.linphone.activities.GenericFragment
-import org.linphone.activities.assistant.AssistantActivity
-import org.linphone.activities.assistant.viewmodels.EmailAccountCreationViewModel
-import org.linphone.activities.assistant.viewmodels.EmailAccountCreationViewModelFactory
-import org.linphone.activities.assistant.viewmodels.SharedAssistantViewModel
-import org.linphone.activities.navigateToEmailAccountValidation
-import org.linphone.databinding.AssistantEmailAccountCreationFragmentBinding
-
-class EmailAccountCreationFragment : GenericFragment() {
- private lateinit var sharedAssistantViewModel: SharedAssistantViewModel
- private lateinit var viewModel: EmailAccountCreationViewModel
-
- override fun getLayoutId(): Int = R.layout.assistant_email_account_creation_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- sharedAssistantViewModel = requireActivity().run {
- ViewModelProvider(this)[SharedAssistantViewModel::class.java]
- }
-
- viewModel = ViewModelProvider(
- this,
- EmailAccountCreationViewModelFactory(sharedAssistantViewModel.getAccountCreator())
- )[EmailAccountCreationViewModel::class.java]
- binding.viewModel = viewModel
-
- viewModel.goToEmailValidationEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- navigateToEmailAccountValidation()
- }
- }
-
- viewModel.onErrorEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume { message ->
- (requireActivity() as AssistantActivity).showSnackBar(message)
- }
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/EmailAccountValidationFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/EmailAccountValidationFragment.kt
deleted file mode 100644
index 98b5548bd..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/EmailAccountValidationFragment.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.os.Bundle
-import android.view.View
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.LinphoneApplication.Companion.corePreferences
-import org.linphone.R
-import org.linphone.activities.GenericFragment
-import org.linphone.activities.assistant.AssistantActivity
-import org.linphone.activities.assistant.viewmodels.*
-import org.linphone.activities.navigateToAccountLinking
-import org.linphone.databinding.AssistantEmailAccountValidationFragmentBinding
-
-class EmailAccountValidationFragment : GenericFragment() {
- private lateinit var sharedAssistantViewModel: SharedAssistantViewModel
- private lateinit var viewModel: EmailAccountValidationViewModel
-
- override fun getLayoutId(): Int = R.layout.assistant_email_account_validation_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- sharedAssistantViewModel = requireActivity().run {
- ViewModelProvider(this)[SharedAssistantViewModel::class.java]
- }
-
- viewModel = ViewModelProvider(
- this,
- EmailAccountValidationViewModelFactory(sharedAssistantViewModel.getAccountCreator())
- )[EmailAccountValidationViewModel::class.java]
- binding.viewModel = viewModel
-
- viewModel.leaveAssistantEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- coreContext.newAccountConfigured(true)
-
- if (!corePreferences.hideLinkPhoneNumber) {
- val args = Bundle()
- args.putBoolean("AllowSkip", true)
- args.putString("Username", viewModel.accountCreator.username)
- args.putString("Password", viewModel.accountCreator.password)
- navigateToAccountLinking(args)
- } else {
- requireActivity().finish()
- }
- }
- }
-
- viewModel.onErrorEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume { message ->
- (requireActivity() as AssistantActivity).showSnackBar(message)
- }
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/GenericAccountLoginFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/GenericAccountLoginFragment.kt
deleted file mode 100644
index a93eea348..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/GenericAccountLoginFragment.kt
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.app.Dialog
-import android.os.Bundle
-import android.view.View
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.LinphoneApplication.Companion.corePreferences
-import org.linphone.R
-import org.linphone.activities.GenericFragment
-import org.linphone.activities.assistant.AssistantActivity
-import org.linphone.activities.assistant.viewmodels.GenericLoginViewModel
-import org.linphone.activities.assistant.viewmodels.GenericLoginViewModelFactory
-import org.linphone.activities.assistant.viewmodels.SharedAssistantViewModel
-import org.linphone.activities.main.viewmodels.DialogViewModel
-import org.linphone.activities.navigateToEchoCancellerCalibration
-import org.linphone.databinding.AssistantGenericAccountLoginFragmentBinding
-import org.linphone.utils.DialogUtils
-
-class GenericAccountLoginFragment : GenericFragment() {
- private lateinit var sharedAssistantViewModel: SharedAssistantViewModel
- private lateinit var viewModel: GenericLoginViewModel
-
- override fun getLayoutId(): Int = R.layout.assistant_generic_account_login_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- sharedAssistantViewModel = requireActivity().run {
- ViewModelProvider(this)[SharedAssistantViewModel::class.java]
- }
-
- viewModel = ViewModelProvider(
- this,
- GenericLoginViewModelFactory(sharedAssistantViewModel.getAccountCreator(true))
- )[GenericLoginViewModel::class.java]
- binding.viewModel = viewModel
-
- viewModel.leaveAssistantEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- val isLinphoneAccount = viewModel.domain.value.orEmpty() == corePreferences.defaultDomain
- coreContext.newAccountConfigured(isLinphoneAccount)
-
- if (coreContext.core.isEchoCancellerCalibrationRequired) {
- navigateToEchoCancellerCalibration()
- } else {
- requireActivity().finish()
- }
- }
- }
-
- viewModel.invalidCredentialsEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- val dialogViewModel =
- DialogViewModel(getString(R.string.assistant_error_invalid_credentials))
- val dialog: Dialog = DialogUtils.getDialog(requireContext(), dialogViewModel)
-
- dialogViewModel.showCancelButton {
- viewModel.removeInvalidProxyConfig()
- dialog.dismiss()
- }
-
- dialogViewModel.showDeleteButton(
- {
- viewModel.continueEvenIfInvalidCredentials()
- dialog.dismiss()
- },
- getString(R.string.assistant_continue_even_if_credentials_invalid)
- )
-
- dialog.show()
- }
- }
-
- viewModel.onErrorEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume { message ->
- (requireActivity() as AssistantActivity).showSnackBar(message)
- }
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/GenericAccountWarningFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/GenericAccountWarningFragment.kt
deleted file mode 100644
index 8c41c0653..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/GenericAccountWarningFragment.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2010-2022 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.os.Bundle
-import android.view.View
-import org.linphone.R
-import org.linphone.activities.GenericFragment
-import org.linphone.activities.navigateToGenericLogin
-import org.linphone.databinding.AssistantGenericAccountWarningFragmentBinding
-
-class GenericAccountWarningFragment : GenericFragment() {
- override fun getLayoutId(): Int = R.layout.assistant_generic_account_warning_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- binding.setUnderstoodClickListener {
- navigateToGenericLogin()
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/NoPushWarningFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/NoPushWarningFragment.kt
deleted file mode 100644
index 1671474bd..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/NoPushWarningFragment.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2010-2023 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.os.Bundle
-import android.view.View
-import org.linphone.R
-import org.linphone.activities.GenericFragment
-import org.linphone.databinding.AssistantNoPushWarningFragmentBinding
-
-class NoPushWarningFragment : GenericFragment() {
- override fun getLayoutId(): Int = R.layout.assistant_no_push_warning_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/PhoneAccountCreationFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/PhoneAccountCreationFragment.kt
deleted file mode 100644
index 4f285e8b5..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/PhoneAccountCreationFragment.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.os.Bundle
-import android.view.View
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.R
-import org.linphone.activities.assistant.AssistantActivity
-import org.linphone.activities.assistant.viewmodels.PhoneAccountCreationViewModel
-import org.linphone.activities.assistant.viewmodels.PhoneAccountCreationViewModelFactory
-import org.linphone.activities.assistant.viewmodels.SharedAssistantViewModel
-import org.linphone.activities.navigateToPhoneAccountValidation
-import org.linphone.databinding.AssistantPhoneAccountCreationFragmentBinding
-
-class PhoneAccountCreationFragment :
- AbstractPhoneFragment() {
- private lateinit var sharedAssistantViewModel: SharedAssistantViewModel
- override lateinit var viewModel: PhoneAccountCreationViewModel
-
- override fun getLayoutId(): Int = R.layout.assistant_phone_account_creation_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- sharedAssistantViewModel = requireActivity().run {
- ViewModelProvider(this)[SharedAssistantViewModel::class.java]
- }
-
- viewModel = ViewModelProvider(
- this,
- PhoneAccountCreationViewModelFactory(sharedAssistantViewModel.getAccountCreator())
- )[PhoneAccountCreationViewModel::class.java]
- binding.viewModel = viewModel
-
- binding.setInfoClickListener {
- showPhoneNumberInfoDialog()
- }
-
- binding.setSelectCountryClickListener {
- val countryPickerFragment = CountryPickerFragment()
- countryPickerFragment.listener = viewModel
- countryPickerFragment.show(childFragmentManager, "CountryPicker")
- }
-
- viewModel.prefix.observe(viewLifecycleOwner) { internationalPrefix ->
- viewModel.getCountryNameFromPrefix(internationalPrefix)
- }
-
- viewModel.goToSmsValidationEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- val args = Bundle()
- args.putBoolean("IsCreation", true)
- args.putString("PhoneNumber", viewModel.accountCreator.phoneNumber)
- navigateToPhoneAccountValidation(args)
- }
- }
-
- viewModel.onErrorEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume { message ->
- (requireActivity() as AssistantActivity).showSnackBar(message)
- }
- }
-
- checkPermissions()
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/PhoneAccountLinkingFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/PhoneAccountLinkingFragment.kt
deleted file mode 100644
index d8fd87e22..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/PhoneAccountLinkingFragment.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.os.Bundle
-import android.view.View
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.R
-import org.linphone.activities.SnackBarActivity
-import org.linphone.activities.assistant.viewmodels.*
-import org.linphone.activities.navigateToEchoCancellerCalibration
-import org.linphone.activities.navigateToPhoneAccountValidation
-import org.linphone.core.tools.Log
-import org.linphone.databinding.AssistantPhoneAccountLinkingFragmentBinding
-
-class PhoneAccountLinkingFragment : AbstractPhoneFragment() {
- private lateinit var sharedAssistantViewModel: SharedAssistantViewModel
- override lateinit var viewModel: PhoneAccountLinkingViewModel
-
- override fun getLayoutId(): Int = R.layout.assistant_phone_account_linking_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- sharedAssistantViewModel = requireActivity().run {
- ViewModelProvider(this)[SharedAssistantViewModel::class.java]
- }
-
- val accountCreator = sharedAssistantViewModel.getAccountCreator()
- viewModel = ViewModelProvider(this, PhoneAccountLinkingViewModelFactory(accountCreator))[PhoneAccountLinkingViewModel::class.java]
- binding.viewModel = viewModel
-
- val username = arguments?.getString("Username")
- Log.i("[Phone Account Linking] username to link is $username")
- viewModel.username.value = username
-
- val password = arguments?.getString("Password")
- accountCreator.password = password
-
- val ha1 = arguments?.getString("HA1")
- accountCreator.ha1 = ha1
-
- val allowSkip = arguments?.getBoolean("AllowSkip", false)
- viewModel.allowSkip.value = allowSkip
-
- binding.setInfoClickListener {
- showPhoneNumberInfoDialog()
- }
-
- binding.setSelectCountryClickListener {
- val countryPickerFragment = CountryPickerFragment()
- countryPickerFragment.listener = viewModel
- countryPickerFragment.show(childFragmentManager, "CountryPicker")
- }
-
- viewModel.prefix.observe(viewLifecycleOwner) { internationalPrefix ->
- viewModel.getCountryNameFromPrefix(internationalPrefix)
- }
-
- viewModel.goToSmsValidationEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- val args = Bundle()
- args.putBoolean("IsLinking", true)
- args.putString("PhoneNumber", viewModel.accountCreator.phoneNumber)
- navigateToPhoneAccountValidation(args)
- }
- }
-
- viewModel.leaveAssistantEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- if (coreContext.core.isEchoCancellerCalibrationRequired) {
- navigateToEchoCancellerCalibration()
- } else {
- requireActivity().finish()
- }
- }
- }
-
- viewModel.onErrorEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume { message ->
- (requireActivity() as SnackBarActivity).showSnackBar(message)
- }
- }
-
- checkPermissions()
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/PhoneAccountValidationFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/PhoneAccountValidationFragment.kt
deleted file mode 100644
index edcf18210..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/PhoneAccountValidationFragment.kt
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.content.ClipboardManager
-import android.content.Context.CLIPBOARD_SERVICE
-import android.os.Bundle
-import android.view.View
-import androidx.lifecycle.ViewModelProvider
-import androidx.navigation.fragment.findNavController
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.R
-import org.linphone.activities.GenericFragment
-import org.linphone.activities.SnackBarActivity
-import org.linphone.activities.assistant.viewmodels.PhoneAccountValidationViewModel
-import org.linphone.activities.assistant.viewmodels.PhoneAccountValidationViewModelFactory
-import org.linphone.activities.assistant.viewmodels.SharedAssistantViewModel
-import org.linphone.activities.navigateToAccountSettings
-import org.linphone.activities.navigateToEchoCancellerCalibration
-import org.linphone.compatibility.Compatibility
-import org.linphone.core.tools.Log
-import org.linphone.databinding.AssistantPhoneAccountValidationFragmentBinding
-
-class PhoneAccountValidationFragment : GenericFragment() {
- private lateinit var sharedAssistantViewModel: SharedAssistantViewModel
- private lateinit var viewModel: PhoneAccountValidationViewModel
-
- override fun getLayoutId(): Int = R.layout.assistant_phone_account_validation_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- sharedAssistantViewModel = requireActivity().run {
- ViewModelProvider(this)[SharedAssistantViewModel::class.java]
- }
-
- viewModel = ViewModelProvider(
- this,
- PhoneAccountValidationViewModelFactory(sharedAssistantViewModel.getAccountCreator())
- )[PhoneAccountValidationViewModel::class.java]
- binding.viewModel = viewModel
-
- viewModel.phoneNumber.value = arguments?.getString("PhoneNumber")
- viewModel.isLogin.value = arguments?.getBoolean("IsLogin", false)
- viewModel.isCreation.value = arguments?.getBoolean("IsCreation", false)
- viewModel.isLinking.value = arguments?.getBoolean("IsLinking", false)
-
- viewModel.leaveAssistantEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume {
- when {
- viewModel.isLogin.value == true || viewModel.isCreation.value == true -> {
- coreContext.newAccountConfigured(true)
-
- if (coreContext.core.isEchoCancellerCalibrationRequired) {
- navigateToEchoCancellerCalibration()
- } else {
- requireActivity().finish()
- }
- }
- viewModel.isLinking.value == true -> {
- if (findNavController().graph.id == R.id.settings_nav_graph_xml) {
- val args = Bundle()
- args.putString(
- "Identity",
- "sip:${viewModel.accountCreator.username}@${viewModel.accountCreator.domain}"
- )
- navigateToAccountSettings(args)
- } else {
- requireActivity().finish()
- }
- }
- }
- }
- }
-
- viewModel.onErrorEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume { message ->
- (requireActivity() as SnackBarActivity).showSnackBar(message)
- }
- }
-
- // This won't work starting Android 10 as clipboard access is denied unless app has focus,
- // which won't be the case when the SMS arrives unless it is added into clipboard from a notification
- val clipboard = requireContext().getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
- clipboard.addPrimaryClipChangedListener {
- val data = clipboard.primaryClip
- if (data != null && data.itemCount > 0) {
- val clip = data.getItemAt(0).text.toString()
- if (clip.length == 4) {
- Log.i(
- "[Assistant] [Phone Account Validation] Found 4 digits as primary clip in clipboard, using it and clear it"
- )
- viewModel.code.value = clip
- Compatibility.clearClipboard(clipboard)
- }
- }
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/QrCodeFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/QrCodeFragment.kt
deleted file mode 100644
index 0fe20d93e..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/QrCodeFragment.kt
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.content.pm.PackageManager
-import android.os.Bundle
-import android.view.View
-import androidx.lifecycle.ViewModelProvider
-import androidx.navigation.fragment.findNavController
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.R
-import org.linphone.activities.GenericFragment
-import org.linphone.activities.assistant.viewmodels.QrCodeViewModel
-import org.linphone.activities.assistant.viewmodels.SharedAssistantViewModel
-import org.linphone.core.tools.Log
-import org.linphone.databinding.AssistantQrCodeFragmentBinding
-import org.linphone.utils.PermissionHelper
-
-class QrCodeFragment : GenericFragment() {
- companion object {
- const val CAMERA_PERMISSION_REQUEST_CODE = 0
- }
-
- private lateinit var sharedAssistantViewModel: SharedAssistantViewModel
- private lateinit var viewModel: QrCodeViewModel
-
- override fun getLayoutId(): Int = R.layout.assistant_qr_code_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- sharedAssistantViewModel = requireActivity().run {
- ViewModelProvider(this)[SharedAssistantViewModel::class.java]
- }
-
- viewModel = ViewModelProvider(this)[QrCodeViewModel::class.java]
- binding.viewModel = viewModel
-
- viewModel.qrCodeFoundEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume { url ->
- sharedAssistantViewModel.remoteProvisioningUrl.value = url
- findNavController().navigateUp()
- }
- }
- viewModel.setBackCamera()
-
- if (!PermissionHelper.required(requireContext()).hasCameraPermission()) {
- Log.i("[QR Code] Asking for CAMERA permission")
- requestPermissions(
- arrayOf(android.Manifest.permission.CAMERA),
- CAMERA_PERMISSION_REQUEST_CODE
- )
- }
- }
-
- override fun onResume() {
- super.onResume()
-
- coreContext.core.nativePreviewWindowId = binding.qrCodeCaptureTexture
- coreContext.core.isQrcodeVideoPreviewEnabled = true
- coreContext.core.isVideoPreviewEnabled = true
- }
-
- override fun onPause() {
- coreContext.core.nativePreviewWindowId = null
- coreContext.core.isQrcodeVideoPreviewEnabled = false
- coreContext.core.isVideoPreviewEnabled = false
-
- super.onPause()
- }
-
- @Deprecated("Deprecated in Java")
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) {
- val granted =
- grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED
- if (granted) {
- Log.i("[QR Code] CAMERA permission granted")
- coreContext.core.reloadVideoDevices()
- viewModel.setBackCamera()
- } else {
- Log.w("[QR Code] CAMERA permission denied")
- findNavController().navigateUp()
- }
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/RemoteProvisioningFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/RemoteProvisioningFragment.kt
deleted file mode 100644
index 5889ba271..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/RemoteProvisioningFragment.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.os.Bundle
-import android.view.View
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.R
-import org.linphone.activities.GenericFragment
-import org.linphone.activities.assistant.AssistantActivity
-import org.linphone.activities.assistant.viewmodels.RemoteProvisioningViewModel
-import org.linphone.activities.assistant.viewmodels.SharedAssistantViewModel
-import org.linphone.activities.navigateToEchoCancellerCalibration
-import org.linphone.activities.navigateToQrCode
-import org.linphone.databinding.AssistantRemoteProvisioningFragmentBinding
-
-class RemoteProvisioningFragment : GenericFragment() {
- private lateinit var sharedAssistantViewModel: SharedAssistantViewModel
- private lateinit var viewModel: RemoteProvisioningViewModel
-
- override fun getLayoutId(): Int = R.layout.assistant_remote_provisioning_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- sharedAssistantViewModel = requireActivity().run {
- ViewModelProvider(this)[SharedAssistantViewModel::class.java]
- }
-
- viewModel = ViewModelProvider(this)[RemoteProvisioningViewModel::class.java]
- binding.viewModel = viewModel
-
- binding.setQrCodeClickListener {
- navigateToQrCode()
- }
-
- viewModel.fetchSuccessfulEvent.observe(
- viewLifecycleOwner
- ) {
- it.consume { success ->
- if (success) {
- if (coreContext.core.isEchoCancellerCalibrationRequired) {
- navigateToEchoCancellerCalibration()
- } else {
- requireActivity().finish()
- }
- } else {
- val activity = requireActivity() as AssistantActivity
- activity.showSnackBar(R.string.assistant_remote_provisioning_failure)
- }
- }
- }
-
- viewModel.urlToFetch.value = sharedAssistantViewModel.remoteProvisioningUrl.value ?: coreContext.core.provisioningUri
- }
-
- override fun onDestroy() {
- super.onDestroy()
-
- if (::sharedAssistantViewModel.isInitialized) {
- sharedAssistantViewModel.remoteProvisioningUrl.value = null
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/TopBarFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/TopBarFragment.kt
deleted file mode 100644
index e1e8ef074..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/TopBarFragment.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.os.Bundle
-import android.view.View
-import org.linphone.R
-import org.linphone.activities.GenericFragment
-import org.linphone.databinding.AssistantTopBarFragmentBinding
-
-class TopBarFragment : GenericFragment() {
- override fun getLayoutId(): Int = R.layout.assistant_top_bar_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
- useMaterialSharedAxisXForwardAnimation = false
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/WelcomeFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/WelcomeFragment.kt
deleted file mode 100644
index 79c54f64d..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/fragments/WelcomeFragment.kt
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.fragments
-
-import android.content.Intent
-import android.content.pm.PackageManager
-import android.net.Uri
-import android.os.Bundle
-import android.text.SpannableString
-import android.text.Spanned
-import android.text.method.LinkMovementMethod
-import android.text.style.ClickableSpan
-import android.view.View
-import androidx.lifecycle.ViewModelProvider
-import java.util.UnknownFormatConversionException
-import java.util.regex.Pattern
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.LinphoneApplication.Companion.corePreferences
-import org.linphone.R
-import org.linphone.activities.*
-import org.linphone.activities.assistant.viewmodels.WelcomeViewModel
-import org.linphone.activities.navigateToAccountLogin
-import org.linphone.activities.navigateToEmailAccountCreation
-import org.linphone.activities.navigateToRemoteProvisioning
-import org.linphone.core.tools.Log
-import org.linphone.databinding.AssistantWelcomeFragmentBinding
-import org.linphone.utils.LinphoneUtils
-
-class WelcomeFragment : GenericFragment() {
- private lateinit var viewModel: WelcomeViewModel
-
- override fun getLayoutId(): Int = R.layout.assistant_welcome_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- viewModel = ViewModelProvider(this)[WelcomeViewModel::class.java]
- binding.viewModel = viewModel
-
- binding.setCreateAccountClickListener {
- if (LinphoneUtils.isPushNotificationAvailable()) {
- Log.i("[Assistant] Core says push notifications are available")
- val deviceHasTelephonyFeature = coreContext.context.packageManager.hasSystemFeature(
- PackageManager.FEATURE_TELEPHONY
- )
- if (!deviceHasTelephonyFeature) {
- Log.i(
- "[Assistant] Device doesn't have TELEPHONY feature, showing email based account creation"
- )
- navigateToEmailAccountCreation()
- } else {
- Log.i(
- "[Assistant] Device has TELEPHONY feature, showing phone based account creation"
- )
- navigateToPhoneAccountCreation()
- }
- } else {
- Log.w(
- "[Assistant] Failed to get push notification info, showing warning instead of phone based account creation"
- )
- navigateToNoPushWarning()
- }
- }
-
- binding.setAccountLoginClickListener {
- navigateToAccountLogin()
- }
-
- binding.setGenericAccountLoginClickListener {
- navigateToGenericLoginWarning()
- }
-
- binding.setRemoteProvisioningClickListener {
- navigateToRemoteProvisioning()
- }
-
- viewModel.termsAndPrivacyAccepted.observe(
- viewLifecycleOwner
- ) {
- if (it) corePreferences.readAndAgreeTermsAndPrivacy = true
- }
-
- setUpTermsAndPrivacyLinks()
- }
-
- private fun setUpTermsAndPrivacyLinks() {
- val terms = getString(R.string.assistant_general_terms)
- val privacy = getString(R.string.assistant_privacy_policy)
-
- val label = try {
- getString(
- R.string.assistant_read_and_agree_terms,
- terms,
- privacy
- )
- } catch (e: UnknownFormatConversionException) {
- Log.e("[Welcome] Wrong R.string.assistant_read_and_agree_terms format!")
- "I accept Belledonne Communications' terms of use and privacy policy"
- }
- val spannable = SpannableString(label)
-
- val termsMatcher = Pattern.compile(terms).matcher(label)
- if (termsMatcher.find()) {
- val clickableSpan: ClickableSpan = object : ClickableSpan() {
- override fun onClick(widget: View) {
- val browserIntent = Intent(
- Intent.ACTION_VIEW,
- Uri.parse(getString(R.string.assistant_general_terms_link))
- )
- try {
- startActivity(browserIntent)
- } catch (e: Exception) {
- Log.e("[Welcome] Can't start activity: $e")
- }
- }
- }
- spannable.setSpan(
- clickableSpan,
- termsMatcher.start(0),
- termsMatcher.end(),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
- )
- }
-
- val policyMatcher = Pattern.compile(privacy).matcher(label)
- if (policyMatcher.find()) {
- val clickableSpan: ClickableSpan = object : ClickableSpan() {
- override fun onClick(widget: View) {
- val browserIntent = Intent(
- Intent.ACTION_VIEW,
- Uri.parse(getString(R.string.assistant_privacy_policy_link))
- )
- try {
- startActivity(browserIntent)
- } catch (e: Exception) {
- Log.e("[Welcome] Can't start activity: $e")
- }
- }
- }
- spannable.setSpan(
- clickableSpan,
- policyMatcher.start(0),
- policyMatcher.end(),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
- )
- }
-
- binding.termsAndPrivacy.text = spannable
- binding.termsAndPrivacy.movementMethod = LinkMovementMethod.getInstance()
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPhoneViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPhoneViewModel.kt
deleted file mode 100644
index 605b0c5ce..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPhoneViewModel.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.MutableLiveData
-import org.linphone.activities.assistant.fragments.CountryPickerFragment
-import org.linphone.core.AccountCreator
-import org.linphone.core.DialPlan
-import org.linphone.core.tools.Log
-import org.linphone.utils.PhoneNumberUtils
-
-abstract class AbstractPhoneViewModel(accountCreator: AccountCreator) :
- AbstractPushTokenViewModel(accountCreator),
- CountryPickerFragment.CountryPickedListener {
-
- val prefix = MutableLiveData()
- val prefixError = MutableLiveData()
-
- val phoneNumber = MutableLiveData()
- val phoneNumberError = MutableLiveData()
-
- val countryName = MutableLiveData()
-
- init {
- prefix.value = "+"
- }
-
- override fun onCountryClicked(dialPlan: DialPlan) {
- prefix.value = "+${dialPlan.countryCallingCode}"
- countryName.value = dialPlan.country
- }
-
- fun isPhoneNumberOk(): Boolean {
- return prefix.value.orEmpty().length > 1 && // Not just '+' character
- prefixError.value.orEmpty().isEmpty() &&
- phoneNumber.value.orEmpty().isNotEmpty() &&
- phoneNumberError.value.orEmpty().isEmpty()
- }
-
- fun updateFromPhoneNumberAndOrDialPlan(number: String?, dialPlan: DialPlan?) {
- val internationalPrefix = "+${dialPlan?.countryCallingCode}"
- if (dialPlan != null) {
- Log.i("[Assistant] Found prefix from dial plan: ${dialPlan.countryCallingCode}")
- prefix.value = internationalPrefix
- getCountryNameFromPrefix(internationalPrefix)
- }
-
- if (number != null) {
- Log.i("[Assistant] Found phone number: $number")
- phoneNumber.value = if (number.startsWith(internationalPrefix)) {
- number.substring(internationalPrefix.length)
- } else {
- number
- }
- }
- }
-
- fun getCountryNameFromPrefix(prefix: String?) {
- if (!prefix.isNullOrEmpty()) {
- val countryCode = if (prefix.first() == '+') prefix.substring(1) else prefix
- val dialPlan = PhoneNumberUtils.getDialPlanFromCountryCallingPrefix(countryCode)
- Log.i("[Assistant] Found dial plan $dialPlan from country code: $countryCode")
- countryName.value = dialPlan?.country
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPushTokenViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPushTokenViewModel.kt
deleted file mode 100644
index 363475e63..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPushTokenViewModel.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2010-2023 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import org.json.JSONException
-import org.json.JSONObject
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.core.AccountCreator
-import org.linphone.core.Core
-import org.linphone.core.CoreListenerStub
-import org.linphone.core.tools.Log
-
-abstract class AbstractPushTokenViewModel(val accountCreator: AccountCreator) : ViewModel() {
- private var waitingForPushToken = false
- private var waitForPushJob: Job? = null
-
- private val coreListener = object : CoreListenerStub() {
- override fun onPushNotificationReceived(core: Core, payload: String?) {
- Log.i("[Assistant] Push received: [$payload]")
-
- val data = payload.orEmpty()
- if (data.isNotEmpty()) {
- try {
- // This is because JSONObject.toString() done by the SDK will result in payload looking like {"custom-payload":"{\"token\":\"value\"}"}
- val cleanPayload = data.replace("\\\"", "\"").replace("\"{", "{").replace(
- "}\"",
- "}"
- )
- Log.i("[Assistant] Cleaned payload is: [$cleanPayload]")
- val json = JSONObject(cleanPayload)
- val customPayload = json.getJSONObject("custom-payload")
- if (customPayload.has("token")) {
- waitForPushJob?.cancel()
- waitingForPushToken = false
-
- val token = customPayload.getString("token")
- if (token.isNotEmpty()) {
- Log.i("[Assistant] Extracted token [$token] from push payload")
- accountCreator.token = token
- onFlexiApiTokenReceived()
- } else {
- Log.e("[Assistant] Push payload JSON object has an empty 'token'!")
- onFlexiApiTokenRequestError()
- }
- } else {
- Log.e("[Assistant] Push payload JSON object has no 'token' key!")
- onFlexiApiTokenRequestError()
- }
- } catch (e: JSONException) {
- Log.e("[Assistant] Exception trying to parse push payload as JSON: [$e]")
- onFlexiApiTokenRequestError()
- }
- } else {
- Log.e("[Assistant] Push payload is null or empty, can't extract auth token!")
- onFlexiApiTokenRequestError()
- }
- }
- }
-
- init {
- coreContext.core.addListener(coreListener)
- }
-
- override fun onCleared() {
- coreContext.core.removeListener(coreListener)
- waitForPushJob?.cancel()
- }
-
- abstract fun onFlexiApiTokenReceived()
- abstract fun onFlexiApiTokenRequestError()
-
- protected fun requestFlexiApiToken() {
- if (!coreContext.core.isPushNotificationAvailable) {
- Log.e(
- "[Assistant] Core says push notification aren't available, can't request a token from FlexiAPI"
- )
- onFlexiApiTokenRequestError()
- return
- }
-
- val pushConfig = coreContext.core.pushNotificationConfig
- if (pushConfig != null) {
- Log.i(
- "[Assistant] Found push notification info: provider [${pushConfig.provider}], param [${pushConfig.param}] and prid [${pushConfig.prid}]"
- )
- accountCreator.pnProvider = pushConfig.provider
- accountCreator.pnParam = pushConfig.param
- accountCreator.pnPrid = pushConfig.prid
-
- // Request an auth token, will be sent by push
- val result = accountCreator.requestAuthToken()
- if (result == AccountCreator.Status.RequestOk) {
- val waitFor = 5000
- waitingForPushToken = true
- waitForPushJob?.cancel()
-
- Log.i("[Assistant] Waiting push with auth token for $waitFor ms")
- waitForPushJob = viewModelScope.launch {
- withContext(Dispatchers.IO) {
- delay(waitFor.toLong())
- }
- withContext(Dispatchers.Main) {
- if (waitingForPushToken) {
- waitingForPushToken = false
- Log.e("[Assistant] Auth token wasn't received by push in $waitFor ms")
- onFlexiApiTokenRequestError()
- }
- }
- }
- } else {
- Log.e("[Assistant] Failed to require a push with an auth token: [$result]")
- onFlexiApiTokenRequestError()
- }
- } else {
- Log.e("[Assistant] No push configuration object in Core, shouldn't happen!")
- onFlexiApiTokenRequestError()
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/AccountLoginViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/AccountLoginViewModel.kt
deleted file mode 100644
index 579a76eb7..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/AccountLoginViewModel.kt
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.viewmodels
-
-import android.content.pm.PackageManager
-import androidx.lifecycle.*
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.core.*
-import org.linphone.core.tools.Log
-import org.linphone.utils.Event
-import org.linphone.utils.LinphoneUtils
-import org.linphone.utils.PhoneNumberUtils
-
-class AccountLoginViewModelFactory(private val accountCreator: AccountCreator) :
- ViewModelProvider.NewInstanceFactory() {
-
- @Suppress("UNCHECKED_CAST")
- override fun create(modelClass: Class): T {
- return AccountLoginViewModel(accountCreator) as T
- }
-}
-
-class AccountLoginViewModel(accountCreator: AccountCreator) : AbstractPhoneViewModel(accountCreator) {
- val loginWithUsernamePassword = MutableLiveData()
-
- val username = MutableLiveData()
- val usernameError = MutableLiveData()
-
- val password = MutableLiveData()
- val passwordError = MutableLiveData()
-
- val loginEnabled = MediatorLiveData()
-
- val waitForServerAnswer = MutableLiveData()
-
- val displayName = MutableLiveData()
-
- val forceLoginUsingUsernameAndPassword = MutableLiveData()
-
- val leaveAssistantEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val invalidCredentialsEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val goToSmsValidationEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val onErrorEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- private val listener = object : AccountCreatorListenerStub() {
- override fun onRecoverAccount(
- creator: AccountCreator,
- status: AccountCreator.Status,
- response: String?
- ) {
- Log.i("[Assistant] [Account Login] Recover account status is $status")
- waitForServerAnswer.value = false
-
- if (status == AccountCreator.Status.RequestOk) {
- goToSmsValidationEvent.value = Event(true)
- } else {
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- }
-
- private var accountToCheck: Account? = null
-
- private val coreListener = object : CoreListenerStub() {
- override fun onAccountRegistrationStateChanged(
- core: Core,
- account: Account,
- state: RegistrationState?,
- message: String
- ) {
- if (account == accountToCheck) {
- Log.i("[Assistant] [Account Login] Registration state is $state: $message")
- if (state == RegistrationState.Ok) {
- waitForServerAnswer.value = false
- leaveAssistantEvent.value = Event(true)
- core.removeListener(this)
- } else if (state == RegistrationState.Failed) {
- waitForServerAnswer.value = false
- invalidCredentialsEvent.value = Event(true)
- core.removeListener(this)
- }
- }
- }
- }
-
- init {
- accountCreator.addListener(listener)
-
- val pushAvailable = LinphoneUtils.isPushNotificationAvailable()
- val deviceHasTelephonyFeature = coreContext.context.packageManager.hasSystemFeature(
- PackageManager.FEATURE_TELEPHONY
- )
- loginWithUsernamePassword.value = !deviceHasTelephonyFeature || !pushAvailable
- forceLoginUsingUsernameAndPassword.value = !pushAvailable
-
- loginEnabled.value = false
- loginEnabled.addSource(prefix) {
- loginEnabled.value = isLoginButtonEnabled()
- }
- loginEnabled.addSource(phoneNumber) {
- loginEnabled.value = isLoginButtonEnabled()
- }
- loginEnabled.addSource(username) {
- loginEnabled.value = isLoginButtonEnabled()
- }
- loginEnabled.addSource(password) {
- loginEnabled.value = isLoginButtonEnabled()
- }
- loginEnabled.addSource(loginWithUsernamePassword) {
- loginEnabled.value = isLoginButtonEnabled()
- }
- loginEnabled.addSource(phoneNumberError) {
- loginEnabled.value = isLoginButtonEnabled()
- }
- loginEnabled.addSource(prefixError) {
- loginEnabled.value = isLoginButtonEnabled()
- }
- }
-
- override fun onCleared() {
- accountCreator.removeListener(listener)
- super.onCleared()
- }
-
- override fun onFlexiApiTokenReceived() {
- Log.i("[Assistant] [Account Login] Using FlexiAPI auth token [${accountCreator.token}]")
- waitForServerAnswer.value = false
- loginWithPhoneNumber()
- }
-
- override fun onFlexiApiTokenRequestError() {
- Log.e("[Assistant] [Account Login] Failed to get an auth token from FlexiAPI")
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: Failed to get an auth token from account manager server")
- }
-
- fun removeInvalidProxyConfig() {
- val account = accountToCheck
- account ?: return
-
- val core = coreContext.core
- val authInfo = account.findAuthInfo()
- if (authInfo != null) core.removeAuthInfo(authInfo)
- core.removeAccount(account)
- accountToCheck = null
-
- // Make sure there is a valid default account
- val accounts = core.accountList
- if (accounts.isNotEmpty() && core.defaultAccount == null) {
- core.defaultAccount = accounts.first()
- core.refreshRegisters()
- }
- }
-
- fun continueEvenIfInvalidCredentials() {
- leaveAssistantEvent.value = Event(true)
- }
-
- private fun loginWithUsername() {
- val result = accountCreator.setUsername(username.value)
- if (result != AccountCreator.UsernameStatus.Ok) {
- Log.e(
- "[Assistant] [Account Login] Error [${result.name}] setting the username: ${username.value}"
- )
- usernameError.value = result.name
- return
- }
- Log.i("[Assistant] [Account Login] Username is ${accountCreator.username}")
-
- val result2 = accountCreator.setPassword(password.value)
- if (result2 != AccountCreator.PasswordStatus.Ok) {
- Log.e("[Assistant] [Account Login] Error [${result2.name}] setting the password")
- passwordError.value = result2.name
- return
- }
-
- waitForServerAnswer.value = true
- coreContext.core.addListener(coreListener)
- if (!createAccountAndAuthInfo()) {
- waitForServerAnswer.value = false
- coreContext.core.removeListener(coreListener)
- onErrorEvent.value = Event("Error: Failed to create account object")
- }
- }
-
- private fun loginWithPhoneNumber() {
- val result = AccountCreator.PhoneNumberStatus.fromInt(
- accountCreator.setPhoneNumber(phoneNumber.value, prefix.value)
- )
- if (result != AccountCreator.PhoneNumberStatus.Ok) {
- Log.e(
- "[Assistant] [Account Login] Error [$result] setting the phone number: ${phoneNumber.value} with prefix: ${prefix.value}"
- )
- phoneNumberError.value = result.name
- return
- }
- Log.i("[Assistant] [Account Login] Phone number is ${accountCreator.phoneNumber}")
-
- val result2 = accountCreator.setUsername(accountCreator.phoneNumber)
- if (result2 != AccountCreator.UsernameStatus.Ok) {
- Log.e(
- "[Assistant] [Account Login] Error [${result2.name}] setting the username: ${accountCreator.phoneNumber}"
- )
- usernameError.value = result2.name
- return
- }
- Log.i("[Assistant] [Account Login] Username is ${accountCreator.username}")
-
- waitForServerAnswer.value = true
- val status = accountCreator.recoverAccount()
- Log.i("[Assistant] [Account Login] Recover account returned $status")
- if (status != AccountCreator.Status.RequestOk) {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
-
- fun login() {
- accountCreator.displayName = displayName.value
-
- if (loginWithUsernamePassword.value == true) {
- loginWithUsername()
- } else {
- val token = accountCreator.token.orEmpty()
- if (token.isNotEmpty()) {
- Log.i(
- "[Assistant] [Account Login] We already have an auth token from FlexiAPI [$token], continue"
- )
- onFlexiApiTokenReceived()
- } else {
- Log.i("[Assistant] [Account Login] Requesting an auth token from FlexiAPI")
- waitForServerAnswer.value = true
- requestFlexiApiToken()
- }
- }
- }
-
- private fun isLoginButtonEnabled(): Boolean {
- return if (loginWithUsernamePassword.value == true) {
- username.value.orEmpty().isNotEmpty() && password.value.orEmpty().isNotEmpty()
- } else {
- isPhoneNumberOk()
- }
- }
-
- private fun createAccountAndAuthInfo(): Boolean {
- val account = accountCreator.createAccountInCore()
- accountToCheck = account
-
- if (account == null) {
- Log.e("[Assistant] [Account Login] Account creator couldn't create account")
- onErrorEvent.value = Event("Error: Failed to create account object")
- return false
- }
-
- val params = account.params.clone()
- params.pushNotificationAllowed = true
-
- if (params.internationalPrefix.isNullOrEmpty()) {
- val dialPlan = PhoneNumberUtils.getDialPlanForCurrentCountry(coreContext.context)
- if (dialPlan != null) {
- Log.i(
- "[Assistant] [Account Login] Found dial plan country ${dialPlan.country} with international prefix ${dialPlan.countryCallingCode}"
- )
- params.internationalPrefix = dialPlan.countryCallingCode
- } else {
- Log.w("[Assistant] [Account Login] Failed to find dial plan")
- }
- }
-
- account.params = params
- Log.i("[Assistant] [Account Login] Account created")
- return true
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/EchoCancellerCalibrationViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/EchoCancellerCalibrationViewModel.kt
deleted file mode 100644
index 09d01c069..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/EchoCancellerCalibrationViewModel.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.core.Core
-import org.linphone.core.CoreListenerStub
-import org.linphone.core.EcCalibratorStatus
-import org.linphone.core.tools.Log
-import org.linphone.utils.Event
-
-class EchoCancellerCalibrationViewModel : ViewModel() {
- val echoCalibrationTerminated = MutableLiveData>()
-
- private val listener = object : CoreListenerStub() {
- override fun onEcCalibrationResult(core: Core, status: EcCalibratorStatus, delayMs: Int) {
- if (status == EcCalibratorStatus.InProgress) return
- echoCancellerCalibrationFinished(status, delayMs)
- }
- }
-
- init {
- coreContext.core.addListener(listener)
- }
-
- fun startEchoCancellerCalibration() {
- coreContext.core.startEchoCancellerCalibration()
- }
-
- fun echoCancellerCalibrationFinished(status: EcCalibratorStatus, delay: Int) {
- coreContext.core.removeListener(listener)
- when (status) {
- EcCalibratorStatus.DoneNoEcho -> {
- Log.i("[Assistant] [Echo Canceller Calibration] Done, no echo")
- }
- EcCalibratorStatus.Done -> {
- Log.i("[Assistant] [Echo Canceller Calibration] Done, delay is ${delay}ms")
- }
- EcCalibratorStatus.Failed -> {
- Log.w("[Assistant] [Echo Canceller Calibration] Failed")
- }
- EcCalibratorStatus.InProgress -> {
- Log.i("[Assistant] [Echo Canceller Calibration] In progress")
- }
- }
- echoCalibrationTerminated.value = Event(true)
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountCreationViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountCreationViewModel.kt
deleted file mode 100644
index dea25074d..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountCreationViewModel.kt
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.MediatorLiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.R
-import org.linphone.core.AccountCreator
-import org.linphone.core.AccountCreatorListenerStub
-import org.linphone.core.tools.Log
-import org.linphone.utils.AppUtils
-import org.linphone.utils.Event
-
-class EmailAccountCreationViewModelFactory(private val accountCreator: AccountCreator) :
- ViewModelProvider.NewInstanceFactory() {
-
- @Suppress("UNCHECKED_CAST")
- override fun create(modelClass: Class): T {
- return EmailAccountCreationViewModel(accountCreator) as T
- }
-}
-
-class EmailAccountCreationViewModel(accountCreator: AccountCreator) : AbstractPushTokenViewModel(
- accountCreator
-) {
- val username = MutableLiveData()
- val usernameError = MutableLiveData()
-
- val email = MutableLiveData()
- val emailError = MutableLiveData()
-
- val password = MutableLiveData()
- val passwordError = MutableLiveData()
-
- val passwordConfirmation = MutableLiveData()
- val passwordConfirmationError = MutableLiveData()
-
- val displayName = MutableLiveData()
-
- val createEnabled: MediatorLiveData = MediatorLiveData()
-
- val waitForServerAnswer = MutableLiveData()
-
- val goToEmailValidationEvent = MutableLiveData>()
-
- val onErrorEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- private val listener = object : AccountCreatorListenerStub() {
- override fun onIsAccountExist(
- creator: AccountCreator,
- status: AccountCreator.Status,
- response: String?
- ) {
- Log.i("[Assistant] [Account Creation] onIsAccountExist status is $status")
- when (status) {
- AccountCreator.Status.AccountExist, AccountCreator.Status.AccountExistWithAlias -> {
- waitForServerAnswer.value = false
- usernameError.value = AppUtils.getString(
- R.string.assistant_error_username_already_exists
- )
- }
- AccountCreator.Status.AccountNotExist -> {
- val createAccountStatus = creator.createAccount()
- if (createAccountStatus != AccountCreator.Status.RequestOk) {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- else -> {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- }
-
- override fun onCreateAccount(
- creator: AccountCreator,
- status: AccountCreator.Status,
- response: String?
- ) {
- Log.i("[Assistant] [Account Creation] onCreateAccount status is $status")
- waitForServerAnswer.value = false
-
- when (status) {
- AccountCreator.Status.AccountCreated -> {
- goToEmailValidationEvent.value = Event(true)
- }
- else -> {
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- }
- }
-
- init {
- accountCreator.addListener(listener)
-
- createEnabled.value = false
- createEnabled.addSource(username) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(usernameError) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(email) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(emailError) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(password) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(passwordError) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(passwordConfirmation) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(passwordConfirmationError) {
- createEnabled.value = isCreateButtonEnabled()
- }
- }
-
- override fun onCleared() {
- accountCreator.removeListener(listener)
- super.onCleared()
- }
-
- override fun onFlexiApiTokenReceived() {
- Log.i("[Assistant] [Account Creation] Using FlexiAPI auth token [${accountCreator.token}]")
-
- waitForServerAnswer.value = true
- val status = accountCreator.isAccountExist
- Log.i("[Assistant] [Account Creation] Account exists returned $status")
- if (status != AccountCreator.Status.RequestOk) {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
-
- override fun onFlexiApiTokenRequestError() {
- Log.e("[Assistant] [Account Creation] Failed to get an auth token from FlexiAPI")
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: Failed to get an auth token from account manager server")
- }
-
- fun create() {
- accountCreator.username = username.value
- accountCreator.password = password.value
- accountCreator.email = email.value
- accountCreator.displayName = displayName.value
-
- val token = accountCreator.token.orEmpty()
- if (token.isNotEmpty()) {
- Log.i(
- "[Assistant] [Account Creation] We already have an auth token from FlexiAPI [$token], continue"
- )
- onFlexiApiTokenReceived()
- } else {
- Log.i("[Assistant] [Account Creation] Requesting an auth token from FlexiAPI")
- waitForServerAnswer.value = true
- requestFlexiApiToken()
- }
- }
-
- private fun isCreateButtonEnabled(): Boolean {
- return username.value.orEmpty().isNotEmpty() &&
- email.value.orEmpty().isNotEmpty() &&
- password.value.orEmpty().isNotEmpty() &&
- passwordConfirmation.value.orEmpty().isNotEmpty() &&
- password.value == passwordConfirmation.value &&
- usernameError.value.orEmpty().isEmpty() &&
- emailError.value.orEmpty().isEmpty() &&
- passwordError.value.orEmpty().isEmpty() &&
- passwordConfirmationError.value.orEmpty().isEmpty()
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountValidationViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountValidationViewModel.kt
deleted file mode 100644
index bc72fbc90..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountValidationViewModel.kt
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.R
-import org.linphone.core.AccountCreator
-import org.linphone.core.AccountCreatorListenerStub
-import org.linphone.core.tools.Log
-import org.linphone.utils.AppUtils
-import org.linphone.utils.Event
-import org.linphone.utils.PhoneNumberUtils
-
-class EmailAccountValidationViewModelFactory(private val accountCreator: AccountCreator) :
- ViewModelProvider.NewInstanceFactory() {
-
- @Suppress("UNCHECKED_CAST")
- override fun create(modelClass: Class): T {
- return EmailAccountValidationViewModel(accountCreator) as T
- }
-}
-
-class EmailAccountValidationViewModel(val accountCreator: AccountCreator) : ViewModel() {
- val email = MutableLiveData()
-
- val waitForServerAnswer = MutableLiveData()
-
- val leaveAssistantEvent = MutableLiveData>()
-
- val onErrorEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- private val listener = object : AccountCreatorListenerStub() {
- override fun onIsAccountActivated(
- creator: AccountCreator,
- status: AccountCreator.Status,
- response: String?
- ) {
- Log.i("[Assistant] [Account Validation] onIsAccountActivated status is $status")
- waitForServerAnswer.value = false
-
- when (status) {
- AccountCreator.Status.AccountActivated -> {
- if (createAccountAndAuthInfo()) {
- leaveAssistantEvent.value = Event(true)
- } else {
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- AccountCreator.Status.AccountNotActivated -> {
- onErrorEvent.value = Event(
- AppUtils.getString(R.string.assistant_create_email_account_not_validated)
- )
- }
- else -> {
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- }
- }
-
- init {
- accountCreator.addListener(listener)
- email.value = accountCreator.email
- }
-
- override fun onCleared() {
- accountCreator.removeListener(listener)
- super.onCleared()
- }
-
- fun finish() {
- waitForServerAnswer.value = true
- val status = accountCreator.isAccountActivated
- Log.i("[Assistant] [Account Validation] Account exists returned $status")
- if (status != AccountCreator.Status.RequestOk) {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
-
- private fun createAccountAndAuthInfo(): Boolean {
- val account = accountCreator.createAccountInCore()
-
- if (account == null) {
- Log.e("[Assistant] [Account Validation] Account creator couldn't create account")
- onErrorEvent.value = Event("Error: Failed to create account object")
- return false
- }
-
- val params = account.params.clone()
- params.pushNotificationAllowed = true
-
- if (params.internationalPrefix.isNullOrEmpty()) {
- val dialPlan = PhoneNumberUtils.getDialPlanForCurrentCountry(coreContext.context)
- if (dialPlan != null) {
- Log.i(
- "[Assistant] [Account Validation] Found dial plan country ${dialPlan.country} with international prefix ${dialPlan.countryCallingCode}"
- )
- params.internationalPrefix = dialPlan.countryCallingCode
- } else {
- Log.w("[Assistant] [Account Validation] Failed to find dial plan")
- }
- }
-
- account.params = params
-
- Log.i("[Assistant] [Account Validation] Account created")
- return true
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/GenericLoginViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/GenericLoginViewModel.kt
deleted file mode 100644
index 5e0e50dfe..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/GenericLoginViewModel.kt
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.MediatorLiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.core.*
-import org.linphone.core.tools.Log
-import org.linphone.utils.Event
-
-class GenericLoginViewModelFactory(private val accountCreator: AccountCreator) :
- ViewModelProvider.NewInstanceFactory() {
-
- @Suppress("UNCHECKED_CAST")
- override fun create(modelClass: Class): T {
- return GenericLoginViewModel(accountCreator) as T
- }
-}
-
-class GenericLoginViewModel(private val accountCreator: AccountCreator) : ViewModel() {
- val username = MutableLiveData()
-
- val password = MutableLiveData()
-
- val domain = MutableLiveData()
-
- val displayName = MutableLiveData()
-
- val transport = MutableLiveData()
-
- val loginEnabled: MediatorLiveData = MediatorLiveData()
-
- val waitForServerAnswer = MutableLiveData()
-
- val leaveAssistantEvent = MutableLiveData>()
-
- val invalidCredentialsEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val onErrorEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- private var accountToCheck: Account? = null
-
- private val coreListener = object : CoreListenerStub() {
- override fun onAccountRegistrationStateChanged(
- core: Core,
- account: Account,
- state: RegistrationState?,
- message: String
- ) {
- if (account == accountToCheck) {
- Log.i("[Assistant] [Generic Login] Registration state is $state: $message")
- if (state == RegistrationState.Ok) {
- waitForServerAnswer.value = false
- leaveAssistantEvent.value = Event(true)
- core.removeListener(this)
- } else if (state == RegistrationState.Failed) {
- waitForServerAnswer.value = false
- invalidCredentialsEvent.value = Event(true)
- core.removeListener(this)
- }
- }
- }
- }
-
- init {
- transport.value = TransportType.Tls
-
- loginEnabled.value = false
- loginEnabled.addSource(username) {
- loginEnabled.value = isLoginButtonEnabled()
- }
- loginEnabled.addSource(password) {
- loginEnabled.value = isLoginButtonEnabled()
- }
- loginEnabled.addSource(domain) {
- loginEnabled.value = isLoginButtonEnabled()
- }
- }
-
- fun setTransport(transportType: TransportType) {
- transport.value = transportType
- }
-
- fun removeInvalidProxyConfig() {
- val account = accountToCheck
- account ?: return
-
- val core = coreContext.core
- val authInfo = account.findAuthInfo()
- if (authInfo != null) core.removeAuthInfo(authInfo)
- core.removeAccount(account)
- accountToCheck = null
-
- // Make sure there is a valid default account
- val accounts = core.accountList
- if (accounts.isNotEmpty() && core.defaultAccount == null) {
- core.defaultAccount = accounts.first()
- core.refreshRegisters()
- }
- }
-
- fun continueEvenIfInvalidCredentials() {
- leaveAssistantEvent.value = Event(true)
- }
-
- fun createAccountAndAuthInfo() {
- waitForServerAnswer.value = true
- coreContext.core.addListener(coreListener)
-
- accountCreator.username = username.value
- accountCreator.password = password.value
- accountCreator.domain = domain.value
- accountCreator.displayName = displayName.value
- accountCreator.transport = transport.value
-
- val account = accountCreator.createAccountInCore()
- accountToCheck = account
-
- if (account == null) {
- Log.e("[Assistant] [Generic Login] Account creator couldn't create account")
- coreContext.core.removeListener(coreListener)
- onErrorEvent.value = Event("Error: Failed to create account object")
- waitForServerAnswer.value = false
- return
- }
-
- Log.i("[Assistant] [Generic Login] Account created")
- }
-
- private fun isLoginButtonEnabled(): Boolean {
- return username.value.orEmpty().isNotEmpty() &&
- domain.value.orEmpty().isNotEmpty() &&
- password.value.orEmpty().isNotEmpty()
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountCreationViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountCreationViewModel.kt
deleted file mode 100644
index 03b6face3..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountCreationViewModel.kt
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.MediatorLiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.LinphoneApplication.Companion.corePreferences
-import org.linphone.R
-import org.linphone.core.AccountCreator
-import org.linphone.core.AccountCreatorListenerStub
-import org.linphone.core.tools.Log
-import org.linphone.utils.AppUtils
-import org.linphone.utils.Event
-
-class PhoneAccountCreationViewModelFactory(private val accountCreator: AccountCreator) :
- ViewModelProvider.NewInstanceFactory() {
-
- @Suppress("UNCHECKED_CAST")
- override fun create(modelClass: Class): T {
- return PhoneAccountCreationViewModel(accountCreator) as T
- }
-}
-
-class PhoneAccountCreationViewModel(accountCreator: AccountCreator) : AbstractPhoneViewModel(
- accountCreator
-) {
- val username = MutableLiveData()
- val useUsername = MutableLiveData()
- val usernameError = MutableLiveData()
-
- val displayName = MutableLiveData()
-
- val createEnabled: MediatorLiveData = MediatorLiveData()
-
- val waitForServerAnswer = MutableLiveData()
-
- val goToSmsValidationEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val onErrorEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- private val listener = object : AccountCreatorListenerStub() {
- override fun onIsAccountExist(
- creator: AccountCreator,
- status: AccountCreator.Status,
- response: String?
- ) {
- Log.i("[Assistant] [Phone Account Creation] onIsAccountExist status is $status")
- when (status) {
- AccountCreator.Status.AccountExist, AccountCreator.Status.AccountExistWithAlias -> {
- waitForServerAnswer.value = false
- usernameError.value = AppUtils.getString(
- R.string.assistant_error_username_already_exists
- )
- }
- AccountCreator.Status.AccountNotExist -> {
- waitForServerAnswer.value = false
- checkPhoneNumber()
- }
- else -> {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- }
-
- override fun onIsAliasUsed(
- creator: AccountCreator,
- status: AccountCreator.Status,
- response: String?
- ) {
- Log.i("[Assistant] [Phone Account Creation] onIsAliasUsed status is $status")
- when (status) {
- AccountCreator.Status.AliasExist -> {
- waitForServerAnswer.value = false
- phoneNumberError.value = AppUtils.getString(
- R.string.assistant_error_phone_number_already_exists
- )
- }
- AccountCreator.Status.AliasIsAccount -> {
- waitForServerAnswer.value = false
- if (useUsername.value == true) {
- usernameError.value = AppUtils.getString(
- R.string.assistant_error_username_already_exists
- )
- } else {
- phoneNumberError.value = AppUtils.getString(
- R.string.assistant_error_phone_number_already_exists
- )
- }
- }
- AccountCreator.Status.AliasNotExist -> {
- val createAccountStatus = creator.createAccount()
- Log.i(
- "[Assistant] [Phone Account Creation] createAccount returned $createAccountStatus"
- )
- if (createAccountStatus != AccountCreator.Status.RequestOk) {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- else -> {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- }
-
- override fun onCreateAccount(
- creator: AccountCreator,
- status: AccountCreator.Status,
- response: String?
- ) {
- Log.i("[Assistant] [Phone Account Creation] onCreateAccount status is $status")
- waitForServerAnswer.value = false
- when (status) {
- AccountCreator.Status.AccountCreated -> {
- goToSmsValidationEvent.value = Event(true)
- }
- AccountCreator.Status.AccountExistWithAlias -> {
- phoneNumberError.value = AppUtils.getString(
- R.string.assistant_error_phone_number_already_exists
- )
- }
- else -> {
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- }
- }
-
- init {
- useUsername.value = false
- accountCreator.addListener(listener)
-
- createEnabled.value = false
- createEnabled.addSource(prefix) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(phoneNumber) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(useUsername) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(username) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(usernameError) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(phoneNumberError) {
- createEnabled.value = isCreateButtonEnabled()
- }
- createEnabled.addSource(prefixError) {
- createEnabled.value = isCreateButtonEnabled()
- }
- }
-
- override fun onCleared() {
- accountCreator.removeListener(listener)
- super.onCleared()
- }
-
- override fun onFlexiApiTokenReceived() {
- Log.i(
- "[Assistant] [Phone Account Creation] Using FlexiAPI auth token [${accountCreator.token}]"
- )
- accountCreator.displayName = displayName.value
-
- val result = AccountCreator.PhoneNumberStatus.fromInt(
- accountCreator.setPhoneNumber(phoneNumber.value, prefix.value)
- )
- if (result != AccountCreator.PhoneNumberStatus.Ok) {
- Log.e(
- "[Assistant] [Phone Account Creation] Error [$result] setting the phone number: ${phoneNumber.value} with prefix: ${prefix.value}"
- )
- phoneNumberError.value = result.name
- return
- }
- Log.i("[Assistant] [Phone Account Creation] Phone number is ${accountCreator.phoneNumber}")
-
- if (useUsername.value == true) {
- accountCreator.username = username.value
- } else {
- accountCreator.username = accountCreator.phoneNumber
- }
-
- if (useUsername.value == true) {
- checkUsername()
- } else {
- checkPhoneNumber()
- }
- }
-
- override fun onFlexiApiTokenRequestError() {
- Log.e("[Assistant] [Phone Account Creation] Failed to get an auth token from FlexiAPI")
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: Failed to get an auth token from account manager server")
- }
-
- private fun checkUsername() {
- val status = accountCreator.isAccountExist
- Log.i("[Assistant] [Phone Account Creation] isAccountExist returned $status")
- if (status != AccountCreator.Status.RequestOk) {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
-
- private fun checkPhoneNumber() {
- val status = accountCreator.isAliasUsed
- Log.i("[Assistant] [Phone Account Creation] isAliasUsed returned $status")
- if (status != AccountCreator.Status.RequestOk) {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
-
- fun create() {
- val token = accountCreator.token.orEmpty()
- if (token.isNotEmpty()) {
- Log.i(
- "[Assistant] [Phone Account Creation] We already have an auth token from FlexiAPI [$token], continue"
- )
- onFlexiApiTokenReceived()
- } else {
- Log.i("[Assistant] [Phone Account Creation] Requesting an auth token from FlexiAPI")
- waitForServerAnswer.value = true
- requestFlexiApiToken()
- }
- }
-
- private fun isCreateButtonEnabled(): Boolean {
- val usernameRegexp = corePreferences.config.getString(
- "assistant",
- "username_regex",
- "^[a-z0-9+_.\\-]*\$"
- )
- return isPhoneNumberOk() && usernameRegexp != null &&
- (
- useUsername.value == false ||
- username.value.orEmpty().matches(Regex(usernameRegexp)) &&
- username.value.orEmpty().isNotEmpty() &&
- usernameError.value.orEmpty().isEmpty()
- )
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountLinkingViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountLinkingViewModel.kt
deleted file mode 100644
index 78c11c04e..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountLinkingViewModel.kt
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.*
-import org.linphone.core.AccountCreator
-import org.linphone.core.AccountCreatorListenerStub
-import org.linphone.core.tools.Log
-import org.linphone.utils.Event
-
-class PhoneAccountLinkingViewModelFactory(private val accountCreator: AccountCreator) :
- ViewModelProvider.NewInstanceFactory() {
-
- @Suppress("UNCHECKED_CAST")
- override fun create(modelClass: Class): T {
- return PhoneAccountLinkingViewModel(accountCreator) as T
- }
-}
-
-class PhoneAccountLinkingViewModel(accountCreator: AccountCreator) : AbstractPhoneViewModel(
- accountCreator
-) {
- val username = MutableLiveData()
-
- val allowSkip = MutableLiveData()
-
- val linkEnabled: MediatorLiveData = MediatorLiveData()
-
- val waitForServerAnswer = MutableLiveData()
-
- val leaveAssistantEvent = MutableLiveData>()
-
- val goToSmsValidationEvent = MutableLiveData>()
-
- val onErrorEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- private val listener = object : AccountCreatorListenerStub() {
- override fun onIsAliasUsed(
- creator: AccountCreator,
- status: AccountCreator.Status,
- response: String?
- ) {
- Log.i("[Assistant] [Phone Account Linking] onIsAliasUsed status is $status")
-
- when (status) {
- AccountCreator.Status.AliasNotExist -> {
- if (creator.linkAccount() != AccountCreator.Status.RequestOk) {
- Log.e("[Assistant] [Phone Account Linking] linkAccount status is $status")
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- AccountCreator.Status.AliasExist, AccountCreator.Status.AliasIsAccount -> {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- else -> {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- }
-
- override fun onLinkAccount(
- creator: AccountCreator,
- status: AccountCreator.Status,
- response: String?
- ) {
- Log.i("[Assistant] [Phone Account Linking] onLinkAccount status is $status")
- waitForServerAnswer.value = false
-
- when (status) {
- AccountCreator.Status.RequestOk -> {
- goToSmsValidationEvent.value = Event(true)
- }
- else -> {
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- }
- }
-
- init {
- accountCreator.addListener(listener)
-
- linkEnabled.value = false
- linkEnabled.addSource(prefix) {
- linkEnabled.value = isLinkButtonEnabled()
- }
- linkEnabled.addSource(phoneNumber) {
- linkEnabled.value = isLinkButtonEnabled()
- }
- linkEnabled.addSource(phoneNumberError) {
- linkEnabled.value = isLinkButtonEnabled()
- }
- linkEnabled.addSource(prefixError) {
- linkEnabled.value = isLinkButtonEnabled()
- }
- }
-
- override fun onCleared() {
- accountCreator.removeListener(listener)
- super.onCleared()
- }
-
- override fun onFlexiApiTokenReceived() {
- accountCreator.setPhoneNumber(phoneNumber.value, prefix.value)
- accountCreator.username = username.value
- Log.i("[Assistant] [Phone Account Linking] Phone number is ${accountCreator.phoneNumber}")
-
- val status: AccountCreator.Status = accountCreator.isAliasUsed
- Log.i("[Assistant] [Phone Account Linking] isAliasUsed returned $status")
- if (status != AccountCreator.Status.RequestOk) {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
-
- override fun onFlexiApiTokenRequestError() {
- Log.e("[Assistant] [Phone Account Linking] Failed to get an auth token from FlexiAPI")
- waitForServerAnswer.value = false
- }
-
- fun link() {
- Log.i("[Assistant] [Phone Account Linking] Requesting an auth token from FlexiAPI")
- waitForServerAnswer.value = true
- requestFlexiApiToken()
- }
-
- fun skip() {
- leaveAssistantEvent.value = Event(true)
- }
-
- private fun isLinkButtonEnabled(): Boolean {
- return isPhoneNumberOk()
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountValidationViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountValidationViewModel.kt
deleted file mode 100644
index cf1f3f787..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountValidationViewModel.kt
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.core.AccountCreator
-import org.linphone.core.AccountCreatorListenerStub
-import org.linphone.core.tools.Log
-import org.linphone.utils.Event
-
-class PhoneAccountValidationViewModelFactory(private val accountCreator: AccountCreator) :
- ViewModelProvider.NewInstanceFactory() {
-
- @Suppress("UNCHECKED_CAST")
- override fun create(modelClass: Class): T {
- return PhoneAccountValidationViewModel(accountCreator) as T
- }
-}
-
-class PhoneAccountValidationViewModel(val accountCreator: AccountCreator) : ViewModel() {
- val phoneNumber = MutableLiveData()
-
- val code = MutableLiveData()
-
- val isLogin = MutableLiveData()
-
- val isCreation = MutableLiveData()
-
- val isLinking = MutableLiveData()
-
- val waitForServerAnswer = MutableLiveData()
-
- val leaveAssistantEvent = MutableLiveData>()
-
- val onErrorEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val listener = object : AccountCreatorListenerStub() {
- override fun onLoginLinphoneAccount(
- creator: AccountCreator,
- status: AccountCreator.Status,
- response: String?
- ) {
- Log.i("[Assistant] [Phone Account Validation] onLoginLinphoneAccount status is $status")
- waitForServerAnswer.value = false
-
- if (status == AccountCreator.Status.RequestOk) {
- if (createAccountAndAuthInfo()) {
- leaveAssistantEvent.value = Event(true)
- } else {
- onErrorEvent.value = Event("Error: Failed to create account object")
- }
- } else {
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
-
- override fun onActivateAlias(
- creator: AccountCreator,
- status: AccountCreator.Status,
- response: String?
- ) {
- Log.i("[Assistant] [Phone Account Validation] onActivateAlias status is $status")
- waitForServerAnswer.value = false
-
- when (status) {
- AccountCreator.Status.AccountActivated -> {
- leaveAssistantEvent.value = Event(true)
- }
- else -> {
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- }
-
- override fun onActivateAccount(
- creator: AccountCreator,
- status: AccountCreator.Status,
- response: String?
- ) {
- Log.i("[Assistant] [Phone Account Validation] onActivateAccount status is $status")
- waitForServerAnswer.value = false
-
- if (status == AccountCreator.Status.AccountActivated) {
- if (createAccountAndAuthInfo()) {
- leaveAssistantEvent.value = Event(true)
- } else {
- onErrorEvent.value = Event("Error: Failed to create account object")
- }
- } else {
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
- }
-
- init {
- accountCreator.addListener(listener)
- }
-
- override fun onCleared() {
- accountCreator.removeListener(listener)
- super.onCleared()
- }
-
- fun finish() {
- accountCreator.activationCode = code.value.orEmpty()
- Log.i(
- "[Assistant] [Phone Account Validation] Phone number is ${accountCreator.phoneNumber} and activation code is ${accountCreator.activationCode}"
- )
- waitForServerAnswer.value = true
-
- val status = when {
- isLogin.value == true -> accountCreator.loginLinphoneAccount()
- isCreation.value == true -> accountCreator.activateAccount()
- isLinking.value == true -> accountCreator.activateAlias()
- else -> AccountCreator.Status.UnexpectedError
- }
- Log.i("[Assistant] [Phone Account Validation] Code validation result is $status")
- if (status != AccountCreator.Status.RequestOk) {
- waitForServerAnswer.value = false
- onErrorEvent.value = Event("Error: ${status.name}")
- }
- }
-
- private fun createAccountAndAuthInfo(): Boolean {
- val account = accountCreator.createAccountInCore()
-
- if (account == null) {
- Log.e(
- "[Assistant] [Phone Account Validation] Account creator couldn't create account"
- )
- return false
- }
-
- val params = account.params.clone()
- params.pushNotificationAllowed = true
- account.params = params
-
- Log.i("[Assistant] [Phone Account Validation] Account created")
- return true
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/QrCodeViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/QrCodeViewModel.kt
deleted file mode 100644
index c0f988d0f..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/QrCodeViewModel.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.core.Core
-import org.linphone.core.CoreListenerStub
-import org.linphone.core.tools.Log
-import org.linphone.utils.Event
-
-class QrCodeViewModel : ViewModel() {
- val qrCodeFoundEvent = MutableLiveData>()
-
- val showSwitchCamera = MutableLiveData()
-
- private val listener = object : CoreListenerStub() {
- override fun onQrcodeFound(core: Core, result: String?) {
- Log.i("[Assistant] [QR Code] Found [$result]")
- if (result != null) qrCodeFoundEvent.postValue(Event(result))
- }
- }
-
- init {
- coreContext.core.addListener(listener)
- showSwitchCamera.value = coreContext.showSwitchCameraButton()
- }
-
- override fun onCleared() {
- coreContext.core.removeListener(listener)
- super.onCleared()
- }
-
- fun setBackCamera() {
- showSwitchCamera.value = coreContext.showSwitchCameraButton()
-
- for (camera in coreContext.core.videoDevicesList) {
- if (camera.contains("Back")) {
- Log.i("[Assistant] [QR Code] Found back facing camera: $camera")
- coreContext.core.videoDevice = camera
- return
- }
- }
-
- val first = coreContext.core.videoDevicesList.firstOrNull()
- if (first != null) {
- Log.i("[Assistant] [QR Code] Using first camera found: $first")
- coreContext.core.videoDevice = first
- }
- }
-
- fun switchCamera() {
- coreContext.switchCamera()
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/RemoteProvisioningViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/RemoteProvisioningViewModel.kt
deleted file mode 100644
index 2f8d75b90..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/RemoteProvisioningViewModel.kt
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.MediatorLiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.core.ConfiguringState
-import org.linphone.core.Core
-import org.linphone.core.CoreListenerStub
-import org.linphone.core.tools.Log
-import org.linphone.utils.Event
-
-class RemoteProvisioningViewModel : ViewModel() {
- val urlToFetch = MutableLiveData()
- val urlError = MutableLiveData()
-
- val fetchEnabled: MediatorLiveData = MediatorLiveData()
- val fetchInProgress = MutableLiveData()
- val fetchSuccessfulEvent = MutableLiveData>()
-
- private val listener = object : CoreListenerStub() {
- override fun onConfiguringStatus(
- core: Core,
- status: ConfiguringState,
- message: String?
- ) {
- fetchInProgress.value = false
- when (status) {
- ConfiguringState.Successful -> {
- fetchSuccessfulEvent.value = Event(true)
- }
- ConfiguringState.Failed -> {
- fetchSuccessfulEvent.value = Event(false)
- }
- else -> {}
- }
- }
- }
-
- init {
- fetchInProgress.value = false
- coreContext.core.addListener(listener)
-
- fetchEnabled.value = false
- fetchEnabled.addSource(urlToFetch) {
- fetchEnabled.value = isFetchEnabled()
- }
- fetchEnabled.addSource(urlError) {
- fetchEnabled.value = isFetchEnabled()
- }
- }
-
- override fun onCleared() {
- coreContext.core.removeListener(listener)
- super.onCleared()
- }
-
- fun fetchAndApply() {
- val url = urlToFetch.value.orEmpty()
- coreContext.core.provisioningUri = url
- Log.w("[Assistant] [Remote Provisioning] Url set to [$url], restarting Core")
- fetchInProgress.value = true
- coreContext.core.stop()
- coreContext.core.start()
- }
-
- private fun isFetchEnabled(): Boolean {
- return urlToFetch.value.orEmpty().isNotEmpty() && urlError.value.orEmpty().isEmpty()
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/SharedAssistantViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/SharedAssistantViewModel.kt
deleted file mode 100644
index d97bdf1b7..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/SharedAssistantViewModel.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import java.util.*
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.LinphoneApplication.Companion.corePreferences
-import org.linphone.core.*
-import org.linphone.core.tools.Log
-
-class SharedAssistantViewModel : ViewModel() {
- val remoteProvisioningUrl = MutableLiveData()
-
- private var accountCreator: AccountCreator
- private var useGenericSipAccount: Boolean = false
-
- init {
- Log.i("[Assistant] Loading linphone default values")
- coreContext.core.loadConfigFromXml(corePreferences.linphoneDefaultValuesPath)
- accountCreator = coreContext.core.createAccountCreator(corePreferences.xmlRpcServerUrl)
- accountCreator.language = Locale.getDefault().language
- }
-
- fun getAccountCreator(genericAccountCreator: Boolean = false): AccountCreator {
- if (genericAccountCreator != useGenericSipAccount) {
- accountCreator.reset()
- accountCreator.language = Locale.getDefault().language
-
- if (genericAccountCreator) {
- Log.i("[Assistant] Loading default values")
- coreContext.core.loadConfigFromXml(corePreferences.defaultValuesPath)
- } else {
- Log.i("[Assistant] Loading linphone default values")
- coreContext.core.loadConfigFromXml(corePreferences.linphoneDefaultValuesPath)
- }
- useGenericSipAccount = genericAccountCreator
- }
- return accountCreator
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/WelcomeViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/WelcomeViewModel.kt
deleted file mode 100644
index d31a2ba89..000000000
--- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/WelcomeViewModel.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.assistant.viewmodels
-
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import org.linphone.LinphoneApplication.Companion.corePreferences
-
-class WelcomeViewModel : ViewModel() {
- val showCreateAccount: Boolean = corePreferences.showCreateAccount
- val showLinphoneLogin: Boolean = corePreferences.showLinphoneLogin
- val showGenericLogin: Boolean = corePreferences.showGenericLogin
- val showRemoteProvisioning: Boolean = corePreferences.showRemoteProvisioning
-
- val termsAndPrivacyAccepted = MutableLiveData()
-
- init {
- termsAndPrivacyAccepted.value = corePreferences.readAndAgreeTermsAndPrivacy
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/chat_bubble/ChatBubbleActivity.kt b/app/src/main/java/org/linphone/activities/chat_bubble/ChatBubbleActivity.kt
deleted file mode 100644
index ddcdefa5b..000000000
--- a/app/src/main/java/org/linphone/activities/chat_bubble/ChatBubbleActivity.kt
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (c) 2010-2021 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.chat_bubble
-
-import android.content.Intent
-import android.os.Bundle
-import android.widget.Toast
-import androidx.databinding.DataBindingUtil
-import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.lifecycleScope
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.R
-import org.linphone.activities.GenericActivity
-import org.linphone.activities.main.MainActivity
-import org.linphone.activities.main.chat.adapters.ChatMessagesListAdapter
-import org.linphone.activities.main.chat.viewmodels.*
-import org.linphone.activities.main.viewmodels.ListTopBarViewModel
-import org.linphone.core.ChatRoom
-import org.linphone.core.ChatRoomListenerStub
-import org.linphone.core.EventLog
-import org.linphone.core.Factory
-import org.linphone.core.tools.Log
-import org.linphone.databinding.ChatBubbleActivityBinding
-import org.linphone.utils.FileUtils
-
-class ChatBubbleActivity : GenericActivity() {
- private lateinit var binding: ChatBubbleActivityBinding
- private lateinit var viewModel: ChatRoomViewModel
- private lateinit var listViewModel: ChatMessagesListViewModel
- private lateinit var chatSendingViewModel: ChatMessageSendingViewModel
- private lateinit var adapter: ChatMessagesListAdapter
-
- private val observer = object : RecyclerView.AdapterDataObserver() {
- override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
- if (positionStart == adapter.itemCount - itemCount) {
- adapter.notifyItemChanged(positionStart - 1) // For grouping purposes
- scrollToBottom()
- }
- }
- }
-
- private val listener = object : ChatRoomListenerStub() {
- override fun onChatMessagesReceived(chatRoom: ChatRoom, eventLogs: Array) {
- chatRoom.markAsRead()
- }
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- binding = DataBindingUtil.setContentView(this, R.layout.chat_bubble_activity)
- binding.lifecycleOwner = this
-
- val localSipUri = intent.getStringExtra("LocalSipUri")
- val remoteSipUri = intent.getStringExtra("RemoteSipUri")
- var chatRoom: ChatRoom? = null
-
- if (localSipUri != null && remoteSipUri != null) {
- Log.i(
- "[Chat Bubble] Found local [$localSipUri] & remote [$remoteSipUri] addresses in arguments"
- )
- val localAddress = Factory.instance().createAddress(localSipUri)
- val remoteSipAddress = Factory.instance().createAddress(remoteSipUri)
- chatRoom = coreContext.core.searchChatRoom(
- null,
- localAddress,
- remoteSipAddress,
- arrayOfNulls(
- 0
- )
- )
- }
-
- if (chatRoom == null) {
- Log.e("[Chat Bubble] Chat room is null, aborting!")
- finish()
- return
- }
-
- viewModel = ViewModelProvider(
- this,
- ChatRoomViewModelFactory(chatRoom)
- )[ChatRoomViewModel::class.java]
- binding.viewModel = viewModel
-
- listViewModel = ViewModelProvider(
- this,
- ChatMessagesListViewModelFactory(chatRoom)
- )[ChatMessagesListViewModel::class.java]
-
- chatSendingViewModel = ViewModelProvider(
- this,
- ChatMessageSendingViewModelFactory(chatRoom)
- )[ChatMessageSendingViewModel::class.java]
- binding.chatSendingViewModel = chatSendingViewModel
-
- val listSelectionViewModel = ViewModelProvider(this)[ListTopBarViewModel::class.java]
- adapter = ChatMessagesListAdapter(listSelectionViewModel, this)
- // SubmitList is done on a background thread
- // We need this adapter data observer to know when to scroll
- binding.chatMessagesList.adapter = adapter
- adapter.registerAdapterDataObserver(observer)
-
- // Disable context menu on each message
- adapter.disableAdvancedContextMenuOptions()
-
- adapter.openContentEvent.observe(
- this
- ) {
- it.consume { content ->
- if (content.isFileEncrypted) {
- Toast.makeText(
- this,
- R.string.chat_bubble_cant_open_enrypted_file,
- Toast.LENGTH_LONG
- ).show()
- } else {
- FileUtils.openFileInThirdPartyApp(this, content.filePath.orEmpty(), true)
- }
- }
- }
-
- val layoutManager = LinearLayoutManager(this)
- layoutManager.stackFromEnd = true
- binding.chatMessagesList.layoutManager = layoutManager
-
- listViewModel.events.observe(
- this
- ) { events ->
- adapter.submitList(events)
- }
-
- chatSendingViewModel.textToSend.observe(
- this
- ) {
- chatSendingViewModel.onTextToSendChanged(it)
- }
-
- binding.setOpenAppClickListener {
- coreContext.notificationsManager.currentlyDisplayedChatRoomAddress = null
- coreContext.notificationsManager.changeDismissNotificationUponReadForChatRoom(
- viewModel.chatRoom,
- false
- )
-
- val intent = Intent(this, MainActivity::class.java)
- intent.putExtra("RemoteSipUri", remoteSipUri)
- intent.putExtra("LocalSipUri", localSipUri)
- intent.putExtra("Chat", true)
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK and Intent.FLAG_ACTIVITY_CLEAR_TASK)
- startActivity(intent)
- }
-
- binding.setCloseBubbleClickListener {
- coreContext.notificationsManager.dismissChatNotification(viewModel.chatRoom)
- }
-
- binding.setSendMessageClickListener {
- chatSendingViewModel.sendMessage()
- binding.message.text?.clear()
- }
- }
-
- override fun onResume() {
- super.onResume()
-
- viewModel.chatRoom.addListener(listener)
-
- // Workaround for the removed notification when a chat room is marked as read
- coreContext.notificationsManager.changeDismissNotificationUponReadForChatRoom(
- viewModel.chatRoom,
- true
- )
- viewModel.chatRoom.markAsRead()
-
- val peerAddress = viewModel.chatRoom.peerAddress.asStringUriOnly()
- coreContext.notificationsManager.currentlyDisplayedChatRoomAddress = peerAddress
- coreContext.notificationsManager.resetChatNotificationCounterForSipUri(peerAddress)
-
- lifecycleScope.launch {
- // Without the delay the scroll to bottom doesn't happen...
- delay(100)
- scrollToBottom()
- }
- }
-
- override fun onPause() {
- viewModel.chatRoom.removeListener(listener)
-
- coreContext.notificationsManager.currentlyDisplayedChatRoomAddress = null
- coreContext.notificationsManager.changeDismissNotificationUponReadForChatRoom(
- viewModel.chatRoom,
- false
- )
-
- super.onPause()
- }
-
- private fun scrollToBottom() {
- if (adapter.itemCount > 0) {
- binding.chatMessagesList.scrollToPosition(adapter.itemCount - 1)
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/MainActivity.kt b/app/src/main/java/org/linphone/activities/main/MainActivity.kt
deleted file mode 100644
index 78798c4c0..000000000
--- a/app/src/main/java/org/linphone/activities/main/MainActivity.kt
+++ /dev/null
@@ -1,740 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main
-
-import android.app.Dialog
-import android.content.ComponentCallbacks2
-import android.content.Context
-import android.content.Intent
-import android.content.res.Configuration
-import android.net.Uri
-import android.os.Bundle
-import android.os.Parcelable
-import android.view.Gravity
-import android.view.MotionEvent
-import android.view.View
-import android.view.inputmethod.InputMethodManager
-import androidx.annotation.StringRes
-import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
-import androidx.core.view.doOnAttach
-import androidx.databinding.DataBindingUtil
-import androidx.fragment.app.FragmentContainerView
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.lifecycleScope
-import androidx.navigation.NavController
-import androidx.navigation.NavDestination
-import androidx.navigation.findNavController
-import androidx.window.layout.FoldingFeature
-import coil.imageLoader
-import com.google.android.material.snackbar.Snackbar
-import java.io.UnsupportedEncodingException
-import java.net.URLDecoder
-import kotlin.math.abs
-import kotlinx.coroutines.*
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.LinphoneApplication.Companion.corePreferences
-import org.linphone.R
-import org.linphone.activities.*
-import org.linphone.activities.assistant.AssistantActivity
-import org.linphone.activities.main.viewmodels.CallOverlayViewModel
-import org.linphone.activities.main.viewmodels.DialogViewModel
-import org.linphone.activities.main.viewmodels.SharedMainViewModel
-import org.linphone.activities.navigateToDialer
-import org.linphone.compatibility.Compatibility
-import org.linphone.contact.ContactsUpdatedListenerStub
-import org.linphone.core.AuthInfo
-import org.linphone.core.AuthMethod
-import org.linphone.core.Core
-import org.linphone.core.CoreListenerStub
-import org.linphone.core.CorePreferences
-import org.linphone.core.tools.Log
-import org.linphone.databinding.MainActivityBinding
-import org.linphone.utils.*
-
-class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestinationChangedListener {
- private lateinit var binding: MainActivityBinding
- private lateinit var sharedViewModel: SharedMainViewModel
- private lateinit var callOverlayViewModel: CallOverlayViewModel
-
- private val listener = object : ContactsUpdatedListenerStub() {
- override fun onContactsUpdated() {
- Log.i("[Main Activity] Contact(s) updated, update shortcuts")
- if (corePreferences.contactsShortcuts) {
- ShortcutsHelper.createShortcutsToContacts(this@MainActivity)
- } else if (corePreferences.chatRoomShortcuts) {
- ShortcutsHelper.createShortcutsToChatRooms(this@MainActivity)
- }
- }
- }
-
- private lateinit var tabsFragment: FragmentContainerView
- private lateinit var statusFragment: FragmentContainerView
-
- private var overlayX = 0f
- private var overlayY = 0f
- private var initPosX = 0f
- private var initPosY = 0f
- private var overlay: View? = null
-
- private val componentCallbacks = object : ComponentCallbacks2 {
- override fun onConfigurationChanged(newConfig: Configuration) { }
-
- override fun onLowMemory() {
- Log.w("[Main Activity] onLowMemory !")
- }
-
- override fun onTrimMemory(level: Int) {
- Log.w("[Main Activity] onTrimMemory called with level $level !")
- applicationContext.imageLoader.memoryCache?.clear()
- }
- }
-
- override fun onLayoutChanges(foldingFeature: FoldingFeature?) {
- sharedViewModel.layoutChangedEvent.value = Event(true)
- }
-
- private var shouldTabsBeVisibleDependingOnDestination = true
- private var shouldTabsBeVisibleDueToOrientationAndKeyboard = true
-
- private val authenticationRequestedEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
- private var authenticationRequiredDialog: Dialog? = null
-
- private val coreListener: CoreListenerStub = object : CoreListenerStub() {
- override fun onAuthenticationRequested(core: Core, authInfo: AuthInfo, method: AuthMethod) {
- if (authInfo.username == null || authInfo.domain == null || authInfo.realm == null) {
- return
- }
-
- Log.w(
- "[Main Activity] Authentication requested for account [${authInfo.username}@${authInfo.domain}] with realm [${authInfo.realm}] using method [$method]"
- )
- authenticationRequestedEvent.value = Event(authInfo)
- }
- }
-
- private val keyboardVisibilityListeners = arrayListOf()
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- // Must be done before the setContentView
- installSplashScreen()
-
- binding = DataBindingUtil.setContentView(this, R.layout.main_activity)
- binding.lifecycleOwner = this
-
- sharedViewModel = ViewModelProvider(this)[SharedMainViewModel::class.java]
- binding.viewModel = sharedViewModel
-
- callOverlayViewModel = ViewModelProvider(this)[CallOverlayViewModel::class.java]
- binding.callOverlayViewModel = callOverlayViewModel
-
- sharedViewModel.toggleDrawerEvent.observe(
- this
- ) {
- it.consume {
- if (binding.sideMenu.isDrawerOpen(Gravity.LEFT)) {
- binding.sideMenu.closeDrawer(binding.sideMenuContent, true)
- } else {
- binding.sideMenu.openDrawer(binding.sideMenuContent, true)
- }
- }
- }
-
- coreContext.callErrorMessageResourceId.observe(
- this
- ) {
- it.consume { message ->
- showSnackBar(message)
- }
- }
-
- authenticationRequestedEvent.observe(
- this
- ) {
- it.consume { authInfo ->
- showAuthenticationRequestedDialog(authInfo)
- }
- }
-
- if (coreContext.core.accountList.isEmpty()) {
- if (corePreferences.firstStart) {
- startActivity(Intent(this, AssistantActivity::class.java))
- }
- }
-
- tabsFragment = findViewById(R.id.tabs_fragment)
- statusFragment = findViewById(R.id.status_fragment)
-
- binding.root.doOnAttach {
- Log.i("[Main Activity] Report UI has been fully drawn (TTFD)")
- try {
- reportFullyDrawn()
- } catch (se: SecurityException) {
- Log.e("[Main Activity] Security exception when doing reportFullyDrawn(): $se")
- }
- }
- }
-
- override fun onNewIntent(intent: Intent?) {
- super.onNewIntent(intent)
-
- if (intent != null) {
- Log.d("[Main Activity] Found new intent")
- handleIntentParams(intent)
- }
- }
-
- override fun onResume() {
- super.onResume()
- coreContext.contactsManager.addListener(listener)
- coreContext.core.addListener(coreListener)
- }
-
- override fun onPause() {
- coreContext.core.removeListener(coreListener)
- coreContext.contactsManager.removeListener(listener)
- super.onPause()
- }
-
- override fun showSnackBar(@StringRes resourceId: Int) {
- Snackbar.make(findViewById(R.id.coordinator), resourceId, Snackbar.LENGTH_LONG).show()
- }
-
- override fun showSnackBar(@StringRes resourceId: Int, action: Int, listener: () -> Unit) {
- Snackbar
- .make(findViewById(R.id.coordinator), resourceId, Snackbar.LENGTH_LONG)
- .setAction(action) {
- Log.i("[Snack Bar] Action listener triggered")
- listener()
- }
- .show()
- }
-
- override fun showSnackBar(message: String) {
- Snackbar.make(findViewById(R.id.coordinator), message, Snackbar.LENGTH_LONG).show()
- }
-
- override fun onPostCreate(savedInstanceState: Bundle?) {
- super.onPostCreate(savedInstanceState)
-
- registerComponentCallbacks(componentCallbacks)
- findNavController(R.id.nav_host_fragment).addOnDestinationChangedListener(this)
-
- binding.rootCoordinatorLayout.setKeyboardInsetListener { keyboardVisible ->
- val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE
- Log.i(
- "[Main Activity] Keyboard is ${if (keyboardVisible) "visible" else "invisible"}, orientation is ${if (portraitOrientation) "portrait" else "landscape"}"
- )
- shouldTabsBeVisibleDueToOrientationAndKeyboard = !portraitOrientation || !keyboardVisible
- updateTabsFragmentVisibility()
-
- for (listener in keyboardVisibilityListeners) {
- listener.onKeyboardVisibilityChanged(keyboardVisible)
- }
- }
-
- initOverlay()
-
- if (intent != null) {
- Log.d("[Main Activity] Found post create intent")
- handleIntentParams(intent)
- }
- }
-
- override fun onDestroy() {
- findNavController(R.id.nav_host_fragment).removeOnDestinationChangedListener(this)
- unregisterComponentCallbacks(componentCallbacks)
- super.onDestroy()
- }
-
- override fun onDestinationChanged(
- controller: NavController,
- destination: NavDestination,
- arguments: Bundle?
- ) {
- hideKeyboard()
- if (statusFragment.visibility == View.GONE) {
- statusFragment.visibility = View.VISIBLE
- }
-
- shouldTabsBeVisibleDependingOnDestination = when (destination.id) {
- R.id.masterCallLogsFragment, R.id.masterContactsFragment, R.id.dialerFragment, R.id.masterChatRoomsFragment ->
- true
- else -> false
- }
- updateTabsFragmentVisibility()
- }
-
- fun addKeyboardVisibilityListener(listener: AppUtils.KeyboardVisibilityListener) {
- keyboardVisibilityListeners.add(listener)
- }
-
- fun removeKeyboardVisibilityListener(listener: AppUtils.KeyboardVisibilityListener) {
- keyboardVisibilityListeners.remove(listener)
- }
-
- fun hideKeyboard() {
- currentFocus?.hideKeyboard()
- }
-
- fun showKeyboard() {
- // Requires a text field to have the focus
- if (currentFocus != null) {
- (getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
- .showSoftInput(currentFocus, 0)
- } else {
- Log.w("[Main Activity] Can't show the keyboard, no focused view")
- }
- }
-
- fun hideStatusFragment(hide: Boolean) {
- statusFragment.visibility = if (hide) View.GONE else View.VISIBLE
- }
-
- private fun updateTabsFragmentVisibility() {
- tabsFragment.visibility = if (shouldTabsBeVisibleDependingOnDestination && shouldTabsBeVisibleDueToOrientationAndKeyboard) View.VISIBLE else View.GONE
- }
-
- private fun handleIntentParams(intent: Intent) {
- Log.i(
- "[Main Activity] Handling intent with action [${intent.action}], type [${intent.type}] and data [${intent.data}]"
- )
-
- when (intent.action) {
- Intent.ACTION_MAIN -> handleMainIntent(intent)
- Intent.ACTION_SEND, Intent.ACTION_SENDTO -> {
- if (intent.type == "text/plain") {
- handleSendText(intent)
- } else {
- lifecycleScope.launch {
- handleSendFile(intent)
- }
- }
- }
- Intent.ACTION_SEND_MULTIPLE -> {
- lifecycleScope.launch {
- handleSendMultipleFiles(intent)
- }
- }
- Intent.ACTION_VIEW -> {
- val uri = intent.data
- if (uri != null) {
- if (
- intent.type == AppUtils.getString(R.string.linphone_address_mime_type) &&
- PermissionHelper.get().hasReadContactsPermission()
- ) {
- val contactId =
- coreContext.contactsManager.getAndroidContactIdFromUri(uri)
- if (contactId != null) {
- Log.i("[Main Activity] Found contact URI parameter in intent: $uri")
- navigateToContact(contactId)
- }
- } else {
- val stringUri = uri.toString()
- if (stringUri.startsWith("linphone-config:")) {
- val remoteConfigUri = stringUri.substring("linphone-config:".length)
- if (corePreferences.autoRemoteProvisioningOnConfigUriHandler) {
- Log.w(
- "[Main Activity] Remote provisioning URL set to [$remoteConfigUri], restarting Core now"
- )
- applyRemoteProvisioning(remoteConfigUri)
- } else {
- Log.i(
- "[Main Activity] Remote provisioning URL found [$remoteConfigUri], asking for user validation"
- )
- showAcceptRemoteConfigurationDialog(remoteConfigUri)
- }
- } else {
- handleTelOrSipUri(uri)
- }
- }
- }
- }
- Intent.ACTION_DIAL, Intent.ACTION_CALL -> {
- val uri = intent.data
- if (uri != null) {
- handleTelOrSipUri(uri)
- }
- }
- Intent.ACTION_VIEW_LOCUS -> {
- if (corePreferences.disableChat) return
- val locus = Compatibility.extractLocusIdFromIntent(intent)
- if (locus != null) {
- Log.i("[Main Activity] Found chat room locus intent extra: $locus")
- handleLocusOrShortcut(locus)
- }
- }
- else -> handleMainIntent(intent)
- }
-
- // Prevent this intent to be processed again
- intent.action = null
- intent.data = null
- val extras = intent.extras
- if (extras != null) {
- for (key in extras.keySet()) {
- intent.removeExtra(key)
- }
- }
- }
-
- private fun handleMainIntent(intent: Intent) {
- when {
- intent.hasExtra("ContactId") -> {
- val id = intent.getStringExtra("ContactId")
- Log.i("[Main Activity] Found contact ID in extras: $id")
- navigateToContact(id)
- }
- intent.hasExtra("Chat") -> {
- if (corePreferences.disableChat) return
-
- if (intent.hasExtra("RemoteSipUri") && intent.hasExtra("LocalSipUri")) {
- val peerAddress = intent.getStringExtra("RemoteSipUri")
- val localAddress = intent.getStringExtra("LocalSipUri")
- Log.i(
- "[Main Activity] Found chat room intent extra: local SIP URI=[$localAddress], peer SIP URI=[$peerAddress]"
- )
- navigateToChatRoom(localAddress, peerAddress)
- } else {
- Log.i("[Main Activity] Found chat intent extra, go to chat rooms list")
- navigateToChatRooms()
- }
- }
- intent.hasExtra("Dialer") -> {
- Log.i("[Main Activity] Found dialer intent extra, go to dialer")
- val isTransfer = intent.getBooleanExtra("Transfer", false)
- sharedViewModel.pendingCallTransfer = isTransfer
- navigateToDialer()
- }
- intent.hasExtra("Contacts") -> {
- Log.i("[Main Activity] Found contacts intent extra, go to contacts list")
- val isTransfer = intent.getBooleanExtra("Transfer", false)
- sharedViewModel.pendingCallTransfer = isTransfer
- navigateToContacts()
- }
- else -> {
- val core = coreContext.core
- val call = core.currentCall ?: core.calls.firstOrNull()
- if (call != null) {
- Log.i(
- "[Main Activity] Launcher clicked while there is at least one active call, go to CallActivity"
- )
- val callIntent = Intent(
- this,
- org.linphone.activities.voip.CallActivity::class.java
- )
- callIntent.addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
- )
- startActivity(callIntent)
- }
- }
- }
- }
-
- private fun handleTelOrSipUri(uri: Uri) {
- Log.i("[Main Activity] Found uri: $uri to call")
- val stringUri = uri.toString()
- var addressToCall: String = stringUri
-
- when {
- addressToCall.startsWith("tel:") -> {
- Log.i("[Main Activity] Removing tel: prefix")
- addressToCall = addressToCall.substring("tel:".length)
- }
- addressToCall.startsWith("linphone:") -> {
- Log.i("[Main Activity] Removing linphone: prefix")
- addressToCall = addressToCall.substring("linphone:".length)
- }
- addressToCall.startsWith("sip-linphone:") -> {
- Log.i("[Main Activity] Removing linphone: sip-linphone")
- addressToCall = addressToCall.substring("sip-linphone:".length)
- }
- }
-
- addressToCall = addressToCall.replace("%40", "@")
-
- val address = coreContext.core.interpretUrl(
- addressToCall,
- LinphoneUtils.applyInternationalPrefix()
- )
- if (address != null) {
- addressToCall = address.asStringUriOnly()
- }
-
- Log.i("[Main Activity] Starting dialer with pre-filled URI $addressToCall")
- val args = Bundle()
- args.putString("URI", addressToCall)
- navigateToDialer(args)
- }
-
- private fun handleSendText(intent: Intent) {
- if (corePreferences.disableChat) return
-
- intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
- sharedViewModel.textToShare.value = it
- }
-
- handleSendChatRoom(intent)
- }
-
- private suspend fun handleSendFile(intent: Intent) {
- if (corePreferences.disableChat) return
-
- Log.i("[Main Activity] Found single file to share with type ${intent.type}")
-
- (intent.getParcelableExtra(Intent.EXTRA_STREAM) as? Uri)?.let {
- val list = arrayListOf()
- coroutineScope {
- val deferred = async {
- FileUtils.getFilePath(this@MainActivity, it)
- }
- val path = deferred.await()
- if (path != null) {
- list.add(path)
- Log.i("[Main Activity] Found single file to share: $path")
- }
- }
- sharedViewModel.filesToShare.value = list
- }
-
- // Check that the current fragment hasn't already handled the event on filesToShare
- // If it has, don't go further.
- // For example this may happen when picking a GIF from the keyboard while inside a chat room
- if (!sharedViewModel.filesToShare.value.isNullOrEmpty()) {
- handleSendChatRoom(intent)
- }
- }
-
- private suspend fun handleSendMultipleFiles(intent: Intent) {
- if (corePreferences.disableChat) return
-
- intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM)?.let {
- val list = arrayListOf()
- coroutineScope {
- val deferred = arrayListOf>()
- for (parcelable in it) {
- val uri = parcelable as Uri
- deferred.add(async { FileUtils.getFilePath(this@MainActivity, uri) })
- }
- val paths = deferred.awaitAll()
- for (path in paths) {
- Log.i("[Main Activity] Found file to share: $path")
- if (path != null) list.add(path)
- }
- }
- sharedViewModel.filesToShare.value = list
- }
-
- handleSendChatRoom(intent)
- }
-
- private fun handleSendChatRoom(intent: Intent) {
- if (corePreferences.disableChat) return
-
- val uri = intent.data
- if (uri != null) {
- Log.i("[Main Activity] Found uri: $uri to send a message to")
- val stringUri = uri.toString()
- var addressToIM: String = stringUri
- try {
- addressToIM = URLDecoder.decode(stringUri, "UTF-8")
- } catch (e: UnsupportedEncodingException) {
- Log.e("[Main Activity] UnsupportedEncodingException: $e")
- }
-
- when {
- addressToIM.startsWith("sms:") ->
- addressToIM = addressToIM.substring("sms:".length)
- addressToIM.startsWith("smsto:") ->
- addressToIM = addressToIM.substring("smsto:".length)
- addressToIM.startsWith("mms:") ->
- addressToIM = addressToIM.substring("mms:".length)
- addressToIM.startsWith("mmsto:") ->
- addressToIM = addressToIM.substring("mmsto:".length)
- }
-
- val localAddress =
- coreContext.core.defaultAccount?.params?.identityAddress?.asStringUriOnly()
- val peerAddress = coreContext.core.interpretUrl(
- addressToIM,
- LinphoneUtils.applyInternationalPrefix()
- )?.asStringUriOnly()
- Log.i(
- "[Main Activity] Navigating to chat room with local [$localAddress] and peer [$peerAddress] addresses"
- )
- navigateToChatRoom(localAddress, peerAddress)
- } else {
- val shortcutId = intent.getStringExtra("android.intent.extra.shortcut.ID") // Intent.EXTRA_SHORTCUT_ID
- if (shortcutId != null) {
- Log.i("[Main Activity] Found shortcut ID: $shortcutId")
- handleLocusOrShortcut(shortcutId)
- } else {
- Log.i("[Main Activity] Going into chat rooms list")
- navigateToChatRooms()
- }
- }
- }
-
- private fun handleLocusOrShortcut(id: String) {
- val split = id.split("~")
- if (split.size == 2) {
- val localAddress = split[0]
- val peerAddress = split[1]
- Log.i(
- "[Main Activity] Navigating to chat room with local [$localAddress] and peer [$peerAddress] addresses, computed from shortcut/locus id"
- )
- navigateToChatRoom(localAddress, peerAddress)
- } else {
- Log.e(
- "[Main Activity] Failed to parse shortcut/locus id: $id, going to chat rooms list"
- )
- navigateToChatRooms()
- }
- }
-
- private fun initOverlay() {
- overlay = binding.root.findViewById(R.id.call_overlay)
- val callOverlay = overlay
- callOverlay ?: return
-
- callOverlay.setOnTouchListener { view, event ->
- when (event.action) {
- MotionEvent.ACTION_DOWN -> {
- overlayX = view.x - event.rawX
- overlayY = view.y - event.rawY
- initPosX = view.x
- initPosY = view.y
- }
- MotionEvent.ACTION_MOVE -> {
- view.animate()
- .x(event.rawX + overlayX)
- .y(event.rawY + overlayY)
- .setDuration(0)
- .start()
- }
- MotionEvent.ACTION_UP -> {
- if (abs(initPosX - view.x) < CorePreferences.OVERLAY_CLICK_SENSITIVITY &&
- abs(initPosY - view.y) < CorePreferences.OVERLAY_CLICK_SENSITIVITY
- ) {
- view.performClick()
- }
- }
- else -> return@setOnTouchListener false
- }
- true
- }
-
- callOverlay.setOnClickListener {
- coreContext.onCallOverlayClick()
- }
- }
-
- private fun applyRemoteProvisioning(remoteConfigUri: String) {
- coreContext.core.provisioningUri = remoteConfigUri
- coreContext.core.stop()
- coreContext.core.start()
- }
-
- private fun showAcceptRemoteConfigurationDialog(remoteConfigUri: String) {
- val dialogViewModel = DialogViewModel(
- remoteConfigUri,
- getString(R.string.dialog_apply_remote_provisioning_title)
- )
- val dialog = DialogUtils.getDialog(this, dialogViewModel)
-
- dialogViewModel.showCancelButton {
- Log.i("[Main Activity] User cancelled remote provisioning config")
- dialog.dismiss()
- }
-
- val okLabel = getString(
- R.string.dialog_apply_remote_provisioning_button
- )
- dialogViewModel.showOkButton(
- {
- Log.w(
- "[Main Activity] Remote provisioning URL set to [$remoteConfigUri], restarting Core now"
- )
- applyRemoteProvisioning(remoteConfigUri)
- dialog.dismiss()
- },
- okLabel
- )
-
- dialog.show()
- }
-
- private fun showAuthenticationRequestedDialog(
- authInfo: AuthInfo
- ) {
- authenticationRequiredDialog?.dismiss()
-
- val accountFound = coreContext.core.accountList.find {
- it.params.identityAddress?.username == authInfo.username && it.params.identityAddress?.domain == authInfo.domain
- }
- if (accountFound == null) {
- Log.w("[Main Activity] Failed to find account matching auth info, aborting auth dialog")
- return
- }
-
- val identity = "${authInfo.username}@${authInfo.domain}"
- Log.i("[Main Activity] Showing authentication required dialog for account [$identity]")
-
- val dialogViewModel = DialogViewModel(
- getString(R.string.dialog_authentication_required_message, identity),
- getString(R.string.dialog_authentication_required_title)
- )
- dialogViewModel.showPassword = true
- dialogViewModel.passwordTitle = getString(
- R.string.settings_password_protection_dialog_input_hint
- )
- val dialog = DialogUtils.getDialog(this, dialogViewModel)
-
- dialogViewModel.showCancelButton {
- dialog.dismiss()
- authenticationRequiredDialog = null
- }
-
- dialogViewModel.showOkButton(
- {
- Log.i(
- "[Main Activity] Updating password for account [$identity] using auth info [$authInfo]"
- )
- val newPassword = dialogViewModel.password
- authInfo.password = newPassword
- coreContext.core.addAuthInfo(authInfo)
-
- coreContext.core.refreshRegisters()
-
- dialog.dismiss()
- authenticationRequiredDialog = null
- },
- getString(R.string.dialog_authentication_required_change_password_label)
- )
-
- dialog.show()
- authenticationRequiredDialog = dialog
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/about/AboutFragment.kt b/app/src/main/java/org/linphone/activities/main/about/AboutFragment.kt
deleted file mode 100644
index e81703192..000000000
--- a/app/src/main/java/org/linphone/activities/main/about/AboutFragment.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.about
-
-import android.content.*
-import android.net.Uri
-import android.os.Bundle
-import android.view.View
-import androidx.lifecycle.ViewModelProvider
-import org.linphone.R
-import org.linphone.activities.main.fragments.SecureFragment
-import org.linphone.core.tools.Log
-import org.linphone.databinding.AboutFragmentBinding
-
-class AboutFragment : SecureFragment() {
- private lateinit var viewModel: AboutViewModel
-
- override fun getLayoutId(): Int = R.layout.about_fragment
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- viewModel = ViewModelProvider(this)[AboutViewModel::class.java]
- binding.viewModel = viewModel
-
- binding.setPrivacyPolicyClickListener {
- val browserIntent = Intent(
- Intent.ACTION_VIEW,
- Uri.parse(getString(R.string.about_privacy_policy_link))
- )
- try {
- startActivity(browserIntent)
- } catch (se: SecurityException) {
- Log.e("[About] Failed to start browser intent, $se")
- }
- }
-
- binding.setLicenseClickListener {
- val browserIntent = Intent(
- Intent.ACTION_VIEW,
- Uri.parse(getString(R.string.about_license_link))
- )
- try {
- startActivity(browserIntent)
- } catch (se: SecurityException) {
- Log.e("[About] Failed to start browser intent, $se")
- }
- }
-
- binding.setWeblateClickListener {
- val browserIntent = Intent(
- Intent.ACTION_VIEW,
- Uri.parse(getString(R.string.about_weblate_link))
- )
- try {
- startActivity(browserIntent)
- } catch (se: SecurityException) {
- Log.e("[About] Failed to start browser intent, $se")
- }
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/about/AboutViewModel.kt b/app/src/main/java/org/linphone/activities/main/about/AboutViewModel.kt
deleted file mode 100644
index 2961af522..000000000
--- a/app/src/main/java/org/linphone/activities/main/about/AboutViewModel.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.about
-
-import androidx.lifecycle.ViewModel
-import org.linphone.LinphoneApplication.Companion.coreContext
-
-class AboutViewModel : ViewModel() {
- val appVersion: String = coreContext.appVersion
-
- val sdkVersion: String = coreContext.sdkVersion
-}
diff --git a/app/src/main/java/org/linphone/activities/main/adapters/SelectionListAdapter.kt b/app/src/main/java/org/linphone/activities/main/adapters/SelectionListAdapter.kt
deleted file mode 100644
index e02070b29..000000000
--- a/app/src/main/java/org/linphone/activities/main/adapters/SelectionListAdapter.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.adapters
-
-import androidx.recyclerview.widget.DiffUtil
-import androidx.recyclerview.widget.ListAdapter
-import androidx.recyclerview.widget.RecyclerView
-import org.linphone.activities.main.viewmodels.ListTopBarViewModel
-
-abstract class SelectionListAdapter(
- selectionVM: ListTopBarViewModel,
- diff: DiffUtil.ItemCallback
-) :
- ListAdapter(diff) {
-
- private var _selectionViewModel: ListTopBarViewModel? = selectionVM
- protected val selectionViewModel get() = _selectionViewModel!!
-
- override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
- super.onDetachedFromRecyclerView(recyclerView)
- _selectionViewModel = null
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/chat/ChatScrollListener.kt b/app/src/main/java/org/linphone/activities/main/chat/ChatScrollListener.kt
deleted file mode 100644
index 795be99ed..000000000
--- a/app/src/main/java/org/linphone/activities/main/chat/ChatScrollListener.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.chat
-
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-
-internal abstract class ChatScrollListener(private val mLayoutManager: LinearLayoutManager) :
- RecyclerView.OnScrollListener() {
- // The total number of items in the data set after the last load
- private var previousTotalItemCount = 0
-
- // True if we are still waiting for the last set of data to load.
- private var loading = true
-
- private var userHasScrolledUp: Boolean = false
-
- // This happens many times a second during a scroll, so be wary of the code you place here.
- // We are given a few useful parameters to help us work out if we need to load some more data,
- // but first we check if we are waiting for the previous load to finish.
- override fun onScrolled(view: RecyclerView, dx: Int, dy: Int) {
- val totalItemCount = mLayoutManager.itemCount
- val firstVisibleItemPosition: Int = mLayoutManager.findFirstVisibleItemPosition()
- val lastVisibleItemPosition: Int = mLayoutManager.findLastVisibleItemPosition()
-
- // If the total item count is zero and the previous isn't, assume the
- // list is invalidated and should be reset back to initial state
- if (totalItemCount < previousTotalItemCount) {
- previousTotalItemCount = totalItemCount
- if (totalItemCount == 0) {
- loading = true
- }
- }
-
- // If it’s still loading, we check to see if the data set count has
- // changed, if so we conclude it has finished loading and update the current page
- // number and total item count.
- if (loading && totalItemCount > previousTotalItemCount) {
- loading = false
- previousTotalItemCount = totalItemCount
- }
-
- userHasScrolledUp = lastVisibleItemPosition != totalItemCount - 1
- if (userHasScrolledUp) {
- onScrolledUp()
- } else {
- onScrolledToEnd()
- }
-
- // If it isn’t currently loading, we check to see if we have breached
- // the mVisibleThreshold and need to reload more data.
- // If we do need to reload some more data, we execute onLoadMore to fetch the data.
- // threshold should reflect how many total columns there are too
- if (!loading &&
- firstVisibleItemPosition < mVisibleThreshold &&
- firstVisibleItemPosition >= 0 &&
- lastVisibleItemPosition < totalItemCount - mVisibleThreshold
- ) {
- onLoadMore(totalItemCount)
- loading = true
- }
- }
-
- // Defines the process for actually loading more data based on page
- protected abstract fun onLoadMore(totalItemsCount: Int)
-
- // Called when user has started to scroll up, opposed to onScrolledToEnd()
- protected abstract fun onScrolledUp()
-
- // Called when user has scrolled and reached the end of the items
- protected abstract fun onScrolledToEnd()
-
- companion object {
- // The minimum amount of items to have below your current scroll position
- // before loading more.
- private const val mVisibleThreshold = 5
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/chat/GroupChatRoomMember.kt b/app/src/main/java/org/linphone/activities/main/chat/GroupChatRoomMember.kt
deleted file mode 100644
index 537b8017c..000000000
--- a/app/src/main/java/org/linphone/activities/main/chat/GroupChatRoomMember.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.chat
-
-import org.linphone.core.Address
-import org.linphone.core.ChatRoom
-
-data class GroupChatRoomMember(
- val address: Address,
- var isAdmin: Boolean = false,
- val securityLevel: ChatRoom.SecurityLevel = ChatRoom.SecurityLevel.ClearText,
- val hasLimeX3DHCapability: Boolean = false,
- // A participant not yet added to a group can't be set admin at the same time it's added
- val canBeSetAdmin: Boolean = false
-)
diff --git a/app/src/main/java/org/linphone/activities/main/chat/adapters/ChatMessagesListAdapter.kt b/app/src/main/java/org/linphone/activities/main/chat/adapters/ChatMessagesListAdapter.kt
deleted file mode 100644
index d922ccd93..000000000
--- a/app/src/main/java/org/linphone/activities/main/chat/adapters/ChatMessagesListAdapter.kt
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.chat.adapters
-
-import android.content.ClipData
-import android.content.ClipboardManager
-import android.content.Context
-import android.view.Gravity
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.PopupWindow
-import android.widget.TextView
-import androidx.databinding.DataBindingUtil
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.MutableLiveData
-import androidx.recyclerview.widget.DiffUtil
-import androidx.recyclerview.widget.RecyclerView
-import kotlin.math.abs
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.LinphoneApplication.Companion.corePreferences
-import org.linphone.R
-import org.linphone.activities.main.adapters.SelectionListAdapter
-import org.linphone.activities.main.chat.data.ChatMessageData
-import org.linphone.activities.main.chat.data.EventData
-import org.linphone.activities.main.chat.data.EventLogData
-import org.linphone.activities.main.chat.data.OnContentClickedListener
-import org.linphone.activities.main.viewmodels.ListTopBarViewModel
-import org.linphone.core.*
-import org.linphone.core.tools.Log
-import org.linphone.databinding.ChatEventListCellBinding
-import org.linphone.databinding.ChatMessageListCellBinding
-import org.linphone.databinding.ChatMessageLongPressMenuBindingImpl
-import org.linphone.databinding.ChatUnreadMessagesListHeaderBinding
-import org.linphone.utils.AppUtils
-import org.linphone.utils.Event
-import org.linphone.utils.HeaderAdapter
-
-class ChatMessagesListAdapter(
- selectionVM: ListTopBarViewModel,
- private val viewLifecycleOwner: LifecycleOwner
-) : SelectionListAdapter(
- selectionVM,
- ChatMessageDiffCallback()
-),
- HeaderAdapter {
- companion object {
- const val MAX_TIME_TO_GROUP_MESSAGES = 60 // 1 minute
- }
-
- val resendMessageEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val deleteMessageEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val forwardMessageEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val replyMessageEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val showImdnForMessageEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val addSipUriToContactEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val openContentEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val urlClickEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val sipUriClickedEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val callConferenceEvent: MutableLiveData>> by lazy {
- MutableLiveData>>()
- }
-
- val scrollToChatMessageEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val showReactionsListEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val errorEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- private val contentClickedListener = object : OnContentClickedListener {
- override fun onContentClicked(content: Content) {
- openContentEvent.value = Event(content)
- }
-
- override fun onWebUrlClicked(url: String) {
- if (popup?.isShowing == true) {
- Log.w(
- "[Chat Message Data] Long press that displayed context menu detected, aborting click on URL [$url]"
- )
- return
- }
- val urlWithScheme = if (!url.startsWith("http")) "http://$url" else url
- urlClickEvent.value = Event(urlWithScheme)
- }
-
- override fun onSipAddressClicked(sipUri: String) {
- if (popup?.isShowing == true) {
- Log.w(
- "[Chat Message Data] Long press that displayed context menu detected, aborting click on SIP URI [$sipUri]"
- )
- return
- }
- sipUriClickedEvent.value = Event(sipUri)
- }
-
- override fun onEmailAddressClicked(email: String) {
- if (popup?.isShowing == true) {
- Log.w(
- "[Chat Message Data] Long press that displayed context menu detected, aborting click on email address [$email]"
- )
- return
- }
- val urlWithScheme = if (!email.startsWith("mailto:")) "mailto:$email" else email
- urlClickEvent.value = Event(urlWithScheme)
- }
-
- override fun onCallConference(address: String, subject: String?) {
- callConferenceEvent.value = Event(Pair(address, subject))
- }
-
- override fun onShowReactionsList(chatMessage: ChatMessage) {
- showReactionsListEvent.value = Event(chatMessage)
- }
-
- override fun onError(messageId: Int) {
- errorEvent.value = Event(messageId)
- }
- }
-
- private var advancedContextMenuOptionsDisabled: Boolean = false
- private var popup: PopupWindow? = null
-
- private var unreadMessagesCount: Int = 0
- private var firstUnreadMessagePosition: Int = -1
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
- return when (viewType) {
- EventLog.Type.ConferenceChatMessage.toInt() -> createChatMessageViewHolder(parent)
- else -> createEventViewHolder(parent)
- }
- }
-
- private fun createChatMessageViewHolder(parent: ViewGroup): ChatMessageViewHolder {
- val binding: ChatMessageListCellBinding = DataBindingUtil.inflate(
- LayoutInflater.from(parent.context),
- R.layout.chat_message_list_cell,
- parent,
- false
- )
- return ChatMessageViewHolder(binding)
- }
-
- private fun createEventViewHolder(parent: ViewGroup): EventViewHolder {
- val binding: ChatEventListCellBinding = DataBindingUtil.inflate(
- LayoutInflater.from(parent.context),
- R.layout.chat_event_list_cell,
- parent,
- false
- )
- return EventViewHolder(binding)
- }
-
- override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
- val eventLog = getItem(position)
- when (holder) {
- is ChatMessageViewHolder -> holder.bind(eventLog)
- is EventViewHolder -> holder.bind(eventLog)
- }
- }
-
- override fun getItemViewType(position: Int): Int {
- val eventLog = getItem(position)
- return eventLog.eventLog.type.toInt()
- }
-
- override fun onCurrentListChanged(
- previousList: MutableList,
- currentList: MutableList
- ) {
- Log.i(
- "[Chat Messages Adapter] List has changed, clearing previous first unread message position"
- )
- // Need to wait for messages to be added before computing new first unread message position
- firstUnreadMessagePosition = -1
- }
-
- override fun displayHeaderForPosition(position: Int): Boolean {
- Log.i(
- "[Chat Messages Adapter] Unread message count is [$unreadMessagesCount], first unread message position is [$firstUnreadMessagePosition]"
- )
- if (unreadMessagesCount > 0 && firstUnreadMessagePosition == -1) {
- computeFirstUnreadMessagePosition()
- }
- return position == firstUnreadMessagePosition
- }
-
- override fun getHeaderViewForPosition(context: Context, position: Int): View {
- val binding: ChatUnreadMessagesListHeaderBinding = DataBindingUtil.inflate(
- LayoutInflater.from(context),
- R.layout.chat_unread_messages_list_header,
- null,
- false
- )
- binding.title = AppUtils.getStringWithPlural(
- R.plurals.chat_room_unread_messages_event,
- unreadMessagesCount
- )
- binding.executePendingBindings()
- return binding.root
- }
-
- fun disableAdvancedContextMenuOptions() {
- advancedContextMenuOptionsDisabled = true
- }
-
- fun setUnreadMessageCount(count: Int, forceUpdate: Boolean) {
- Log.i("[Chat Messages Adapter] [$count] unread message in chat room")
- // Once list has been filled once, don't show the unread message header
- // when new messages are added to the history whilst it is visible
- unreadMessagesCount = if (itemCount == 0 || forceUpdate) count else 0
- firstUnreadMessagePosition = -1
- Log.i(
- "[Chat Messages Adapter] Set [$unreadMessagesCount] unread message(s) for current chat room"
- )
- }
-
- fun getFirstUnreadMessagePosition(): Int {
- Log.i(
- "[Chat Messages Adapter] First unread message position is [$firstUnreadMessagePosition]"
- )
- return firstUnreadMessagePosition
- }
-
- private fun computeFirstUnreadMessagePosition() {
- Log.i(
- "[Chat Messages Adapter] [$unreadMessagesCount] unread message(s) for current chat room"
- )
- if (unreadMessagesCount > 0) {
- Log.i("[Chat Messages Adapter] Computing first unread message position")
- var messageCount = 0
- for (position in itemCount - 1 downTo 0) {
- val eventLog = getItem(position)
- val data = eventLog.data
- if (data is ChatMessageData) {
- messageCount += 1
- if (messageCount == unreadMessagesCount) {
- firstUnreadMessagePosition = position
- Log.i(
- "[Chat Messages Adapter] First unread message position found [$firstUnreadMessagePosition]"
- )
- break
- }
- }
- }
- }
- }
-
- inner class ChatMessageViewHolder(
- val binding: ChatMessageListCellBinding
- ) : RecyclerView.ViewHolder(binding.root) {
- fun bind(eventLog: EventLogData) {
- with(binding) {
- if (eventLog.eventLog.type == EventLog.Type.ConferenceChatMessage) {
- val chatMessageData = eventLog.data as ChatMessageData
- chatMessageData.setContentClickListener(contentClickedListener)
-
- val chatMessage = chatMessageData.chatMessage
- data = chatMessageData
-
- chatMessageData.contactNewlyFoundEvent.observe(viewLifecycleOwner) {
- it.consume {
- // Post to prevent IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
- binding.root.post {
- try {
- notifyItemChanged(bindingAdapterPosition)
- } catch (e: Exception) {
- Log.e(
- "[Chat Messages Adapter] Can't notify item [$bindingAdapterPosition] has changed: $e"
- )
- }
- }
- }
- }
-
- lifecycleOwner = viewLifecycleOwner
-
- // This is for item selection through ListTopBarFragment
- selectionListViewModel = selectionViewModel
- selectionViewModel.isEditionEnabled.observe(
- viewLifecycleOwner
- ) {
- position = bindingAdapterPosition
- }
-
- setClickListener {
- if (selectionViewModel.isEditionEnabled.value == true) {
- selectionViewModel.onToggleSelect(bindingAdapterPosition)
- }
- }
-
- setReplyClickListener {
- val reply = chatMessageData.replyData.value?.chatMessage
- if (reply != null) {
- scrollToChatMessageEvent.value = Event(reply)
- }
- }
-
- // Grouping
- var hasPrevious = false
- var hasNext = false
-
- if (bindingAdapterPosition > 0) {
- val previousItem = getItem(bindingAdapterPosition - 1)
- if (previousItem.eventLog.type == EventLog.Type.ConferenceChatMessage) {
- val previousMessage = previousItem.eventLog.chatMessage
- if (previousMessage != null && previousMessage.fromAddress.weakEqual(
- chatMessage.fromAddress
- )
- ) {
- if (abs(chatMessage.time - previousMessage.time) < MAX_TIME_TO_GROUP_MESSAGES) {
- hasPrevious = true
- }
- }
- }
- }
-
- if (bindingAdapterPosition >= 0 && bindingAdapterPosition < itemCount - 1) {
- val nextItem = getItem(bindingAdapterPosition + 1)
- if (nextItem.eventLog.type == EventLog.Type.ConferenceChatMessage) {
- val nextMessage = nextItem.eventLog.chatMessage
- if (nextMessage != null && nextMessage.fromAddress.weakEqual(
- chatMessage.fromAddress
- )
- ) {
- if (abs(nextMessage.time - chatMessage.time) < MAX_TIME_TO_GROUP_MESSAGES) {
- hasNext = true
- }
- }
- }
- }
-
- chatMessageData.updateBubbleBackground(hasPrevious, hasNext)
-
- executePendingBindings()
-
- setContextMenuClickListener {
- val popupView: ChatMessageLongPressMenuBindingImpl = DataBindingUtil.inflate(
- LayoutInflater.from(root.context),
- R.layout.chat_message_long_press_menu,
- null,
- false
- )
-
- val itemSize = AppUtils.getDimension(R.dimen.chat_message_popup_item_height).toInt()
- var totalSize = itemSize * 8
- if (chatMessage.chatRoom.hasCapability(
- ChatRoom.Capabilities.OneToOne.toInt()
- )
- ) {
- // No message id
- popupView.imdnHidden = true
- totalSize -= itemSize
- }
- if (chatMessage.state != ChatMessage.State.NotDelivered) {
- popupView.resendHidden = true
- totalSize -= itemSize
- }
- if (chatMessage.contents.find { content -> content.isText } == null) {
- popupView.copyTextHidden = true
- totalSize -= itemSize
- }
- if (chatMessage.isOutgoing ||
- chatMessageData.contact.value != null ||
- advancedContextMenuOptionsDisabled ||
- corePreferences.readOnlyNativeContacts
- ) {
- popupView.addToContactsHidden = true
- totalSize -= itemSize
- }
- if (chatMessage.chatRoom.isReadOnly) {
- popupView.replyHidden = true
- totalSize -= itemSize
- }
- if (advancedContextMenuOptionsDisabled) {
- popupView.forwardHidden = true
- totalSize -= itemSize
- }
-
- val reaction = chatMessage.ownReaction
- if (reaction != null) {
- when (reaction.body) {
- AppUtils.getString(R.string.emoji_love) -> {
- popupView.heartSelected = true
- }
- AppUtils.getString(R.string.emoji_laughing) -> {
- popupView.laughingSelected = true
- }
- AppUtils.getString(R.string.emoji_surprised) -> {
- popupView.surprisedSelected = true
- }
- AppUtils.getString(R.string.emoji_thumbs_up) -> {
- popupView.thumbsUpSelected = true
- }
- AppUtils.getString(R.string.emoji_tear) -> {
- popupView.cryingSelected = true
- }
- }
- }
-
- // When using WRAP_CONTENT instead of real size, fails to place the
- // popup window above if not enough space is available below
- val popupWindow = PopupWindow(
- popupView.root,
- AppUtils.getDimension(R.dimen.chat_message_popup_width).toInt(),
- totalSize,
- true
- )
- popup = popupWindow
-
- // Elevation is for showing a shadow around the popup
- popupWindow.elevation = 20f
-
- popupView.setEmojiClickListener {
- val emoji = it as? TextView
- if (emoji != null) {
- reactToMessage(emoji.text.toString())
- popupWindow.dismiss()
- }
- }
- popupView.setResendClickListener {
- resendMessage()
- popupWindow.dismiss()
- }
- popupView.setCopyTextClickListener {
- copyTextToClipboard()
- popupWindow.dismiss()
- }
- popupView.setForwardClickListener {
- forwardMessage()
- popupWindow.dismiss()
- }
- popupView.setReplyClickListener {
- replyMessage()
- popupWindow.dismiss()
- }
- popupView.setImdnClickListener {
- showImdnDeliveryFragment()
- popupWindow.dismiss()
- }
- popupView.setAddToContactsClickListener {
- addSenderToContacts()
- popupWindow.dismiss()
- }
- popupView.setDeleteClickListener {
- deleteMessage()
- popupWindow.dismiss()
- }
-
- val gravity = if (chatMessage.isOutgoing) Gravity.END else Gravity.START
- popupWindow.showAsDropDown(background, 0, 0, gravity or Gravity.TOP)
-
- true
- }
- }
- }
- }
-
- private fun reactToMessage(reaction: String) {
- val chatMessage = binding.data?.chatMessage
- if (chatMessage != null) {
- val ownReaction = chatMessage.ownReaction
- if (ownReaction != null && ownReaction.body == reaction) {
- Log.i(
- "[Chat Message Data] Removing our reaction to message [$chatMessage] (previously [$reaction])"
- )
- // Empty string means remove existing reaction
- val reactionMessage = chatMessage.createReaction("")
- reactionMessage.send()
- } else {
- Log.i(
- "[Chat Message Data] Reacting to message [$chatMessage] with [$reaction] emoji"
- )
- val reactionMessage = chatMessage.createReaction(reaction)
- reactionMessage.send()
- }
- }
- }
-
- private fun resendMessage() {
- val chatMessage = binding.data?.chatMessage
- if (chatMessage != null) {
- chatMessage.userData = bindingAdapterPosition
- resendMessageEvent.value = Event(chatMessage)
- }
- }
-
- private fun copyTextToClipboard() {
- val chatMessage = binding.data?.chatMessage
- if (chatMessage != null) {
- val content = chatMessage.contents.find { content -> content.isText }
- if (content != null) {
- val clipboard: ClipboardManager =
- coreContext.context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
- val clip = ClipData.newPlainText("Message", content.utf8Text)
- clipboard.setPrimaryClip(clip)
- }
- }
- }
-
- private fun forwardMessage() {
- val chatMessage = binding.data?.chatMessage
- if (chatMessage != null) {
- forwardMessageEvent.value = Event(chatMessage)
- }
- }
-
- private fun replyMessage() {
- val chatMessage = binding.data?.chatMessage
- if (chatMessage != null) {
- replyMessageEvent.value = Event(chatMessage)
- }
- }
-
- private fun showImdnDeliveryFragment() {
- val chatMessage = binding.data?.chatMessage
- if (chatMessage != null) {
- showImdnForMessageEvent.value = Event(chatMessage)
- }
- }
-
- private fun deleteMessage() {
- val chatMessage = binding.data?.chatMessage
- if (chatMessage != null) {
- chatMessage.userData = bindingAdapterPosition
- deleteMessageEvent.value = Event(chatMessage)
- }
- }
-
- private fun addSenderToContacts() {
- val chatMessage = binding.data?.chatMessage
- if (chatMessage != null) {
- val copy = chatMessage.fromAddress.clone()
- copy.clean() // To remove gruu if any
- addSipUriToContactEvent.value = Event(copy.asStringUriOnly())
- }
- }
- }
-
- inner class EventViewHolder(
- private val binding: ChatEventListCellBinding
- ) : RecyclerView.ViewHolder(binding.root) {
- fun bind(eventLog: EventLogData) {
- with(binding) {
- val eventViewModel = eventLog.data as EventData
- data = eventViewModel
-
- binding.lifecycleOwner = viewLifecycleOwner
-
- // This is for item selection through ListTopBarFragment
- selectionListViewModel = selectionViewModel
- selectionViewModel.isEditionEnabled.observe(
- viewLifecycleOwner
- ) {
- position = bindingAdapterPosition
- }
-
- binding.setClickListener {
- if (selectionViewModel.isEditionEnabled.value == true) {
- selectionViewModel.onToggleSelect(bindingAdapterPosition)
- }
- }
-
- executePendingBindings()
- }
- }
- }
-}
-
-private class ChatMessageDiffCallback : DiffUtil.ItemCallback() {
- override fun areItemsTheSame(
- oldItem: EventLogData,
- newItem: EventLogData
- ): Boolean {
- return if (oldItem.type == EventLog.Type.ConferenceChatMessage &&
- newItem.type == EventLog.Type.ConferenceChatMessage
- ) {
- val oldData = (oldItem.data as ChatMessageData)
- val newData = (newItem.data as ChatMessageData)
-
- oldData.time.value == newData.time.value &&
- oldData.isOutgoing == newData.isOutgoing
- } else {
- oldItem.notifyId == newItem.notifyId
- }
- }
-
- override fun areContentsTheSame(
- oldItem: EventLogData,
- newItem: EventLogData
- ): Boolean {
- return if (oldItem.type == EventLog.Type.ConferenceChatMessage &&
- newItem.type == EventLog.Type.ConferenceChatMessage
- ) {
- val oldData = (oldItem.data as ChatMessageData)
- val newData = (newItem.data as ChatMessageData)
-
- val previous = oldData.hasPreviousMessage == newData.hasPreviousMessage
- val next = oldData.hasNextMessage == newData.hasNextMessage
- val isDisplayed = newData.isDisplayed.value == true
- isDisplayed && previous && next
- } else {
- oldItem.type != EventLog.Type.ConferenceChatMessage &&
- newItem.type != EventLog.Type.ConferenceChatMessage
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/chat/adapters/ChatRoomsListAdapter.kt b/app/src/main/java/org/linphone/activities/main/chat/adapters/ChatRoomsListAdapter.kt
deleted file mode 100644
index 12e6c7157..000000000
--- a/app/src/main/java/org/linphone/activities/main/chat/adapters/ChatRoomsListAdapter.kt
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.chat.adapters
-
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import androidx.databinding.DataBindingUtil
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.MutableLiveData
-import androidx.recyclerview.widget.DiffUtil
-import androidx.recyclerview.widget.RecyclerView
-import org.linphone.R
-import org.linphone.activities.main.adapters.SelectionListAdapter
-import org.linphone.activities.main.chat.data.ChatRoomData
-import org.linphone.activities.main.viewmodels.ListTopBarViewModel
-import org.linphone.core.ChatRoom
-import org.linphone.core.tools.Log
-import org.linphone.databinding.ChatRoomListCellBinding
-import org.linphone.utils.Event
-
-class ChatRoomsListAdapter(
- selectionVM: ListTopBarViewModel,
- private val viewLifecycleOwner: LifecycleOwner
-) : SelectionListAdapter(selectionVM, ChatRoomDiffCallback()) {
- val selectedChatRoomEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- private var isForwardPending = false
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val binding: ChatRoomListCellBinding = DataBindingUtil.inflate(
- LayoutInflater.from(parent.context),
- R.layout.chat_room_list_cell,
- parent,
- false
- )
- return ViewHolder(binding)
- }
-
- override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
- (holder as ViewHolder).bind(getItem(position))
- }
-
- fun forwardPending(pending: Boolean) {
- isForwardPending = pending
- notifyItemRangeChanged(0, itemCount)
- }
-
- inner class ViewHolder(
- private val binding: ChatRoomListCellBinding
- ) : RecyclerView.ViewHolder(binding.root) {
- fun bind(chatRoomData: ChatRoomData) {
- with(binding) {
- chatRoomData.update()
- data = chatRoomData
-
- chatRoomData.contactNewlyFoundEvent.observe(viewLifecycleOwner) {
- it.consume {
- // Post to prevent IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
- binding.root.post {
- try {
- notifyItemChanged(bindingAdapterPosition)
- } catch (e: Exception) {
- Log.e(
- "[Chat Rooms Adapter] Can't notify item [$bindingAdapterPosition] has changed: $e"
- )
- }
- }
- }
- }
-
- lifecycleOwner = viewLifecycleOwner
-
- // This is for item selection through ListTopBarFragment
- selectionListViewModel = selectionViewModel
- selectionViewModel.isEditionEnabled.observe(
- viewLifecycleOwner
- ) {
- position = bindingAdapterPosition
- }
-
- forwardPending = isForwardPending
-
- setClickListener {
- if (selectionViewModel.isEditionEnabled.value == true) {
- selectionViewModel.onToggleSelect(bindingAdapterPosition)
- } else {
- selectedChatRoomEvent.value = Event(chatRoomData.chatRoom)
- }
- }
-
- setLongClickListener {
- if (selectionViewModel.isEditionEnabled.value == false) {
- selectionViewModel.isEditionEnabled.value = true
- // Selection will be handled by click listener
- true
- }
- false
- }
-
- executePendingBindings()
- }
- }
- }
-}
-
-private class ChatRoomDiffCallback : DiffUtil.ItemCallback() {
- override fun areItemsTheSame(
- oldItem: ChatRoomData,
- newItem: ChatRoomData
- ): Boolean {
- return oldItem.id == newItem.id
- }
-
- override fun areContentsTheSame(
- oldItem: ChatRoomData,
- newItem: ChatRoomData
- ): Boolean {
- return false // To force redraw
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/chat/adapters/GroupInfoParticipantsAdapter.kt b/app/src/main/java/org/linphone/activities/main/chat/adapters/GroupInfoParticipantsAdapter.kt
deleted file mode 100644
index b9d13bc60..000000000
--- a/app/src/main/java/org/linphone/activities/main/chat/adapters/GroupInfoParticipantsAdapter.kt
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.chat.adapters
-
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import androidx.databinding.DataBindingUtil
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.MutableLiveData
-import androidx.recyclerview.widget.DiffUtil
-import androidx.recyclerview.widget.ListAdapter
-import androidx.recyclerview.widget.RecyclerView
-import org.linphone.R
-import org.linphone.activities.main.chat.GroupChatRoomMember
-import org.linphone.activities.main.chat.data.GroupInfoParticipantData
-import org.linphone.databinding.ChatRoomGroupInfoParticipantCellBinding
-import org.linphone.utils.Event
-
-class GroupInfoParticipantsAdapter(
- private val viewLifecycleOwner: LifecycleOwner,
- private val isEncryptionEnabled: Boolean
-) : ListAdapter(ParticipantDiffCallback()) {
- private var showAdmin: Boolean = false
-
- val participantRemovedEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val binding: ChatRoomGroupInfoParticipantCellBinding = DataBindingUtil.inflate(
- LayoutInflater.from(parent.context),
- R.layout.chat_room_group_info_participant_cell,
- parent,
- false
- )
- return ViewHolder(binding)
- }
-
- override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
- (holder as ViewHolder).bind(getItem(position))
- }
-
- fun showAdminControls(show: Boolean) {
- showAdmin = show
- notifyItemRangeChanged(0, itemCount)
- }
-
- inner class ViewHolder(
- val binding: ChatRoomGroupInfoParticipantCellBinding
- ) : RecyclerView.ViewHolder(binding.root) {
- fun bind(participantViewModel: GroupInfoParticipantData) {
- with(binding) {
- participantViewModel.showAdminControls.value = showAdmin
- data = participantViewModel
-
- lifecycleOwner = viewLifecycleOwner
-
- setRemoveClickListener {
- participantRemovedEvent.value = Event(participantViewModel.participant)
- }
- isEncrypted = isEncryptionEnabled
-
- executePendingBindings()
- }
- }
- }
-}
-
-private class ParticipantDiffCallback : DiffUtil.ItemCallback() {
- override fun areItemsTheSame(
- oldItem: GroupInfoParticipantData,
- newItem: GroupInfoParticipantData
- ): Boolean {
- return oldItem.sipUri == newItem.sipUri
- }
-
- override fun areContentsTheSame(
- oldItem: GroupInfoParticipantData,
- newItem: GroupInfoParticipantData
- ): Boolean {
- return false
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/chat/adapters/ImdnAdapter.kt b/app/src/main/java/org/linphone/activities/main/chat/adapters/ImdnAdapter.kt
deleted file mode 100644
index 3226780ea..000000000
--- a/app/src/main/java/org/linphone/activities/main/chat/adapters/ImdnAdapter.kt
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.chat.adapters
-
-import android.content.Context
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.databinding.DataBindingUtil
-import androidx.lifecycle.LifecycleOwner
-import androidx.recyclerview.widget.DiffUtil
-import androidx.recyclerview.widget.ListAdapter
-import androidx.recyclerview.widget.RecyclerView
-import org.linphone.R
-import org.linphone.activities.main.chat.data.ImdnParticipantData
-import org.linphone.core.ChatMessage
-import org.linphone.databinding.ChatRoomImdnParticipantCellBinding
-import org.linphone.databinding.ImdnListHeaderBinding
-import org.linphone.utils.HeaderAdapter
-
-class ImdnAdapter(
- private val viewLifecycleOwner: LifecycleOwner
-) : ListAdapter(ParticipantImdnStateDiffCallback()), HeaderAdapter {
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val binding: ChatRoomImdnParticipantCellBinding = DataBindingUtil.inflate(
- LayoutInflater.from(parent.context),
- R.layout.chat_room_imdn_participant_cell,
- parent,
- false
- )
- return ViewHolder(binding)
- }
-
- override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
- (holder as ViewHolder).bind(getItem(position))
- }
-
- inner class ViewHolder(
- val binding: ChatRoomImdnParticipantCellBinding
- ) : RecyclerView.ViewHolder(binding.root) {
- fun bind(participantImdnData: ImdnParticipantData) {
- with(binding) {
- data = participantImdnData
-
- lifecycleOwner = viewLifecycleOwner
-
- executePendingBindings()
- }
- }
- }
-
- override fun displayHeaderForPosition(position: Int): Boolean {
- if (position >= itemCount) return false
- val participantImdnState = getItem(position)
- val previousPosition = position - 1
- return if (previousPosition >= 0) {
- getItem(previousPosition).imdnState.state != participantImdnState.imdnState.state
- } else {
- true
- }
- }
-
- override fun getHeaderViewForPosition(context: Context, position: Int): View {
- val participantImdnState = getItem(position).imdnState
- val binding: ImdnListHeaderBinding = DataBindingUtil.inflate(
- LayoutInflater.from(context),
- R.layout.imdn_list_header,
- null,
- false
- )
- when (participantImdnState.state) {
- ChatMessage.State.Displayed -> {
- binding.title = R.string.chat_message_imdn_displayed
- binding.textColor = R.color.imdn_read_color
- binding.icon = R.drawable.chat_read
- }
- ChatMessage.State.DeliveredToUser -> {
- binding.title = R.string.chat_message_imdn_delivered
- binding.textColor = R.color.grey_color
- binding.icon = R.drawable.chat_delivered
- }
- ChatMessage.State.Delivered -> {
- binding.title = R.string.chat_message_imdn_sent
- binding.textColor = R.color.grey_color
- binding.icon = R.drawable.chat_delivered
- }
- ChatMessage.State.NotDelivered -> {
- binding.title = R.string.chat_message_imdn_undelivered
- binding.textColor = R.color.red_color
- binding.icon = R.drawable.chat_error
- }
- else -> {}
- }
- binding.executePendingBindings()
- return binding.root
- }
-}
-
-private class ParticipantImdnStateDiffCallback : DiffUtil.ItemCallback() {
- override fun areItemsTheSame(
- oldItem: ImdnParticipantData,
- newItem: ImdnParticipantData
- ): Boolean {
- return oldItem.sipUri == newItem.sipUri
- }
-
- override fun areContentsTheSame(
- oldItem: ImdnParticipantData,
- newItem: ImdnParticipantData
- ): Boolean {
- return false
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageAttachmentData.kt b/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageAttachmentData.kt
deleted file mode 100644
index fc66b68a5..000000000
--- a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageAttachmentData.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.chat.data
-
-import android.webkit.MimeTypeMap
-import org.linphone.utils.FileUtils
-
-class ChatMessageAttachmentData(
- val path: String,
- private val deleteCallback: (attachment: ChatMessageAttachmentData) -> Unit
-) {
- val fileName: String = FileUtils.getNameFromFilePath(path)
- val isImage: Boolean
- val isVideo: Boolean
- val isAudio: Boolean
- val isPdf: Boolean
-
- init {
- val extension = FileUtils.getExtensionFromFileName(path)
- val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
- val mimeType = FileUtils.getMimeType(mime)
- isImage = mimeType == FileUtils.MimeType.Image
- isVideo = mimeType == FileUtils.MimeType.Video
- isAudio = mimeType == FileUtils.MimeType.Audio
- isPdf = mimeType == FileUtils.MimeType.Pdf
- }
-
- fun delete() {
- deleteCallback(this)
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageContentData.kt b/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageContentData.kt
deleted file mode 100644
index 451a89eb7..000000000
--- a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageContentData.kt
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.chat.data
-
-import android.text.Spannable
-import android.text.SpannableString
-import android.text.Spanned
-import android.text.style.UnderlineSpan
-import android.webkit.MimeTypeMap
-import android.widget.Toast
-import androidx.lifecycle.MutableLiveData
-import androidx.media.AudioFocusRequestCompat
-import java.io.BufferedReader
-import java.io.FileReader
-import java.lang.StringBuilder
-import java.text.SimpleDateFormat
-import java.util.*
-import java.util.concurrent.TimeUnit
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.R
-import org.linphone.core.*
-import org.linphone.core.tools.Log
-import org.linphone.utils.AppUtils
-import org.linphone.utils.AudioRouteUtils
-import org.linphone.utils.FileUtils
-import org.linphone.utils.TimestampUtils
-
-class ChatMessageContentData(
- private val chatMessage: ChatMessage,
- private val contentIndex: Int
-) {
- var listener: OnContentClickedListener? = null
-
- val isOutgoing = chatMessage.isOutgoing
-
- val isImage = MutableLiveData()
- val isVideo = MutableLiveData()
- val isAudio = MutableLiveData()
- val isPdf = MutableLiveData()
- val isGenericFile = MutableLiveData()
- val isVoiceRecording = MutableLiveData()
- val isConferenceSchedule = MutableLiveData()
- val isConferenceUpdated = MutableLiveData()
- val isConferenceCancelled = MutableLiveData()
- val isBroadcast = MutableLiveData()
- val isSpeaker = MutableLiveData()
-
- val fileName = MutableLiveData()
- val filePath = MutableLiveData()
-
- val downloadable = MutableLiveData()
- val fileTransferProgress = MutableLiveData()
- val fileTransferProgressInt = MutableLiveData()
- val downloadLabel = MutableLiveData()
-
- val voiceRecordDuration = MutableLiveData()
- val formattedDuration = MutableLiveData()
- val voiceRecordPlayingPosition = MutableLiveData()
- val isVoiceRecordPlaying = MutableLiveData()
-
- val conferenceSubject = MutableLiveData()
- val conferenceDescription = MutableLiveData()
- val conferenceParticipantCount = MutableLiveData()
- val conferenceDate = MutableLiveData()
- val conferenceTime = MutableLiveData()
- val conferenceDuration = MutableLiveData()
- val showDuration = MutableLiveData()
-
- val isAlone: Boolean
- get() {
- var count = 0
- for (content in chatMessage.contents) {
- if (content.isFileTransfer || content.isFile) {
- count += 1
- }
- }
- return count == 1
- }
-
- private var isFileEncrypted: Boolean = false
-
- private var voiceRecordAudioFocusRequest: AudioFocusRequestCompat? = null
-
- private lateinit var voiceRecordingPlayer: Player
- private val playerListener = PlayerListener {
- Log.i("[Voice Recording] End of file reached")
- stopVoiceRecording()
- }
-
- private var conferenceAddress: String? = null
-
- private fun getContent(): Content {
- return chatMessage.contents[contentIndex]
- }
-
- private val chatMessageListener: ChatMessageListenerStub = object : ChatMessageListenerStub() {
- override fun onFileTransferProgressIndication(
- message: ChatMessage,
- c: Content,
- offset: Int,
- total: Int
- ) {
- if (c.filePath == getContent().filePath) {
- if (fileTransferProgress.value == false) {
- fileTransferProgress.value = true
- }
- val percent = ((offset * 100.0) / total).toInt() // Conversion from int to double and back to int is required
- Log.d("[Content] Transfer progress is: $offset / $total -> $percent%")
- fileTransferProgressInt.value = percent
- }
- }
-
- override fun onMsgStateChanged(message: ChatMessage, state: ChatMessage.State) {
- if (state == ChatMessage.State.FileTransferDone || state == ChatMessage.State.FileTransferError) {
- fileTransferProgress.value = false
- updateContent()
-
- if (state == ChatMessage.State.FileTransferDone) {
- Log.i("[Chat Message] File transfer done")
- if (!message.isOutgoing && !message.isEphemeral) {
- Log.i("[Chat Message] Adding content to media store")
- coreContext.addContentToMediaStore(getContent())
- }
- }
- }
- }
- }
-
- private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
-
- init {
- isVoiceRecordPlaying.value = false
- voiceRecordDuration.value = 0
- voiceRecordPlayingPosition.value = 0
- fileTransferProgress.value = false
- fileTransferProgressInt.value = 0
-
- updateContent()
- chatMessage.addListener(chatMessageListener)
- }
-
- fun destroy() {
- scope.cancel()
-
- deletePlainFilePath()
- chatMessage.removeListener(chatMessageListener)
-
- if (this::voiceRecordingPlayer.isInitialized) {
- Log.i("[Voice Recording] Destroying voice record")
- stopVoiceRecording()
- voiceRecordingPlayer.removeListener(playerListener)
- }
- }
-
- fun download() {
- if (chatMessage.isFileTransferInProgress) {
- Log.w(
- "[Content] Another FileTransfer content for this message is currently being downloaded, can't start another one for now"
- )
- listener?.onError(R.string.chat_message_download_already_in_progress)
- return
- }
-
- val content = getContent()
- val filePath = content.filePath
- if (content.isFileTransfer) {
- if (filePath.isNullOrEmpty()) {
- val contentName = content.name
- if (contentName != null) {
- val file = FileUtils.getFileStoragePath(contentName)
- content.filePath = file.path
- Log.i("[Content] Started downloading $contentName into ${content.filePath}")
- } else {
- Log.e("[Content] Content name is null, can't download it!")
- return
- }
- } else {
- Log.w(
- "[Content] File path already set [$filePath] using it (auto download that failed probably)"
- )
- }
-
- if (!chatMessage.downloadContent(content)) {
- Log.e("[Content] Failed to start content download!")
- }
- } else {
- Log.e("[Content] Content is not a FileTransfer, can't download it!")
- }
- }
-
- fun openFile() {
- listener?.onContentClicked(getContent())
- }
-
- private fun deletePlainFilePath() {
- val path = filePath.value.orEmpty()
- if (path.isNotEmpty() && isFileEncrypted) {
- Log.i("[Content] [VFS] Deleting file used for preview: $path")
- FileUtils.deleteFile(path)
- filePath.value = ""
- }
- }
-
- private fun updateContent() {
- Log.i("[Content] Updating content")
- deletePlainFilePath()
-
- val content = getContent()
- isFileEncrypted = content.isFileEncrypted
- Log.i(
- "[Content] Is ${if (content.isFile) "file" else "file transfer"} content encrypted ? $isFileEncrypted"
- )
-
- val contentName = content.name
- val contentFilePath = content.filePath
- val name = if (contentName.isNullOrEmpty()) {
- if (!contentFilePath.isNullOrEmpty()) {
- FileUtils.getNameFromFilePath(contentFilePath)
- } else {
- ""
- }
- } else {
- contentName
- }
- fileName.value = name
- filePath.value = ""
-
- // Display download size and underline text
- val fileSize = AppUtils.bytesToDisplayableSize(content.fileSize.toLong())
- val spannable = SpannableString(
- "${AppUtils.getString(R.string.chat_message_download_file)} ($fileSize)"
- )
- spannable.setSpan(UnderlineSpan(), 0, spannable.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
- downloadLabel.value = spannable
-
- isImage.value = false
- isVideo.value = false
- isAudio.value = false
- isPdf.value = false
- isVoiceRecording.value = false
- isConferenceSchedule.value = false
- isConferenceUpdated.value = false
- isConferenceCancelled.value = false
-
- if (content.isFile || (content.isFileTransfer && chatMessage.isOutgoing)) {
- val path = if (isFileEncrypted) {
- Log.i(
- "[Content] [VFS] Content is encrypted, requesting plain file path for file [${content.filePath}]"
- )
- content.exportPlainFile()
- } else {
- content.filePath ?: ""
- }
- downloadable.value = content.filePath.orEmpty().isEmpty()
-
- val isVoiceRecord = content.isVoiceRecording
- isVoiceRecording.value = isVoiceRecord
-
- val isConferenceIcs = content.isIcalendar
- isConferenceSchedule.value = isConferenceIcs
-
- if (path.isNotEmpty()) {
- filePath.value = path
- val extension = FileUtils.getExtensionFromFileName(path)
- val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
- val type = when (FileUtils.getMimeType(mime)) {
- FileUtils.MimeType.Image -> {
- isImage.value = true
- "image"
- }
- FileUtils.MimeType.Video -> {
- isVideo.value = !isVoiceRecord
- if (isVoiceRecord) "voice recording" else "video"
- }
- FileUtils.MimeType.Audio -> {
- isAudio.value = !isVoiceRecord
- if (isVoiceRecord) "voice recording" else "audio"
- }
- FileUtils.MimeType.Pdf -> {
- isPdf.value = true
- "pdf"
- }
- else -> {
- if (isConferenceIcs) "conference invitation" else "unknown"
- }
- }
- Log.i(
- "[Content] Extension for file [$path] is [$extension], deduced type from MIME is [$type]"
- )
-
- if (isVoiceRecord) {
- val duration = content.fileDuration // duration is in ms
- voiceRecordDuration.value = duration
- formattedDuration.value = SimpleDateFormat("mm:ss", Locale.getDefault()).format(
- duration
- )
- Log.i(
- "[Content] Voice recording duration is ${voiceRecordDuration.value} ($duration)"
- )
- } else if (isConferenceIcs) {
- parseConferenceInvite(content)
- }
- } else if (isConferenceIcs) {
- Log.i("[Content] Found content with icalendar file")
- parseConferenceInvite(content)
- } else {
- Log.w(
- "[Content] Found ${if (content.isFile) "file" else "file transfer"} content with empty path..."
- )
- }
- } else if (content.isFileTransfer) {
- downloadable.value = true
- val extension = FileUtils.getExtensionFromFileName(name)
- val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
- when (FileUtils.getMimeType(mime)) {
- FileUtils.MimeType.Image -> {
- isImage.value = true
- }
- FileUtils.MimeType.Video -> {
- isVideo.value = true
- }
- FileUtils.MimeType.Audio -> {
- isAudio.value = true
- }
- FileUtils.MimeType.Pdf -> {
- isPdf.value = true
- }
- else -> {}
- }
- } else if (content.isIcalendar) {
- Log.i("[Content] Found content with icalendar body")
- isConferenceSchedule.value = true
- parseConferenceInvite(content)
- } else {
- Log.w("[Content] Found content that's neither a file or a file transfer")
- }
-
- isGenericFile.value = !isPdf.value!! && !isAudio.value!! && !isVideo.value!! && !isImage.value!! && !isVoiceRecording.value!! && !isConferenceSchedule.value!!
- }
-
- private fun parseConferenceInvite(content: Content) {
- val conferenceInfo = Factory.instance().createConferenceInfoFromIcalendarContent(content)
- val conferenceUri = conferenceInfo?.uri?.asStringUriOnly() ?: ""
- if (conferenceInfo != null && conferenceUri.isNotEmpty()) {
- conferenceAddress = conferenceUri
- Log.i(
- "[Content] Created conference info from ICS with address $conferenceAddress"
- )
- conferenceSubject.value = conferenceInfo.subject
- conferenceDescription.value = conferenceInfo.description
-
- val state = conferenceInfo.state
- isConferenceUpdated.value = state == ConferenceInfo.State.Updated
- isConferenceCancelled.value = state == ConferenceInfo.State.Cancelled
-
- conferenceDate.value = TimestampUtils.dateToString(conferenceInfo.dateTime)
- conferenceTime.value = TimestampUtils.timeToString(conferenceInfo.dateTime)
-
- val minutes = conferenceInfo.duration
- val hours = TimeUnit.MINUTES.toHours(minutes.toLong())
- val remainMinutes = minutes - TimeUnit.HOURS.toMinutes(hours).toInt()
- conferenceDuration.value = TimestampUtils.durationToString(hours.toInt(), remainMinutes)
- showDuration.value = minutes > 0
-
- // Check if organizer is part of participants list
- var participantsCount = conferenceInfo.participants.size
- val organizer = conferenceInfo.organizer
- var organizerFound = false
- var allSpeaker = true
- isSpeaker.value = true
- for (info in conferenceInfo.participantInfos) {
- val participant = info.address
- if (participant.weakEqual(chatMessage.chatRoom.localAddress)) {
- isSpeaker.value = info.role == Participant.Role.Speaker
- }
-
- if (info.role == Participant.Role.Listener) {
- allSpeaker = false
- }
-
- if (organizer != null) {
- if (participant.weakEqual(organizer)) {
- organizerFound = true
- }
- }
- }
- isBroadcast.value = allSpeaker == false
-
- if (!organizerFound) participantsCount += 1 // +1 for organizer
- conferenceParticipantCount.value = String.format(
- AppUtils.getString(R.string.conference_invite_participants_count),
- participantsCount
- )
- } else if (conferenceInfo == null) {
- if (content.filePath != null) {
- try {
- val br = BufferedReader(FileReader(content.filePath))
- var line: String?
- val textBuilder = StringBuilder()
- while (br.readLine().also { line = it } != null) {
- textBuilder.append(line)
- textBuilder.append('\n')
- }
- br.close()
- Log.e(
- "[Content] Failed to create conference info from ICS file [${content.filePath}]: $textBuilder"
- )
- } catch (e: Exception) {
- Log.e("[Content] Failed to read content of ICS file [${content.filePath}]: $e")
- }
- } else {
- Log.e("[Content] Failed to create conference info from ICS: ${content.utf8Text}")
- }
- } else if (conferenceInfo.uri == null) {
- Log.e(
- "[Content] Failed to find the conference URI in conference info [$conferenceInfo]"
- )
- }
- }
-
- fun callConferenceAddress() {
- val address = conferenceAddress
- if (address == null) {
- Log.e("[Content] Can't call null conference address!")
- return
- }
- listener?.onCallConference(address, conferenceSubject.value)
- }
-
- /** Voice recording specifics */
-
- fun playVoiceRecording() {
- Log.i("[Voice Recording] Playing voice record")
- if (isPlayerClosed()) {
- Log.w("[Voice Recording] Player closed, let's open it first")
- initVoiceRecordPlayer()
- }
-
- if (AppUtils.isMediaVolumeLow(coreContext.context)) {
- Toast.makeText(
- coreContext.context,
- R.string.chat_message_voice_recording_playback_low_volume,
- Toast.LENGTH_LONG
- ).show()
- }
-
- if (voiceRecordAudioFocusRequest == null) {
- voiceRecordAudioFocusRequest = AppUtils.acquireAudioFocusForVoiceRecordingOrPlayback(
- coreContext.context
- )
- }
- voiceRecordingPlayer.start()
- isVoiceRecordPlaying.value = true
- tickerFlow().onEach {
- withContext(Dispatchers.Main) {
- voiceRecordPlayingPosition.value = voiceRecordingPlayer.currentPosition
- }
- }.launchIn(scope)
- }
-
- fun pauseVoiceRecording() {
- Log.i("[Voice Recording] Pausing voice record")
- if (!isPlayerClosed()) {
- voiceRecordingPlayer.pause()
- }
-
- val request = voiceRecordAudioFocusRequest
- if (request != null) {
- AppUtils.releaseAudioFocusForVoiceRecordingOrPlayback(coreContext.context, request)
- voiceRecordAudioFocusRequest = null
- }
-
- isVoiceRecordPlaying.value = false
- }
-
- private fun tickerFlow() = flow {
- while (isVoiceRecordPlaying.value == true) {
- emit(Unit)
- delay(100)
- }
- }
-
- private fun initVoiceRecordPlayer() {
- Log.i("[Voice Recording] Creating player for voice record")
- val playbackSoundCard = AudioRouteUtils.getAudioPlaybackDeviceIdForCallRecordingOrVoiceMessage()
- Log.i(
- "[Voice Recording] Using device $playbackSoundCard to make the voice message playback"
- )
-
- val localPlayer = coreContext.core.createLocalPlayer(playbackSoundCard, null, null)
- if (localPlayer != null) {
- voiceRecordingPlayer = localPlayer
- } else {
- Log.e("[Voice Recording] Couldn't create local player!")
- return
- }
- voiceRecordingPlayer.addListener(playerListener)
-
- val path = filePath.value
- voiceRecordingPlayer.open(path.orEmpty())
- voiceRecordDuration.value = voiceRecordingPlayer.duration
- formattedDuration.value = SimpleDateFormat("mm:ss", Locale.getDefault()).format(
- voiceRecordingPlayer.duration
- ) // is already in milliseconds
- Log.i(
- "[Voice Recording] Duration is ${voiceRecordDuration.value} (${voiceRecordingPlayer.duration})"
- )
- }
-
- private fun stopVoiceRecording() {
- if (!isPlayerClosed()) {
- Log.i("[Voice Recording] Stopping voice record")
- pauseVoiceRecording()
- voiceRecordingPlayer.seek(0)
- voiceRecordPlayingPosition.value = 0
- voiceRecordingPlayer.close()
- }
- }
-
- private fun isPlayerClosed(): Boolean {
- return !this::voiceRecordingPlayer.isInitialized || voiceRecordingPlayer.state == Player.State.Closed
- }
-}
-
-interface OnContentClickedListener {
- fun onContentClicked(content: Content)
-
- fun onSipAddressClicked(sipUri: String)
-
- fun onEmailAddressClicked(email: String)
-
- fun onWebUrlClicked(url: String)
-
- fun onCallConference(address: String, subject: String?)
-
- fun onShowReactionsList(chatMessage: ChatMessage)
-
- fun onError(messageId: Int)
-}
diff --git a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageData.kt b/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageData.kt
deleted file mode 100644
index f4d27b5dc..000000000
--- a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageData.kt
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (c) 2010-2020 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.chat.data
-
-import android.os.CountDownTimer
-import android.text.Spannable
-import android.util.Patterns
-import androidx.lifecycle.MutableLiveData
-import java.util.regex.Pattern
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.R
-import org.linphone.contact.ContactsUpdatedListenerStub
-import org.linphone.contact.GenericContactData
-import org.linphone.core.Address
-import org.linphone.core.ChatMessage
-import org.linphone.core.ChatMessageListenerStub
-import org.linphone.core.ChatMessageReaction
-import org.linphone.core.tools.Log
-import org.linphone.utils.AppUtils
-import org.linphone.utils.Event
-import org.linphone.utils.PatternClickableSpan
-import org.linphone.utils.TimestampUtils
-
-class ChatMessageData(val chatMessage: ChatMessage) : GenericContactData(chatMessage.fromAddress) {
- private var contentListener: OnContentClickedListener? = null
-
- val sendInProgress = MutableLiveData()
-
- val showImdn = MutableLiveData()
-
- val imdnIcon = MutableLiveData()
-
- val backgroundRes = MutableLiveData()
-
- val hideAvatar = MutableLiveData()
-
- val hideTime = MutableLiveData()
-
- val contents = MutableLiveData>()
-
- val time = MutableLiveData()
-
- val ephemeralLifetime = MutableLiveData()
-
- val text = MutableLiveData()
-
- val isTextEmoji = MutableLiveData()
-
- val replyData = MutableLiveData()
-
- val isDisplayed = MutableLiveData()
-
- val isOutgoing = chatMessage.isOutgoing
-
- val contactNewlyFoundEvent: MutableLiveData> by lazy {
- MutableLiveData>()
- }
-
- val reactions = MutableLiveData>()
-
- var hasPreviousMessage = false
- var hasNextMessage = false
-
- private var countDownTimer: CountDownTimer? = null
-
- private val listener = object : ChatMessageListenerStub() {
- override fun onMsgStateChanged(message: ChatMessage, state: ChatMessage.State) {
- time.value = TimestampUtils.toString(chatMessage.time)
- updateChatMessageState(state)
- }
-
- override fun onEphemeralMessageTimerStarted(message: ChatMessage) {
- updateEphemeralTimer()
- }
-
- override fun onNewMessageReaction(message: ChatMessage, reaction: ChatMessageReaction) {
- Log.i(
- "[Chat Message Data] New reaction to display [${reaction.body}] from [${reaction.fromAddress.asStringUriOnly()}]"
- )
- updateReactionsList()
- }
-
- override fun onReactionRemoved(message: ChatMessage, address: Address) {
- Log.i(
- "[Chat Message Data] [${address.asStringUriOnly()}] removed it's previous reaction"
- )
- updateReactionsList()
- }
- }
-
- private val contactsListener = object : ContactsUpdatedListenerStub() {
- override fun onContactsUpdated() {
- contactLookup()
- if (contact.value != null) {
- coreContext.contactsManager.removeListener(this)
- contactNewlyFoundEvent.value = Event(true)
- }
- }
- }
-
- init {
- chatMessage.addListener(listener)
-
- backgroundRes.value = if (chatMessage.isOutgoing) R.drawable.chat_bubble_outgoing_full else R.drawable.chat_bubble_incoming_full
- hideAvatar.value = false
-
- if (chatMessage.isReply) {
- val reply = chatMessage.replyMessage
- if (reply != null) {
- Log.i(
- "[Chat Message Data] Message is a reply of message id [${chatMessage.replyMessageId}] sent by [${chatMessage.replyMessageSenderAddress?.asStringUriOnly()}]"
- )
- replyData.value = ChatMessageData(reply)
- }
- }
-
- time.value = TimestampUtils.toString(chatMessage.time)
- updateEphemeralTimer()
-
- updateChatMessageState(chatMessage.state)
- updateContentsList()
-
- if (contact.value == null) {
- coreContext.contactsManager.addListener(contactsListener)
- }
-
- updateReactionsList()
- }
-
- override fun destroy() {
- super.destroy()
-
- if (chatMessage.isReply) {
- replyData.value?.destroy()
- }
-
- contents.value.orEmpty().forEach(ChatMessageContentData::destroy)
- chatMessage.removeListener(listener)
- contentListener = null
- }
-
- fun updateBubbleBackground(hasPrevious: Boolean, hasNext: Boolean) {
- hasPreviousMessage = hasPrevious
- hasNextMessage = hasNext
- hideTime.value = false
- hideAvatar.value = false
-
- if (hasPrevious) {
- hideTime.value = true
- }
-
- if (chatMessage.isOutgoing) {
- if (hasNext && hasPrevious) {
- backgroundRes.value = R.drawable.chat_bubble_outgoing_split_2
- } else if (hasNext) {
- backgroundRes.value = R.drawable.chat_bubble_outgoing_split_1
- } else if (hasPrevious) {
- backgroundRes.value = R.drawable.chat_bubble_outgoing_split_3
- } else {
- backgroundRes.value = R.drawable.chat_bubble_outgoing_full
- }
- } else {
- if (hasNext && hasPrevious) {
- hideAvatar.value = true
- backgroundRes.value = R.drawable.chat_bubble_incoming_split_2
- } else if (hasNext) {
- backgroundRes.value = R.drawable.chat_bubble_incoming_split_1
- } else if (hasPrevious) {
- hideAvatar.value = true
- backgroundRes.value = R.drawable.chat_bubble_incoming_split_3
- } else {
- backgroundRes.value = R.drawable.chat_bubble_incoming_full
- }
- }
- }
-
- fun setContentClickListener(listener: OnContentClickedListener) {
- contentListener = listener
-
- for (data in contents.value.orEmpty()) {
- data.listener = listener
- }
- }
-
- fun showReactionsList() {
- contentListener?.onShowReactionsList(chatMessage)
- }
-
- private fun updateChatMessageState(state: ChatMessage.State) {
- sendInProgress.value = when (state) {
- ChatMessage.State.InProgress, ChatMessage.State.FileTransferInProgress, ChatMessage.State.FileTransferDone -> true
- else -> false
- }
-
- showImdn.value = when (state) {
- ChatMessage.State.DeliveredToUser, ChatMessage.State.Displayed,
- ChatMessage.State.NotDelivered, ChatMessage.State.FileTransferError -> true
- else -> false
- }
-
- imdnIcon.value = when (state) {
- ChatMessage.State.DeliveredToUser -> R.drawable.chat_delivered
- ChatMessage.State.Displayed -> R.drawable.chat_read
- ChatMessage.State.FileTransferError, ChatMessage.State.NotDelivered -> R.drawable.chat_error
- else -> R.drawable.chat_error
- }
-
- isDisplayed.value = state == ChatMessage.State.Displayed
- }
-
- private fun updateContentsList() {
- contents.value.orEmpty().forEach(ChatMessageContentData::destroy)
- val list = arrayListOf()
-
- val contentsList = chatMessage.contents
- for (index in contentsList.indices) {
- val content = contentsList[index]
- if (content.isFileTransfer || content.isFile || content.isIcalendar) {
- val data = ChatMessageContentData(chatMessage, index)
- data.listener = contentListener
- list.add(data)
- } else if (content.isText) {
- val textContent = content.utf8Text.orEmpty().trim()
- val spannable = Spannable.Factory.getInstance().newSpannable(textContent)
- text.value = PatternClickableSpan()
- .add(
- Pattern.compile(
- "(?:)?"
- ),
- object : PatternClickableSpan.SpannableClickedListener {
- override fun onSpanClicked(text: String) {
- Log.i("[Chat Message Data] Clicked on SIP URI: $text")
- contentListener?.onSipAddressClicked(text)
- }
- }
- )
- .add(
- Patterns.EMAIL_ADDRESS,
- object : PatternClickableSpan.SpannableClickedListener {
- override fun onSpanClicked(text: String) {
- Log.i("[Chat Message Data] Clicked on email address: $text")
- contentListener?.onEmailAddressClicked(text)
- }
- }
- )
- .add(
- Patterns.PHONE,
- object : PatternClickableSpan.SpannableClickedListener {
- override fun onSpanClicked(text: String) {
- Log.i("[Chat Message Data] Clicked on phone number: $text")
- contentListener?.onSipAddressClicked(text)
- }
- }
- )
- .add(
- Patterns.WEB_URL,
- object : PatternClickableSpan.SpannableClickedListener {
- override fun onSpanClicked(text: String) {
- Log.i("[Chat Message Data] Clicked on web URL: $text")
- contentListener?.onWebUrlClicked(text)
- }
- }
- ).build(spannable)
- isTextEmoji.value = AppUtils.isTextOnlyContainingEmoji(textContent)
- } else {
- Log.e(
- "[Chat Message Data] Unexpected content with type: ${content.type}/${content.subtype}"
- )
- }
- }
-
- contents.value = list
- }
-
- fun updateReactionsList() {
- val reactionsList = arrayListOf()
- val allReactions = chatMessage.reactions
-
- var sameReactionTwiceOrMore = false
- if (allReactions.isNotEmpty()) {
- for (reaction in allReactions) {
- val body = reaction.body
- if (!reactionsList.contains(body)) {
- reactionsList.add(body)
- } else {
- sameReactionTwiceOrMore = true
- }
- }
-
- if (sameReactionTwiceOrMore) {
- reactionsList.add(allReactions.size.toString())
- }
- }
-
- reactions.value = reactionsList
- }
-
- private fun updateEphemeralTimer() {
- if (chatMessage.isEphemeral) {
- if (chatMessage.ephemeralExpireTime == 0L) {
- // This means the message hasn't been read by all participants yet, so the countdown hasn't started
- // In this case we simply display the configured value for lifetime
- ephemeralLifetime.value = formatLifetime(chatMessage.ephemeralLifetime)
- } else {
- // Countdown has started, display remaining time
- val remaining = chatMessage.ephemeralExpireTime - (System.currentTimeMillis() / 1000)
- ephemeralLifetime.value = formatLifetime(remaining)
- if (countDownTimer == null) {
- countDownTimer = object : CountDownTimer(remaining * 1000, 1000) {
- override fun onFinish() {}
-
- override fun onTick(millisUntilFinished: Long) {
- ephemeralLifetime.postValue(formatLifetime(millisUntilFinished / 1000))
- }
- }
- countDownTimer?.start()
- }
- }
- }
- }
-
- private fun formatLifetime(seconds: Long): String {
- val days = seconds / 86400
- return when {
- days >= 1L -> AppUtils.getStringWithPlural(R.plurals.days, days.toInt())
- else -> String.format(
- "%02d:%02d:%02d",
- seconds / 3600,
- (seconds % 3600) / 60,
- (seconds % 60)
- )
- }
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageReactionData.kt b/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageReactionData.kt
deleted file mode 100644
index c73b423d8..000000000
--- a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageReactionData.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2010-2022 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.chat.data
-
-import androidx.lifecycle.MutableLiveData
-import org.linphone.contact.GenericContactData
-import org.linphone.core.ChatMessageReaction
-
-class ChatMessageReactionData(
- chatMessageReaction: ChatMessageReaction
-) : GenericContactData(chatMessageReaction.fromAddress) {
-
- val reaction = MutableLiveData()
-
- init {
- reaction.value = chatMessageReaction.body
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageReactionsListData.kt b/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageReactionsListData.kt
deleted file mode 100644
index 820195087..000000000
--- a/app/src/main/java/org/linphone/activities/main/chat/data/ChatMessageReactionsListData.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2010-2022 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.chat.data
-
-import androidx.lifecycle.MutableLiveData
-import org.linphone.core.Address
-import org.linphone.core.ChatMessage
-import org.linphone.core.ChatMessageListenerStub
-import org.linphone.core.ChatMessageReaction
-import org.linphone.core.tools.Log
-
-class ChatMessageReactionsListData(private val chatMessage: ChatMessage) {
- val reactions = MutableLiveData>()
-
- val filteredReactions = MutableLiveData>()
-
- val reactionsMap = HashMap()
-
- val listener = object : ChatMessageListenerStub() {
- override fun onNewMessageReaction(message: ChatMessage, reaction: ChatMessageReaction) {
- val address = reaction.fromAddress
- Log.i(
- "[Chat Message Reactions List] Reaction received [${reaction.body}] from [${address.asStringUriOnly()}]"
- )
- updateReactionsList(message)
- }
-
- override fun onReactionRemoved(message: ChatMessage, address: Address) {
- Log.i(
- "[Chat Message Reactions List] Reaction removed by [${address.asStringUriOnly()}]"
- )
- updateReactionsList(message)
- }
- }
-
- private var filter = ""
-
- init {
- chatMessage.addListener(listener)
-
- updateReactionsList(chatMessage)
- }
-
- fun onDestroy() {
- chatMessage.removeListener(listener)
- }
-
- fun updateFilteredReactions(newFilter: String) {
- filter = newFilter
- filteredReactions.value.orEmpty().forEach(ChatMessageReactionData::destroy)
-
- val reactionsList = arrayListOf()
- for (reaction in reactions.value.orEmpty()) {
- if (filter.isEmpty() || filter == reaction.body) {
- val data = ChatMessageReactionData(reaction)
- reactionsList.add(data)
- }
- }
- filteredReactions.value = reactionsList
- }
-
- private fun updateReactionsList(chatMessage: ChatMessage) {
- reactionsMap.clear()
-
- val reactionsList = arrayListOf()
- for (reaction in chatMessage.reactions) {
- val body = reaction.body
- val count = if (reactionsMap.containsKey(body)) {
- reactionsMap[body] ?: 0
- } else {
- 0
- }
- // getOrDefault isn't available for API 23 :'(
- reactionsMap[body] = count + 1
- reactionsList.add(reaction)
- }
- reactions.value = reactionsList
-
- updateFilteredReactions(filter)
- }
-}
diff --git a/app/src/main/java/org/linphone/activities/main/chat/data/ChatRoomData.kt b/app/src/main/java/org/linphone/activities/main/chat/data/ChatRoomData.kt
deleted file mode 100644
index 233ae0985..000000000
--- a/app/src/main/java/org/linphone/activities/main/chat/data/ChatRoomData.kt
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (c) 2010-2022 Belledonne Communications SARL.
- *
- * This file is part of linphone-android
- * (see https://www.linphone.org).
- *
- * 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
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.linphone.activities.main.chat.data
-
-import android.graphics.Typeface
-import android.text.SpannableStringBuilder
-import android.text.style.StyleSpan
-import androidx.lifecycle.MutableLiveData
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import org.linphone.LinphoneApplication.Companion.coreContext
-import org.linphone.R
-import org.linphone.contact.ContactDataInterface
-import org.linphone.contact.ContactsUpdatedListenerStub
-import org.linphone.core.*
-import org.linphone.core.tools.Log
-import org.linphone.utils.AppUtils
-import org.linphone.utils.Event
-import org.linphone.utils.LinphoneUtils
-import org.linphone.utils.TimestampUtils
-
-class ChatRoomData(val chatRoom: ChatRoom) : ContactDataInterface {
- override val contact: MutableLiveData = MutableLiveData()
- override val displayName: MutableLiveData = MutableLiveData()
- override val securityLevel: MutableLiveData = MutableLiveData()
- override val showGroupChatAvatar: Boolean
- get() = !oneToOneChatRoom
- override val presenceStatus: MutableLiveData = MutableLiveData()
- override val coroutineScope: CoroutineScope = coreContext.coroutineScope
-
- val id = LinphoneUtils.getChatRoomId(chatRoom)
-
- val unreadMessagesCount = MutableLiveData()
-
- val subject = MutableLiveData()
-
- val securityLevelIcon = MutableLiveData()
-
- val securityLevelContentDescription = MutableLiveData()
-
- val ephemeralEnabled = MutableLiveData()
-
- val lastUpdate = MutableLiveData()
-
- val lastMessageText = MutableLiveData()
-
- val showLastMessageImdnIcon = MutableLiveData