Skip to content

Commit

Permalink
Merge pull request #97 from remotv/develop
Browse files Browse the repository at this point in the history
Develop -> master
  • Loading branch information
SkyeOfBreeze authored Feb 27, 2020
2 parents b3f84ae + bf5eb6c commit bd1c77d
Show file tree
Hide file tree
Showing 29 changed files with 601 additions and 19 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ For setup guide and button templates, please check out the [WIKI](https://github

### Android Studio

- Version 3.5 or higher. May not be buildable on lower versions
- Version 3.6 or higher. May not be buildable on lower versions
- Android SDK (should be installed with Android Studio)
- Java 7 or 8 JDK (might be installed with Android Studio)

Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ android {
applicationId "tv.remo.android.controller"
minSdkVersion 16
targetSdkVersion 28
versionCode 12
versionName "0.14.0"
versionCode 13
versionName "0.15.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
package tv.remo.android.controller.fragments
import android.content.Intent
import android.os.Bundle
import androidx.preference.Preference
import tv.remo.android.controller.R
import tv.remo.android.settingsutil.fragments.BasePreferenceFragmentCompat

class SettingsDisplay : BasePreferenceFragmentCompat(
R.xml.settings_display
)
){
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
super.onCreatePreferences(savedInstanceState, rootKey)
handleDozeKey()
}

private fun handleDozeKey() {
activity?:return
val pref = preferenceManager.findPreference<Preference>(
getString(R.string.dozeSystemSettingsKey)
) ?: return
val launchIntent = Intent("android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS")
if(launchIntent.resolveActivity(activity!!.packageManager) == null) return
pref.intent = launchIntent
pref.isVisible = true
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package tv.remo.android.controller.fragments

import android.bluetooth.BluetoothAdapter
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.View
import android.widget.Toast
Expand All @@ -12,6 +14,8 @@ import org.btelman.controlsdk.utils.ClassScanner
import tv.remo.android.controller.R
import tv.remo.android.settingsutil.fragments.BasePreferenceFragmentCompat
import tv.remo.android.settingsutil.preferences.ListSettingsPreference
import java.util.*
import kotlin.collections.ArrayList

class SettingsRobot : BasePreferenceFragmentCompat(
R.xml.settings_robot,
Expand Down Expand Up @@ -46,12 +50,22 @@ class SettingsRobot : BasePreferenceFragmentCompat(
pref ?: return //skip if null
val classes = ClassScanner.getClassesWithAnnotation(context!!, annotation)
val classNames = ArrayList<String>()
classes.forEach {
classNames.add(it.name)
}
val simpleClassNames = ArrayList<String>()
classes.forEach {
simpleClassNames.add(it.simpleName)
var deviceSupportsHardware = true
if(annotation == DriverComponent::class.java){
//check via hardcoding for now.
if(it.name.toLowerCase(Locale.US).contains("bluetooth")){
//driver is a bluetooth driver
if(!context!!.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH))
deviceSupportsHardware = false //no support found
//TODO check for ble?
}
}
if(deviceSupportsHardware){
classNames.add(it.name)
simpleClassNames.add(it.simpleName)
}
}
val nameArray = simpleClassNames.toArray(Array(0){""})
val valueArray = classNames.toArray(Array(0){""})
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
<string name="cameraDeviceIdTitle">Camera Device ID (0 is back)</string>
<string name="cameraSettingsSummary">Resolution, Orientation, Bitrate</string>
<string name="cameraResolutionTitle">Resolution</string>
<string name="cameraFocusTitle">Auto Focus</string>
<string name="cameraOrientationTitle">Orientation</string>
<string name="camera2DisabledTitle">Camera2 Disabled</string>
<string name="camera2DisabledSummary">Device is using legacy camera API.
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/res/xml/settings_camera.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@
app:useSimpleSummaryProvider="true"
app:entries="@array/resolution_pref_list"
app:entryValues="@array/resolution_pref_list"/>
<androidx.preference.ListPreference
app:key="@string/cameraFocusKey"
app:dependency="@string/useCamera2"
app:title="@string/cameraFocusTitle"
app:defaultValue="auto"
app:useSimpleSummaryProvider="true"
app:entries="@array/focus_pref_list"
app:entryValues="@array/focus_pref_list_values"/>
<androidx.preference.ListPreference
app:key="@string/cameraOrientationKey"
app:title="@string/cameraOrientationTitle"
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/res/xml/settings_display.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@
</Preference>

<Preference
app:isPreferenceVisible="false"
app:key="@string/dozeSystemSettingsKey"
app:title="@string/dozeSettingsPageTitle"
app:summary="@string/dozeSettingsPageSummary">
<intent android:action="android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS"/>
<intent android:action=""/>
</Preference>
</PreferenceCategory>
</androidx.preference.PreferenceScreen>
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.android.tools.build:gradle:3.6.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

// NOTE: Do not place your application dependencies here; they belong
Expand Down
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-5.6.4-all.zip
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ enum class LicenseType {
APACHE2_0,
MIT,
GPL3,
LGPL3,
BSD3Clause;

fun getDefaultLink(): String {
return when(this){
APACHE2_0 -> "https://www.apache.org/licenses/LICENSE-2.0.txt"
MIT -> "https://opensource.org/licenses/MIT"
GPL3 -> "https://www.gnu.org/licenses/gpl-3.0.txt"
LGPL3 -> "https://www.gnu.org/licenses/lgpl-3.0.txt"
BSD3Clause -> "https://opensource.org/licenses/BSD-3-Clause"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class RemoSettingsUtil(context : Context, sharedPreferences: SharedPreferences)
//Camera related settings
val cameraEnabled = BooleanPref(context, sharedPreferences, R.string.cameraSettingsEnableKey, false)
val cameraResolution = StringPref(context, sharedPreferences, R.string.cameraResolutionKey, "640x480")
val cameraFocus = StringPref(context, sharedPreferences, R.string.cameraFocusKey, "auto")
val cameraOrientation = StringPref(context, sharedPreferences, R.string.cameraOrientationKey, "DIR_90")
val cameraDeviceId = IntPref(context, sharedPreferences, R.string.cameraDeviceIdKey, 0)
val cameraBitrate = StringPref(context, sharedPreferences, R.string.cameraBitrateKey, "1024")
Expand Down Expand Up @@ -68,6 +69,10 @@ class RemoSettingsUtil(context : Context, sharedPreferences: SharedPreferences)
val keepScreenOn = BooleanPref(context, sharedPreferences, R.string.displayPersistKey, false)
val hideScreenControls = BooleanPref(context, sharedPreferences, R.string.autoHideControlsEnabledKey, false)

//misc settings
val streamSleepMode = BooleanPref(context, sharedPreferences, R.string.streamAutoSleepEnabledKey, false)
val streamSleepTimeOut = IntPref(context, sharedPreferences, R.string.streamAutoSleepTimeoutKey, 5*60) //5 minutes

companion object{
private var INSTANCE : RemoSettingsUtil? = null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.btelman.controlsdk.models.Component
import org.btelman.controlsdk.models.ComponentEventObject
import org.btelman.controlsdk.tts.TTSBaseComponent
import tv.remo.android.controller.sdk.RemoSettingsUtil
import tv.remo.android.controller.sdk.interfaces.RemoCommandSender
import tv.remo.android.controller.sdk.models.api.User
import tv.remo.android.controller.sdk.utils.ChatUtil
import kotlin.system.exitProcess
Expand All @@ -21,7 +22,7 @@ import kotlin.system.exitProcess
* Commands can come from a button or from the chat. Commands from chat are only able to be used
* by the owner and moderators
*/
class RemoCommandHandler : Component(){
class RemoCommandHandler : Component(), RemoCommandSender {
private var devModeEnabled = false
private var stationary = false
private var serverOwner = ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.btelman.controlsdk.models.ComponentEventObject
import org.btelman.controlsdk.tts.TTSBaseComponent
import org.json.JSONObject
import tv.remo.android.controller.sdk.RemoSettingsUtil
import tv.remo.android.controller.sdk.interfaces.RemoCommandSender
import tv.remo.android.controller.sdk.models.api.*
import tv.remo.android.controller.sdk.utils.ChatUtil
import tv.remo.android.controller.sdk.utils.EndpointBuilder
Expand All @@ -24,7 +25,7 @@ import tv.remo.android.controller.sdk.utils.isUrl
*
* Note: Do not instantiate in the activity! Must pass it to the ControlSDK Service
*/
class RemoSocketComponent : Component() {
class RemoSocketComponent : Component() , RemoCommandSender {
private var socket: WebSocket? = null
var apiKey : String? = null
var activeChannelId : String? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.os.Bundle
import org.btelman.controlsdk.models.ComponentEventObject
import org.btelman.controlsdk.streaming.models.StreamInfo
import tv.remo.android.controller.sdk.interfaces.CommandStreamHandler
import tv.remo.android.controller.sdk.interfaces.RemoCommandSender
import tv.remo.android.controller.sdk.models.api.Channel
import tv.remo.android.controller.sdk.utils.EndpointBuilder

Expand All @@ -20,7 +21,7 @@ class StreamCommandHandler(val context: Context?, val streamHandler : CommandStr
private val subscriptionList = streamHandler.onRegisterCustomCommands()

fun handleExternalMessage(message: ComponentEventObject){
if(message.source is RemoSocketComponent || message.source is RemoCommandHandler){
if(message.source is RemoCommandSender){
handleSocketCommand(message)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import tv.remo.android.controller.sdk.components.RemoCommandHandler
import tv.remo.android.controller.sdk.components.RemoSocketComponent
import tv.remo.android.controller.sdk.components.StreamCommandHandler
import tv.remo.android.controller.sdk.interfaces.CommandStreamHandler
import tv.remo.android.controller.sdk.interfaces.RemoCommandSender
import tv.remo.android.controller.sdk.models.CommandSubscriptionData
import tv.remo.android.controller.sdk.utils.ChatUtil

Expand All @@ -38,7 +39,7 @@ class RemoAudioComponent : AudioComponent() , CommandStreamHandler {
}

override fun handleExternalMessage(message: ComponentEventObject): Boolean {
if(message.source is RemoSocketComponent || message.source is RemoCommandHandler){
if(message.source is RemoCommandSender){
commandHandler?.handleExternalMessage(message)
}
return super.handleExternalMessage(message)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,41 @@
package tv.remo.android.controller.sdk.components.hardware

import android.content.Context
import android.os.Bundle
import org.btelman.controlsdk.enums.ComponentType
import org.btelman.controlsdk.models.Component
import org.btelman.controlsdk.models.ComponentEventObject
import tv.remo.android.controller.sdk.RemoSettingsUtil
import tv.remo.android.controller.sdk.interfaces.RemoCommandSender
import tv.remo.android.controller.sdk.utils.ChatUtil

/**
* Watchdog component that will send a stop command
* 200 milliseconds after a command goes through if there are no more commands.
*
* Not useful if non drive motors are still being controlled after timeout, so solution should really be handled on the bot
*/
class HardwareWatchdogComponent : Component() {
class HardwareWatchdogComponent : Component(), RemoCommandSender{
private var sleepMode = false
/**
* time in seconds to wait to sleep the stream
*/
private var streamSleepTime: Long = 5*60 //default if settings fails
private var sleepEnabled = false

override fun onInitializeComponent(applicationContext: Context, bundle: Bundle?) {
super.onInitializeComponent(applicationContext, bundle)
reloadSleepSettings(applicationContext)
}

private fun reloadSleepSettings(maybeContext: Context?) {
val context = maybeContext?:return
RemoSettingsUtil.with(context){ settings ->
sleepEnabled = settings.streamSleepMode.getPref()
streamSleepTime = settings.streamSleepTimeOut.getPref().toLong()
}
}

override fun disableInternal() {
//not needed
}
Expand All @@ -23,13 +48,102 @@ class HardwareWatchdogComponent : Component() {
if(message.type == ComponentType.HARDWARE){
when(message.what){
EVENT_MAIN -> {
resetTimeout()
(message.data as? String)?.let {
if(it != "stop" && !it.startsWith(".")){
maybeResetSleepTimer()
}
resetTimeout()
}
}
}
}
else if(message.source is RemoCommandSender){
(message.data as? String)?.let {
handleStringCommand(message.data as String)
}
}
return super.handleExternalMessage(message)
}

private fun handleStringCommand(data: String) {
context?:return
when (data) {
".stream sleep" -> {
sleepMode = true
killSleepTimer()
}
".stream wakeup" -> {
maybeResetSleepTimer()
sleepMode = false
}
".stream reset" -> {
maybeResetSleepTimer()
sleepMode = false
}
else -> {
if(data.startsWith(".stream sleeptime ")){
handleSleepCommand(data.replace(".stream sleeptime ", "").trim())
}
}
}
}

private fun handleSleepCommand(data: String) {
var maybeTime : Int? = null
kotlin.runCatching {
maybeTime = data.toInt()
}
maybeTime?.let { time ->
val chatMessage : String = if(time > 0){
saveSleepTime(time)
"Setting sleeptime to $maybeTime seconds"
} else{
saveSleepTime(-1)
"Setting sleeptime to disabled (time < 0)"
}
killSleepTimer()
maybeResetSleepTimer()
ChatUtil.sendToSiteChat(eventDispatcher, chatMessage)
} ?: run{
ChatUtil.sendToSiteChat(eventDispatcher, ".stream sleeptime {seconds}")
}
}

private fun saveSleepTime(time: Int){
val context = context?:return
RemoSettingsUtil.with(context){ settings ->
settings.streamSleepMode.savePref(time > 0)
settings.streamSleepTimeOut.savePref(time)
reloadSleepSettings(context)
}
}


private fun killSleepTimer(){
handler.removeCallbacks(sleepRobot)
}

/**
* Reset the sleep counter when called.
*/
private fun maybeResetSleepTimer() {
if(sleepEnabled){
if(sleepMode){
sleepMode = false //apparently we don't get sent our own events back, so track it here
//we want events sent to the bot to wake it up automatically
eventDispatcher?.handleMessage(ComponentType.HARDWARE, EVENT_MAIN, ".stream wakeup", this as RemoCommandSender)
}
killSleepTimer()
handler.postDelayed(sleepRobot, streamSleepTime*1000)
}
}

private val sleepRobot = Runnable {
eventDispatcher?.handleMessage(ComponentType.HARDWARE, EVENT_MAIN, ".stream sleep", this as RemoCommandSender)
sleepMode = true //apparently we don't get sent our own events back, so track it here
killSleepTimer()
}

private val runnable = Runnable {
eventDispatcher?.handleMessage(ComponentType.HARDWARE, EVENT_MAIN, "stop", this)
}
Expand Down
Loading

0 comments on commit bd1c77d

Please sign in to comment.