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

Commit

Permalink
Implement notification preview mentioned in issue #1235 (#1562)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
kunzef and CommanderStorm authored May 27, 2023
1 parent 1912fc2 commit 4d27542
Show file tree
Hide file tree
Showing 11 changed files with 254 additions and 1 deletion.
11 changes: 11 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,17 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".component.other.settings.SettingsActivity" />
</activity>
<activity
android:name=".component.notifications.overview.NotificationOverviewActivity"
android:configChanges="orientation|screenSize"
android:label="@string/notification_overview"
android:launchMode="singleTop"
android:parentActivityName=".component.ui.overview.InformationActivity"
android:theme="@style/AppTheme.NoDrawerLayout">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".component.ui.overview.InformationActivity" />
</activity>
<activity
android:name=".component.ui.eduroam.SetupEduroamActivity"
android:configChanges="orientation|screenSize"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package de.tum.`in`.tumcampusapp.component.notifications.overview

import de.tum.`in`.tumcampusapp.component.other.generic.adapter.SimpleStickyListHeadersAdapter

data class NotificationItemForStickyList(
val notificationString: String,
val notificationSource: String
) : SimpleStickyListHeadersAdapter.SimpleStickyListItem {

override fun getHeadName(): String {
return notificationSource
}

override fun getHeaderId(): String {
return notificationSource
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package de.tum.`in`.tumcampusapp.component.notifications.overview

import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Bundle
import de.tum.`in`.tumcampusapp.R
import de.tum.`in`.tumcampusapp.component.notifications.receivers.NotificationAlarmReceiver
import de.tum.`in`.tumcampusapp.component.notifications.receivers.NotificationReceiver
import de.tum.`in`.tumcampusapp.component.other.generic.activity.BaseActivity
import de.tum.`in`.tumcampusapp.database.TcaDb
import de.tum.`in`.tumcampusapp.databinding.ActivityNotificationOverviewBinding

class NotificationOverviewActivity : BaseActivity(R.layout.activity_notification_overview) {

private lateinit var binding: ActivityNotificationOverviewBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

binding = ActivityNotificationOverviewBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbarInformation.toolbar)
supportActionBar?.apply {
setDisplayHomeAsUpEnabled(true)
setDisplayShowHomeEnabled(true)
}

// get currently active notifications
val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val activeNotifications = notificationManager.activeNotifications.asList()
// get notifications stored in database
val scheduledNotifications = TcaDb.getInstance(applicationContext).scheduledNotificationsDao().getAllScheduledNotifications()
val alarms = TcaDb.getInstance(applicationContext).activeNotificationsDao().getAllAlarms()
// get PendingIntent for every NotificationType
val typesList = (0..5)
// get PendingIntent for every ScheduledNotification
val scheduledNotificationIds = scheduledNotifications.map { it.typeId }

// store all notifications into one list
val notificationsList = emptyList<NotificationItemForStickyList>().toMutableList()
activeNotifications.forEach {
notificationsList.add(NotificationItemForStickyList(it.toString(), getString(R.string.active_notifications)))
}
scheduledNotifications.forEach {
notificationsList.add(NotificationItemForStickyList(it.toString(), getString(R.string.scheduled_notifications)))
}
alarms.forEach {
notificationsList.add(NotificationItemForStickyList(it.toString(), getString(R.string.alarms)))
}
typesList.forEach { type ->
getAlarmIntentPerType(type)?.let {
notificationsList.add(NotificationItemForStickyList(it.toString(), getString(R.string.pendingintents_per_type)))
}
}
scheduledNotificationIds.forEach { id ->
getAlarmIntent(id)?.let {
notificationsList.add(NotificationItemForStickyList(it.toString(), getString(R.string.pendingintents_per_scheduled_notification)))
}
}

binding.notificationsListView.adapter = NotificationsListAdapter(applicationContext, notificationsList)
}

// mimics NotificationScheduler.getAlarmIntent(type: NotificationType) method
private fun getAlarmIntentPerType(type: Int): PendingIntent? {
// extra data is ignored according to intent filter
val intent = Intent(applicationContext, NotificationAlarmReceiver::class.java)
// FLAG_NO_CREATE to only show existing intents
return PendingIntent.getBroadcast(applicationContext, type, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_NO_CREATE)
}

// mimics NotificationScheduler.getAlarmIntent(futureNotification: FutureNotification, globalNotificationId: Long) method
private fun getAlarmIntent(id: Int): PendingIntent? {
// extra data is ignored according to intent filter
val intent = Intent(applicationContext, NotificationReceiver::class.java)
// FLAG_NO_CREATE to only show existing intents
return PendingIntent.getBroadcast(
applicationContext,
id,
intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_NO_CREATE
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package de.tum.`in`.tumcampusapp.component.notifications.overview

import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import de.tum.`in`.tumcampusapp.R
import de.tum.`in`.tumcampusapp.component.other.generic.adapter.SimpleStickyListHeadersAdapter

class NotificationsListAdapter(context: Context, results: MutableList<NotificationItemForStickyList>) : SimpleStickyListHeadersAdapter<NotificationItemForStickyList>(context, results) {

override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val holder: ViewHolder
val view: View

if (convertView == null) {
view = inflater.inflate(R.layout.notification_row_item, parent, false)
holder = ViewHolder()
holder.textView = view.findViewById(R.id.textView)
view.tag = holder
} else {
view = convertView
holder = view.tag as ViewHolder
}

val notification = itemList[position]

holder.textView?.text = notification.notificationString

return view
}

// the layout of the list
internal class ViewHolder {
var textView: TextView? = null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ interface ActiveAlarmsDao {
@Query("SELECT CASE WHEN count(*) < $MAX_ACTIVE THEN $MAX_ACTIVE - count(*) ELSE 0 END FROM active_alarms")
fun maxAlarmsToSchedule(): Int

@Query("SELECT * FROM active_alarms")
fun getAllAlarms(): List<ActiveAlarm>

companion object {
private const val MAX_ACTIVE = 100
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ interface ScheduledNotificationsDao {

@Query("DELETE FROM scheduled_notifications WHERE type_id = :typeId AND content_id = :contentId")
fun delete(typeId: Int, contentId: Int)

@Query("SELECT * FROM scheduled_notifications")
fun getAllScheduledNotifications(): List<ScheduledNotification>
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ import android.view.ViewGroup
import android.widget.TableLayout
import android.widget.TableRow
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.pm.PackageInfoCompat
import de.psdev.licensesdialog.LicensesDialog
import de.tum.`in`.tumcampusapp.BuildConfig
import de.tum.`in`.tumcampusapp.R
import de.tum.`in`.tumcampusapp.component.notifications.overview.NotificationOverviewActivity
import de.tum.`in`.tumcampusapp.component.other.generic.activity.BaseActivity
import de.tum.`in`.tumcampusapp.databinding.ActivityInformationBinding
import de.tum.`in`.tumcampusapp.utils.Const
Expand Down Expand Up @@ -60,6 +62,43 @@ class InformationActivity : BaseActivity(R.layout.activity_information) {
.show()
}

// opens notification overview after 5 quick clicks
var timeDebugInfoLastClicked = 0L
var countDebugInfoClicked = 0
// create Toast beforehand to be able to cancel before showing new one
var countdownToast = Toast.makeText(baseContext, "", Toast.LENGTH_LONG)
binding.txtVersion.setOnClickListener {
if (System.currentTimeMillis() - timeDebugInfoLastClicked < 2000) {
countDebugInfoClicked++
when (countDebugInfoClicked) {
2, 3 -> {
countdownToast.cancel()
countdownToast = Toast.makeText(
baseContext,
getString(R.string.show_notification_view_progress_multiple, 5 - countDebugInfoClicked),
Toast.LENGTH_LONG)
countdownToast.show()
}
4 -> {
countdownToast.cancel()
countdownToast = Toast.makeText(
baseContext,
getString(R.string.show_notification_view_progress_single),
Toast.LENGTH_LONG)
countdownToast.show()
}
5 -> {
countdownToast.cancel()
val intent = Intent(this, NotificationOverviewActivity::class.java)
startActivity(intent)
}
}
} else {
countDebugInfoClicked = 1
}
timeDebugInfoLastClicked = System.currentTimeMillis()
}

displayDebugInfo()
}

Expand Down
24 changes: 24 additions & 0 deletions app/src/main/res/layout/activity_notification_overview.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<include layout="@layout/toolbar" android:id="@+id/toolbar_information"/>

<se.emilsjolander.stickylistheaders.StickyListHeadersListView
android:id="@+id/notificationsListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAutofill="noExcludeDescendants"
android:scrollbars="vertical" />
</LinearLayout>

</androidx.drawerlayout.widget.DrawerLayout>
12 changes: 12 additions & 0 deletions app/src/main/res/layout/notification_row_item.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="@dimen/material_default_padding">

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
13 changes: 12 additions & 1 deletion app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,19 @@
<string name="send_email">E-Mail Feedback senden</string>
<string name="show_feedback">Feedback senden</string>
<string name="feedbackSubj">Feedback für TUM Campus App</string>
<!-- END Translated, please do not change identifiers -->
<string name="show_notification_view_progress_single">Die Benachrichtigungsübersicht öffnet sich in einem Klick.</string>
<string name="show_notification_view_progress_multiple">Die Benachrichtigungsübersicht öffnet sich in %1$d Klicks.</string>

<!-- Notification Overview -->
<string name="notification_overview">Benarichtigungsübersicht</string>
<string name="active_notifications">Aktive Benarichtigungen</string>
<string name="scheduled_notifications">Geplante Benarichtigungen</string>
<string name="alarms">Alarme</string>
<string name="pendingintents_per_type">PendingIntents nach NotificationType</string>
<string name="pendingintents_per_scheduled_notification">PendingIntents nach ScheduledNotification</string>


<!-- END Translated, please do not change identifiers -->
<string name="min_search_len">Text muss mindestens %d Zeichen lang sein</string>
<string name="default_cafeteria">Standardmensa</string>
<string name="default_station">Standardhaltestelle</string>
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,16 @@
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.
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 ([email protected]) if you have any special concerns or requests.
</string>
<string name="show_notification_view_progress_single">The notification overview opens in one click.</string>
<string name="show_notification_view_progress_multiple">The notification overview opens in %1$d clicks.</string>

<!-- Notification Overview -->
<string name="notification_overview">Notification Overview</string>
<string name="active_notifications">Active Notifications</string>
<string name="scheduled_notifications">Scheduled Notifications</string>
<string name="alarms">Alarms</string>
<string name="pendingintents_per_type">PendingIntents per NotificationType</string>
<string name="pendingintents_per_scheduled_notification">PendingIntents per ScheduledNotification</string>

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

0 comments on commit 4d27542

Please sign in to comment.