1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.calendar.alerts
17 
18 import android.app.Notification
19 import android.app.NotificationManager
20 import android.app.Service
21 import android.content.Intent
22 import android.os.IBinder
23 import android.os.Looper
24 import android.provider.CalendarContract.CalendarAlerts
25 import java.util.ArrayList
26 
27 /**
28  * This service is used to handle calendar event reminders.
29  */
30 class AlertService : Service() {
31     @Volatile
32     private var mServiceLooper: Looper? = null
33 
34     // Added wrapper for testing
35     class NotificationWrapper {
36         var mNotification: Notification
37         var mEventId: Long = 0
38         var mBegin: Long = 0
39         var mEnd: Long = 0
40         var mNw: ArrayList<NotificationWrapper>? = null
41 
42         constructor(
43             n: Notification,
44             notificationId: Int,
45             eventId: Long,
46             startMillis: Long,
47             endMillis: Long,
48             doPopup: Boolean
49         ) {
50             mNotification = n
51             mEventId = eventId
52             mBegin = startMillis
53             mEnd = endMillis
54 
55             // popup?
56             // notification id?
57         }
58 
59         constructor(n: Notification) {
60             mNotification = n
61         }
62 
addnull63         fun add(nw: NotificationWrapper?) {
64             val temp = mNw
65             if (temp == null) {
66                 mNw = ArrayList<NotificationWrapper>()
67             }
68             mNw?.add(nw as AlertService.NotificationWrapper)
69         }
70     }
71 
72     // Added wrapper for testing
73     class NotificationMgrWrapper(nm: NotificationManager) : NotificationMgr() {
74         var mNm: NotificationManager
75         @Override
cancelnull76         override fun cancel(id: Int) {
77             mNm.cancel(id)
78         }
79 
80         @Override
notifynull81         override fun notify(id: Int, nw: NotificationWrapper?) {
82             mNm.notify(id, nw?.mNotification)
83         }
84 
85         init {
86             mNm = nm
87         }
88     }
89 
90     internal class NotificationInfo(
91         var eventName: String,
92         var location: String,
93         var description: String,
94         var startMillis: Long,
95         var endMillis: Long,
96         var eventId: Long,
97         var allDay: Boolean,
98         var newAlert: Boolean
99     )
100 
101     @Override
onCreatenull102     override fun onCreate() {
103     }
104 
105     @Override
onStartCommandnull106     override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
107         return START_REDELIVER_INTENT
108     }
109 
110     @Override
onDestroynull111     override fun onDestroy() {
112         mServiceLooper?.quit()
113     }
114 
115     @Override
onBindnull116     override fun onBind(intent: Intent?): IBinder? {
117         return null
118     }
119 
120     companion object {
121         const val DEBUG = true
122         private const val TAG = "AlertService"
123         val ALERT_PROJECTION = arrayOf<String>(
124             CalendarAlerts._ID, // 0
125             CalendarAlerts.EVENT_ID, // 1
126             CalendarAlerts.STATE, // 2
127             CalendarAlerts.TITLE, // 3
128             CalendarAlerts.EVENT_LOCATION, // 4
129             CalendarAlerts.SELF_ATTENDEE_STATUS, // 5
130             CalendarAlerts.ALL_DAY, // 6
131             CalendarAlerts.ALARM_TIME, // 7
132             CalendarAlerts.MINUTES, // 8
133             CalendarAlerts.BEGIN, // 9
134             CalendarAlerts.END, // 10
135             CalendarAlerts.DESCRIPTION
136         )
137         private const val ALERT_INDEX_ID = 0
138         private const val ALERT_INDEX_EVENT_ID = 1
139         private const val ALERT_INDEX_STATE = 2
140         private const val ALERT_INDEX_TITLE = 3
141         private const val ALERT_INDEX_EVENT_LOCATION = 4
142         private const val ALERT_INDEX_SELF_ATTENDEE_STATUS = 5
143         private const val ALERT_INDEX_ALL_DAY = 6
144         private const val ALERT_INDEX_ALARM_TIME = 7
145         private const val ALERT_INDEX_MINUTES = 8
146         private const val ALERT_INDEX_BEGIN = 9
147         private const val ALERT_INDEX_END = 10
148         private const val ALERT_INDEX_DESCRIPTION = 11
149         private val ACTIVE_ALERTS_SELECTION = ("(" + CalendarAlerts.STATE.toString() + "=? OR " +
150             CalendarAlerts.STATE.toString() + "=?) AND " +
151             CalendarAlerts.ALARM_TIME.toString() + "<=")
152         private val ACTIVE_ALERTS_SELECTION_ARGS = arrayOf<String>(
153             Integer.toString(CalendarAlerts.STATE_FIRED),
154             Integer.toString(CalendarAlerts.STATE_SCHEDULED)
155         )
156         private const val ACTIVE_ALERTS_SORT = "begin DESC, end DESC"
157         private val DISMISS_OLD_SELECTION: String = (CalendarAlerts.END.toString() + "<? AND " +
158             CalendarAlerts.STATE + "=?")
159         private const val MINUTE_MS = 60 * 1000
160 
161         // The grace period before changing a notification's priority bucket.
162         private const val MIN_DEPRIORITIZE_GRACE_PERIOD_MS = 15 * MINUTE_MS
163 
164         // Hard limit to the number of notifications displayed.
165         const val MAX_NOTIFICATIONS = 20
166     }
167 }