unified-video-framework 1.4.382 → 1.4.384

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.
Files changed (42) hide show
  1. package/package.json +1 -1
  2. package/packages/core/dist/interfaces.d.ts +28 -2
  3. package/packages/core/dist/interfaces.d.ts.map +1 -1
  4. package/packages/core/dist/interfaces.js +0 -1
  5. package/packages/core/dist/interfaces.js.map +1 -1
  6. package/packages/core/src/interfaces.ts +53 -3
  7. package/packages/react-native/dist/drm/AndroidDRMProtection.js +1 -1
  8. package/packages/react-native/dist/drm/iOSDRMProtection.js +1 -1
  9. package/packages/web/dist/WebPlayer.d.ts +2 -0
  10. package/packages/web/dist/WebPlayer.d.ts.map +1 -1
  11. package/packages/web/dist/WebPlayer.js +9731 -9644
  12. package/packages/web/dist/WebPlayer.js.map +1 -1
  13. package/packages/web/dist/drm/DRMHelper.d.ts +28 -0
  14. package/packages/web/dist/drm/DRMHelper.d.ts.map +1 -0
  15. package/packages/web/dist/drm/DRMHelper.js +117 -0
  16. package/packages/web/dist/drm/DRMHelper.js.map +1 -0
  17. package/packages/web/dist/index.d.ts +0 -1
  18. package/packages/web/dist/index.d.ts.map +1 -1
  19. package/packages/web/dist/index.js +6 -7
  20. package/packages/web/dist/index.js.map +1 -1
  21. package/packages/web/dist/react/WebPlayerView.d.ts +21 -0
  22. package/packages/web/dist/react/WebPlayerView.d.ts.map +1 -1
  23. package/packages/web/dist/react/WebPlayerView.js.map +1 -1
  24. package/packages/web/dist/security/CanvasVideoRenderer.d.ts +26 -0
  25. package/packages/web/dist/security/CanvasVideoRenderer.d.ts.map +1 -0
  26. package/packages/web/dist/security/CanvasVideoRenderer.js +143 -0
  27. package/packages/web/dist/security/CanvasVideoRenderer.js.map +1 -0
  28. package/packages/web/dist/security/ScreenProtectionController.d.ts +39 -0
  29. package/packages/web/dist/security/ScreenProtectionController.d.ts.map +1 -0
  30. package/packages/web/dist/security/ScreenProtectionController.js +278 -0
  31. package/packages/web/dist/security/ScreenProtectionController.js.map +1 -0
  32. package/packages/web/src/WebPlayer.ts +120 -2
  33. package/packages/web/src/drm/DRMHelper.ts +203 -0
  34. package/packages/web/src/index.ts +0 -3
  35. package/packages/web/src/react/WebPlayerView.tsx +24 -0
  36. package/packages/web/src/security/CanvasVideoRenderer.ts +246 -0
  37. package/packages/web/src/security/ScreenProtectionController.ts +391 -0
  38. package/scripts/fix-imports.js +18 -16
  39. package/packages/core/src/interfaces/IDRMProtection.ts +0 -285
  40. package/packages/react-native/src/drm/AndroidDRMProtection.ts +0 -419
  41. package/packages/react-native/src/drm/iOSDRMProtection.ts +0 -415
  42. package/packages/web/src/drm/WebDRMProtection.ts +0 -596
@@ -1,285 +0,0 @@
1
- /**
2
- * Netflix-Like DRM Protection Interface
3
- *
4
- * Provides comprehensive content protection against:
5
- * - Screen recording
6
- * - Audio capture
7
- * - Screenshots
8
- *
9
- * While allowing:
10
- * - Official casting (Chromecast, AirPlay, Smart TVs)
11
- */
12
-
13
- /**
14
- * DRM Protection Configuration
15
- * All features can be enabled/disabled via boolean flags
16
- */
17
- export interface IDRMProtectionConfig {
18
- /**
19
- * Master switch - enables/disables all DRM protection
20
- * @default false
21
- */
22
- enabled: boolean;
23
-
24
- /**
25
- * Block screen recording (video capture)
26
- * @default true (when enabled)
27
- */
28
- blockScreenRecording?: boolean;
29
-
30
- /**
31
- * Block audio capture (system audio recording)
32
- * @default true (when enabled)
33
- */
34
- blockAudioCapture?: boolean;
35
-
36
- /**
37
- * Block screenshots
38
- * @default true (when enabled)
39
- */
40
- blockScreenshots?: boolean;
41
-
42
- /**
43
- * Allow official casting (Chromecast, AirPlay, Smart TVs)
44
- * @default true (when enabled)
45
- */
46
- allowCasting?: boolean;
47
-
48
- /**
49
- * Block display mirroring (prevent screen sharing apps)
50
- * @default true (when enabled)
51
- */
52
- blockMirroring?: boolean;
53
-
54
- /**
55
- * DRM license server URL
56
- * Required for Widevine/PlayReady/FairPlay
57
- */
58
- licenseServerUrl?: string;
59
-
60
- /**
61
- * DRM certificate URL (for FairPlay)
62
- */
63
- certificateUrl?: string;
64
-
65
- /**
66
- * Custom headers for license requests
67
- */
68
- licenseHeaders?: Record<string, string>;
69
-
70
- /**
71
- * Widevine security level (Android)
72
- * L1 = Hardware-backed DRM (most secure)
73
- * L3 = Software DRM
74
- * @default 'L1'
75
- */
76
- widevineSecurityLevel?: 'L1' | 'L3';
77
-
78
- /**
79
- * Callback when screen recording is detected
80
- */
81
- onScreenRecordingDetected?: () => void;
82
-
83
- /**
84
- * Callback when screenshot is attempted
85
- */
86
- onScreenshotAttempted?: () => void;
87
-
88
- /**
89
- * Callback when mirroring is detected
90
- */
91
- onMirroringDetected?: () => void;
92
-
93
- /**
94
- * Callback when casting starts
95
- */
96
- onCastingStarted?: (deviceName: string, deviceType: CastDeviceType) => void;
97
-
98
- /**
99
- * Callback when casting ends
100
- */
101
- onCastingEnded?: () => void;
102
-
103
- /**
104
- * Callback when DRM license is acquired
105
- */
106
- onLicenseAcquired?: () => void;
107
-
108
- /**
109
- * Callback when DRM error occurs
110
- */
111
- onDRMError?: (error: DRMError) => void;
112
- }
113
-
114
- /**
115
- * Cast device types
116
- */
117
- export type CastDeviceType = 'chromecast' | 'airplay' | 'smart_tv' | 'dlna' | 'miracast';
118
-
119
- /**
120
- * DRM Error types
121
- */
122
- export interface DRMError {
123
- code: DRMErrorCode;
124
- message: string;
125
- platform: 'web' | 'android' | 'ios';
126
- recoverable: boolean;
127
- details?: any;
128
- }
129
-
130
- export enum DRMErrorCode {
131
- LICENSE_REQUEST_FAILED = 'LICENSE_REQUEST_FAILED',
132
- LICENSE_SERVER_UNREACHABLE = 'LICENSE_SERVER_UNREACHABLE',
133
- INVALID_LICENSE = 'INVALID_LICENSE',
134
- DEVICE_NOT_SUPPORTED = 'DEVICE_NOT_SUPPORTED',
135
- WIDEVINE_NOT_AVAILABLE = 'WIDEVINE_NOT_AVAILABLE',
136
- FAIRPLAY_NOT_AVAILABLE = 'FAIRPLAY_NOT_AVAILABLE',
137
- PLAYREADY_NOT_AVAILABLE = 'PLAYREADY_NOT_AVAILABLE',
138
- HARDWARE_DRM_NOT_AVAILABLE = 'HARDWARE_DRM_NOT_AVAILABLE',
139
- SCREEN_RECORDING_DETECTED = 'SCREEN_RECORDING_DETECTED',
140
- MIRRORING_DETECTED = 'MIRRORING_DETECTED',
141
- HDMI_OUTPUT_BLOCKED = 'HDMI_OUTPUT_BLOCKED',
142
- }
143
-
144
- /**
145
- * DRM Protection Status
146
- */
147
- export interface IDRMProtectionStatus {
148
- /**
149
- * Is DRM protection active
150
- */
151
- isProtected: boolean;
152
-
153
- /**
154
- * Active DRM system (Widevine, FairPlay, PlayReady)
155
- */
156
- drmSystem: 'widevine' | 'fairplay' | 'playready' | 'none';
157
-
158
- /**
159
- * Is screen recording currently blocked
160
- */
161
- isScreenRecordingBlocked: boolean;
162
-
163
- /**
164
- * Is audio capture currently blocked
165
- */
166
- isAudioCaptureBlocked: boolean;
167
-
168
- /**
169
- * Is screenshot currently blocked
170
- */
171
- isScreenshotBlocked: boolean;
172
-
173
- /**
174
- * Is casting active
175
- */
176
- isCasting: boolean;
177
-
178
- /**
179
- * Current cast device (if casting)
180
- */
181
- castDevice?: {
182
- name: string;
183
- type: CastDeviceType;
184
- };
185
-
186
- /**
187
- * Is screen recording detected (may still be attempting to record)
188
- */
189
- screenRecordingDetected: boolean;
190
-
191
- /**
192
- * Is mirroring detected
193
- */
194
- mirroringDetected: boolean;
195
-
196
- /**
197
- * DRM security level (for Widevine)
198
- */
199
- securityLevel?: 'L1' | 'L3';
200
-
201
- /**
202
- * License expiration time (if available)
203
- */
204
- licenseExpiration?: Date;
205
- }
206
-
207
- /**
208
- * DRM Protection Controller Interface
209
- */
210
- export interface IDRMProtection {
211
- /**
212
- * Initialize DRM protection
213
- */
214
- initialize(config: IDRMProtectionConfig): Promise<void>;
215
-
216
- /**
217
- * Get current protection status
218
- */
219
- getStatus(): IDRMProtectionStatus;
220
-
221
- /**
222
- * Enable/disable DRM protection
223
- */
224
- setEnabled(enabled: boolean): void;
225
-
226
- /**
227
- * Enable/disable specific protection feature
228
- */
229
- setFeature(feature: keyof IDRMProtectionConfig, enabled: boolean): void;
230
-
231
- /**
232
- * Start casting to device
233
- */
234
- startCasting(deviceId: string): Promise<void>;
235
-
236
- /**
237
- * Stop casting
238
- */
239
- stopCasting(): Promise<void>;
240
-
241
- /**
242
- * Get available cast devices
243
- */
244
- getAvailableCastDevices(): Promise<CastDevice[]>;
245
-
246
- /**
247
- * Renew DRM license
248
- */
249
- renewLicense(): Promise<void>;
250
-
251
- /**
252
- * Cleanup DRM resources
253
- */
254
- dispose(): void;
255
- }
256
-
257
- /**
258
- * Cast device information
259
- */
260
- export interface CastDevice {
261
- id: string;
262
- name: string;
263
- type: CastDeviceType;
264
- isAvailable: boolean;
265
- capabilities: {
266
- supportsVideo: boolean;
267
- supportsAudio: boolean;
268
- supportsDRM: boolean;
269
- maxResolution?: string;
270
- };
271
- }
272
-
273
- /**
274
- * DRM Key System Configuration
275
- */
276
- export interface DRMKeySystemConfig {
277
- keySystem: string;
278
- licenseServerUrl: string;
279
- certificateUrl?: string;
280
- headers?: Record<string, string>;
281
- audioRobustness?: string;
282
- videoRobustness?: string;
283
- persistentState?: 'required' | 'optional' | 'not-allowed';
284
- distinctiveIdentifier?: 'required' | 'optional' | 'not-allowed';
285
- }
@@ -1,419 +0,0 @@
1
- /**
2
- * Android DRM Protection Implementation
3
- *
4
- * Implements Netflix-like content protection for Android using:
5
- * - FLAG_SECURE for screenshot/recording prevention
6
- * - Widevine DRM (L1/L3)
7
- * - MediaDrm + ExoPlayer
8
- * - Chromecast support (remote playback, not mirroring)
9
- * - Display mirroring detection
10
- */
11
-
12
- import { NativeModules, NativeEventEmitter } from 'react-native';
13
- import {
14
- IDRMProtection,
15
- IDRMProtectionConfig,
16
- IDRMProtectionStatus,
17
- CastDevice,
18
- DRMErrorCode,
19
- } from '@unified-video/core';
20
-
21
- const { DRMProtectionModule } = NativeModules;
22
- const drmEventEmitter = new NativeEventEmitter(DRMProtectionModule);
23
-
24
- /**
25
- * Android DRM Protection
26
- */
27
- export class AndroidDRMProtection implements IDRMProtection {
28
- private config: IDRMProtectionConfig;
29
- private status: IDRMProtectionStatus;
30
- private listeners: any[] = [];
31
-
32
- constructor() {
33
- this.config = { enabled: false };
34
- this.status = {
35
- isProtected: false,
36
- drmSystem: 'none',
37
- isScreenRecordingBlocked: false,
38
- isAudioCaptureBlocked: false,
39
- isScreenshotBlocked: false,
40
- isCasting: false,
41
- screenRecordingDetected: false,
42
- mirroringDetected: false,
43
- };
44
- }
45
-
46
- /**
47
- * Initialize DRM protection
48
- */
49
- async initialize(config: IDRMProtectionConfig): Promise<void> {
50
- this.config = {
51
- blockScreenRecording: true,
52
- blockAudioCapture: true,
53
- blockScreenshots: true,
54
- allowCasting: true,
55
- blockMirroring: true,
56
- widevineSecurityLevel: 'L1',
57
- ...config,
58
- };
59
-
60
- if (!this.config.enabled) {
61
- console.log('[DRM-Android] Protection disabled');
62
- return;
63
- }
64
-
65
- console.log('[DRM-Android] Initializing...', this.config);
66
-
67
- try {
68
- // Enable FLAG_SECURE to block screenshots and screen recording
69
- if (this.config.blockScreenshots || this.config.blockScreenRecording) {
70
- await DRMProtectionModule.enableFlagSecure(true);
71
- this.status.isScreenshotBlocked = true;
72
- this.status.isScreenRecordingBlocked = true;
73
- console.log('[DRM-Android] FLAG_SECURE enabled');
74
- }
75
-
76
- // Initialize Widevine DRM
77
- if (this.config.licenseServerUrl) {
78
- await this.initializeWidevine();
79
- }
80
-
81
- // Start mirroring detection
82
- if (this.config.blockMirroring) {
83
- await this.startMirroringDetection();
84
- }
85
-
86
- // Initialize Chromecast
87
- if (this.config.allowCasting) {
88
- await this.initializeChromecast();
89
- }
90
-
91
- // Setup event listeners
92
- this.setupEventListeners();
93
-
94
- this.status.isProtected = true;
95
- console.log('[DRM-Android] Protection initialized');
96
- } catch (error) {
97
- console.error('[DRM-Android] Initialization failed:', error);
98
- throw error;
99
- }
100
- }
101
-
102
- /**
103
- * Initialize Widevine DRM
104
- */
105
- private async initializeWidevine(): Promise<void> {
106
- console.log('[DRM-Android] Initializing Widevine...');
107
-
108
- const widevineConfig = {
109
- licenseServerUrl: this.config.licenseServerUrl,
110
- licenseHeaders: this.config.licenseHeaders,
111
- securityLevel: this.config.widevineSecurityLevel,
112
- };
113
-
114
- const result = await DRMProtectionModule.initializeWidevine(widevineConfig);
115
-
116
- if (result.success) {
117
- this.status.drmSystem = 'widevine';
118
- this.status.securityLevel = result.securityLevel;
119
- console.log(`[DRM-Android] Widevine initialized with security level: ${result.securityLevel}`);
120
-
121
- if (result.securityLevel === 'L3' && this.config.widevineSecurityLevel === 'L1') {
122
- console.warn('[DRM-Android] ⚠️ Requested L1 but got L3 - device may not support hardware DRM');
123
- }
124
- } else {
125
- throw {
126
- code: DRMErrorCode.WIDEVINE_NOT_AVAILABLE,
127
- message: 'Widevine initialization failed',
128
- platform: 'android',
129
- recoverable: false,
130
- };
131
- }
132
- }
133
-
134
- /**
135
- * Start display mirroring detection
136
- */
137
- private async startMirroringDetection(): Promise<void> {
138
- console.log('[DRM-Android] Starting mirroring detection...');
139
-
140
- // Monitor for external displays and mirroring
141
- await DRMProtectionModule.startMirroringDetection();
142
- }
143
-
144
- /**
145
- * Initialize Chromecast
146
- */
147
- private async initializeChromecast(): Promise<void> {
148
- console.log('[DRM-Android] Initializing Chromecast...');
149
-
150
- await DRMProtectionModule.initializeChromecast({
151
- appId: 'CC1AD845', // Default Media Receiver
152
- });
153
- }
154
-
155
- /**
156
- * Setup event listeners
157
- */
158
- private setupEventListeners(): void {
159
- // Screen recording detected
160
- this.listeners.push(
161
- drmEventEmitter.addListener('onScreenRecordingDetected', () => {
162
- console.warn('[DRM-Android] ⚠️ Screen recording detected!');
163
- this.status.screenRecordingDetected = true;
164
- this.config.onScreenRecordingDetected?.();
165
- })
166
- );
167
-
168
- // Mirroring detected
169
- this.listeners.push(
170
- drmEventEmitter.addListener('onMirroringDetected', (event: any) => {
171
- console.warn('[DRM-Android] ⚠️ Display mirroring detected:', event.displayName);
172
- this.status.mirroringDetected = true;
173
- this.config.onMirroringDetected?.();
174
- })
175
- );
176
-
177
- // Casting started
178
- this.listeners.push(
179
- drmEventEmitter.addListener('onCastingStarted', (event: any) => {
180
- console.log('[DRM-Android] Casting started:', event.deviceName);
181
- this.status.isCasting = true;
182
- this.status.castDevice = {
183
- name: event.deviceName,
184
- type: 'chromecast',
185
- };
186
- this.config.onCastingStarted?.(event.deviceName, 'chromecast');
187
- })
188
- );
189
-
190
- // Casting ended
191
- this.listeners.push(
192
- drmEventEmitter.addListener('onCastingEnded', () => {
193
- console.log('[DRM-Android] Casting ended');
194
- this.status.isCasting = false;
195
- this.status.castDevice = undefined;
196
- this.config.onCastingEnded?.();
197
- })
198
- );
199
-
200
- // License acquired
201
- this.listeners.push(
202
- drmEventEmitter.addListener('onLicenseAcquired', (event: any) => {
203
- console.log('[DRM-Android] License acquired');
204
- this.status.licenseExpiration = event.expirationTime ? new Date(event.expirationTime) : undefined;
205
- this.config.onLicenseAcquired?.();
206
- })
207
- );
208
-
209
- // DRM error
210
- this.listeners.push(
211
- drmEventEmitter.addListener('onDRMError', (error: any) => {
212
- console.error('[DRM-Android] DRM Error:', error);
213
- this.config.onDRMError?.(error);
214
- })
215
- );
216
- }
217
-
218
- /**
219
- * Get current status
220
- */
221
- getStatus(): IDRMProtectionStatus {
222
- return { ...this.status };
223
- }
224
-
225
- /**
226
- * Enable/disable protection
227
- */
228
- setEnabled(enabled: boolean): void {
229
- this.config.enabled = enabled;
230
- DRMProtectionModule.setEnabled(enabled);
231
- }
232
-
233
- /**
234
- * Set specific feature
235
- */
236
- setFeature(feature: keyof IDRMProtectionConfig, enabled: boolean): void {
237
- (this.config as any)[feature] = enabled;
238
-
239
- switch (feature) {
240
- case 'blockScreenshots':
241
- case 'blockScreenRecording':
242
- DRMProtectionModule.enableFlagSecure(enabled);
243
- this.status.isScreenshotBlocked = enabled;
244
- this.status.isScreenRecordingBlocked = enabled;
245
- break;
246
- }
247
- }
248
-
249
- /**
250
- * Start casting
251
- */
252
- async startCasting(deviceId: string): Promise<void> {
253
- await DRMProtectionModule.startCasting(deviceId);
254
- }
255
-
256
- /**
257
- * Stop casting
258
- */
259
- async stopCasting(): Promise<void> {
260
- await DRMProtectionModule.stopCasting();
261
- }
262
-
263
- /**
264
- * Get available cast devices
265
- */
266
- async getAvailableCastDevices(): Promise<CastDevice[]> {
267
- const devices = await DRMProtectionModule.getAvailableCastDevices();
268
- return devices.map((device: any) => ({
269
- id: device.id,
270
- name: device.name,
271
- type: 'chromecast',
272
- isAvailable: device.isAvailable,
273
- capabilities: {
274
- supportsVideo: true,
275
- supportsAudio: true,
276
- supportsDRM: device.supportsDRM,
277
- maxResolution: device.maxResolution,
278
- },
279
- }));
280
- }
281
-
282
- /**
283
- * Renew license
284
- */
285
- async renewLicense(): Promise<void> {
286
- await DRMProtectionModule.renewLicense();
287
- }
288
-
289
- /**
290
- * Cleanup
291
- */
292
- dispose(): void {
293
- this.listeners.forEach((listener) => listener.remove());
294
- this.listeners = [];
295
- DRMProtectionModule.dispose();
296
- this.status.isProtected = false;
297
- }
298
- }
299
-
300
- /**
301
- * NATIVE ANDROID MODULE (Java/Kotlin)
302
- *
303
- * File: android/app/src/main/java/com/yourapp/DRMProtectionModule.kt
304
- *
305
- * ```kotlin
306
- * package com.yourapp
307
- *
308
- * import android.view.WindowManager
309
- * import android.hardware.display.DisplayManager
310
- * import android.media.MediaDrm
311
- * import com.facebook.react.bridge.*
312
- * import com.facebook.react.modules.core.DeviceEventManagerModule
313
- * import com.google.android.gms.cast.framework.CastContext
314
- * import com.google.android.exoplayer2.drm.*
315
- *
316
- * class DRMProtectionModule(reactContext: ReactApplicationContext) :
317
- * ReactContextBaseJavaModule(reactContext) {
318
- *
319
- * private val WIDEVINE_UUID = UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL)
320
- * private var mediaDrm: MediaDrm? = null
321
- * private var displayManager: DisplayManager? = null
322
- *
323
- * override fun getName(): String = "DRMProtectionModule"
324
- *
325
- * @ReactMethod
326
- * fun enableFlagSecure(enabled: Boolean, promise: Promise) {
327
- * try {
328
- * currentActivity?.runOnUiThread {
329
- * val window = currentActivity?.window
330
- * if (enabled) {
331
- * window?.setFlags(
332
- * WindowManager.LayoutParams.FLAG_SECURE,
333
- * WindowManager.LayoutParams.FLAG_SECURE
334
- * )
335
- * } else {
336
- * window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
337
- * }
338
- * }
339
- * promise.resolve(true)
340
- * } catch (e: Exception) {
341
- * promise.reject("FLAG_SECURE_ERROR", e.message)
342
- * }
343
- * }
344
- *
345
- * @ReactMethod
346
- * fun initializeWidevine(config: ReadableMap, promise: Promise) {
347
- * try {
348
- * mediaDrm = MediaDrm(WIDEVINE_UUID)
349
- *
350
- * val securityLevel = mediaDrm?.getPropertyString("securityLevel")
351
- * val hdcpLevel = mediaDrm?.getPropertyString("hdcpLevel")
352
- *
353
- * val result = Arguments.createMap().apply {
354
- * putBoolean("success", true)
355
- * putString("securityLevel", securityLevel)
356
- * putString("hdcpLevel", hdcpLevel)
357
- * }
358
- *
359
- * promise.resolve(result)
360
- * } catch (e: Exception) {
361
- * promise.reject("WIDEVINE_ERROR", e.message)
362
- * }
363
- * }
364
- *
365
- * @ReactMethod
366
- * fun startMirroringDetection(promise: Promise) {
367
- * try {
368
- * displayManager = reactApplicationContext
369
- * .getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
370
- *
371
- * val callback = object : DisplayManager.DisplayListener {
372
- * override fun onDisplayAdded(displayId: Int) {
373
- * val display = displayManager?.getDisplay(displayId)
374
- * if (display != null && display.displayId != Display.DEFAULT_DISPLAY) {
375
- * // External display detected - could be mirroring
376
- * sendEvent("onMirroringDetected", Arguments.createMap().apply {
377
- * putInt("displayId", displayId)
378
- * putString("displayName", display.name)
379
- * })
380
- * }
381
- * }
382
- *
383
- * override fun onDisplayRemoved(displayId: Int) {}
384
- * override fun onDisplayChanged(displayId: Int) {}
385
- * }
386
- *
387
- * displayManager?.registerDisplayListener(callback, null)
388
- * promise.resolve(true)
389
- * } catch (e: Exception) {
390
- * promise.reject("MIRRORING_DETECTION_ERROR", e.message)
391
- * }
392
- * }
393
- *
394
- * @ReactMethod
395
- * fun initializeChromecast(config: ReadableMap, promise: Promise) {
396
- * try {
397
- * // Initialize Google Cast
398
- * CastContext.getSharedInstance(reactApplicationContext)
399
- * promise.resolve(true)
400
- * } catch (e: Exception) {
401
- * promise.reject("CHROMECAST_ERROR", e.message)
402
- * }
403
- * }
404
- *
405
- * private fun sendEvent(eventName: String, params: WritableMap) {
406
- * reactApplicationContext
407
- * .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
408
- * .emit(eventName, params)
409
- * }
410
- * }
411
- * ```
412
- *
413
- * MANIFEST PERMISSIONS:
414
- * ```xml
415
- * <uses-permission android:name="android.permission.INTERNET" />
416
- * <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
417
- * <uses-permission android:name="com.google.android.gms.permission.AD_ID" />
418
- * ```
419
- */