Create preferences
This commit is contained in:
@@ -33,6 +33,7 @@ dependencies {
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'org.nanohttpd:nanohttpd:2.2.0'
|
||||
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
|
||||
implementation 'androidx.preference:preference:1.1.0-rc01'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name=".preference.PreferencesActivity"
|
||||
android:label="@string/title_activity_preferences"
|
||||
android:parentActivityName=".MainActivity"/>
|
||||
|
||||
<service
|
||||
android:name=".service.ForegroundService"
|
||||
|
||||
@@ -3,10 +3,13 @@ package io.bartek
|
||||
import android.content.*
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import io.bartek.preference.PreferencesActivity
|
||||
import io.bartek.service.ForegroundService
|
||||
import io.bartek.service.ServiceState
|
||||
|
||||
@@ -24,6 +27,19 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_main, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when(item.itemId) {
|
||||
R.id.open_preferences -> startActivity(Intent(this, PreferencesActivity::class.java))
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun updateViewAccordingToServiceState(newState: ServiceState) {
|
||||
controlServerButton.isEnabled = true
|
||||
when (newState) {
|
||||
@@ -53,8 +69,6 @@ class MainActivity : AppCompatActivity() {
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
fun openTTSSettings(view: View) = startActivity(Intent("com.android.settings.TTS_SETTINGS"))
|
||||
|
||||
fun controlServer(view: View) {
|
||||
controlServerButton.isEnabled = false
|
||||
when (ForegroundService.state) {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package io.bartek.preference
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import io.bartek.R
|
||||
|
||||
class PreferencesActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_preferences)
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.preferences, PreferencesFragment())
|
||||
.commit()
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package io.bartek.preference
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreference
|
||||
import io.bartek.R
|
||||
|
||||
class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
private lateinit var portPreference: EditTextPreference
|
||||
private lateinit var sayEndpointPreference: SwitchPreference
|
||||
private lateinit var waveEndpointPreference: SwitchPreference
|
||||
private lateinit var ttsEnginePreference: Preference
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.preferences, rootKey)
|
||||
portPreference = findPreference("preference_port")!!
|
||||
sayEndpointPreference = findPreference("preference_enable_say_endpoint")!!
|
||||
waveEndpointPreference = findPreference("preference_enable_wave_endpoint")!!
|
||||
ttsEnginePreference = findPreference("preference_tts")!!
|
||||
ttsEnginePreference.setOnPreferenceClickListener {
|
||||
startActivity(Intent("com.android.settings.TTS_SETTINGS"))
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,24 +3,30 @@ package io.bartek.service
|
||||
import android.app.*
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Color
|
||||
import android.os.Binder
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
import androidx.preference.PreferenceManager
|
||||
import io.bartek.MainActivity
|
||||
import io.bartek.R
|
||||
import io.bartek.web.TTSServer
|
||||
import java.lang.Integer.parseInt
|
||||
|
||||
|
||||
class ForegroundService : Service() {
|
||||
private var port: Int = 8080
|
||||
private lateinit var preferences: SharedPreferences
|
||||
private var wakeLock: PowerManager.WakeLock? = null
|
||||
private var isServiceStarted = false
|
||||
private var ttsServer: TTSServer? = null
|
||||
private val port: Int
|
||||
get() = parseInt(preferences.getString("preference_port", "8080")!!)
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
startForeground(1, createNotification())
|
||||
}
|
||||
|
||||
@@ -68,10 +74,7 @@ class ForegroundService : Service() {
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
intent?.let {
|
||||
when(it.action) {
|
||||
START -> {
|
||||
port = it.getIntExtra(PORT, port)
|
||||
startService()
|
||||
}
|
||||
START -> startService()
|
||||
STOP -> stopService()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,10 @@ package io.bartek.web
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.speech.tts.TextToSpeech
|
||||
import android.widget.Toast
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import androidx.preference.PreferenceManager
|
||||
import fi.iki.elonen.NanoHTTPD
|
||||
import fi.iki.elonen.NanoHTTPD.Response.Status.*
|
||||
import io.bartek.R
|
||||
import io.bartek.service.ServiceState
|
||||
import io.bartek.tts.TTS
|
||||
import org.json.JSONObject
|
||||
@@ -18,11 +17,19 @@ private data class TTSRequestData(val text: String, val language: Locale)
|
||||
|
||||
class TTSServer(port: Int, private val context: Context) : NanoHTTPD(port),
|
||||
TextToSpeech.OnInitListener {
|
||||
private val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
private val tts = TTS(context, this)
|
||||
|
||||
override fun serve(session: IHTTPSession?): Response {
|
||||
try {
|
||||
return tryToServe(session)
|
||||
session?.let {
|
||||
return when(it.uri) {
|
||||
"/wave" -> wave(it)
|
||||
else -> throw ResponseException(NOT_FOUND, "")
|
||||
}
|
||||
}
|
||||
|
||||
throw ResponseException(BAD_REQUEST, "")
|
||||
} catch (e: ResponseException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
@@ -30,18 +37,8 @@ class TTSServer(port: Int, private val context: Context) : NanoHTTPD(port),
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryToServe(session: IHTTPSession?): Response {
|
||||
val (text, language) = getRequestData(validateRequest(session))
|
||||
val (stream, size) = tts.performTTS(text, language)
|
||||
return newFixedLengthResponse(OK, "audio/x-wav", stream, size)
|
||||
}
|
||||
|
||||
private fun validateRequest(session: IHTTPSession?): IHTTPSession {
|
||||
if (session == null) {
|
||||
throw ResponseException(BAD_REQUEST, "")
|
||||
}
|
||||
|
||||
if (session.uri != "/") {
|
||||
private fun wave(session: IHTTPSession): Response {
|
||||
if(!preferences.getBoolean("preference_enable_wave_endpoint", true)) {
|
||||
throw ResponseException(NOT_FOUND, "")
|
||||
}
|
||||
|
||||
@@ -53,8 +50,9 @@ class TTSServer(port: Int, private val context: Context) : NanoHTTPD(port),
|
||||
throw ResponseException(BAD_REQUEST, "")
|
||||
}
|
||||
|
||||
|
||||
return session
|
||||
val (text, language) = getRequestData(session)
|
||||
val (stream, size) = tts.performTTS(text, language)
|
||||
return newFixedLengthResponse(OK, "audio/x-wav", stream, size)
|
||||
}
|
||||
|
||||
private fun getRequestData(session: IHTTPSession): TTSRequestData {
|
||||
|
||||
9
app/src/main/res/drawable/ic_settings.xml
Normal file
9
app/src/main/res/drawable/ic_settings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19.1,12.9a2.8,2.8 0,0 0,0.1 -0.9,2.8 2.8,0 0,0 -0.1,-0.9l2.1,-1.6a0.7,0.7 0,0 0,0.1 -0.6L19.4,5.5a0.7,0.7 0,0 0,-0.6 -0.2l-2.4,1a6.5,6.5 0,0 0,-1.6 -0.9l-0.4,-2.6a0.5,0.5 0,0 0,-0.5 -0.4H10.1a0.5,0.5 0,0 0,-0.5 0.4L9.3,5.4a5.6,5.6 0,0 0,-1.7 0.9l-2.4,-1a0.4,0.4 0,0 0,-0.5 0.2l-2,3.4c-0.1,0.2 0,0.4 0.2,0.6l2,1.6a2.8,2.8 0,0 0,-0.1 0.9,2.8 2.8,0 0,0 0.1,0.9L2.8,14.5a0.7,0.7 0,0 0,-0.1 0.6l1.9,3.4a0.7,0.7 0,0 0,0.6 0.2l2.4,-1a6.5,6.5 0,0 0,1.6 0.9l0.4,2.6a0.5,0.5 0,0 0,0.5 0.4h3.8a0.5,0.5 0,0 0,0.5 -0.4l0.3,-2.6a5.6,5.6 0,0 0,1.7 -0.9l2.4,1a0.4,0.4 0,0 0,0.5 -0.2l2,-3.4c0.1,-0.2 0,-0.4 -0.2,-0.6ZM12,15.6A3.6,3.6 0,1 1,15.6 12,3.6 3.6,0 0,1 12,15.6Z"/>
|
||||
</vector>
|
||||
@@ -1,30 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/control_server_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="2"
|
||||
android:onClick="controlServer"
|
||||
android:text="@string/main_activity_run" />
|
||||
</LinearLayout>
|
||||
android:orientation="vertical"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<Button
|
||||
android:id="@+id/ttsSettings"
|
||||
android:id="@+id/control_server_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:onClick="openTTSSettings"
|
||||
android:text="@string/main_activity_tts_settings" />
|
||||
</LinearLayout>
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="2"
|
||||
android:onClick="controlServer"
|
||||
android:text="@string/main_activity_run" />
|
||||
</LinearLayout>
|
||||
|
||||
9
app/src/main/res/layout/activity_preferences.xml
Normal file
9
app/src/main/res/layout/activity_preferences.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/preferences"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
5
app/src/main/res/menu/menu_main.xml
Normal file
5
app/src/main/res/menu/menu_main.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/open_preferences" android:icon="@drawable/ic_settings" app:showAsAction="always" android:title="Preferences" />
|
||||
</menu>
|
||||
@@ -1,12 +1,23 @@
|
||||
<resources>
|
||||
<string name="app_name">TTS Server</string>
|
||||
|
||||
<string name="main_activity_run">Run</string>
|
||||
<string name="main_activity_stop">Stop</string>
|
||||
|
||||
<string name="service_notification_category_name">HTTP Server</string>
|
||||
<string name="service_notification_category_description">The fixed notification keeping the HTTP server alive</string>
|
||||
<string name="service_notification_title">Server is running</string>
|
||||
<string name="service_notification_text">The HTTP server is listening on port %1$d</string>
|
||||
|
||||
<string name="main_activity_server_port">Server port</string>
|
||||
<string name="main_activity_run">Run</string>
|
||||
<string name="main_activity_stop">Stop</string>
|
||||
<string name="main_activity_tts_settings">TTS Settings</string>
|
||||
<string name="title_activity_preferences">Settings</string>
|
||||
<string name="preference_port_summary">The desired port on which HTTP server is intended to listening</string>
|
||||
<string name="preference_port_title">Server port</string>
|
||||
<string name="preference_enable_say_endpoint_summary">Allow HTTP clients to use /say endpoint which enables them to say message using builtin speakers or external ones connected to the device</string>
|
||||
<string name="preference_enable_say_endpoint_title">Enable /say endpoint</string>
|
||||
<string name="preference_enable_wave_endpoint_summary">Allow HTTP clients to use /wave endpoint which enables them to retrieve TTS message as wave file</string>
|
||||
<string name="preference_enable_wave_endpoint_title">Enable /wave endpoint</string>
|
||||
<string name="preference_tts_summary">Go to platform\'s TTS engine settings and adjust its parameters</string>
|
||||
<string name="preference_tts_title">TTS engine settings</string>
|
||||
<string name="preference_category_tts">TTS engine</string>
|
||||
<string name="preference_category_server">Server</string>
|
||||
</resources>
|
||||
|
||||
38
app/src/main/res/xml/preferences.xml
Normal file
38
app/src/main/res/xml/preferences.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<PreferenceCategory android:title="@string/preference_category_server" app:iconSpaceReserved="false">
|
||||
<EditTextPreference
|
||||
android:defaultValue="8080"
|
||||
android:inputType="number"
|
||||
android:key="preference_port"
|
||||
android:summary="@string/preference_port_summary"
|
||||
android:title="@string/preference_port_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:key="preference_enable_say_endpoint"
|
||||
android:summary="@string/preference_enable_say_endpoint_summary"
|
||||
android:title="@string/preference_enable_say_endpoint_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:key="preference_enable_wave_endpoint"
|
||||
android:summary="@string/preference_enable_wave_endpoint_summary"
|
||||
android:title="@string/preference_enable_wave_endpoint_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/preference_category_tts" app:iconSpaceReserved="false">
|
||||
<Preference
|
||||
android:key="preference_tts"
|
||||
android:summary="@string/preference_tts_summary"
|
||||
android:title="@string/preference_tts_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
||||
Reference in New Issue
Block a user