@takeoffmedia/react-native-penthera 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +203 -0
- package/android/build.gradle +105 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +51 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/AssetQueueObserver.kt +148 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/EventEmitter.kt +53 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/PentheraModule.kt +104 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/PentheraPackage.kt +16 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/YourPlayerActivity.kt +14 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/DemoLicenseManager.kt +50 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/OfflineVideoEngine.kt +227 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/PentheraContentProvider.kt +17 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/ServiceStarter.kt +65 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/data/Drm.kt +6 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/data/Item.kt +34 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/notification/NotificationFactory.kt +279 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/notification/NotificationType.kt +10 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/notification/ServiceForegroundNotificationProvider.kt +98 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/util/Util.kt +22 -0
- package/android/src/main/res/drawable/ic_launcher_background.xml +170 -0
- package/android/src/main/res/drawable/small_logo.png +0 -0
- package/android/src/main/res/values/colors.xml +6 -0
- package/android/src/main/res/values/strings.xml +61 -0
- package/android/src/main/res/values/styles.xml +10 -0
- package/android/src/main/res/xml/network_security_config.xml +9 -0
- package/ios/Catalog.swift +30 -0
- package/ios/EventEmitter.swift +53 -0
- package/ios/Penthera-Bridging-Header.h +3 -0
- package/ios/Penthera.m +40 -0
- package/ios/Penthera.swift +384 -0
- package/ios/Penthera.xcodeproj/project.pbxproj +283 -0
- package/ios/Util.swift +16 -0
- package/ios/drm/FairPlayDrmSetup.swift +107 -0
- package/ios/drm/FairPlayLicenseProcessingDelegate.swift +42 -0
- package/lib/commonjs/data/data.json +58 -0
- package/lib/commonjs/hooks/index.js +13 -0
- package/lib/commonjs/hooks/index.js.map +1 -0
- package/lib/commonjs/hooks/usePenthera.js +146 -0
- package/lib/commonjs/hooks/usePenthera.js.map +1 -0
- package/lib/commonjs/index.js +36 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/interface/HomeTypes.js +6 -0
- package/lib/commonjs/interface/HomeTypes.js.map +1 -0
- package/lib/commonjs/interface/Idata.js +2 -0
- package/lib/commonjs/interface/Idata.js.map +1 -0
- package/lib/commonjs/interface/PentheraTypes.js +2 -0
- package/lib/commonjs/interface/PentheraTypes.js.map +1 -0
- package/lib/commonjs/nativeModules/index.js +48 -0
- package/lib/commonjs/nativeModules/index.js.map +1 -0
- package/lib/commonjs/utils/Penthera.js +19 -0
- package/lib/commonjs/utils/Penthera.js.map +1 -0
- package/lib/module/data/data.json +58 -0
- package/lib/module/hooks/index.js +2 -0
- package/lib/module/hooks/index.js.map +1 -0
- package/lib/module/hooks/usePenthera.js +139 -0
- package/lib/module/hooks/usePenthera.js.map +1 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/interface/HomeTypes.js +2 -0
- package/lib/module/interface/HomeTypes.js.map +1 -0
- package/lib/module/interface/Idata.js +2 -0
- package/lib/module/interface/Idata.js.map +1 -0
- package/lib/module/interface/PentheraTypes.js +2 -0
- package/lib/module/interface/PentheraTypes.js.map +1 -0
- package/lib/module/nativeModules/index.js +35 -0
- package/lib/module/nativeModules/index.js.map +1 -0
- package/lib/module/utils/Penthera.js +12 -0
- package/lib/module/utils/Penthera.js.map +1 -0
- package/lib/typescript/hooks/index.d.ts +2 -0
- package/lib/typescript/hooks/index.d.ts.map +1 -0
- package/lib/typescript/hooks/usePenthera.d.ts +19 -0
- package/lib/typescript/hooks/usePenthera.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +4 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/interface/HomeTypes.d.ts +15 -0
- package/lib/typescript/interface/HomeTypes.d.ts.map +1 -0
- package/lib/typescript/interface/Idata.d.ts +30 -0
- package/lib/typescript/interface/Idata.d.ts.map +1 -0
- package/lib/typescript/interface/PentheraTypes.d.ts +104 -0
- package/lib/typescript/interface/PentheraTypes.d.ts.map +1 -0
- package/lib/typescript/nativeModules/index.d.ts +9 -0
- package/lib/typescript/nativeModules/index.d.ts.map +1 -0
- package/lib/typescript/utils/Penthera.d.ts +11 -0
- package/lib/typescript/utils/Penthera.d.ts.map +1 -0
- package/package.json +166 -0
- package/src/data/data.json +58 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/usePenthera.ts +160 -0
- package/src/index.tsx +5 -0
- package/src/interface/HomeTypes.ts +16 -0
- package/src/interface/Idata.ts +34 -0
- package/src/interface/PentheraTypes.ts +104 -0
- package/src/nativeModules/index.ts +58 -0
- package/src/utils/Penthera.ts +10 -0
- package/takeoffmedia-react-native-penthera.podspec +36 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
package com.takeoffmediareactnativepenthera.virtuoso.notification
|
|
2
|
+
|
|
3
|
+
import android.app.Notification
|
|
4
|
+
import android.app.NotificationChannel
|
|
5
|
+
import android.app.NotificationManager
|
|
6
|
+
import android.app.PendingIntent
|
|
7
|
+
import android.content.ComponentName
|
|
8
|
+
import android.content.Context
|
|
9
|
+
import android.content.Intent
|
|
10
|
+
import android.content.pm.PackageManager
|
|
11
|
+
import android.os.Build
|
|
12
|
+
import android.util.Log
|
|
13
|
+
import androidx.core.app.NotificationCompat
|
|
14
|
+
import com.google.gson.Gson
|
|
15
|
+
import com.penthera.virtuososdk.Common
|
|
16
|
+
import com.penthera.virtuososdk.client.IAsset
|
|
17
|
+
import com.penthera.virtuososdk.client.IEvent
|
|
18
|
+
import com.takeoffmediareactnativepenthera.PentheraModule
|
|
19
|
+
import com.takeoffmediareactnativepenthera.R
|
|
20
|
+
import com.takeoffmediareactnativepenthera.virtuoso.data.Item
|
|
21
|
+
|
|
22
|
+
class NotificationFactory(private val applicationName: String) {
|
|
23
|
+
|
|
24
|
+
companion object {
|
|
25
|
+
fun channelId() = "Penthera example"
|
|
26
|
+
fun channelName() = "Penthera example channel"
|
|
27
|
+
fun channelDescription() = "Penthera example description"
|
|
28
|
+
|
|
29
|
+
private val TAG = NotificationFactory::class.java.simpleName
|
|
30
|
+
private var notificationChannel : NotificationChannel? = null
|
|
31
|
+
private var compatNotificationBuilder: NotificationCompat.Builder? = null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
/** Internal list of types of notifications in this factory */
|
|
36
|
+
private val PROGRESS_NOTIFICATION = 0
|
|
37
|
+
private val COMPLETED_NOTIFICATION = 1
|
|
38
|
+
private val STOPPED_NOTIFICATION = 2
|
|
39
|
+
private val PAUSED_NOTIFICATION = 3
|
|
40
|
+
private val RESTART_NOTIFICATION = 4
|
|
41
|
+
private val FAILED_NOTIFICATION = 5
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* This defines a default intent for the app which can be used if none is provided in the request
|
|
45
|
+
*/
|
|
46
|
+
private fun defaultNotificationIntent(context: Context) : Intent {
|
|
47
|
+
|
|
48
|
+
val notificationIntent = Intent(context, PentheraModule::class.java)
|
|
49
|
+
notificationIntent.action = "foregroundservice.action.ForegroundServiceNotificationAction"
|
|
50
|
+
notificationIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
|
51
|
+
return notificationIntent
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
fun getNotification(context: Context, intent: Intent?): Notification? {
|
|
55
|
+
// A default intent is used if no intent is delivered in the request.
|
|
56
|
+
val notificationIntent = intent ?: defaultNotificationIntent(context)
|
|
57
|
+
|
|
58
|
+
val clientReference: String?
|
|
59
|
+
|
|
60
|
+
// Get package name for use in modifying actions
|
|
61
|
+
try {
|
|
62
|
+
val ai = context.packageManager.getApplicationInfo(context.packageName, PackageManager.GET_META_DATA)
|
|
63
|
+
val b = ai.metaData
|
|
64
|
+
|
|
65
|
+
clientReference = b.getString(Common.CLIENT_PACKAGE)
|
|
66
|
+
|
|
67
|
+
} catch (e: Exception) {
|
|
68
|
+
throw RuntimeException("cannot retrieve client", e)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
val action = notificationIntent.action
|
|
72
|
+
if (clientReference == null || action == null) {
|
|
73
|
+
return null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// If the intent action contains the NOTIFICATION_EVENT_TAG, then this is a log event broadcast sent from
|
|
77
|
+
// the SDK analytics system. For debugging, we might want to post status bar notifications, but in general,
|
|
78
|
+
// these events are used to push SDK analytics events into a custom/3rd party analytics platform, and shouldn't
|
|
79
|
+
// be sent to the status bar. For the purposes of this demo, we'll log them and return null, which prevents the
|
|
80
|
+
// status bar notice from being shown.
|
|
81
|
+
if (action.contains(com.penthera.common.Common.Notifications.NOTIFICATION_EVENT_TAG)) {
|
|
82
|
+
|
|
83
|
+
val event: IEvent? = notificationIntent.getParcelableExtra(com.penthera.common.Common.Notifications.EXTRA_NOTIFICATION_EVENT)
|
|
84
|
+
|
|
85
|
+
Log.d(TAG, "Got event named(" + event?.name() + ") asset(" + event?.assetId() + " data(" + event?.numericData() + ")")
|
|
86
|
+
return null
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
val notificationType : Int
|
|
90
|
+
var file: IAsset? = null
|
|
91
|
+
|
|
92
|
+
if (action == Common.START_VIRTUOSO_SERVICE) {
|
|
93
|
+
notificationType = RESTART_NOTIFICATION
|
|
94
|
+
} else {
|
|
95
|
+
var hasInfo = false
|
|
96
|
+
val extras = notificationIntent.extras
|
|
97
|
+
var info = Common.Notifications.DownloadStopReason.NO_ERROR
|
|
98
|
+
|
|
99
|
+
if (extras != null) {
|
|
100
|
+
if (extras.containsKey(Common.Notifications.EXTRA_NOTIFICATION_DOWNLOAD_STOP_REASON)) {
|
|
101
|
+
hasInfo = true
|
|
102
|
+
info = extras.getInt(Common.Notifications.EXTRA_NOTIFICATION_DOWNLOAD_STOP_REASON)
|
|
103
|
+
}
|
|
104
|
+
file = extras.getParcelable(Common.Notifications.EXTRA_NOTIFICATION_FILE)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
when(action.replace(clientReference, "")){
|
|
108
|
+
|
|
109
|
+
Common.Notifications.INTENT_NOTIFICATION_DOWNLOAD_COMPLETE -> {
|
|
110
|
+
if (file != null) {
|
|
111
|
+
Log.d(TAG, "DOWNLOAD COMPLETE NOTIFICATION FOR " + file?.uuid + " stat: " + if (hasInfo) info else "unknown")
|
|
112
|
+
} else {
|
|
113
|
+
Log.d(TAG, "DOWNLOAD COMPLETE NOTIFICATION FOR UNKNOWN" + " stat: " + if (hasInfo) info else "unknown")
|
|
114
|
+
}
|
|
115
|
+
notificationType = COMPLETED_NOTIFICATION
|
|
116
|
+
}
|
|
117
|
+
Common.Notifications.INTENT_NOTIFICATION_DOWNLOAD_START ->{
|
|
118
|
+
if(file != null) {
|
|
119
|
+
Log.d(TAG, "DOWNLOAD START NOTIFICATION FOR " + file?.uuid + " stat: " + if (hasInfo) info else "unknown")
|
|
120
|
+
} else {
|
|
121
|
+
Log.d(TAG, "DOWNLOAD START NOTIFICATION FOR UNKNOWN" + " stat: " + if (hasInfo) info else "unknown")
|
|
122
|
+
}
|
|
123
|
+
notificationType = PROGRESS_NOTIFICATION
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
Common.Notifications.INTENT_NOTIFICATION_DOWNLOAD_STOPPED-> {
|
|
127
|
+
if (file != null) {
|
|
128
|
+
Log.d(TAG, "DOWNLOAD STOP NOTIFICATION FOR " + file.uuid + " stat: " + if (hasInfo) info else "unknown")
|
|
129
|
+
} else {
|
|
130
|
+
Log.d(TAG, "DOWNLOAD STOP NOTIFICATION FOR UNKNOWN" + " stat: " + if (hasInfo) info else "unknown")
|
|
131
|
+
}
|
|
132
|
+
notificationType = STOPPED_NOTIFICATION
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
Common.Notifications.INTENT_NOTIFICATION_DOWNLOADS_PAUSED -> {
|
|
136
|
+
if (file != null) {
|
|
137
|
+
Log.d(TAG, "DOWNLOAD PAUSED NOTIFICATION FOR " + file.uuid + " stat: " + if (hasInfo) info else "unknown")
|
|
138
|
+
} else {
|
|
139
|
+
Log.d(TAG, "DOWNLOAD PAUSED NOTIFICATION FOR UNKNOWN" + " stat: " + if (hasInfo) info else "unknown")
|
|
140
|
+
}
|
|
141
|
+
notificationType = PAUSED_NOTIFICATION
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
Common.Notifications.INTENT_NOTIFICATION_DOWNLOAD_UPDATE -> {
|
|
145
|
+
if (file != null) {
|
|
146
|
+
Log.d(TAG, "DOWNLOAD UPDATE NOTIFICATION FOR " + file?.uuid + " stat: " + if (hasInfo) info else "unknown")
|
|
147
|
+
} else {
|
|
148
|
+
Log.d(TAG, "DOWNLOAD UPDATE NOTIFICATION FOR UNKNOWN" + " stat: " + if (hasInfo) info else "unknown")
|
|
149
|
+
}
|
|
150
|
+
notificationType = PROGRESS_NOTIFICATION
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
Common.Notifications.INTENT_NOTIFICATION_MANIFEST_PARSE_FAILED-> {
|
|
154
|
+
notificationType = FAILED_NOTIFICATION
|
|
155
|
+
Log.d(TAG, "EXCEPTIONAL CIRCUMSTANCE NOTIFICATION for asset failed to be queued while in background")
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
else ->{
|
|
159
|
+
notificationType = RESTART_NOTIFICATION
|
|
160
|
+
Log.d(TAG, "UNHANDLED NOTIFICATION ACTION $action")
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
var notification: Notification? = null
|
|
167
|
+
if (notificationType > -1) {
|
|
168
|
+
notification = createNotification(notificationType, context, file)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return notification
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Create the notification for the specified type.
|
|
176
|
+
* @param type The notification type.
|
|
177
|
+
* @param context The context to be used
|
|
178
|
+
* @param asset the asset (may be null)
|
|
179
|
+
* @return the notification.
|
|
180
|
+
*/
|
|
181
|
+
private fun createNotification(type: Int, context: Context, asset: IAsset?): Notification? {
|
|
182
|
+
var title = "$applicationName: "
|
|
183
|
+
var contentText = ""
|
|
184
|
+
var progress = -1
|
|
185
|
+
|
|
186
|
+
val item = Gson().fromJson(asset?.metadata, Item::class.java)
|
|
187
|
+
|
|
188
|
+
when (type) {
|
|
189
|
+
PROGRESS_NOTIFICATION -> {
|
|
190
|
+
progress = getDownloadProgress(asset)
|
|
191
|
+
title += item.title
|
|
192
|
+
contentText += progress.toString() + "%" + " : " + String.format(" ( %1$,.0f)", asset?.currentSize)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
COMPLETED_NOTIFICATION -> {
|
|
196
|
+
progress = 100
|
|
197
|
+
title += asset?.metadata + " complete."
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
STOPPED_NOTIFICATION -> title += "stopped downloads."
|
|
201
|
+
|
|
202
|
+
PAUSED_NOTIFICATION -> title += "paused downloads."
|
|
203
|
+
|
|
204
|
+
RESTART_NOTIFICATION -> title += "is starting up..."
|
|
205
|
+
|
|
206
|
+
FAILED_NOTIFICATION -> title += " asset could not be queued"
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
val pendingIntent = PendingIntent.getActivity(context, 0, createIntent(context), PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT)
|
|
210
|
+
|
|
211
|
+
if(compatNotificationBuilder == null) {
|
|
212
|
+
synchronized(this) {
|
|
213
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
214
|
+
|
|
215
|
+
notificationChannel = NotificationChannel(channelId(), channelName(), NotificationManager.IMPORTANCE_LOW)
|
|
216
|
+
notificationChannel?.apply {
|
|
217
|
+
description = channelDescription()
|
|
218
|
+
enableLights(false)
|
|
219
|
+
enableVibration(false)
|
|
220
|
+
}
|
|
221
|
+
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
222
|
+
manager.createNotificationChannel(notificationChannel!!)
|
|
223
|
+
compatNotificationBuilder = NotificationCompat.Builder(context, channelId())
|
|
224
|
+
|
|
225
|
+
} else {
|
|
226
|
+
@Suppress("DEPRECATION")
|
|
227
|
+
compatNotificationBuilder = NotificationCompat.Builder(context)
|
|
228
|
+
compatNotificationBuilder?.setOnlyAlertOnce(true)
|
|
229
|
+
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return compatNotificationBuilder!!.apply {
|
|
236
|
+
setSmallIcon(R.drawable.small_logo)
|
|
237
|
+
setContentTitle(title)
|
|
238
|
+
setContentIntent(pendingIntent)
|
|
239
|
+
color = context.resources.getColor(android.R.color.holo_blue_bright)
|
|
240
|
+
setContentText(contentText)
|
|
241
|
+
if(progress >= 0)setProgress(100, progress, false)
|
|
242
|
+
setWhen(System.currentTimeMillis())
|
|
243
|
+
setOngoing(true)
|
|
244
|
+
}.build()
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* calculates the progress of the current download.
|
|
250
|
+
* @param asset the current asset downloading
|
|
251
|
+
* @return progress
|
|
252
|
+
*/
|
|
253
|
+
private fun getDownloadProgress(asset: IAsset?): Int {
|
|
254
|
+
var ret = 0.0
|
|
255
|
+
asset?.let{
|
|
256
|
+
var fractionComplete = it.fractionComplete
|
|
257
|
+
fractionComplete *= 100
|
|
258
|
+
if (fractionComplete > 99.0) {
|
|
259
|
+
fractionComplete = 99.0
|
|
260
|
+
}
|
|
261
|
+
ret = fractionComplete
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return ret.toInt()
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* create an intent for opening the application when the user clicks on the notification.
|
|
270
|
+
* @param aContext used to get the package name
|
|
271
|
+
* @return the intent
|
|
272
|
+
*/
|
|
273
|
+
private fun createIntent(aContext: Context): Intent {
|
|
274
|
+
return Intent(aContext.packageName + ".DEMO_NOTIFICATION").apply{
|
|
275
|
+
component = ComponentName(aContext.packageName, PentheraModule::class.java.name)
|
|
276
|
+
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_FROM_BACKGROUND
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
package com.takeoffmediareactnativepenthera.virtuoso.notification
|
|
2
|
+
|
|
3
|
+
enum class NotificationType(value: Int) {
|
|
4
|
+
PROGRESS_NOTIFICATION(0),
|
|
5
|
+
COMPLETED_NOTIFICATION(1),
|
|
6
|
+
STOPPED_NOTIFICATION(2),
|
|
7
|
+
PAUSED_NOTIFICATION(3),
|
|
8
|
+
RESTART_NOTIFICATION(4),
|
|
9
|
+
FAILED_NOTIFICATION(5)
|
|
10
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
package com.takeoffmediareactnativepenthera.virtuoso.notification
|
|
2
|
+
|
|
3
|
+
import android.app.Notification
|
|
4
|
+
import android.app.NotificationChannel
|
|
5
|
+
import android.app.NotificationManager
|
|
6
|
+
import android.content.Context
|
|
7
|
+
import android.content.Intent
|
|
8
|
+
import android.os.Build
|
|
9
|
+
import android.util.Log
|
|
10
|
+
import com.penthera.common.Common.Notifications.NOTIFICATION_EVENT_TAG
|
|
11
|
+
import com.penthera.virtuososdk.client.IAsset
|
|
12
|
+
import com.penthera.virtuososdk.client.IForegroundNotificationProvider
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* This implements the IForegroundNotificationProvider interface, which enables notifications to be built
|
|
16
|
+
* within the service process so they do not need to cross the process boundary. Notifications created in the service starter
|
|
17
|
+
* would be passed in an intent over the process boundary into the service process, and this introduces limitations due to the
|
|
18
|
+
* size of object that can be passed over that boundary. This object is instantiated within the service process instead,
|
|
19
|
+
* so no limitations exist on the way the notifications are used, but the process should be considered. Any resources which
|
|
20
|
+
* are required to generate the notification will need to be loaded within this process as they cannot be shared with the process
|
|
21
|
+
* which contains the UI.
|
|
22
|
+
*
|
|
23
|
+
* This example uses the same Factory class to generate notifications. Please remember this is a
|
|
24
|
+
* separate instance of the NotificationFactory, running within a different process than the traditional one in ServiceStarter.
|
|
25
|
+
*/
|
|
26
|
+
class ServiceForegroundNotificationProvider : IForegroundNotificationProvider{
|
|
27
|
+
|
|
28
|
+
private var context: Context? = null
|
|
29
|
+
private var notificationChannel: NotificationChannel? = null
|
|
30
|
+
private var channelId: String? = null
|
|
31
|
+
private var currentNotification: Notification? = null
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* This method provides a place where you can setup any necessary resources when the provider is instantiated.
|
|
36
|
+
* This is called directly after construction.
|
|
37
|
+
* @param context A context from the service which can be used for access to Android resources.
|
|
38
|
+
*/
|
|
39
|
+
override fun prepareNotificationProvider(context: Context?) {
|
|
40
|
+
this.context = context
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* This method allows the client to select for which intents the service will request a new notification.
|
|
45
|
+
* @param context A context object
|
|
46
|
+
* @param reasonIntent The updated intent from the service
|
|
47
|
+
* @return true if the notification should be updated, false otherwise.
|
|
48
|
+
*/
|
|
49
|
+
override fun shouldUpdateForegroundServiceNotificationOnIntent(context: Context?, reasonIntent: Intent?): Boolean {
|
|
50
|
+
|
|
51
|
+
if(context != null) {
|
|
52
|
+
reasonIntent?.let {
|
|
53
|
+
val action = it.action
|
|
54
|
+
Log.d("ForegroundNotification", "got action: $action")
|
|
55
|
+
action?.let{// Do not update progress for events
|
|
56
|
+
return !action.contains(NOTIFICATION_EVENT_TAG)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* This method provides the notification provider with a copy of the original launch notification which was
|
|
65
|
+
* passed to the service upon startup via the ServiceStarter. This can be used to retrieve the channel details and
|
|
66
|
+
* notification ID, which enables the manipulation of the same notification on each request.
|
|
67
|
+
* @param notification The existing notification
|
|
68
|
+
*/
|
|
69
|
+
override fun setExistingNotificationForReuse(notification: Notification?) {
|
|
70
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
71
|
+
val channelId = notification?.channelId
|
|
72
|
+
if (currentNotification != null && notificationChannel != null && currentNotification?.channelId == channelId) {
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
val manager = context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
76
|
+
notificationChannel = manager.getNotificationChannel(channelId)
|
|
77
|
+
this.channelId = channelId
|
|
78
|
+
currentNotification = notification
|
|
79
|
+
} else {
|
|
80
|
+
currentNotification = notification
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Return a new notification, given the file and intent. Always return a notification.
|
|
86
|
+
* @param context A context to use in processing
|
|
87
|
+
* @param file The asset for which the notification is being created
|
|
88
|
+
* @param reasonIntent The intent for which the notification is being created
|
|
89
|
+
* @return The notification
|
|
90
|
+
*/
|
|
91
|
+
override fun getForegroundServiceNotification(context: Context?, file: IAsset?, reasonIntent: Intent?): Notification {
|
|
92
|
+
if (reasonIntent == null) return currentNotification!!
|
|
93
|
+
|
|
94
|
+
currentNotification = NotificationFactory("PentheraExample").getNotification(context!!, reasonIntent )
|
|
95
|
+
|
|
96
|
+
return currentNotification!!
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
package com.takeoffmediareactnativepenthera.virtuoso.util
|
|
2
|
+
|
|
3
|
+
import android.os.Build
|
|
4
|
+
import java.util.*
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
object Util {
|
|
8
|
+
|
|
9
|
+
fun getDeviceName(): String? {
|
|
10
|
+
val manufacturer = Build.MANUFACTURER
|
|
11
|
+
val model = Build.MODEL
|
|
12
|
+
return if (model.lowercase(Locale.getDefault())
|
|
13
|
+
.startsWith(manufacturer.lowercase(Locale.getDefault()))
|
|
14
|
+
) {
|
|
15
|
+
(model)
|
|
16
|
+
} else {
|
|
17
|
+
(manufacturer).toString() + " " + model
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
android:width="108dp"
|
|
4
|
+
android:height="108dp"
|
|
5
|
+
android:viewportWidth="108"
|
|
6
|
+
android:viewportHeight="108">
|
|
7
|
+
<path
|
|
8
|
+
android:fillColor="#3DDC84"
|
|
9
|
+
android:pathData="M0,0h108v108h-108z" />
|
|
10
|
+
<path
|
|
11
|
+
android:fillColor="#00000000"
|
|
12
|
+
android:pathData="M9,0L9,108"
|
|
13
|
+
android:strokeWidth="0.8"
|
|
14
|
+
android:strokeColor="#33FFFFFF" />
|
|
15
|
+
<path
|
|
16
|
+
android:fillColor="#00000000"
|
|
17
|
+
android:pathData="M19,0L19,108"
|
|
18
|
+
android:strokeWidth="0.8"
|
|
19
|
+
android:strokeColor="#33FFFFFF" />
|
|
20
|
+
<path
|
|
21
|
+
android:fillColor="#00000000"
|
|
22
|
+
android:pathData="M29,0L29,108"
|
|
23
|
+
android:strokeWidth="0.8"
|
|
24
|
+
android:strokeColor="#33FFFFFF" />
|
|
25
|
+
<path
|
|
26
|
+
android:fillColor="#00000000"
|
|
27
|
+
android:pathData="M39,0L39,108"
|
|
28
|
+
android:strokeWidth="0.8"
|
|
29
|
+
android:strokeColor="#33FFFFFF" />
|
|
30
|
+
<path
|
|
31
|
+
android:fillColor="#00000000"
|
|
32
|
+
android:pathData="M49,0L49,108"
|
|
33
|
+
android:strokeWidth="0.8"
|
|
34
|
+
android:strokeColor="#33FFFFFF" />
|
|
35
|
+
<path
|
|
36
|
+
android:fillColor="#00000000"
|
|
37
|
+
android:pathData="M59,0L59,108"
|
|
38
|
+
android:strokeWidth="0.8"
|
|
39
|
+
android:strokeColor="#33FFFFFF" />
|
|
40
|
+
<path
|
|
41
|
+
android:fillColor="#00000000"
|
|
42
|
+
android:pathData="M69,0L69,108"
|
|
43
|
+
android:strokeWidth="0.8"
|
|
44
|
+
android:strokeColor="#33FFFFFF" />
|
|
45
|
+
<path
|
|
46
|
+
android:fillColor="#00000000"
|
|
47
|
+
android:pathData="M79,0L79,108"
|
|
48
|
+
android:strokeWidth="0.8"
|
|
49
|
+
android:strokeColor="#33FFFFFF" />
|
|
50
|
+
<path
|
|
51
|
+
android:fillColor="#00000000"
|
|
52
|
+
android:pathData="M89,0L89,108"
|
|
53
|
+
android:strokeWidth="0.8"
|
|
54
|
+
android:strokeColor="#33FFFFFF" />
|
|
55
|
+
<path
|
|
56
|
+
android:fillColor="#00000000"
|
|
57
|
+
android:pathData="M99,0L99,108"
|
|
58
|
+
android:strokeWidth="0.8"
|
|
59
|
+
android:strokeColor="#33FFFFFF" />
|
|
60
|
+
<path
|
|
61
|
+
android:fillColor="#00000000"
|
|
62
|
+
android:pathData="M0,9L108,9"
|
|
63
|
+
android:strokeWidth="0.8"
|
|
64
|
+
android:strokeColor="#33FFFFFF" />
|
|
65
|
+
<path
|
|
66
|
+
android:fillColor="#00000000"
|
|
67
|
+
android:pathData="M0,19L108,19"
|
|
68
|
+
android:strokeWidth="0.8"
|
|
69
|
+
android:strokeColor="#33FFFFFF" />
|
|
70
|
+
<path
|
|
71
|
+
android:fillColor="#00000000"
|
|
72
|
+
android:pathData="M0,29L108,29"
|
|
73
|
+
android:strokeWidth="0.8"
|
|
74
|
+
android:strokeColor="#33FFFFFF" />
|
|
75
|
+
<path
|
|
76
|
+
android:fillColor="#00000000"
|
|
77
|
+
android:pathData="M0,39L108,39"
|
|
78
|
+
android:strokeWidth="0.8"
|
|
79
|
+
android:strokeColor="#33FFFFFF" />
|
|
80
|
+
<path
|
|
81
|
+
android:fillColor="#00000000"
|
|
82
|
+
android:pathData="M0,49L108,49"
|
|
83
|
+
android:strokeWidth="0.8"
|
|
84
|
+
android:strokeColor="#33FFFFFF" />
|
|
85
|
+
<path
|
|
86
|
+
android:fillColor="#00000000"
|
|
87
|
+
android:pathData="M0,59L108,59"
|
|
88
|
+
android:strokeWidth="0.8"
|
|
89
|
+
android:strokeColor="#33FFFFFF" />
|
|
90
|
+
<path
|
|
91
|
+
android:fillColor="#00000000"
|
|
92
|
+
android:pathData="M0,69L108,69"
|
|
93
|
+
android:strokeWidth="0.8"
|
|
94
|
+
android:strokeColor="#33FFFFFF" />
|
|
95
|
+
<path
|
|
96
|
+
android:fillColor="#00000000"
|
|
97
|
+
android:pathData="M0,79L108,79"
|
|
98
|
+
android:strokeWidth="0.8"
|
|
99
|
+
android:strokeColor="#33FFFFFF" />
|
|
100
|
+
<path
|
|
101
|
+
android:fillColor="#00000000"
|
|
102
|
+
android:pathData="M0,89L108,89"
|
|
103
|
+
android:strokeWidth="0.8"
|
|
104
|
+
android:strokeColor="#33FFFFFF" />
|
|
105
|
+
<path
|
|
106
|
+
android:fillColor="#00000000"
|
|
107
|
+
android:pathData="M0,99L108,99"
|
|
108
|
+
android:strokeWidth="0.8"
|
|
109
|
+
android:strokeColor="#33FFFFFF" />
|
|
110
|
+
<path
|
|
111
|
+
android:fillColor="#00000000"
|
|
112
|
+
android:pathData="M19,29L89,29"
|
|
113
|
+
android:strokeWidth="0.8"
|
|
114
|
+
android:strokeColor="#33FFFFFF" />
|
|
115
|
+
<path
|
|
116
|
+
android:fillColor="#00000000"
|
|
117
|
+
android:pathData="M19,39L89,39"
|
|
118
|
+
android:strokeWidth="0.8"
|
|
119
|
+
android:strokeColor="#33FFFFFF" />
|
|
120
|
+
<path
|
|
121
|
+
android:fillColor="#00000000"
|
|
122
|
+
android:pathData="M19,49L89,49"
|
|
123
|
+
android:strokeWidth="0.8"
|
|
124
|
+
android:strokeColor="#33FFFFFF" />
|
|
125
|
+
<path
|
|
126
|
+
android:fillColor="#00000000"
|
|
127
|
+
android:pathData="M19,59L89,59"
|
|
128
|
+
android:strokeWidth="0.8"
|
|
129
|
+
android:strokeColor="#33FFFFFF" />
|
|
130
|
+
<path
|
|
131
|
+
android:fillColor="#00000000"
|
|
132
|
+
android:pathData="M19,69L89,69"
|
|
133
|
+
android:strokeWidth="0.8"
|
|
134
|
+
android:strokeColor="#33FFFFFF" />
|
|
135
|
+
<path
|
|
136
|
+
android:fillColor="#00000000"
|
|
137
|
+
android:pathData="M19,79L89,79"
|
|
138
|
+
android:strokeWidth="0.8"
|
|
139
|
+
android:strokeColor="#33FFFFFF" />
|
|
140
|
+
<path
|
|
141
|
+
android:fillColor="#00000000"
|
|
142
|
+
android:pathData="M29,19L29,89"
|
|
143
|
+
android:strokeWidth="0.8"
|
|
144
|
+
android:strokeColor="#33FFFFFF" />
|
|
145
|
+
<path
|
|
146
|
+
android:fillColor="#00000000"
|
|
147
|
+
android:pathData="M39,19L39,89"
|
|
148
|
+
android:strokeWidth="0.8"
|
|
149
|
+
android:strokeColor="#33FFFFFF" />
|
|
150
|
+
<path
|
|
151
|
+
android:fillColor="#00000000"
|
|
152
|
+
android:pathData="M49,19L49,89"
|
|
153
|
+
android:strokeWidth="0.8"
|
|
154
|
+
android:strokeColor="#33FFFFFF" />
|
|
155
|
+
<path
|
|
156
|
+
android:fillColor="#00000000"
|
|
157
|
+
android:pathData="M59,19L59,89"
|
|
158
|
+
android:strokeWidth="0.8"
|
|
159
|
+
android:strokeColor="#33FFFFFF" />
|
|
160
|
+
<path
|
|
161
|
+
android:fillColor="#00000000"
|
|
162
|
+
android:pathData="M69,19L69,89"
|
|
163
|
+
android:strokeWidth="0.8"
|
|
164
|
+
android:strokeColor="#33FFFFFF" />
|
|
165
|
+
<path
|
|
166
|
+
android:fillColor="#00000000"
|
|
167
|
+
android:pathData="M79,19L79,89"
|
|
168
|
+
android:strokeWidth="0.8"
|
|
169
|
+
android:strokeColor="#33FFFFFF" />
|
|
170
|
+
</vector>
|
|
Binary file
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
2
|
+
<string name="app_name">Penthera Example</string>
|
|
3
|
+
|
|
4
|
+
<string name="status_queued">Queued</string>
|
|
5
|
+
<string name="status_downloading">Downloading</string>
|
|
6
|
+
<string name="status_downloaded">Downloaded</string>
|
|
7
|
+
<string name="status_pending">Queued</string>
|
|
8
|
+
<string name="status_expired">Expired</string>
|
|
9
|
+
|
|
10
|
+
<string name="asset_status_pending">pending</string>
|
|
11
|
+
<string name="asset_status_downloading">downloading</string>
|
|
12
|
+
<string name="asset_status_complete">complete</string>
|
|
13
|
+
<string name="asset_status_expired">expired</string>
|
|
14
|
+
<string name="asset_status_denied_mad">DENIED : MAD</string>
|
|
15
|
+
<string name="asset_status_denied_mda">DENIED : MDA</string>
|
|
16
|
+
<string name="asset_status_denied_ext">DENIED : EXT</string>
|
|
17
|
+
<string name="asset_status_denied_mpd">DENIED : MPD</string>
|
|
18
|
+
<string name="asset_status_denied_copies">DENIED : COPIES</string>
|
|
19
|
+
<string name="asset_status_await_permission">AWAITING PERMISSION</string>
|
|
20
|
+
|
|
21
|
+
<string name="asset_status">File %1$s with %2$d errors, current state: %3$s</string>
|
|
22
|
+
|
|
23
|
+
<!-- Drm key fetch messages -->
|
|
24
|
+
<string name="license_fetch_success">Fetched license for asset id: %1$s</string>
|
|
25
|
+
<string name="license_fetch_failure">License fetch failed for asset id: %1$s</string>
|
|
26
|
+
|
|
27
|
+
<!-- Drm error messages -->
|
|
28
|
+
<string name="error_drm_unknown">An unknown DRM error occurred</string>
|
|
29
|
+
|
|
30
|
+
<string name="error_drm_not_supported">Protected content not supported on API levels below 18</string>
|
|
31
|
+
|
|
32
|
+
<string name="error_drm_unsupported_scheme">This device does not support the required DRM scheme</string>
|
|
33
|
+
|
|
34
|
+
<!-- Playback error messages -->
|
|
35
|
+
|
|
36
|
+
<string name="error_cannot_play">Cannot play asset</string>
|
|
37
|
+
|
|
38
|
+
<string name="error_invalid_url">Cannot play asset - playlist issue</string>
|
|
39
|
+
|
|
40
|
+
<string name="unexpected_intent_action">Unexpected intent action: <xliff:g id="action">%1$s</xliff:g></string>
|
|
41
|
+
|
|
42
|
+
<!-- Exoplayer error message strings, taken directly from Exoplayer demo -->
|
|
43
|
+
|
|
44
|
+
<string name="error_generic">Playback failed</string>
|
|
45
|
+
|
|
46
|
+
<string name="error_querying_decoders">Unable to query device decoders</string>
|
|
47
|
+
|
|
48
|
+
<string name="error_no_decoder">This device does not provide a decoder for <xliff:g id="mime_type">%1$s</xliff:g></string>
|
|
49
|
+
|
|
50
|
+
<string name="error_no_secure_decoder">This device does not provide a secure decoder for <xliff:g id="mime_type">%1$s</xliff:g></string>
|
|
51
|
+
|
|
52
|
+
<string name="error_instantiating_decoder">Unable to instantiate decoder <xliff:g id="decoder_name">%1$s</xliff:g></string>
|
|
53
|
+
|
|
54
|
+
<string name="error_unsupported_video">Media includes video tracks, but none are playable by this device</string>
|
|
55
|
+
|
|
56
|
+
<string name="error_unsupported_audio">Media includes audio tracks, but none are playable by this device</string>
|
|
57
|
+
|
|
58
|
+
<string name="storage_permission_denied">Permission to access storage was denied</string>
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
</resources>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<resources>
|
|
2
|
+
<!-- Base application theme. -->
|
|
3
|
+
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
|
4
|
+
<!-- Customize your theme here. -->
|
|
5
|
+
<item name="colorPrimary">@color/colorPrimary</item>
|
|
6
|
+
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
|
7
|
+
<item name="colorAccent">@color/colorAccent</item>
|
|
8
|
+
</style>
|
|
9
|
+
|
|
10
|
+
</resources>
|