Skip to content
This repository was archived by the owner on Jan 10, 2024. It is now read-only.

Commit 4d27542

Browse files
Implement notification preview mentioned in issue #1235 (#1562)
* Added notification overview * Added queues to retrive scheduled and active notifications Adjusted NotificationDebugViewFragment to display these * Fixed falsely added whitespace in DrawerMenuHelper.kt * Added logic in InformationActivity.kt for opening the NotificationOverview after 5 quick clicks * Changed to Activity and improved file structure * Added localization to StickyList headers * Added padding to StickyListItem * Added notifications from AlarmManager per NotificationType * Added get PendingIntent for every ScheduledNotification * Only textview txtVersion triggers click now * Removed unnecessary import * fixed a typo in the translations * Fixed ktlint errors * Fixed ktlint errors --------- Co-authored-by: Frank Elsinga <frank@elsinga.de>
1 parent 1912fc2 commit 4d27542

File tree

11 files changed

+254
-1
lines changed

11 files changed

+254
-1
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,17 @@
296296
android:name="android.support.PARENT_ACTIVITY"
297297
android:value=".component.other.settings.SettingsActivity" />
298298
</activity>
299+
<activity
300+
android:name=".component.notifications.overview.NotificationOverviewActivity"
301+
android:configChanges="orientation|screenSize"
302+
android:label="@string/notification_overview"
303+
android:launchMode="singleTop"
304+
android:parentActivityName=".component.ui.overview.InformationActivity"
305+
android:theme="@style/AppTheme.NoDrawerLayout">
306+
<meta-data
307+
android:name="android.support.PARENT_ACTIVITY"
308+
android:value=".component.ui.overview.InformationActivity" />
309+
</activity>
299310
<activity
300311
android:name=".component.ui.eduroam.SetupEduroamActivity"
301312
android:configChanges="orientation|screenSize"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package de.tum.`in`.tumcampusapp.component.notifications.overview
2+
3+
import de.tum.`in`.tumcampusapp.component.other.generic.adapter.SimpleStickyListHeadersAdapter
4+
5+
data class NotificationItemForStickyList(
6+
val notificationString: String,
7+
val notificationSource: String
8+
) : SimpleStickyListHeadersAdapter.SimpleStickyListItem {
9+
10+
override fun getHeadName(): String {
11+
return notificationSource
12+
}
13+
14+
override fun getHeaderId(): String {
15+
return notificationSource
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package de.tum.`in`.tumcampusapp.component.notifications.overview
2+
3+
import android.app.NotificationManager
4+
import android.app.PendingIntent
5+
import android.content.Context
6+
import android.content.Intent
7+
import android.os.Bundle
8+
import de.tum.`in`.tumcampusapp.R
9+
import de.tum.`in`.tumcampusapp.component.notifications.receivers.NotificationAlarmReceiver
10+
import de.tum.`in`.tumcampusapp.component.notifications.receivers.NotificationReceiver
11+
import de.tum.`in`.tumcampusapp.component.other.generic.activity.BaseActivity
12+
import de.tum.`in`.tumcampusapp.database.TcaDb
13+
import de.tum.`in`.tumcampusapp.databinding.ActivityNotificationOverviewBinding
14+
15+
class NotificationOverviewActivity : BaseActivity(R.layout.activity_notification_overview) {
16+
17+
private lateinit var binding: ActivityNotificationOverviewBinding
18+
19+
override fun onCreate(savedInstanceState: Bundle?) {
20+
super.onCreate(savedInstanceState)
21+
22+
binding = ActivityNotificationOverviewBinding.inflate(layoutInflater)
23+
setContentView(binding.root)
24+
setSupportActionBar(binding.toolbarInformation.toolbar)
25+
supportActionBar?.apply {
26+
setDisplayHomeAsUpEnabled(true)
27+
setDisplayShowHomeEnabled(true)
28+
}
29+
30+
// get currently active notifications
31+
val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
32+
val activeNotifications = notificationManager.activeNotifications.asList()
33+
// get notifications stored in database
34+
val scheduledNotifications = TcaDb.getInstance(applicationContext).scheduledNotificationsDao().getAllScheduledNotifications()
35+
val alarms = TcaDb.getInstance(applicationContext).activeNotificationsDao().getAllAlarms()
36+
// get PendingIntent for every NotificationType
37+
val typesList = (0..5)
38+
// get PendingIntent for every ScheduledNotification
39+
val scheduledNotificationIds = scheduledNotifications.map { it.typeId }
40+
41+
// store all notifications into one list
42+
val notificationsList = emptyList<NotificationItemForStickyList>().toMutableList()
43+
activeNotifications.forEach {
44+
notificationsList.add(NotificationItemForStickyList(it.toString(), getString(R.string.active_notifications)))
45+
}
46+
scheduledNotifications.forEach {
47+
notificationsList.add(NotificationItemForStickyList(it.toString(), getString(R.string.scheduled_notifications)))
48+
}
49+
alarms.forEach {
50+
notificationsList.add(NotificationItemForStickyList(it.toString(), getString(R.string.alarms)))
51+
}
52+
typesList.forEach { type ->
53+
getAlarmIntentPerType(type)?.let {
54+
notificationsList.add(NotificationItemForStickyList(it.toString(), getString(R.string.pendingintents_per_type)))
55+
}
56+
}
57+
scheduledNotificationIds.forEach { id ->
58+
getAlarmIntent(id)?.let {
59+
notificationsList.add(NotificationItemForStickyList(it.toString(), getString(R.string.pendingintents_per_scheduled_notification)))
60+
}
61+
}
62+
63+
binding.notificationsListView.adapter = NotificationsListAdapter(applicationContext, notificationsList)
64+
}
65+
66+
// mimics NotificationScheduler.getAlarmIntent(type: NotificationType) method
67+
private fun getAlarmIntentPerType(type: Int): PendingIntent? {
68+
// extra data is ignored according to intent filter
69+
val intent = Intent(applicationContext, NotificationAlarmReceiver::class.java)
70+
// FLAG_NO_CREATE to only show existing intents
71+
return PendingIntent.getBroadcast(applicationContext, type, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_NO_CREATE)
72+
}
73+
74+
// mimics NotificationScheduler.getAlarmIntent(futureNotification: FutureNotification, globalNotificationId: Long) method
75+
private fun getAlarmIntent(id: Int): PendingIntent? {
76+
// extra data is ignored according to intent filter
77+
val intent = Intent(applicationContext, NotificationReceiver::class.java)
78+
// FLAG_NO_CREATE to only show existing intents
79+
return PendingIntent.getBroadcast(
80+
applicationContext,
81+
id,
82+
intent,
83+
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_NO_CREATE
84+
)
85+
}
86+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package de.tum.`in`.tumcampusapp.component.notifications.overview
2+
3+
import android.content.Context
4+
import android.view.View
5+
import android.view.ViewGroup
6+
import android.widget.TextView
7+
import de.tum.`in`.tumcampusapp.R
8+
import de.tum.`in`.tumcampusapp.component.other.generic.adapter.SimpleStickyListHeadersAdapter
9+
10+
class NotificationsListAdapter(context: Context, results: MutableList<NotificationItemForStickyList>) : SimpleStickyListHeadersAdapter<NotificationItemForStickyList>(context, results) {
11+
12+
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
13+
val holder: ViewHolder
14+
val view: View
15+
16+
if (convertView == null) {
17+
view = inflater.inflate(R.layout.notification_row_item, parent, false)
18+
holder = ViewHolder()
19+
holder.textView = view.findViewById(R.id.textView)
20+
view.tag = holder
21+
} else {
22+
view = convertView
23+
holder = view.tag as ViewHolder
24+
}
25+
26+
val notification = itemList[position]
27+
28+
holder.textView?.text = notification.notificationString
29+
30+
return view
31+
}
32+
33+
// the layout of the list
34+
internal class ViewHolder {
35+
var textView: TextView? = null
36+
}
37+
}

app/src/main/java/de/tum/in/tumcampusapp/component/notifications/persistence/ActiveAlarmsDao.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ interface ActiveAlarmsDao {
1414
@Query("SELECT CASE WHEN count(*) < $MAX_ACTIVE THEN $MAX_ACTIVE - count(*) ELSE 0 END FROM active_alarms")
1515
fun maxAlarmsToSchedule(): Int
1616

17+
@Query("SELECT * FROM active_alarms")
18+
fun getAllAlarms(): List<ActiveAlarm>
19+
1720
companion object {
1821
private const val MAX_ACTIVE = 100
1922
}

app/src/main/java/de/tum/in/tumcampusapp/component/notifications/persistence/ScheduledNotificationsDao.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ interface ScheduledNotificationsDao {
1616

1717
@Query("DELETE FROM scheduled_notifications WHERE type_id = :typeId AND content_id = :contentId")
1818
fun delete(typeId: Int, contentId: Int)
19+
20+
@Query("SELECT * FROM scheduled_notifications")
21+
fun getAllScheduledNotifications(): List<ScheduledNotification>
1922
}

app/src/main/java/de/tum/in/tumcampusapp/component/ui/overview/InformationActivity.kt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ import android.view.ViewGroup
1414
import android.widget.TableLayout
1515
import android.widget.TableRow
1616
import android.widget.TextView
17+
import android.widget.Toast
1718
import androidx.core.content.pm.PackageInfoCompat
1819
import de.psdev.licensesdialog.LicensesDialog
1920
import de.tum.`in`.tumcampusapp.BuildConfig
2021
import de.tum.`in`.tumcampusapp.R
22+
import de.tum.`in`.tumcampusapp.component.notifications.overview.NotificationOverviewActivity
2123
import de.tum.`in`.tumcampusapp.component.other.generic.activity.BaseActivity
2224
import de.tum.`in`.tumcampusapp.databinding.ActivityInformationBinding
2325
import de.tum.`in`.tumcampusapp.utils.Const
@@ -60,6 +62,43 @@ class InformationActivity : BaseActivity(R.layout.activity_information) {
6062
.show()
6163
}
6264

65+
// opens notification overview after 5 quick clicks
66+
var timeDebugInfoLastClicked = 0L
67+
var countDebugInfoClicked = 0
68+
// create Toast beforehand to be able to cancel before showing new one
69+
var countdownToast = Toast.makeText(baseContext, "", Toast.LENGTH_LONG)
70+
binding.txtVersion.setOnClickListener {
71+
if (System.currentTimeMillis() - timeDebugInfoLastClicked < 2000) {
72+
countDebugInfoClicked++
73+
when (countDebugInfoClicked) {
74+
2, 3 -> {
75+
countdownToast.cancel()
76+
countdownToast = Toast.makeText(
77+
baseContext,
78+
getString(R.string.show_notification_view_progress_multiple, 5 - countDebugInfoClicked),
79+
Toast.LENGTH_LONG)
80+
countdownToast.show()
81+
}
82+
4 -> {
83+
countdownToast.cancel()
84+
countdownToast = Toast.makeText(
85+
baseContext,
86+
getString(R.string.show_notification_view_progress_single),
87+
Toast.LENGTH_LONG)
88+
countdownToast.show()
89+
}
90+
5 -> {
91+
countdownToast.cancel()
92+
val intent = Intent(this, NotificationOverviewActivity::class.java)
93+
startActivity(intent)
94+
}
95+
}
96+
} else {
97+
countDebugInfoClicked = 1
98+
}
99+
timeDebugInfoLastClicked = System.currentTimeMillis()
100+
}
101+
63102
displayDebugInfo()
64103
}
65104

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
android:id="@+id/drawer_layout"
5+
android:layout_width="match_parent"
6+
android:layout_height="match_parent"
7+
android:fitsSystemWindows="true">
8+
9+
<LinearLayout
10+
android:layout_width="match_parent"
11+
android:layout_height="match_parent"
12+
android:orientation="vertical">
13+
14+
<include layout="@layout/toolbar" android:id="@+id/toolbar_information"/>
15+
16+
<se.emilsjolander.stickylistheaders.StickyListHeadersListView
17+
android:id="@+id/notificationsListView"
18+
android:layout_width="match_parent"
19+
android:layout_height="match_parent"
20+
android:importantForAutofill="noExcludeDescendants"
21+
android:scrollbars="vertical" />
22+
</LinearLayout>
23+
24+
</androidx.drawerlayout.widget.DrawerLayout>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:layout_width="match_parent"
4+
android:layout_height="wrap_content"
5+
android:gravity="center_vertical"
6+
android:padding="@dimen/material_default_padding">
7+
8+
<TextView
9+
android:id="@+id/textView"
10+
android:layout_width="wrap_content"
11+
android:layout_height="wrap_content"/>
12+
</FrameLayout>

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,19 @@
317317
<string name="send_email">E-Mail Feedback senden</string>
318318
<string name="show_feedback">Feedback senden</string>
319319
<string name="feedbackSubj">Feedback für TUM Campus App</string>
320-
<!-- END Translated, please do not change identifiers -->
320+
<string name="show_notification_view_progress_single">Die Benachrichtigungsübersicht öffnet sich in einem Klick.</string>
321+
<string name="show_notification_view_progress_multiple">Die Benachrichtigungsübersicht öffnet sich in %1$d Klicks.</string>
322+
323+
<!-- Notification Overview -->
324+
<string name="notification_overview">Benarichtigungsübersicht</string>
325+
<string name="active_notifications">Aktive Benarichtigungen</string>
326+
<string name="scheduled_notifications">Geplante Benarichtigungen</string>
327+
<string name="alarms">Alarme</string>
328+
<string name="pendingintents_per_type">PendingIntents nach NotificationType</string>
329+
<string name="pendingintents_per_scheduled_notification">PendingIntents nach ScheduledNotification</string>
321330

331+
332+
<!-- END Translated, please do not change identifiers -->
322333
<string name="min_search_len">Text muss mindestens %d Zeichen lang sein</string>
323334
<string name="default_cafeteria">Standardmensa</string>
324335
<string name="default_station">Standardhaltestelle</string>

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,16 @@
369369
The TUM Campus App is being developed by volunteers, students of the Android practical course and employees of the Chair of Operating Systems led by Professor Dr. Baumgarten.
370370
The app can be used on smartphones and tablets and is available for both iOS and Android.\n\nYou can reach us via the feedback form in the app or via email (app@tum.de) if you have any special concerns or requests.
371371
</string>
372+
<string name="show_notification_view_progress_single">The notification overview opens in one click.</string>
373+
<string name="show_notification_view_progress_multiple">The notification overview opens in %1$d clicks.</string>
374+
375+
<!-- Notification Overview -->
376+
<string name="notification_overview">Notification Overview</string>
377+
<string name="active_notifications">Active Notifications</string>
378+
<string name="scheduled_notifications">Scheduled Notifications</string>
379+
<string name="alarms">Alarms</string>
380+
<string name="pendingintents_per_type">PendingIntents per NotificationType</string>
381+
<string name="pendingintents_per_scheduled_notification">PendingIntents per ScheduledNotification</string>
372382

373383
<!-- END Translated, please do not change identifiers -->
374384
<string name="min_search_len" tools:ignore="PluralsCandidate">Query must be at least %d chars long</string>

0 commit comments

Comments
 (0)