Skip to content
This repository has been archived by the owner on Jun 30, 2022. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
initial version of event companion app (#2156)
  • Loading branch information
chon219 authored and ryanisgrig committed Aug 20, 2019
1 parent 9581154 commit 09e6a4c
Show file tree
Hide file tree
Showing 59 changed files with 1,845 additions and 0 deletions.
13 changes: 13 additions & 0 deletions solutions/android/EventCompanion/.gitignore
@@ -0,0 +1,13 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
1 change: 1 addition & 0 deletions solutions/android/EventCompanion/app/.gitignore
@@ -0,0 +1 @@
/build
35 changes: 35 additions & 0 deletions solutions/android/EventCompanion/app/build.gradle
@@ -0,0 +1,35 @@
apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
compileSdkVersion 29
buildToolsVersion "29.0.0"
defaultConfig {
applicationId "com.microsoft.bot.builder.solutions.eventcompanion"
minSdkVersion 23
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.core:core-ktx:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
}
21 changes: 21 additions & 0 deletions solutions/android/EventCompanion/app/proguard-rules.pro
@@ -0,0 +1,21 @@
# 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
55 changes: 55 additions & 0 deletions solutions/android/EventCompanion/app/src/main/AndroidManifest.xml
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" package="com.microsoft.bot.builder.solutions.eventcompanion">

<application
android:name=".MainApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme" tools:ignore="AllowBackup,GoogleAppIndexingWarning">

<receiver
android:name=".ToggleWidget"
android:label="@string/widget_toggle">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>

<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/toggle_widget_info"/>
</receiver>
<receiver
android:name=".NumericWidget"
android:label="@string/widget_numeric">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>

<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/numeric_widget_info"/>
</receiver>

<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>

<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".ToggleWidgetConfigureActivity">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
<activity android:name=".NumericWidgetConfigureActivity">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
</application>

</manifest>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,21 @@
{
"label": "Temperature",
"event": "AutomotiveSkill.Temperature",
"ranges": [{
"unit": "°C",
"minimum": 14,
"maximum": 32
}, {
"unit": "°F",
"minimum": 56,
"maximum": 91
}, {
"unit": "°",
"minimum": 14,
"maximum": 91
}, {
"unit": "",
"minimum": 14,
"maximum": 91
}]
}
@@ -0,0 +1,5 @@
{
"label": "Max Defrost",
"event": "AutomotiveSkill.Max Defrost",
"icon": "file:///android_asset/icons/defrost.png"
}
@@ -0,0 +1,5 @@
{
"label": "Seat Heater",
"event": "AutomotiveSkill.Seat Heater",
"icon": "file:///android_asset/icons/seat_heater.png"
}
@@ -0,0 +1,88 @@
package com.microsoft.bot.builder.solutions.eventcompanion

import android.appwidget.AppWidgetManager
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import com.google.gson.Gson

class EventReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, receivedIntent: Intent) {
// This method is called when the BroadcastReceiver is receiving an Intent broadcast.
if (receivedIntent.hasExtra("WidgetUpdate")) {
val activityString = receivedIntent.getStringExtra("WidgetUpdate")
val botActivity = Gson().fromJson(activityString, BotActivity::class.java)
if (botActivity.type == "event") {
val eventName = botActivity.name
val appWidgetManager = AppWidgetManager.getInstance(context)
val toggleWidgetIds = appWidgetManager.getAppWidgetIds(ComponentName(context, ToggleWidget::class.java))
for (id in toggleWidgetIds) {
val widgetConf = ToggleWidgetConfigureActivity.loadConf(context, id)
if (eventName == widgetConf.event) {
val widgetData = ToggleWidgetConfigureActivity.loadData(context, id)
when (botActivity.getValue()) {
"On" -> widgetData.value = true
"Off" -> widgetData.value = false
}
ToggleWidgetConfigureActivity.saveData(context, id, widgetData)
ToggleWidget.updateAppWidget(context, appWidgetManager, id)
}
}
val numericWidgetIds = appWidgetManager.getAppWidgetIds(ComponentName(context, NumericWidget::class.java))
for (id in numericWidgetIds) {
val widgetConf = NumericWidgetConfigureActivity.loadConf(context, id)
if (eventName == widgetConf.event) {
val eventValue = botActivity.getValue()
val eventAmount = botActivity.getAmount()
val eventUnit = botActivity.getUnit()
val widgetData = NumericWidgetConfigureActivity.loadData(context, id)
when (eventValue) {
"Increase" -> widgetData.value += if (eventAmount != 0F) {
eventAmount
} else {
1F//TODO: make constant
}
"Decrease" -> widgetData.value += if (eventAmount != 0F) {
eventAmount
} else {
-1F//TODO: make constant
}
"Set" -> widgetData.value = eventAmount
}
for (range in widgetConf.ranges) {
if (range.unit == eventUnit) {
if (widgetData.value < range.minimum) {
widgetData.value = range.minimum
} else if (widgetData.value > range.maximum) {
widgetData.value = range.maximum
}
widgetData.unit = range.unit
break
}
}
NumericWidgetConfigureActivity.saveData(context, id, widgetData)
NumericWidget.updateAppWidget(context, appWidgetManager, id)
}
}
}
}
}

private data class Value(val value: String?, val amount: Amount?)
private data class Amount(val amount: Float?, val unit: String?)
private data class BotActivity(val name: String, val type: String, val value: Value?) {
fun getValue(): String {
return value?.value?: ""
}
fun getAmount(): Float {
return value?.amount?.amount?: 0F
}
fun getUnit(): String {
return value?.amount?.unit?: ""
}
}
}


@@ -0,0 +1,94 @@
package com.microsoft.bot.builder.solutions.eventcompanion

import android.app.Activity
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {

private var widgetConfList: ArrayList<WidgetConf> = ArrayList()
private lateinit var recyclerView: RecyclerView
private lateinit var viewAdapter: RecyclerView.Adapter<*>
private lateinit var viewManager: RecyclerView.LayoutManager

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

viewManager = LinearLayoutManager(this)
viewAdapter = WidgetListAdapter(this, widgetConfList)
recyclerView = findViewById(R.id.widget_list)
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = viewAdapter
}
}

override fun onResume() {
super.onResume()
refreshWidgetList()
}

private fun refreshWidgetList() {
val appWidgetManager = AppWidgetManager.getInstance(this)
widgetConfList.clear()
val toggleWidgetIds = appWidgetManager.getAppWidgetIds(ComponentName(this, ToggleWidget::class.java))
for (id in toggleWidgetIds) {
val conf = ToggleWidgetConfigureActivity.loadConf(this, id)
widgetConfList.add(WidgetConf(id, conf.label, conf.event, WidgetType.TOGGLE))
}
val numericWidgetIds = appWidgetManager.getAppWidgetIds(ComponentName(this, NumericWidget::class.java))
for (id in numericWidgetIds) {
val conf = NumericWidgetConfigureActivity.loadConf(this, id)
widgetConfList.add(WidgetConf(id, conf.label, conf.event, WidgetType.NUMERIC))
}
viewAdapter.notifyDataSetChanged()
}

private enum class WidgetType {
TOGGLE,
NUMERIC
}

private data class WidgetConf(val id: Int, val label: String, val event: String, val type: WidgetType)

private class WidgetListAdapter(private val activity: Activity, private val widgetConfList: ArrayList<WidgetConf>) : RecyclerView.Adapter<WidgetListAdapter.WidgetListViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WidgetListViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.widget_list_item, parent, false)
return WidgetListViewHolder(view)
}
override fun onBindViewHolder(holder: WidgetListViewHolder, position: Int) {
val widget = widgetConfList[position]
holder.view.findViewById<TextView>(R.id.widget_label).text = widget.label
holder.view.findViewById<TextView>(R.id.widget_event).text = widget.event
holder.view.findViewById<TextView>(R.id.widget_type).text = widget.type.name
holder.view.setOnClickListener {
val intent = Intent(it.context, when(widget.type) {
WidgetType.TOGGLE -> ToggleWidgetConfigureActivity::class.java
WidgetType.NUMERIC -> NumericWidgetConfigureActivity::class.java
})
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetConfList[position].id)
activity.startActivityForResult(intent, CONFIGURE_REQUEST_CODE)
}
}
override fun getItemCount(): Int = widgetConfList.size
class WidgetListViewHolder(val view: View) : RecyclerView.ViewHolder(view)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
}

companion object {
private const val CONFIGURE_REQUEST_CODE = 1
}
}
@@ -0,0 +1,20 @@
package com.microsoft.bot.builder.solutions.eventcompanion

import android.app.Application
import android.content.IntentFilter

class MainApplication: Application() {
private lateinit var eventReceiver: EventReceiver

override fun onCreate() {
super.onCreate()
eventReceiver = EventReceiver()
val filter = IntentFilter()
filter.addAction(ACTION_BROADCAST)
registerReceiver(eventReceiver, filter)
}

companion object {
private const val ACTION_BROADCAST: String = "com.microsoft.broadcast"
}
}
@@ -0,0 +1,21 @@
package com.microsoft.bot.builder.solutions.eventcompanion

import android.content.Context
import android.util.AttributeSet
import android.widget.Spinner

class MySpinner(context: Context, attributeSet: AttributeSet) : Spinner(context, attributeSet) {
private lateinit var listener: OnItemSelectedListener
override fun setSelection(position: Int) {
super.setSelection(position)
if (position == selectedItemPosition) {
listener.onItemSelected(null, null, position, 0)
}
}

override fun setOnItemSelectedListener(listener: OnItemSelectedListener?) {
if (listener != null) {
this.listener = listener
}
}
}

0 comments on commit 09e6a4c

Please sign in to comment.