Browse Source

added timeout and other error handling

feature/exam_notifications
Nareshkumar Rao 4 years ago
parent
commit
09f63cb4da
  1. 4
      app/build.gradle
  2. BIN
      app/release/app-release.apk
  3. 4
      app/release/output-metadata.json
  4. 76
      app/src/main/java/com/nareshkumarrao/eiweblog/HISUtility.kt
  5. 2
      app/src/main/java/com/nareshkumarrao/eiweblog/UpdateWorker.kt
  6. 11
      app/src/main/java/com/nareshkumarrao/eiweblog/Utilities.kt
  7. 9
      app/src/main/java/com/nareshkumarrao/eiweblog/ui/main/SectionsFragment.kt
  8. 1
      app/src/main/res/layout/dialog_login.xml
  9. 2
      app/src/main/res/values-de/strings.xml
  10. 2
      app/src/main/res/values-en/strings.xml
  11. 2
      app/src/main/res/values/strings.xml
  12. 1
      images/launcher.svg

4
app/build.gradle

@ -11,8 +11,8 @@ android {
applicationId "com.nareshkumarrao.eiweblog"
minSdkVersion 16
targetSdkVersion 30
versionCode 5
versionName "0.10.1"
versionCode 6
versionName "0.10.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

BIN
app/release/app-release.apk

Binary file not shown.

4
app/release/output-metadata.json

@ -10,8 +10,8 @@
{
"type": "SINGLE",
"filters": [],
"versionCode": 5,
"versionName": "0.10.1",
"versionCode": 6,
"versionName": "0.10.2",
"outputFile": "app-release.apk"
}
]

76
app/src/main/java/com/nareshkumarrao/eiweblog/HISUtility.kt

@ -1,17 +1,20 @@
package com.nareshkumarrao.eiweblog
import android.app.Activity
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import android.widget.Toast
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import org.jsoup.Connection
import org.jsoup.Jsoup
import java.net.SocketTimeoutException
data class ExamRow(val name: String, val grade: String, val attempt: String, val date: String)
@ -77,6 +80,8 @@ internal object HISUtility {
?: return null
val runnable = Runnable {
try {
val postData: MutableMap<String, String> = mutableMapOf()
postData["asdf"] = username
postData["fdsa"] = password
@ -85,14 +90,19 @@ internal object HISUtility {
.method(Connection.Method.POST)
.userAgent("Mozilla")
.data(postData)
.timeout(60000)
.execute()
val selectNotenspiegel = Jsoup.connect(context.getString(R.string.ossc_select_noten))
val selectNotenspiegel =
Jsoup.connect(context.getString(R.string.ossc_select_noten))
.userAgent("Mozilla")
.cookies(loginPage.cookies())
.timeout(60000)
.get()
val notenspiegelURL = selectNotenspiegel.select("a[href]:containsOwn(Notenspiegel)").first()?.attr("href")
val notenspiegelURL =
selectNotenspiegel.select("a[href]:containsOwn(Notenspiegel)").first()
?.attr("href")
?: kotlin.run {
callback(null)
return@Runnable
@ -101,22 +111,30 @@ internal object HISUtility {
val selectStudiengangUnhide = Jsoup.connect(notenspiegelURL)
.userAgent("Mozilla")
.cookies(loginPage.cookies())
.timeout(60000)
.get()
val selectStudiengangUnhideURL = selectStudiengangUnhide.select("a[href]:containsOwn(Abschluss)").first().attr("href")
val selectStudiengangUnhideURL =
selectStudiengangUnhide.select("a[href]:containsOwn(Abschluss)").first()
.attr("href")
val selectStudiengang = Jsoup.connect(selectStudiengangUnhideURL)
.userAgent("Mozilla")
.cookies(loginPage.cookies())
.timeout(60000)
.get()
val studiengangURL = selectStudiengang.select("a[href]:containsOwn(Leistungen anzeigen)").first().attr("href")
val studiengangURL =
selectStudiengang.select("a[href]:containsOwn(Leistungen anzeigen)").first()
.attr("href")
val notenSpiegelPage = Jsoup.connect(studiengangURL)
.userAgent("Mozilla")
.cookies(loginPage.cookies())
.timeout(60000)
.get()
val allGradesRows = notenSpiegelPage.select("div.fixedContainer > table > tbody > tr")
val allGradesRows =
notenSpiegelPage.select("div.fixedContainer > table > tbody > tr")
val examRows: MutableList<ExamRow> = mutableListOf()
for (row in allGradesRows) {
if (row.select("td.tabelle1_alignleft").size < 1) {
@ -126,26 +144,54 @@ internal object HISUtility {
if (columns.size < 1) {
continue
}
val examRow = ExamRow(columns[1].text(), columns[3].text(), columns[6].text(), columns[7].text())
val examRow = ExamRow(
columns[1].text(),
columns[3].text(),
columns[6].text(),
columns[7].text()
)
examRows.add(examRow)
}
saveExamRows(context, examRows)
callback(examRows)
} catch (e: Exception) {
if (context is Activity) context.runOnUiThread {
when (e) {
is SocketTimeoutException -> {
Toast.makeText(
context,
context.getString(R.string.ossc_timeout_message),
Toast.LENGTH_LONG
).show()
}
else -> {
Toast.makeText(context, e.localizedMessage, Toast.LENGTH_LONG).show()
}
}
context.finish()
}
}
}
return Thread(runnable).start()
}
fun sendNotification(context: Context?, examRow: ExamRow, id: Int) {
val intent = Intent(context, NotificationSettingsActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
val builder = NotificationCompat.Builder(context!!, context.getString(R.string.grades_notification_channel_id))
val builder = NotificationCompat.Builder(
context!!,
context.getString(R.string.grades_notification_channel_id)
)
.setSmallIcon(R.drawable.ic_stat_name)
.setContentTitle(context.getString(R.string.exam_results_notification))
.setStyle(NotificationCompat.BigTextStyle()
.bigText("${examRow.name}: ${examRow.grade}"))
.setStyle(
NotificationCompat.BigTextStyle()
.bigText("${examRow.name}: ${examRow.grade}")
)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true)
@ -158,12 +204,18 @@ internal object HISUtility {
fun createNotificationChannel(context: Context?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = context?.getString(R.string.grades_notification_channel_name)
val descriptionText = context?.getString(R.string.grades_notification_channel_description)
val descriptionText =
context?.getString(R.string.grades_notification_channel_description)
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(context?.getString(R.string.grades_notification_channel_id), name, importance).apply {
val channel = NotificationChannel(
context?.getString(R.string.grades_notification_channel_id),
name,
importance
).apply {
description = descriptionText
}
val notificationManager: NotificationManager = context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationManager: NotificationManager =
context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}

2
app/src/main/java/com/nareshkumarrao/eiweblog/UpdateWorker.kt

@ -16,11 +16,13 @@ class UpdateWorker(private val context: Context, workerParams: WorkerParameters)
if(weblogNotificationsEnabled!!){
Utilities.weblogList(context) { articles ->
articles ?: return@weblogList
val lastArticle = Utilities.getLatestRelevantArticle(articles)!!
val hashString = lastArticle.title + lastArticle.content + lastArticle.date
val oldHash = md5(hashString)
Utilities.fetchWeblogXML(applicationContext){newArticles ->
newArticles ?: return@fetchWeblogXML
val lastNewArticle = Utilities.getLatestRelevantArticle(newArticles)!!
val newHashString = lastNewArticle.title + lastNewArticle.content + lastNewArticle.date
val newHash = md5(newHashString)

11
app/src/main/java/com/nareshkumarrao/eiweblog/Utilities.kt

@ -22,7 +22,7 @@ import java.io.StringReader
internal object Utilities {
fun weblogList(context: Context?, function: (d: List<Article>) -> Unit){
fun weblogList(context: Context?, function: (d: List<Article>?) -> Unit) {
val sharedPref = context?.getSharedPreferences(context.getString(R.string.preference_file_key), Context.MODE_PRIVATE)
val weblogResponse = sharedPref?.getString(context.getString(R.string.weblog_response_key), null)
if (weblogResponse == null) {
@ -37,7 +37,7 @@ internal object Utilities {
function(parseXML(parser))
}
fun fetchWeblogXML(context: Context?, function: (d: List<Article>) -> Unit) {
fun fetchWeblogXML(context: Context?, callback: (d: List<Article>?) -> Unit) {
val queue = Volley.newRequestQueue(context)
@ -62,10 +62,13 @@ internal object Utilities {
parser.nextTag()
val articles = parseXML(parser)
function(articles)
callback(articles)
},
{ error -> Log.e("XMLLIST", error.toString()) })
{ error ->
Log.e("XMLLIST", error.toString())
callback(null)
})
queue.add(stringRequest)
}

9
app/src/main/java/com/nareshkumarrao/eiweblog/ui/main/SectionsFragment.kt

@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -48,8 +49,14 @@ class SectionsFragment : Fragment() {
}
}
private fun updateView(get_articles: List<Article>){
private fun updateView(get_articles: List<Article>?) {
this.swipeRefreshLayout?.isRefreshing = false
if (get_articles == null) {
Toast.makeText(context, getString(R.string.load_weblog_error_message), Toast.LENGTH_LONG).show()
return
}
val articles: MutableList<Article> = mutableListOf()
val title = arguments?.getString(ARG_SECTION_NAME) ?: return
for (article in get_articles) {

1
app/src/main/res/layout/dialog_login.xml

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

2
app/src/main/res/values-de/strings.xml

@ -32,4 +32,6 @@
<string name="enable_grades_notifications_text">Benachrichtige mich bei neuem Klausurergebnis</string>
<string name="login_dialog_title">Anmelden bei OSSC</string>
<string name="error">FEHLER!</string>
<string name="ossc_timeout_message">Timeout-Fehler bei OSSC. Versuch mal später.</string>
<string name="load_weblog_error_message">Weblog kann nicht aktualisiert werden. Versuch mal später.</string>
</resources>

2
app/src/main/res/values-en/strings.xml

@ -33,4 +33,6 @@
<string name="enable_grades_notifications_text">Notify me when I get new grades</string>
<string name="login_dialog_title">Login to OSSC</string>
<string name="error">ERROR!</string>
<string name="ossc_timeout_message">OSSC has timed out. Try again later.</string>
<string name="load_weblog_error_message">Could not load new weblog data. Try again later.</string>
</resources>

2
app/src/main/res/values/strings.xml

@ -54,4 +54,6 @@
<string name="enable_grades_notifications_key" translatable="false">com.nareshkumarrao.eiweblog.grades_notifications.key</string>
<string name="login_dialog_title">Login to OSSC</string>
<string name="error">ERROR!</string>
<string name="ossc_timeout_message">OSSC has timed out. Try again later.</string>
<string name="load_weblog_error_message">Could not load new weblog data. Try again later.</string>
</resources>

1
images/launcher.svg

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--suppress ALL -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Loading…
Cancel
Save