Skip to content

Commit 8e4ee3b

Browse files
authored
Merge pull request #5 from Xiue233/android_applet
feat: add Android widget about electricity and class table.
2 parents 460067a + 6cd8acd commit 8e4ee3b

22 files changed

+671
-198
lines changed

android/app/src/main/AndroidManifest.xml

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,79 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2-
package="org.superbart.watermeter">
2+
package="org.superbart.watermeter">
3+
34
<application
4-
android:label="Traintime PDA"
5-
android:name="${applicationName}"
6-
android:icon="@mipmap/ic_launcher">
5+
android:name="${applicationName}"
6+
android:icon="@mipmap/ic_launcher"
7+
android:label="Traintime PDA">
78
<activity
8-
android:name="MainActivity"
9-
android:exported="true"
10-
android:launchMode="singleTop"
11-
android:theme="@style/LaunchTheme"
12-
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
13-
android:hardwareAccelerated="true"
14-
android:windowSoftInputMode="adjustResize">
9+
android:name="MainActivity"
10+
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
11+
android:exported="true"
12+
android:hardwareAccelerated="true"
13+
android:launchMode="singleTop"
14+
android:theme="@style/LaunchTheme"
15+
android:windowSoftInputMode="adjustResize">
1516
<!-- Specifies an Android theme to apply to this Activity as soon as
1617
the Android process has started. This theme is visible to the user
1718
while the Flutter UI initializes. After that, this theme continues
1819
to determine the Window background behind the Flutter UI. -->
1920
<meta-data
20-
android:name="io.flutter.embedding.android.NormalTheme"
21-
android:resource="@style/NormalTheme"
22-
/>
21+
android:name="io.flutter.embedding.android.NormalTheme"
22+
android:resource="@style/NormalTheme" />
2323
<intent-filter>
24-
<action android:name="android.intent.action.MAIN"/>
25-
<category android:name="android.intent.category.LAUNCHER"/>
24+
<action android:name="android.intent.action.MAIN" />
25+
<category android:name="android.intent.category.LAUNCHER" />
2626
</intent-filter>
2727
</activity>
2828

29-
<receiver android:name="HomeWidgetExampleProvider" android:exported="true">
29+
<receiver
30+
android:name="ElectricityWidgetProvider"
31+
android:exported="true">
3032
<intent-filter>
3133
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
3234
</intent-filter>
33-
<meta-data android:name="android.appwidget.provider"
34-
android:resource="@xml/home_widget_example" />
35+
<meta-data
36+
android:name="android.appwidget.provider"
37+
android:resource="@xml/electricity_widget_config" />
38+
</receiver>
39+
40+
<receiver
41+
android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver"
42+
android:exported="true">
43+
<intent-filter>
44+
<action android:name="es.antonborri.home_widget.action.BACKGROUND" />
45+
</intent-filter>
3546
</receiver>
3647

48+
<service
49+
android:name="es.antonborri.home_widget.HomeWidgetBackgroundService"
50+
android:exported="true"
51+
android:permission="android.permission.BIND_JOB_SERVICE" />
3752

38-
<receiver android:name="ClassTableViewProvider" android:exported="true">
53+
<receiver
54+
android:name="ClassTableWidgetProvider"
55+
android:exported="true">
3956
<intent-filter>
4057
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
4158
</intent-filter>
42-
<meta-data android:name="android.appwidget.provider"
43-
android:resource="@xml/home_widget_example" />
59+
<meta-data
60+
android:name="android.appwidget.provider"
61+
android:resource="@xml/classtable_widget_config" />
4462
</receiver>
4563

64+
<service
65+
android:name=".ClassTableItemsService"
66+
android:exported="true"
67+
android:permission="android.permission.BIND_REMOTEVIEWS" />
68+
69+
4670
<!-- Don't delete the meta-data below.
4771
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
4872
<meta-data
49-
android:name="flutterEmbedding"
50-
android:value="2"/>
73+
android:name="flutterEmbedding"
74+
android:value="2" />
5175
</application>
76+
5277
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
5378
<uses-permission android:name="android.permission.INTERNET" />
5479
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package org.superbart.watermeter
2+
3+
import android.widget.RemoteViews
4+
import android.widget.RemoteViewsService.RemoteViewsFactory
5+
import org.json.JSONObject
6+
7+
private val CLASS_INDEX_TIME = arrayOf(
8+
"08:30",
9+
"09:15",
10+
"09:20",
11+
"10:05",
12+
"10:25",
13+
"11:10",
14+
"11:15",
15+
"12:00",
16+
"14:00",
17+
"14:45",
18+
"14:50",
19+
"15:35",
20+
"15:55",
21+
"16:40",
22+
"16:45",
23+
"17:30",
24+
"19:00",
25+
"19:45",
26+
"19:55",
27+
"20:30",
28+
)
29+
30+
data class ClassItem(
31+
val name: String,
32+
val teacher: String,
33+
val start: Int,
34+
val end: Int,
35+
val classroom: String,
36+
val startTime: String,
37+
val endTime: String,
38+
)
39+
40+
class ClassTableItemsFactory(private val packageName: String) :
41+
RemoteViewsFactory {
42+
private val classItems = ArrayList<ClassItem>()
43+
44+
companion object {
45+
// It is difficult for RemoteViewsFactory to get access to SharedPreference.
46+
// However we need SharedPreference to act as data bridge between Native and Dart,
47+
// this json variable is used to store the latest data of class table.
48+
// Also see ClassTableWidgetProvider.onUpdate(...), in which the json is updated.
49+
var json = "{\"list\":[]}"
50+
@Synchronized
51+
set(value) {
52+
field = value
53+
}
54+
}
55+
56+
init {
57+
reloadData()
58+
}
59+
60+
private fun reloadData() {
61+
try {
62+
val jsonObject = JSONObject(ClassTableItemsFactory.json)
63+
val classList = jsonObject.getJSONArray("list")
64+
for (i in 0 until classList.length()) {
65+
classList.getJSONObject(i).run {
66+
val start = getInt("start_time")
67+
val end = getInt("end_time")
68+
classItems.add(
69+
ClassItem(
70+
getString("name"),
71+
getString("teacher"),
72+
start,
73+
end,
74+
getString("place"),
75+
CLASS_INDEX_TIME[start - 1],
76+
CLASS_INDEX_TIME[end - 1]
77+
)
78+
)
79+
}
80+
}
81+
} catch (e: Exception) {
82+
e.printStackTrace()
83+
}
84+
}
85+
86+
override fun onCreate() {
87+
}
88+
89+
override fun onDataSetChanged() {
90+
classItems.clear()
91+
reloadData()
92+
}
93+
94+
override fun onDestroy() {
95+
}
96+
97+
override fun getCount(): Int = classItems.size
98+
99+
override fun getViewAt(position: Int): RemoteViews? {
100+
if (position < 0 || position >= classItems.size) {
101+
return null
102+
}
103+
val classItem = classItems[position]
104+
return RemoteViews(packageName, R.layout.widget_classtable_item).apply {
105+
setTextViewText(R.id.widget_classtable_item_start, classItem.start.toString())
106+
setTextViewText(R.id.widget_classtable_item_end, classItem.end.toString())
107+
setTextViewText(R.id.widget_classtable_item_start_time, classItem.startTime)
108+
setTextViewText(R.id.widget_classtable_item_end_time, classItem.endTime)
109+
setTextViewText(R.id.widget_classtable_item_name, classItem.name)
110+
setTextViewText(R.id.widget_classtable_item_classroom, classItem.classroom)
111+
setTextViewText(R.id.widget_classtable_item_teacher, classItem.teacher)
112+
}
113+
}
114+
115+
override fun getLoadingView(): RemoteViews? = null
116+
117+
override fun getViewTypeCount(): Int = 1
118+
119+
override fun getItemId(position: Int): Long = position.toLong()
120+
121+
override fun hasStableIds(): Boolean = false
122+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.superbart.watermeter
2+
3+
import android.content.Intent
4+
import android.widget.RemoteViewsService
5+
import org.superbart.watermeter.ClassTableItemsFactory
6+
7+
class ClassTableItemsService : RemoteViewsService() {
8+
override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory =
9+
ClassTableItemsFactory(
10+
intent!!.getStringExtra("packageName")!!
11+
)
12+
}

android/app/src/main/kotlin/org/superbart/watermeter/ClassTableViewProvider.kt

Lines changed: 0 additions & 50 deletions
This file was deleted.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package org.superbart.watermeter
2+
3+
import android.app.PendingIntent
4+
import android.appwidget.AppWidgetManager
5+
import android.content.Context
6+
import android.content.Intent
7+
import android.content.SharedPreferences
8+
import android.net.Uri
9+
import android.os.Build
10+
import android.os.Bundle
11+
import android.util.Log
12+
import android.widget.RemoteViews
13+
import es.antonborri.home_widget.HomeWidgetBackgroundIntent
14+
import es.antonborri.home_widget.HomeWidgetPlugin
15+
import es.antonborri.home_widget.HomeWidgetProvider
16+
17+
private object ClassTableWidgetKeys {
18+
const val SWITCHER_NEXT = "class_table_switcher_next"
19+
const val DATE = "class_table_date"
20+
const val CLASS_TABLE_JSON = "class_table_json"
21+
}
22+
23+
class ClassTableWidgetProvider : HomeWidgetProvider() {
24+
override fun onAppWidgetOptionsChanged(
25+
context: Context,
26+
appWidgetManager: AppWidgetManager,
27+
appWidgetId: Int,
28+
newOptions: Bundle
29+
) {
30+
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
31+
onUpdate(context, appWidgetManager, arrayOf(appWidgetId).toIntArray())
32+
}
33+
34+
override fun onUpdate(
35+
context: Context,
36+
appWidgetManager: AppWidgetManager,
37+
appWidgetIds: IntArray,
38+
widgetData: SharedPreferences
39+
) {
40+
//cache context
41+
//when ClassTableItemsService loads data, the context is needed for SharePreference.
42+
widgetData.registerOnSharedPreferenceChangeListener { sharedPreferences, key ->
43+
if (ClassTableWidgetKeys.CLASS_TABLE_JSON == key) {
44+
ClassTableItemsFactory.json = sharedPreferences.getString(key, "{\"list\":[]}")!!
45+
}
46+
}
47+
appWidgetIds.forEach { widgetID ->
48+
val views = RemoteViews(
49+
context.packageName,
50+
R.layout.widget_class_table_layout
51+
).apply {
52+
setImageViewResource(
53+
R.id.widget_classtable_switcher,
54+
if (widgetData.getBoolean(ClassTableWidgetKeys.SWITCHER_NEXT, true)) {
55+
R.drawable.icon_next
56+
} else {
57+
R.drawable.icon_previous
58+
}
59+
)
60+
setOnClickPendingIntent(
61+
R.id.widget_classtable_switcher,
62+
HomeWidgetBackgroundIntent.getBroadcast(
63+
context,
64+
Uri.parse("widget://switcherClicked?widgetName=ClassTable")
65+
)
66+
)
67+
setTextViewText(
68+
R.id.widget_classtable_date,
69+
widgetData.getString(ClassTableWidgetKeys.DATE, "Date Loading...")
70+
)
71+
//load class items
72+
val intent = Intent(context, ClassTableItemsService::class.java)
73+
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
74+
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetID)
75+
intent.putExtra(
76+
"json",
77+
widgetData.getString(ClassTableWidgetKeys.CLASS_TABLE_JSON, "{\"list\":[]}")
78+
)
79+
intent.putExtra("packageName", context.packageName)
80+
setRemoteAdapter(R.id.widget_classtable_list, intent)
81+
}
82+
appWidgetManager.updateAppWidget(widgetID, views)
83+
}
84+
appWidgetManager.notifyAppWidgetViewDataChanged(
85+
appWidgetIds,
86+
R.id.widget_classtable_list
87+
)
88+
}
89+
}

0 commit comments

Comments
 (0)