Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Feature: Use the android TTS feature to speech messages #1813

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions android-smsmms/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,14 @@ android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 25
versionCode 1
versionName "1.0"
}

lintOptions {
abortOnError false
}

useLibrary 'org.apache.http.legacy'
namespace 'com.klinker.android.send_message'
lint {
abortOnError false
}
}

dependencies {
Expand Down
10 changes: 7 additions & 3 deletions android-smsmms/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
package="com.klinker.android.send_message"
xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<queries>
<intent>
<action android:name="android.intent.action.TTS_SERVICE" />
</intent>
</queries>

<application>

Expand Down
8 changes: 4 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ buildscript {
ext.exoplayer_version = "2.8.1"
ext.glide_version = "4.8.0"
ext.junit_version = '4.12'
ext.kotlin_version = '1.3.60'
ext.kotlin_version = '1.6.21'
ext.lifecycle_version = '2.1.0'
ext.material_version = '1.0.0'
ext.mockito_version = '2.18.3'
Expand All @@ -42,9 +42,9 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:3.5.4'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.4.1'
classpath 'com.google.gms:google-services:4.2.0'
classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.2'
classpath 'com.google.gms:google-services:4.3.10'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "io.realm:realm-gradle-plugin:$realm_version"
}
Expand Down
1 change: 1 addition & 0 deletions common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

}
namespace 'com.moez.QKSMS.common'
}

dependencies {
Expand Down
2 changes: 1 addition & 1 deletion common/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
~ You should have received a copy of the GNU General Public License
~ along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest package="com.moez.QKSMS.common" />
<manifest />
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ package com.moez.QKSMS.common.util.extensions

import android.app.job.JobScheduler
import android.content.Context
import android.content.pm.PackageInfo
import android.content.res.ColorStateList
import android.graphics.Color
import android.util.TypedValue
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.content.pm.PackageInfoCompat
import com.moez.QKSMS.util.tryOrNull

fun Context.getColorCompat(colorRes: Int): Int {
Expand Down Expand Up @@ -85,7 +87,7 @@ fun Context.isInstalled(packageName: String): Boolean {
}

val Context.versionCode: Int
get() = packageManager.getPackageInfo(packageName, 0).versionCode
get() = PackageInfoCompat.getLongVersionCode(PackageInfo()).toInt()

val Context.jobScheduler: JobScheduler
get() = getSystemService()!!
1 change: 1 addition & 0 deletions data/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ android {
withAnalytics { dimension "analytics" }
noAnalytics { dimension "analytics" }
}
namespace 'com.moez.QKSMS.data'
}

dependencies {
Expand Down
2 changes: 1 addition & 1 deletion data/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
~ You should have received a copy of the GNU General Public License
~ along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest package="com.moez.QKSMS.data" />
<manifest />
1 change: 1 addition & 0 deletions domain/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ android {
minSdkVersion 21
targetSdkVersion 29
}
namespace 'com.moez.QKSMS.domain'
}

dependencies {
Expand Down
2 changes: 1 addition & 1 deletion domain/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
~ You should have received a copy of the GNU General Public License
~ along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest package="com.moez.QKSMS.domain" />
<manifest />
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
8 changes: 4 additions & 4 deletions presentation/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ apply plugin: 'kotlin-kapt'

android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
flavorDimensions "analytics"

defaultConfig {
Expand Down Expand Up @@ -61,14 +60,15 @@ android {
jvmTarget = "1.8"
}

lintOptions {
abortOnError false
}

productFlavors {
withAnalytics { dimension "analytics" }
noAnalytics { dimension "analytics" }
}
namespace 'com.moez.QKSMS'
lint {
abortOnError false
}

if (System.getenv("CI") == "true") {
signingConfigs.release.storeFile = file("../keystore")
Expand Down
3 changes: 1 addition & 2 deletions presentation/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
~ You should have received a copy of the GNU General Public License
~ along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.moez.QKSMS">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.moez.QKSMS.common.widget

import android.content.Context
import android.util.AttributeSet
import kotlin.math.ceil

class TightTextView @JvmOverloads constructor(
context: Context,
Expand All @@ -35,11 +36,9 @@ class TightTextView @JvmOverloads constructor(
return
}

val maxLineWidth = (0 until layout.lineCount)
.map(layout::getLineWidth)
.max() ?: 0f
val maxLineWidth = (0 until layout.lineCount).maxOfOrNull(layout::getLineWidth) ?: 0f

val width = Math.ceil(maxLineWidth.toDouble()).toInt() + compoundPaddingLeft + compoundPaddingRight
val width = ceil(maxLineWidth.toDouble()).toInt() + compoundPaddingLeft + compoundPaddingRight
if (width < measuredWidth) {
val widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.getMode(widthMeasureSpec))
super.onMeasure(widthSpec, heightMeasureSpec)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class BackupPresenter @Inject constructor(
.distinctUntilChanged()
.switchMap { backupRepo.getBackups() }
.doOnNext { backups -> newState { copy(backups = backups) } }
.map { backups -> backups.map { it.date }.max() ?: 0L }
.map { backups -> backups.maxOfOrNull { it.date } ?: 0L }
.map { lastBackup ->
when (lastBackup) {
0L -> context.getString(R.string.backup_never)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
* Copyright (C) 2017,2021 Moez Bhatti <moez.bhatti@gmail.com>,to268
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should i add my real name and my email address instead ?

*
* This file is part of QKSMS.
*
Expand Down Expand Up @@ -30,7 +30,9 @@ import android.os.Build
import android.os.Bundle
import android.provider.ContactsContract
import android.provider.MediaStore
import android.speech.tts.TextToSpeech
import android.text.format.DateFormat
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.AlertDialog
Expand Down Expand Up @@ -66,12 +68,16 @@ import io.reactivex.Observable
import io.reactivex.subjects.PublishSubject
import io.reactivex.subjects.Subject
import kotlinx.android.synthetic.main.compose_activity.*
import kotlinx.android.synthetic.main.compose_activity.attachments
import kotlinx.android.synthetic.main.compose_activity.sim
import kotlinx.android.synthetic.main.compose_activity.simIndex
import kotlinx.android.synthetic.main.message_list_item_in.*
import java.text.SimpleDateFormat
import java.util.*
import javax.inject.Inject
import kotlin.collections.HashMap

class ComposeActivity : QkThemedActivity(), ComposeView {
class ComposeActivity : QkThemedActivity(), ComposeView, TextToSpeech.OnInitListener {

companion object {
private const val SelectContactRequestCode = 0
Expand All @@ -82,12 +88,18 @@ class ComposeActivity : QkThemedActivity(), ComposeView {
private const val CameraDestinationKey = "camera_destination"
}

@Inject lateinit var attachmentAdapter: AttachmentAdapter
@Inject lateinit var chipsAdapter: ChipsAdapter
@Inject lateinit var dateFormatter: DateFormatter
@Inject lateinit var messageAdapter: MessagesAdapter
@Inject lateinit var navigator: Navigator
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
@Inject
lateinit var attachmentAdapter: AttachmentAdapter
@Inject
lateinit var chipsAdapter: ChipsAdapter
@Inject
lateinit var dateFormatter: DateFormatter
@Inject
lateinit var messageAdapter: MessagesAdapter
@Inject
lateinit var navigator: Navigator
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory

override val activityVisibleIntent: Subject<Boolean> = PublishSubject.create()
override val chipsSelectedIntent: Subject<HashMap<String, String?>> = PublishSubject.create()
Expand Down Expand Up @@ -119,6 +131,7 @@ class ComposeActivity : QkThemedActivity(), ComposeView {
private val viewModel by lazy { ViewModelProviders.of(this, viewModelFactory)[ComposeViewModel::class.java] }

private var cameraDestination: Uri? = null
private var tts: TextToSpeech? = null

override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
Expand Down Expand Up @@ -160,6 +173,9 @@ class ComposeActivity : QkThemedActivity(), ComposeView {
if (Build.VERSION.SDK_INT <= 22) {
messageBackground.setBackgroundTint(resolveThemeColor(R.attr.bubbleColor))
}

// Set tts info
tts = TextToSpeech(this, this)
}

override fun onStart() {
Expand Down Expand Up @@ -206,6 +222,7 @@ class ComposeActivity : QkThemedActivity(), ComposeView {
toolbar.menu.findItem(R.id.details)?.isVisible = !state.editingMode && state.selectedMessages == 1
toolbar.menu.findItem(R.id.delete)?.isVisible = !state.editingMode && state.selectedMessages > 0
toolbar.menu.findItem(R.id.forward)?.isVisible = !state.editingMode && state.selectedMessages == 1
toolbar.menu.findItem(R.id.speech)?.isVisible = !state.editingMode && state.selectedMessages == 1
toolbar.menu.findItem(R.id.previous)?.isVisible = state.selectedMessages == 0 && state.query.isNotEmpty()
toolbar.menu.findItem(R.id.next)?.isVisible = state.selectedMessages == 0 && state.query.isNotEmpty()
toolbar.menu.findItem(R.id.clear)?.isVisible = state.selectedMessages == 0 && state.query.isNotEmpty()
Expand Down Expand Up @@ -251,6 +268,10 @@ class ComposeActivity : QkThemedActivity(), ComposeView {
.show()
}

override fun speechText(text: String) {
tts!!.speak(text, TextToSpeech.QUEUE_FLUSH, null, "")
}

override fun requestDefaultSms() {
navigator.showDefaultSmsDialog(this)
}
Expand Down Expand Up @@ -399,4 +420,27 @@ class ComposeActivity : QkThemedActivity(), ComposeView {

override fun onBackPressed() = backPressedIntent.onNext(Unit)

// Text to speech
override fun onInit(status: Int) {
if (status == TextToSpeech.SUCCESS) {
val result = tts!!.setLanguage(Locale.getDefault())

if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.e("TTS", "The default language is not supported !")
}

} else {
Log.e("TTS", "Initialization failed !")
}
}

override fun onDestroy() {
if (tts != null) {
tts!!.stop()
tts!!.shutdown()
}

super.onDestroy()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ interface ComposeView : QkView<ComposeState> {

fun clearSelection()
fun showDetails(details: String)
fun speechText(text: String)
fun requestDefaultSms()
fun requestStoragePermission()
fun requestSmsPermission()
Expand Down
Loading