├── .aiexclude ├── .gitignore ├── LICENSE ├── PrivacyPolicy.md ├── README.md ├── TermsConditions.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── FDroid │ └── java │ │ └── info │ │ └── dvkr │ │ └── screenstream │ │ ├── AdMob.kt │ │ ├── AppReview.kt │ │ ├── AppUpdateActivity.kt │ │ └── ScreenStreamApp.kt │ ├── PlayStore │ └── java │ │ └── info │ │ └── dvkr │ │ └── screenstream │ │ ├── AdMob.kt │ │ ├── AppReview.kt │ │ ├── AppUpdateActivity.kt │ │ └── ScreenStreamApp.kt │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── info │ │ └── dvkr │ │ └── screenstream │ │ ├── BaseApp.kt │ │ ├── SingleActivity.kt │ │ ├── logger │ │ ├── AppLogger.kt │ │ └── CollectingLogsUi.kt │ │ ├── notification │ │ ├── NotificationHelperImpl.kt │ │ └── NotificationPermission.kt │ │ ├── tile │ │ └── TileActionService.kt │ │ └── ui │ │ ├── ScreenStreamContent.kt │ │ ├── enableEdgeToEdge.kt │ │ ├── tabs │ │ ├── AppTabs.kt │ │ ├── about │ │ │ └── AboutTabContent.kt │ │ ├── settings │ │ │ ├── SettingsTabContent.kt │ │ │ ├── SettingsTabViewModel.kt │ │ │ └── app │ │ │ │ ├── AppModuleSettings.kt │ │ │ │ └── settings │ │ │ │ ├── GeneralGroup.kt │ │ │ │ └── general │ │ │ │ ├── AppLocale.kt │ │ │ │ ├── DynamicTheme.kt │ │ │ │ ├── Logging.kt │ │ │ │ ├── NightMode.kt │ │ │ │ ├── Notifications.kt │ │ │ │ └── Tile.kt │ │ └── stream │ │ │ └── StreamTabContent.kt │ │ └── theme │ │ ├── Color.kt │ │ ├── Theme.kt │ │ └── Type.kt │ └── res │ ├── drawable-nodpi │ └── logo.webp │ ├── drawable │ ├── ic_launcher_background.xml │ ├── ic_launcher_foreground.xml │ ├── ic_notification_small_24dp.xml │ ├── ic_notification_small_anim0_24dp.xml │ ├── ic_notification_small_anim1_24dp.xml │ ├── ic_notification_small_anim2_24dp.xml │ ├── ic_notification_small_anim3_24dp.xml │ ├── ic_notification_small_anim_24dp.xml │ └── ic_tile_24dp.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-mdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── resources.properties │ ├── values-af │ └── strings.xml │ ├── values-am │ └── strings.xml │ ├── values-ar │ └── strings.xml │ ├── values-bn │ └── strings.xml │ ├── values-de │ └── strings.xml │ ├── values-es │ └── strings.xml │ ├── values-eu │ └── strings.xml │ ├── values-fr │ └── strings.xml │ ├── values-hi │ └── strings.xml │ ├── values-in │ └── strings.xml │ ├── values-it │ └── strings.xml │ ├── values-ja │ └── strings.xml │ ├── values-jv │ └── strings.xml │ ├── values-ka │ └── strings.xml │ ├── values-night │ └── colors.xml │ ├── values-nl │ └── strings.xml │ ├── values-pl │ └── strings.xml │ ├── values-pt │ └── strings.xml │ ├── values-ru │ └── strings.xml │ ├── values-uk │ └── strings.xml │ ├── values-uz │ └── strings.xml │ ├── values-zh-rTW │ └── strings.xml │ ├── values-zh │ └── strings.xml │ ├── values │ ├── colors.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ ├── data_extraction_rules.xml │ └── filepaths.xml ├── build.gradle.kts ├── common ├── .gitignore ├── build.gradle.kts └── src │ └── main │ ├── java │ ├── info │ │ └── dvkr │ │ │ └── screenstream │ │ │ └── common │ │ │ ├── CommonKoinModule.kt │ │ │ ├── ModuleSettings.kt │ │ │ ├── extensions.kt │ │ │ ├── module │ │ │ ├── StreamingModule.kt │ │ │ ├── StreamingModuleManager.kt │ │ │ └── StreamingModuleService.kt │ │ │ ├── notification │ │ │ └── NotificationHelper.kt │ │ │ ├── settings │ │ │ ├── AppSettings.kt │ │ │ └── AppSettingsImpl.kt │ │ │ └── ui │ │ │ ├── DoubleClickProtection.kt │ │ │ ├── ExpandableCard.kt │ │ │ ├── MediaProjectionPermission.kt │ │ │ └── composeExtenstions.kt │ └── io │ │ └── nayuki │ │ └── qrcodegen │ │ ├── BitBuffer.java │ │ ├── QrCode.java │ │ └── QrSegment.java │ └── res │ └── font │ └── roboto_mono_bold.ttf ├── debug-key.jks ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── mjpeg ├── .gitignore ├── build.gradle.kts └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── dev │ │ ├── babel.config.json │ │ ├── package.json │ │ └── script.js │ ├── favicon.ico │ ├── index.html │ ├── logo.png │ └── logo.svg │ ├── java │ └── info │ │ └── dvkr │ │ └── screenstream │ │ └── mjpeg │ │ ├── MjpegKoinModule.kt │ │ ├── MjpegModuleService.kt │ │ ├── MjpegStreamingModule.kt │ │ ├── internal │ │ ├── BitmapCapture.kt │ │ ├── HttpServer.kt │ │ ├── HttpServerData.kt │ │ ├── MjpegEvent.kt │ │ ├── MjpegNetInterface.kt │ │ ├── MjpegStreamingService.kt │ │ ├── NetworkHelper.kt │ │ └── extentions.kt │ │ ├── settings │ │ ├── MjpegSettings.kt │ │ └── MjpegSettingsImpl.kt │ │ └── ui │ │ ├── MjpegMainScreenUI.kt │ │ ├── MjpegModuleSettings.kt │ │ ├── main │ │ ├── ClientsCard.kt │ │ ├── ErrorCard.kt │ │ ├── InterfacesCard.kt │ │ ├── PinCard.kt │ │ └── TrafficCard.kt │ │ ├── models.kt │ │ └── settings │ │ ├── AdvancedGroup.kt │ │ ├── GeneralGroup.kt │ │ ├── ImageGroup.kt │ │ ├── SecurityGroup.kt │ │ ├── advanced │ │ ├── EnableIPv6.kt │ │ ├── EnableLocalhost.kt │ │ ├── LocalhostOnly.kt │ │ ├── ServerPort.kt │ │ └── WifiOnly.kt │ │ ├── general │ │ ├── HtmlBackColor.kt │ │ ├── HtmlEnableButtons.kt │ │ ├── HtmlFitWindow.kt │ │ ├── HtmlShowPressStart.kt │ │ ├── KeepAwake.kt │ │ ├── NotifySlowConnections.kt │ │ ├── StopOnConfigurationChange.kt │ │ └── StopOnSleep.kt │ │ ├── image │ │ ├── CropImage.kt │ │ ├── Grayscale.kt │ │ ├── JpegQuality.kt │ │ ├── MaxFPS.kt │ │ ├── ResizeImage.kt │ │ ├── Rotation.kt │ │ └── VrMode.kt │ │ └── security │ │ ├── AutoChangePin.kt │ │ ├── BlockAddress.kt │ │ ├── EnablePin.kt │ │ ├── HidePinOnStart.kt │ │ ├── NewPinOnAppStart.kt │ │ └── Pin.kt │ └── res │ ├── values-af │ └── strings.xml │ ├── values-am │ └── strings.xml │ ├── values-ar │ └── strings.xml │ ├── values-bn │ └── strings.xml │ ├── values-de │ └── strings.xml │ ├── values-es │ └── strings.xml │ ├── values-eu │ └── strings.xml │ ├── values-fr │ └── strings.xml │ ├── values-hi │ └── strings.xml │ ├── values-in │ └── strings.xml │ ├── values-it │ └── strings.xml │ ├── values-ja │ └── strings.xml │ ├── values-jv │ └── strings.xml │ ├── values-ka │ └── strings.xml │ ├── values-nl │ └── strings.xml │ ├── values-pl │ └── strings.xml │ ├── values-pt │ └── strings.xml │ ├── values-ru │ └── strings.xml │ ├── values-uk │ └── strings.xml │ ├── values-uz │ └── strings.xml │ ├── values-zh-rTW │ └── strings.xml │ ├── values-zh │ └── strings.xml │ └── values │ └── strings.xml ├── rtsp ├── .gitignore ├── build.gradle.kts └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── info │ │ └── dvkr │ │ └── screenstream │ │ └── rtsp │ │ ├── RtspKoinModule.kt │ │ ├── RtspModuleService.kt │ │ ├── RtspStreamingModule.kt │ │ ├── internal │ │ ├── EncoderUtils.kt │ │ ├── MasterClock.kt │ │ ├── RtspEvent.kt │ │ ├── RtspStreamingService.kt │ │ ├── audio │ │ │ ├── AudioCapture.kt │ │ │ ├── AudioEncoder.kt │ │ │ ├── AudioSource.kt │ │ │ ├── G711Codec.kt │ │ │ ├── InternalAudioSource.kt │ │ │ ├── MicrophoneSource.kt │ │ │ └── MixAudioSource.kt │ │ ├── models.kt │ │ ├── rtsp │ │ │ ├── BitrateCalculator.kt │ │ │ ├── CommandsManager.kt │ │ │ ├── RtcpReporter.kt │ │ │ ├── RtspClient.kt │ │ │ ├── RtspUrl.kt │ │ │ ├── packets │ │ │ │ ├── AacPacket.kt │ │ │ │ ├── Av1Packet.kt │ │ │ │ ├── BaseRtpPacket.kt │ │ │ │ ├── G711Packet.kt │ │ │ │ ├── H264Packet.kt │ │ │ │ ├── H265Packet.kt │ │ │ │ └── OpusPacket.kt │ │ │ └── sockets │ │ │ │ ├── TcpStreamSocket.kt │ │ │ │ └── UdpStreamSocket.kt │ │ └── video │ │ │ ├── EglRenderer.kt │ │ │ ├── FpsCalculator.kt │ │ │ └── VideoEncoder.kt │ │ ├── settings │ │ ├── RtspSettings.kt │ │ └── RtspSettingsImpl.kt │ │ └── ui │ │ ├── RtspMainScreenUI.kt │ │ ├── RtspModuleSettings.kt │ │ ├── main │ │ ├── AudioCard.kt │ │ ├── EncoderItem.kt │ │ ├── ErrorCard.kt │ │ ├── MediaServerCard.kt │ │ └── VideoCard.kt │ │ └── models.kt │ └── res │ ├── values-af │ └── strings.xml │ ├── values-am │ └── strings.xml │ ├── values-ar │ └── strings.xml │ ├── values-bn │ └── strings.xml │ ├── values-de │ └── strings.xml │ ├── values-es │ └── strings.xml │ ├── values-eu │ └── strings.xml │ ├── values-fr │ └── strings.xml │ ├── values-hi │ └── strings.xml │ ├── values-in │ └── strings.xml │ ├── values-it │ └── strings.xml │ ├── values-ja │ └── strings.xml │ ├── values-jv │ └── strings.xml │ ├── values-ka │ └── strings.xml │ ├── values-nl │ └── strings.xml │ ├── values-pl │ └── strings.xml │ ├── values-pt │ └── strings.xml │ ├── values-ru │ └── strings.xml │ ├── values-uk │ └── strings.xml │ ├── values-uz │ └── strings.xml │ ├── values-zh-rTW │ └── strings.xml │ ├── values-zh │ └── strings.xml │ └── values │ └── strings.xml ├── screenshots ├── about_image_full.png ├── screenshot_about_d.png ├── screenshot_gm_d.png ├── screenshot_gm_d_about.png ├── screenshot_lm_d.png ├── screenshot_lm_d_about.png ├── screenshot_rtsp_d.png ├── screenshot_rtsp_d_about.png ├── screenshot_rtsp_d_audio.png ├── screenshot_rtsp_d_video.png ├── screenshot_settings_1_d.png ├── screenshot_settings_1_l.png ├── screenshot_settings_2_d.png ├── screenshot_settings_2_l.png ├── screenshot_settings_3_d.png ├── screenshot_settings_3_l.png ├── screenshot_settings_4_d.png └── screenshot_settings_4_l.png ├── settings.gradle.kts └── webrtc ├── .gitignore ├── build.gradle.kts ├── consumer-rules.pro └── src └── main ├── AndroidManifest.xml ├── java ├── info │ └── dvkr │ │ └── screenstream │ │ └── webrtc │ │ ├── WebRtcKoinModule.kt │ │ ├── WebRtcModuleService.kt │ │ ├── WebRtcStreamingModule.kt │ │ ├── internal │ │ ├── JWTHelper.kt │ │ ├── PlayIntegrity.kt │ │ ├── ScreenCapturerAndroid.kt │ │ ├── SocketSignaling.kt │ │ ├── WebRtcClient.kt │ │ ├── WebRtcEnvironment.kt │ │ ├── WebRtcProjection.kt │ │ ├── WebRtcStreamingService.kt │ │ └── webRtcModels.kt │ │ ├── settings │ │ ├── WebRtcSettings.kt │ │ └── WebRtcSettingsImpl.kt │ │ └── ui │ │ ├── WebRtcMainScreenUI.kt │ │ ├── WebRtcModuleSettings.kt │ │ ├── main │ │ ├── AudioCard.kt │ │ ├── ClientsCard.kt │ │ ├── ErrorCard.kt │ │ └── StreamCard.kt │ │ ├── models.kt │ │ └── settings │ │ ├── GeneralGroup.kt │ │ └── general │ │ ├── KeepAwake.kt │ │ └── StopOnSleep.kt └── org │ ├── jni_zero │ ├── AccessedByNative.java │ ├── CalledByNative.java │ ├── CalledByNativeForTesting.java │ ├── CalledByNativeUnchecked.java │ ├── CheckDiscard.java │ ├── JNINamespace.java │ ├── JniInit.java │ ├── JniType.java │ ├── JniUtil.java │ ├── NativeClassQualifiedName.java │ ├── NativeMethods.java │ ├── UsedReflectively.java │ └── internal │ │ ├── NullUnmarked.java │ │ └── Nullable.java │ └── webrtc │ ├── AddIceObserver.java │ ├── AndroidVideoDecoder.java │ ├── ApplicationContextProvider.java │ ├── AudioDecoderFactoryFactory.java │ ├── AudioEncoderFactoryFactory.java │ ├── AudioProcessingFactory.java │ ├── AudioSource.java │ ├── AudioTrack.java │ ├── BaseBitrateAdjuster.java │ ├── BitrateAdjuster.java │ ├── BuiltinAudioDecoderFactoryFactory.java │ ├── BuiltinAudioEncoderFactoryFactory.java │ ├── CallSessionFileRotatingLogSink.java │ ├── CalledByNative.java │ ├── CalledByNativeUnchecked.java │ ├── Camera1Capturer.java │ ├── Camera1Enumerator.java │ ├── Camera1Session.java │ ├── Camera2Capturer.java │ ├── Camera2Enumerator.java │ ├── Camera2Session.java │ ├── CameraCapturer.java │ ├── CameraEnumerationAndroid.java │ ├── CameraEnumerator.java │ ├── CameraSession.java │ ├── CameraVideoCapturer.java │ ├── CandidatePairChangeEvent.java │ ├── CapturerObserver.java │ ├── ContextUtils.java │ ├── CryptoOptions.java │ ├── DataChannel.java │ ├── Dav1dDecoder.java │ ├── DefaultVideoDecoderFactory.java │ ├── DefaultVideoEncoderFactory.java │ ├── DtmfSender.java │ ├── DynamicBitrateAdjuster.java │ ├── EglBase.java │ ├── EglBase10.java │ ├── EglBase10Impl.java │ ├── EglBase14.java │ ├── EglBase14Impl.java │ ├── EglRenderer.java │ ├── EglThread.java │ ├── Empty.java │ ├── EncodedImage.java │ ├── FecControllerFactoryFactoryInterface.java │ ├── FileVideoCapturer.java │ ├── FrameDecryptor.java │ ├── FrameEncryptor.java │ ├── FramerateBitrateAdjuster.java │ ├── GlGenericDrawer.java │ ├── GlRectDrawer.java │ ├── GlShader.java │ ├── GlTextureFrameBuffer.java │ ├── GlUtil.java │ ├── H264Utils.java │ ├── HardwareVideoDecoderFactory.java │ ├── HardwareVideoEncoder.java │ ├── HardwareVideoEncoderFactory.java │ ├── Histogram.java │ ├── IceCandidate.java │ ├── IceCandidateErrorEvent.java │ ├── JNILogging.java │ ├── JavaI420Buffer.java │ ├── JniCommon.java │ ├── JniHelper.java │ ├── LibaomAv1Encoder.java │ ├── LibvpxVp8Decoder.java │ ├── LibvpxVp8Encoder.java │ ├── LibvpxVp9Decoder.java │ ├── LibvpxVp9Encoder.java │ ├── Loggable.java │ ├── Logging.java │ ├── MediaCodecUtils.java │ ├── MediaCodecVideoDecoderFactory.java │ ├── MediaCodecWrapper.java │ ├── MediaCodecWrapperFactory.java │ ├── MediaCodecWrapperFactoryImpl.java │ ├── MediaConstraints.java │ ├── MediaSource.java │ ├── MediaStream.java │ ├── MediaStreamTrack.java │ ├── Metrics.java │ ├── NV12Buffer.java │ ├── NV21Buffer.java │ ├── NativeAndroidVideoTrackSource.java │ ├── NativeCapturerObserver.java │ ├── NativeLibrary.java │ ├── NativeLibraryLoader.java │ ├── NativePeerConnectionFactory.java │ ├── NetEqFactoryFactory.java │ ├── NetworkChangeDetector.java │ ├── NetworkChangeDetectorFactory.java │ ├── NetworkControllerFactoryFactory.java │ ├── NetworkMonitor.java │ ├── NetworkMonitorAutoDetect.java │ ├── NetworkPreference.java │ ├── NetworkStatePredictorFactoryFactory.java │ ├── PeerConnection.java │ ├── PeerConnectionDependencies.java │ ├── PeerConnectionFactory.java │ ├── PlatformSoftwareVideoDecoderFactory.java │ ├── Predicate.java │ ├── Priority.java │ ├── RTCStats.java │ ├── RTCStatsCollectorCallback.java │ ├── RTCStatsReport.java │ ├── RefCountDelegate.java │ ├── RefCounted.java │ ├── RenderSynchronizer.java │ ├── RendererCommon.java │ ├── RtcCertificatePem.java │ ├── RtcError.java │ ├── RtcException.java │ ├── RtpCapabilities.java │ ├── RtpParameters.java │ ├── RtpReceiver.java │ ├── RtpSender.java │ ├── RtpTransceiver.java │ ├── SSLCertificateVerifier.java │ ├── ScreenCapturerAndroid.java │ ├── SdpObserver.java │ ├── SessionDescription.java │ ├── Size.java │ ├── SoftwareVideoDecoderFactory.java │ ├── SoftwareVideoEncoderFactory.java │ ├── StatsObserver.java │ ├── StatsReport.java │ ├── SurfaceEglRenderer.java │ ├── SurfaceTextureHelper.java │ ├── SurfaceViewRenderer.java │ ├── TextureBufferImpl.java │ ├── ThreadUtils.java │ ├── TimestampAligner.java │ ├── TurnCustomizer.java │ ├── VideoCapturer.java │ ├── VideoCodecInfo.java │ ├── VideoCodecMimeType.java │ ├── VideoCodecStatus.java │ ├── VideoDecoder.java │ ├── VideoDecoderFactory.java │ ├── VideoDecoderFallback.java │ ├── VideoDecoderWrapper.java │ ├── VideoEncoder.java │ ├── VideoEncoderFactory.java │ ├── VideoEncoderFallback.java │ ├── VideoEncoderWrapper.java │ ├── VideoFileRenderer.java │ ├── VideoFrame.java │ ├── VideoFrameBufferType.java │ ├── VideoFrameDrawer.java │ ├── VideoProcessor.java │ ├── VideoSink.java │ ├── VideoSource.java │ ├── VideoTrack.java │ ├── WebRtcClassLoader.java │ ├── WrappedNativeI420Buffer.java │ ├── WrappedNativeVideoDecoder.java │ ├── WrappedNativeVideoEncoder.java │ ├── YuvConverter.java │ ├── YuvHelper.java │ └── audio │ ├── AudioDeviceModule.java │ ├── AudioRecordDataCallback.java │ ├── JavaAudioDeviceModule.java │ ├── LowLatencyAudioBufferManager.java │ ├── VolumeLogger.java │ ├── WebRtcAudioEffects.java │ ├── WebRtcAudioManager.java │ ├── WebRtcAudioRecord.java │ ├── WebRtcAudioTrack.java │ └── WebRtcAudioUtils.java ├── jniLibs ├── arm64-v8a │ └── libjingle_peerconnection_so.so ├── armeabi-v7a │ └── libjingle_peerconnection_so.so ├── x86 │ └── libjingle_peerconnection_so.so └── x86_64 │ └── libjingle_peerconnection_so.so └── res ├── values-af └── strings.xml ├── values-am └── strings.xml ├── values-ar └── strings.xml ├── values-bn └── strings.xml ├── values-de └── strings.xml ├── values-es └── strings.xml ├── values-eu └── strings.xml ├── values-fr └── strings.xml ├── values-hi └── strings.xml ├── values-in └── strings.xml ├── values-it └── strings.xml ├── values-ja └── strings.xml ├── values-jv └── strings.xml ├── values-ka └── strings.xml ├── values-nl └── strings.xml ├── values-pl └── strings.xml ├── values-pt └── strings.xml ├── values-ru └── strings.xml ├── values-uk └── strings.xml ├── values-uz └── strings.xml ├── values-zh-rTW └── strings.xml ├── values-zh └── strings.xml └── values └── strings.xml /.aiexclude: -------------------------------------------------------------------------------- 1 | local.properties -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | fabric.properties 23 | google-services.json 24 | 25 | # Proguard folder generated by Eclipse 26 | proguard/ 27 | 28 | # Log Files 29 | *.log 30 | 31 | # Android Studio Navigation editor temp files 32 | .navigation/ 33 | 34 | # Android Studio captures folder 35 | captures/ 36 | 37 | # Intellij 38 | *.iml 39 | .idea 40 | 41 | .kotlin/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Dmytro Kryvoruchko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | -keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | -renamesourcefileattribute SourceFile 22 | 23 | -keepnames class info.dvkr.screenstream.** { *; } 24 | 25 | # Please add these rules to your existing keep rules in order to suppress warnings. 26 | # This is generated automatically by the Android Gradle plugin. 27 | -dontwarn com.google.android.gms.common.annotation.NoNullnessRewrite 28 | -dontwarn java.lang.management.ManagementFactory 29 | -dontwarn java.lang.management.RuntimeMXBean -------------------------------------------------------------------------------- /app/src/FDroid/java/info/dvkr/screenstream/AdMob.kt: -------------------------------------------------------------------------------- 1 | package info.dvkr.screenstream 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.ui.Modifier 7 | 8 | public class AdMob(context: Context) { 9 | public val isPrivacyOptionsRequired: Boolean = false 10 | 11 | public fun showPrivacyOptionsForm(activity: Activity) {} 12 | } 13 | 14 | @Composable 15 | public fun AdaptiveBanner(modifier: Modifier = Modifier, collapsible: Boolean = false) { 16 | } -------------------------------------------------------------------------------- /app/src/FDroid/java/info/dvkr/screenstream/AppReview.kt: -------------------------------------------------------------------------------- 1 | package info.dvkr.screenstream 2 | 3 | import android.app.Activity 4 | 5 | public object AppReview { 6 | public suspend fun showReviewUi(activity: Activity?) { 7 | } 8 | } -------------------------------------------------------------------------------- /app/src/FDroid/java/info/dvkr/screenstream/AppUpdateActivity.kt: -------------------------------------------------------------------------------- 1 | package info.dvkr.screenstream 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.appcompat.app.AppCompatDelegate 6 | import com.elvishew.xlog.XLog 7 | import info.dvkr.screenstream.common.getLog 8 | import kotlinx.coroutines.flow.MutableStateFlow 9 | import kotlinx.coroutines.flow.StateFlow 10 | import kotlinx.coroutines.flow.asStateFlow 11 | 12 | public abstract class AppUpdateActivity : ComponentActivity() { 13 | 14 | protected val updateFlow: StateFlow<((Boolean) -> Unit)?> = MutableStateFlow(null).asStateFlow() 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | 19 | AppCompatDelegate.setApplicationLocales(AppCompatDelegate.getApplicationLocales()) 20 | 21 | XLog.d(getLog("onCreate")) 22 | } 23 | 24 | override fun onStart() { 25 | super.onStart() 26 | XLog.d(getLog("onStart")) 27 | } 28 | 29 | override fun onResume() { 30 | super.onResume() 31 | XLog.d(getLog("onResume")) 32 | } 33 | 34 | override fun onPause() { 35 | XLog.d(getLog("onPause")) 36 | super.onPause() 37 | } 38 | 39 | override fun onStop() { 40 | XLog.d(getLog("onStop")) 41 | super.onStop() 42 | } 43 | 44 | override fun onDestroy() { 45 | XLog.d(getLog("onDestroy")) 46 | super.onDestroy() 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/FDroid/java/info/dvkr/screenstream/ScreenStreamApp.kt: -------------------------------------------------------------------------------- 1 | package info.dvkr.screenstream 2 | 3 | import android.content.pm.ApplicationInfo 4 | import com.elvishew.xlog.LogConfiguration 5 | import com.elvishew.xlog.LogItem 6 | import com.elvishew.xlog.interceptor.AbstractFilterInterceptor 7 | import info.dvkr.screenstream.common.CommonKoinModule 8 | import info.dvkr.screenstream.logger.AppLogger 9 | import info.dvkr.screenstream.mjpeg.MjpegKoinModule 10 | import info.dvkr.screenstream.rtsp.RtspKoinModule 11 | import org.koin.core.module.Module 12 | 13 | public class ScreenStreamApp : BaseApp() { 14 | 15 | override fun configureLogger(builder: LogConfiguration.Builder) { 16 | if (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) return 17 | 18 | builder.addInterceptor(object : AbstractFilterInterceptor() { 19 | override fun reject(log: LogItem): Boolean = AppLogger.isLoggingOn 20 | }) 21 | } 22 | 23 | override val streamingModules: Array = arrayOf(CommonKoinModule, MjpegKoinModule, RtspKoinModule) 24 | } -------------------------------------------------------------------------------- /app/src/PlayStore/java/info/dvkr/screenstream/AppReview.kt: -------------------------------------------------------------------------------- 1 | package info.dvkr.screenstream 2 | 3 | import android.app.Activity 4 | import android.content.SharedPreferences 5 | import androidx.appcompat.app.AppCompatActivity.MODE_PRIVATE 6 | import androidx.core.content.edit 7 | import com.elvishew.xlog.XLog 8 | import com.google.android.play.core.ktx.launchReview 9 | import com.google.android.play.core.ktx.requestReview 10 | import com.google.android.play.core.review.ReviewManagerFactory 11 | import info.dvkr.screenstream.common.getLog 12 | import kotlin.coroutines.cancellation.CancellationException 13 | 14 | public object AppReview { 15 | private const val APP_REVIEW_REQUEST_TIMEOUT = 30 * 24 * 60 * 60 * 1000L // 30 days. Don't need exact time frame 16 | private const val LAST_REVIEW_REQUEST_TIME = "LAST_REVIEW_REQUEST_TIME" 17 | 18 | private lateinit var sharedPreferences: SharedPreferences 19 | private var lastReviewRequest: Long = 0 20 | 21 | public suspend fun showReviewUi(activity: Activity?) { 22 | if (activity == null) return 23 | 24 | if (::sharedPreferences.isInitialized.not()) { 25 | sharedPreferences = activity.getSharedPreferences("play_review.xml", MODE_PRIVATE) 26 | } 27 | 28 | try { 29 | lastReviewRequest = sharedPreferences.getLong(LAST_REVIEW_REQUEST_TIME, 0) 30 | if (lastReviewRequest <= 0) { 31 | sharedPreferences.edit { putLong(LAST_REVIEW_REQUEST_TIME, System.currentTimeMillis() - 20 * 24 * 60 * 60 * 1000L) } 32 | return 33 | } 34 | if (System.currentTimeMillis() - lastReviewRequest < APP_REVIEW_REQUEST_TIMEOUT) return 35 | 36 | val reviewManager = ReviewManagerFactory.create(activity) // FakeReviewManager 37 | reviewManager.launchReview(activity, reviewManager.requestReview()) 38 | } catch (error: CancellationException) { 39 | throw error 40 | } catch (error: Throwable) { 41 | XLog.d(activity.getLog("AppReview.showReviewUI", "Error: ${error}")) 42 | } finally { 43 | sharedPreferences.edit { putLong(LAST_REVIEW_REQUEST_TIME, System.currentTimeMillis()) } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/PlayStore/java/info/dvkr/screenstream/ScreenStreamApp.kt: -------------------------------------------------------------------------------- 1 | package info.dvkr.screenstream 2 | 3 | import android.content.pm.ApplicationInfo 4 | import com.elvishew.xlog.LogConfiguration 5 | import com.elvishew.xlog.LogItem 6 | import com.elvishew.xlog.interceptor.AbstractFilterInterceptor 7 | import com.elvishew.xlog.internal.util.StackTraceUtil 8 | import com.google.firebase.crashlytics.FirebaseCrashlytics 9 | import info.dvkr.screenstream.common.CommonKoinModule 10 | import info.dvkr.screenstream.logger.AppLogger 11 | import info.dvkr.screenstream.mjpeg.MjpegKoinModule 12 | import info.dvkr.screenstream.rtsp.RtspKoinModule 13 | import info.dvkr.screenstream.webrtc.WebRtcKoinModule 14 | import org.koin.core.module.Module 15 | 16 | public class ScreenStreamApp : BaseApp() { 17 | 18 | override fun configureLogger(builder: LogConfiguration.Builder) { 19 | if (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0) return 20 | 21 | val crashlytics = FirebaseCrashlytics.getInstance() 22 | 23 | builder 24 | .throwableFormatter { 25 | crashlytics.recordException(it) 26 | StackTraceUtil.getStackTraceString(it) 27 | } 28 | .addInterceptor(object : AbstractFilterInterceptor() { 29 | override fun reject(log: LogItem): Boolean { 30 | crashlytics.log(log.msg) 31 | return AppLogger.isLoggingOn 32 | } 33 | }) 34 | } 35 | 36 | override val streamingModules: Array = arrayOf(CommonKoinModule, MjpegKoinModule, RtspKoinModule, WebRtcKoinModule) 37 | } -------------------------------------------------------------------------------- /app/src/main/java/info/dvkr/screenstream/ui/enableEdgeToEdge.kt: -------------------------------------------------------------------------------- 1 | package info.dvkr.screenstream.ui 2 | 3 | import android.os.Build 4 | import android.view.WindowManager 5 | import androidx.activity.ComponentActivity 6 | import androidx.compose.ui.graphics.Color 7 | import androidx.compose.ui.graphics.luminance 8 | import androidx.compose.ui.graphics.toArgb 9 | import androidx.core.view.WindowCompat 10 | import androidx.core.view.WindowInsetsControllerCompat 11 | 12 | // Based on androidx.activity.ComponentActivity.enableEdgeToEdge 13 | @Suppress("DEPRECATION") 14 | internal fun ComponentActivity.enableEdgeToEdge(statusBarColor: Color, navigationBarColor: Color) { 15 | WindowCompat.setDecorFitsSystemWindows(window, false) 16 | 17 | // Transparent on Android 15+ 18 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) { 19 | window.statusBarColor = statusBarColor.toArgb() 20 | } 21 | 22 | // No navigationBarColor for API < 26 as it works bad 23 | // Transparent on Android 15+ 24 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) { 25 | window.navigationBarColor = navigationBarColor.toArgb() 26 | } 27 | 28 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 29 | window.isStatusBarContrastEnforced = false 30 | window.isNavigationBarContrastEnforced = false 31 | } 32 | 33 | WindowInsetsControllerCompat(window, window.decorView).run { 34 | isAppearanceLightStatusBars = statusBarColor.luminance() > 0.5f 35 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 36 | isAppearanceLightNavigationBars = navigationBarColor.luminance() > 0.5f 37 | } 38 | } 39 | 40 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 41 | window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS 42 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 43 | window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 44 | } 45 | } -------------------------------------------------------------------------------- /app/src/main/java/info/dvkr/screenstream/ui/tabs/settings/app/AppModuleSettings.kt: -------------------------------------------------------------------------------- 1 | package info.dvkr.screenstream.ui.tabs.settings.app 2 | 3 | import androidx.compose.material3.MaterialTheme 4 | import androidx.compose.material3.Text 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.ui.Modifier 7 | import androidx.compose.ui.res.stringResource 8 | import androidx.compose.ui.unit.sp 9 | import info.dvkr.screenstream.R 10 | import info.dvkr.screenstream.common.ModuleSettings 11 | import info.dvkr.screenstream.ui.tabs.settings.app.settings.GeneralGroup 12 | 13 | internal class AppModuleSettings : ModuleSettings { 14 | override val id: String = "APP" 15 | override val groups: List = 16 | listOf(GeneralGroup).sortedBy { GeneralGroup.position } 17 | 18 | @Composable 19 | override fun TitleUI(modifier: Modifier) { 20 | Text( 21 | text = stringResource(id = R.string.app_pref_settings), 22 | modifier = modifier, 23 | fontSize = 18.sp, 24 | style = MaterialTheme.typography.titleMedium 25 | ) 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/info/dvkr/screenstream/ui/tabs/settings/app/settings/GeneralGroup.kt: -------------------------------------------------------------------------------- 1 | package info.dvkr.screenstream.ui.tabs.settings.app.settings 2 | 3 | import info.dvkr.screenstream.common.ModuleSettings 4 | import info.dvkr.screenstream.ui.tabs.settings.app.settings.general.AppLocale 5 | import info.dvkr.screenstream.ui.tabs.settings.app.settings.general.DynamicTheme 6 | import info.dvkr.screenstream.ui.tabs.settings.app.settings.general.Logging 7 | import info.dvkr.screenstream.ui.tabs.settings.app.settings.general.NightMode 8 | import info.dvkr.screenstream.ui.tabs.settings.app.settings.general.Notifications 9 | import info.dvkr.screenstream.ui.tabs.settings.app.settings.general.Tile 10 | 11 | public data object GeneralGroup : ModuleSettings.Group { 12 | override val id: String = "GENERAL" 13 | override val position: Int = -1 14 | override val items: List = 15 | listOf(AppLocale, NightMode, DynamicTheme, Notifications, Tile, Logging) 16 | .filter { it.available }.sortedBy { it.position } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/info/dvkr/screenstream/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | package info.dvkr.screenstream.ui.theme 2 | 3 | import androidx.compose.material3.Typography 4 | 5 | internal val AppTypography = Typography() -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkrivoruchko/ScreenStream/2d5b43685afab1704cc6e57fa5bf3c6ba6c9a307/app/src/main/res/drawable-nodpi/logo.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notification_small_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notification_small_anim0_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notification_small_anim1_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notification_small_anim2_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notification_small_anim3_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notification_small_anim_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 10 | 13 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_tile_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkrivoruchko/ScreenStream/2d5b43685afab1704cc6e57fa5bf3c6ba6c9a307/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkrivoruchko/ScreenStream/2d5b43685afab1704cc6e57fa5bf3c6ba6c9a307/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkrivoruchko/ScreenStream/2d5b43685afab1704cc6e57fa5bf3c6ba6c9a307/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkrivoruchko/ScreenStream/2d5b43685afab1704cc6e57fa5bf3c6ba6c9a307/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkrivoruchko/ScreenStream/2d5b43685afab1704cc6e57fa5bf3c6ba6c9a307/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkrivoruchko/ScreenStream/2d5b43685afab1704cc6e57fa5bf3c6ba6c9a307/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkrivoruchko/ScreenStream/2d5b43685afab1704cc6e57fa5bf3c6ba6c9a307/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkrivoruchko/ScreenStream/2d5b43685afab1704cc6e57fa5bf3c6ba6c9a307/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkrivoruchko/ScreenStream/2d5b43685afab1704cc6e57fa5bf3c6ba6c9a307/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkrivoruchko/ScreenStream/2d5b43685afab1704cc6e57fa5bf3c6ba6c9a307/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/resources.properties: -------------------------------------------------------------------------------- 1 | unqualifiedResLocale=en -------------------------------------------------------------------------------- /app/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF101418 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFF8F9FF 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 |