Commit ea71d06b authored by Daniel Sonck's avatar Daniel Sonck
Browse files

Merge pull request #46 in THFM/fm.touhou.touhoufm from devel/dsonck to development

* commit 'ad82d490':
  [THFMA-33] Fix unit test results
  [THFMA-30] [THFMA-31] [THFMA-32] Version checking
parents 21474234 ad82d490
...@@ -17,6 +17,7 @@ plugins { ...@@ -17,6 +17,7 @@ plugins {
id 'com.github.triplet.play' version '2.4.1' id 'com.github.triplet.play' version '2.4.1'
} }
apply from: 'version.gradle' apply from: 'version.gradle'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
...@@ -62,6 +63,9 @@ dependencies { ...@@ -62,6 +63,9 @@ dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:$rootProject.navigationVersion" implementation "androidx.navigation:navigation-fragment-ktx:$rootProject.navigationVersion"
implementation "androidx.navigation:navigation-ui-ktx:$rootProject.navigationVersion" implementation "androidx.navigation:navigation-ui-ktx:$rootProject.navigationVersion"
implementation 'com.android.volley:volley:1.1.0'
implementation project(':changelog')
} }
// The sample build uses multiple directories to // The sample build uses multiple directories to
...@@ -74,16 +78,17 @@ List<String> dirs = [ ...@@ -74,16 +78,17 @@ List<String> dirs = [
android { android {
compileSdkVersion 28 compileSdkVersion 29
defaultConfig { defaultConfig {
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 28 targetSdkVersion 29
applicationId "fm.touhou.touhoufm" applicationId "fm.touhou.touhoufm"
versionCode gitVersionCode versionCode gitVersionCode
versionName gitVersionName versionName gitVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
compileOptions { compileOptions {
...@@ -124,6 +129,13 @@ android { ...@@ -124,6 +129,13 @@ android {
path 'src/main/cpp/CMakeLists.txt' path 'src/main/cpp/CMakeLists.txt'
} }
} }
testOptions {
unitTests.all {
useJUnitPlatform()
}
}
} }
if(file('release.gradle').exists()) { if(file('release.gradle').exists()) {
......
...@@ -35,9 +35,16 @@ ...@@ -35,9 +35,16 @@
package fm.touhou.touhoufm.ui package fm.touhou.touhoufm.ui
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
...@@ -45,24 +52,39 @@ import androidx.navigation.NavController ...@@ -45,24 +52,39 @@ import androidx.navigation.NavController
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.* import androidx.navigation.ui.*
import ch.derlin.changelog.Changelog
import com.android.volley.RequestQueue
import com.android.volley.Response
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import com.google.android.material.navigation.NavigationView import com.google.android.material.navigation.NavigationView
import fm.touhou.touhoufm.BuildConfig
import fm.touhou.touhoufm.R import fm.touhou.touhoufm.R
import org.json.JSONObject
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration : AppBarConfiguration private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var queue: RequestQueue
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
queue = Volley.newRequestQueue(this)
val prefs = getSharedPreferences("AppDetails", Context.MODE_PRIVATE);
setContentView(R.layout.navigation_activity) setContentView(R.layout.navigation_activity)
val toolbar = findViewById<Toolbar>(R.id.toolbar) val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
val host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment? ?: return val host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment?
?: return
val navController = host.navController val navController = host.navController
val drawerLayout : DrawerLayout? = findViewById(R.id.drawer_layout) val drawerLayout: DrawerLayout? = findViewById(R.id.drawer_layout)
appBarConfiguration = AppBarConfiguration( appBarConfiguration = AppBarConfiguration(
setOf(R.id.home_dest), setOf(R.id.home_dest),
drawerLayout) drawerLayout)
...@@ -70,8 +92,77 @@ class MainActivity : AppCompatActivity() { ...@@ -70,8 +92,77 @@ class MainActivity : AppCompatActivity() {
setupActionBar(navController, appBarConfiguration) setupActionBar(navController, appBarConfiguration)
setupNavigationMenu(navController) setupNavigationMenu(navController)
val appVersion = BuildConfig.VERSION_CODE
val lastVersion = 42//prefs.getInt("LatestVersion", 0)
val lastKnownVersion = prefs.getInt("LatestReleaseVersion", 0)
val jsonRequest = JsonObjectRequest("https://www.touhou.fm/app-release.json", null,
Response.Listener { response: JSONObject ->
val supported: Boolean;
when {
appVersion < response.getInt("supported") -> {
supported = false;
AlertDialog.Builder(this)
.setTitle("Unsupported app version")
.setMessage("This version of the app is currently unsupported, please download the new version from the play store")
.setPositiveButton("Download", DialogInterface.OnClickListener { dialogInterface, i ->
val appPackageName = packageName
try {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$appPackageName")))
} catch (anfe: android.content.ActivityNotFoundException) {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=$appPackageName")))
}
})
.setNegativeButton("Quit", DialogInterface.OnClickListener { dialogInterface, i ->
this@MainActivity.finish()
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
appVersion < response.getInt("beta") - 1 -> {
supported = true;
if (lastVersion != appVersion || lastKnownVersion != response.getInt("beta") - 1) {
AlertDialog.Builder(this)
.setTitle("New version")
.setMessage("A new version is available in the play store")
.setPositiveButton("Download", DialogInterface.OnClickListener { dialogInterface, i ->
val appPackageName = packageName
try {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$appPackageName")))
} catch (anfe: android.content.ActivityNotFoundException) {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=$appPackageName")))
}
})
.setNegativeButton(android.R.string.cancel, null)
.setIcon(android.R.drawable.ic_dialog_info)
.show();
}
}
appVersion < response.getInt("alpha") -> {
supported = true;
Toast.makeText(this, "Thanks for being a beta tester", LENGTH_LONG).show()
}
else -> {
supported = true;
Toast.makeText(this, "Thanks for being an alpha tester", LENGTH_LONG).show()
}
}
if (supported && lastVersion != appVersion) {
prefs.edit().putInt("LatestVersion", appVersion).apply()
Changelog.createDialog(this, versionCode = lastVersion).show()
}
}, Response.ErrorListener {
Toast.makeText(this, "Failed to check latest version", Toast.LENGTH_LONG).show();
})
queue.add(jsonRequest);
} }
private fun setupNavigationMenu(navController: NavController) { private fun setupNavigationMenu(navController: NavController) {
val sideNavView = findViewById<NavigationView>(R.id.nav_view) val sideNavView = findViewById<NavigationView>(R.id.nav_view)
sideNavView.setupWithNavController(navController) sideNavView.setupWithNavController(navController)
...@@ -80,7 +171,7 @@ class MainActivity : AppCompatActivity() { ...@@ -80,7 +171,7 @@ class MainActivity : AppCompatActivity() {
private fun setupActionBar(navController: NavController, private fun setupActionBar(navController: NavController,
appBarConfig : AppBarConfiguration) { appBarConfig: AppBarConfiguration) {
setupActionBarWithNavController(navController, appBarConfig) setupActionBarWithNavController(navController, appBarConfig)
} }
......
This application tunes into the TouHou.FM radio. This radio streams original and doujin music from Touhou Project by TeamShanghaiAlice.
Zurzeit ist es eine Alpha-Version, in welcher nicht Alles implementiert ist.
Unter anderem lassen sich auch einige Bugs bzw. Fehler finden.
Ich bitte Sie eine Nachricht für alle Fehler, Anregungen, positives oder negatives Feedback, an app@touhou.fm zu senden.
\ No newline at end of file
Hören Sie TouHow.FM direkt von ihrem Handy, Tablet oder allen anderen Geräten.
\ No newline at end of file
Radio Spieler von TouHou.FM
\ No newline at end of file
Fixed Metadatei informationen
Stabiele weiterentwicklung
Widget zugefügt
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
* Copyright 2018 Daniel Sonck, translation Patrick Büchele
*
* This file is part of fm.touhou.touhoufm.
*
* fm.touhou.touhoufm 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, version 2.
*
* fm.touhou.touhoufm 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 fm.touhou.touhoufm. If not, see <http://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">TouHou.FM</string>
<string name="label_stop">Stop</string>
<string name="label_pause">Pause</string>
<string name="label_play">Abspielen</string>
<string name="label_play_pause">Pause und Abspielen umschalten</string>
<string name="time_format">%2$d:%1$02d</string><!-- MM:SS -->
<string name="album_format">( %1$s )</string><!-- ( <album name> ) -->
<string name="artist_circle_format">%1$s ( %2$s )</string><!-- <artist name> ( <circle name> ) -->
<string name="unknown_song">Unbekantes Lied</string>
<string name="unknown_album">Unbekantes Album</string>
<string name="unknown_artist">Umbekanter Künstler</string>
<string name="unknown_circle">Unbekanter Kreise</string>
<string name="home">Home</string>
<string name="settings">Einstellungen</string>
<string name="stream_port_summary">Welchen Port benutzen fürs streaming</string>
<string name="stream_port_title">Streaming Port</string>
<string name="stream_custom_title">Benutze benutzerdefinierten stream server</string>
<string name="stream_host_summary">Welche Adresse fürs Streaming benutzt wird</string>
<string name="stream_host_title">Streaming Host</string>
<string name="category_advanced_summary">Einstellungen für Power User</string>
<string name="category_advanced_title">Fortgeschritten</string>
<string name="keep_metadata_alive_summary">Lass die Verbindung offen fürs erhalten von Metadata Updates. Es braucht Daten, auch wenn der Vorgang gestoppt ist.</string>
<string name="keep_metadata_alive_title">Immer Fordern nach metadata</string>
<string name="show_data_summary">Zeigt den Datenverbrauch vom streaming</string>
<string name="show_data_title">Datenverbrauch</string>
<string name="streaming_rate_title">Streaming Bitrate</string>
<string name="streaming_rate_summary">Maximal verfügbare Bitrate fürs Streaming</string>
<string name="category_streaming_title">Streaming</string>
<string name="category_streaming_summary">Feinjustieren für die Streamingqualität und den Datenverbrauch</string>
</resources>
\ No newline at end of file
...@@ -40,5 +40,6 @@ ...@@ -40,5 +40,6 @@
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item> <item name="colorAccent">@color/colorAccent</item>
<item name="changelogStyle">@style/LibChangelog</item>
</style> </style>
</resources> </resources>
<?xml version="1.0" encoding="utf-8"?>
<changelog >
<release version="v2.0.19" versioncode="44">
<change>Updated translations, added German</change>
<change>Add this changelog window</change>
<change>Notify users when version is outdated, prevent launch when unsupported</change>
<change>Fix crash on pause</change>
<change>Show song progress information</change>
<change>Expert: Add ability to pick a streaming server</change>
<change>Widget support</change>
<change>Update icon to allow launchers to use their style</change>
</release>
<release version="v2.0.18" versioncode="33">
<change>Update to new streaming specifications</change>
<change>Song info works again</change>
<change>Fixed code causing crashes</change>
</release>
<release version="v2.0.13" versioncode="27">
<change>Updated translations</change>
<change>Fix memoryleak</change>
</release>
<release version="v2.0.12" versioncode="24">
<change>Fix crash on startup</change>
</release>
<release version="v2.0.11" versioncode="23">
<change>THFMA-8: Using app Quit will remove notification as well</change>
<change>THFMA-9: Add information and playback buttons to the notification</change>
<change>THFMA-10: Fix app not stopping playback immediately</change>
<change>THFMA-11: Fix music sounding slow after switch from Data to Wifi</change>
<change>THFMA-12: Integrate better with android. App will advertise it's playing and automatically stop if another source is starting (e.g. youtube)</change>
</release>
<release version="v2.0.10" versioncode="22">
<change>Small compatibility fixes</change>
</release>
<release version="v2.0.9" versioncode="21">
<change>Improved stability</change>
</release>
<release version="v2.0.8" versioncode="20">
<change>Fixed endless asking for power management</change>
</release>
<release version="v2.0.7" versioncode="19">
<change>Fix battery optimization detection</change>
</release>
<release version="v2.0.6" versioncode="18">
<change>Added dialog to disable optimisations for the app which can cause random issues during streaming while screen is off</change>
<change>Updated translations</change>
</release>
<release version="v2.0.5" versioncode="17">
<change>Fixed crashing bug</change>
</release>
<release version="v2.0.4" versioncode="16">
<change>Added translations: French and Hungarian</change>
<change>Fixed bug causing crash when no network is available</change>
</release>
<release version="v2.0.3" versioncode="15">
<change>Removed failing login UI</change>
<change>Removed unused settings screen</change>
</release>
<release version="v2.0.0" versioncode="12">
<change>New streaming technology improving reliability and quality especially on roaming networks</change>
</release>
</changelog>
\ No newline at end of file
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<PreferenceCategory <PreferenceCategory
android:summary="@string/category_streaming_summary" android:summary="@string/category_streaming_summary"
android:title="@string/category_streaming_title" android:title="@string/category_streaming_title"
app:isPreferenceVisible="false"> app:isPreferenceVisible="true">
<ListPreference <ListPreference
android:defaultValue="-1" android:defaultValue="-1"
...@@ -27,12 +27,7 @@ ...@@ -27,12 +27,7 @@
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:summary="@string/category_advanced_summary" android:summary="@string/category_advanced_summary"
android:title="@string/category_advanced_title" android:title="@string/category_advanced_title">
app:initialExpandedChildrenCount="0">
<SwitchPreference
android:defaultValue="false"
android:key="stream_custom"
android:title="@string/stream_custom_title" />
<EditTextPreference <EditTextPreference
android:defaultValue="strm.touhou.fm" android:defaultValue="strm.touhou.fm"
android:key="stream_host" android:key="stream_host"
...@@ -49,5 +44,9 @@ ...@@ -49,5 +44,9 @@
android:summary="@string/stream_port_summary" android:summary="@string/stream_port_summary"
android:title="@string/stream_port_title" android:title="@string/stream_port_title"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<SwitchPreference
android:defaultValue="false"
android:key="stream_custom"
android:title="@string/stream_custom_title" />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>
\ No newline at end of file
...@@ -23,9 +23,9 @@ import android.util.Log ...@@ -23,9 +23,9 @@ import android.util.Log
import fm.touhou.touhoufm.radio.RingBuffer import fm.touhou.touhoufm.radio.RingBuffer
import io.mockk.every import io.mockk.every
import io.mockk.mockkStatic import io.mockk.mockkStatic
import org.junit.Assert.* import org.junit.jupiter.api.Assertions.*
import org.junit.Before import org.junit.jupiter.api.BeforeEach
import org.junit.Test import org.junit.jupiter.api.Test
import java.util.* import java.util.*
/** /**
...@@ -33,20 +33,16 @@ import java.util.* ...@@ -33,20 +33,16 @@ import java.util.*
*/ */
class RingBufferTest { class RingBufferTest {
internal inner class Reader(private val buff: RingBuffer, size: Int) : Thread() { internal inner class Reader(private val buff: RingBuffer, size: Int) : Thread() {
var out: ShortArray var out: ShortArray = ShortArray(size)
var readReturn: Int = 0 var readReturn: Int = 0
init {
out = ShortArray(size)
}
override fun run() { override fun run() {
readReturn = buff.read(out, out.size) readReturn = buff.read(out, out.size)
} }
} }
@Before @BeforeEach
fun setupMocks() { fun setupMocks() {
mockkStatic(Log::class) mockkStatic(Log::class)
every { Log.v(any(), any()) } returns 0 every { Log.v(any(), any()) } returns 0
......
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 14
targetSdkVersion 28
versionCode 2
versionName "2.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0-alpha04'
implementation 'androidx.recyclerview:recyclerview:1.1.0-alpha04'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "com.google.android.material:material:1.1.0-alpha05"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0-alpha03'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-alpha03'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
repositories {
mavenCentral()
}
# 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
package ch.derlin.changelog;
import android.content.Context;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("ch.derlin.changelog.test", appContext.getPackageName());
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ch.derlin.changelog" />
package ch.derlin.changelog
import android.app.Activity
import android.app.AlertDialog
import android.content.Context