diff --git a/.vscode/launch.json b/.vscode/launch.json index df5a726..995076f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,39 +7,8 @@ { "name": "no_screenshot", "request": "launch", - "type": "dart" - }, - { - "name": "no_screenshot (profile mode)", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "no_screenshot (release mode)", - "request": "launch", - "type": "dart", - "flutterMode": "release" - }, - { - "name": "example", - "cwd": "example", - "request": "launch", - "type": "dart" - }, - { - "name": "example (profile mode)", - "cwd": "example", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "example (release mode)", - "cwd": "example", - "request": "launch", - "type": "dart", - "flutterMode": "release" + "type": "dart", + "program": "example/lib/main.dart" } ] } \ No newline at end of file diff --git a/LICENSE b/LICENSE index 5316aed..8130832 100644 --- a/LICENSE +++ b/LICENSE @@ -1,26 +1,26 @@ -Copyright (c) 2022, FlutterPlaza -All rights reserved. +Copyright (c) 2022, FlutterPlaza +All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of FlutterPlaza nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of FlutterPlaza nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/android/src/main/kotlin/com/flutterplaza/no_screenshot/NoScreenshotPlugin.kt b/android/src/main/kotlin/com/flutterplaza/no_screenshot/NoScreenshotPlugin.kt index bd7dc60..57ee82a 100644 --- a/android/src/main/kotlin/com/flutterplaza/no_screenshot/NoScreenshotPlugin.kt +++ b/android/src/main/kotlin/com/flutterplaza/no_screenshot/NoScreenshotPlugin.kt @@ -9,71 +9,89 @@ import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result -import android.view.WindowManager.LayoutParams; +import android.view.WindowManager.LayoutParams import io.flutter.embedding.engine.plugins.activity.ActivityAware import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding +const val SCREENSHOT_ON_CONST = "screenshotOn" +const val SCREENSHOT_OFF_CONST = "screenshotOff" +const val TOGGLE_SCREENSHOT_CONST = "toggleScreenshot" /** NoScreenshotPlugin */ -class NoScreenshotPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { - /// The MethodChannel that will the communication between Flutter and native Android - /// - /// This local reference serves to register the plugin with the Flutter Engine and unregister it - /// when the Flutter Engine is detached from the Activity - private lateinit var channel : MethodChannel - private lateinit var context: Context - private lateinit var activity: Activity - - override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.flutterplaza.no_screenshot") - channel.setMethodCallHandler(this) - context = flutterPluginBinding.applicationContext - - } - - override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) = - if (call.method == "screenshotOff") { - screenshotOff(); - result.success(true); - } - else if(call.method == "screenshotOn"){ - screenshotOn(); - result.success(true); - } - else if(call.method == "toggleScreenshot"){ - var flags: Int = activity.window.attributes.flags; - if( (flags and LayoutParams.FLAG_SECURE) != 0){ - screenshotOn(); - }else { - screenshotOff(); - } - result.success(true); +class NoScreenshotPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { + /// The MethodChannel that will the communication between Flutter and native Android + /// + /// This local reference serves to register the plugin with the Flutter Engine and unregister it + /// when the Flutter Engine is detached from the Activity + private lateinit var channel: MethodChannel + private lateinit var context: Context + private lateinit var activity: Activity + + override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + channel = + MethodChannel(flutterPluginBinding.binaryMessenger, "com.flutterplaza.no_screenshot") + channel.setMethodCallHandler(this) + context = flutterPluginBinding.applicationContext + } - else { - result.notImplemented() + + override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) = + when (call.method) { + SCREENSHOT_OFF_CONST -> { + val value: Boolean = screenshotOff() + result.success(value) + } + SCREENSHOT_ON_CONST -> { + val value = screenshotOn() + + result.success(value) + } + TOGGLE_SCREENSHOT_CONST -> { + val flags: Int = activity.window.attributes.flags + if ((flags and LayoutParams.FLAG_SECURE) != 0) { + screenshotOn() + } else { + screenshotOff() + } + result.success(true) + } + else -> { + result.notImplemented() + } + } + + private fun screenshotOff(): Boolean { + try { + activity.window.addFlags(LayoutParams.FLAG_SECURE) + return true + } catch (e: Exception) { + return false + } } - private fun screenshotOff(){ - activity.window.addFlags(LayoutParams.FLAG_SECURE); - } - private fun screenshotOn(){ - activity.window.clearFlags(LayoutParams.FLAG_SECURE); - } + private fun screenshotOn() : Boolean{ + try { + activity.window.clearFlags(LayoutParams.FLAG_SECURE) + return true + } catch (e: Exception) { + return false + } + } - override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { - channel.setMethodCallHandler(null) - } + override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { + channel.setMethodCallHandler(null) + } - override fun onAttachedToActivity(binding: ActivityPluginBinding) { - activity = binding.activity; - } + override fun onAttachedToActivity(binding: ActivityPluginBinding) { + activity = binding.activity + } override fun onDetachedFromActivityForConfigChanges() {} - override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { - activity = binding.activity; + override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { + activity = binding.activity - } + } override fun onDetachedFromActivity() {} } diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index b4dc4b1..181459e 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -43,7 +43,6 @@ android { } defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.flutterplaza.no_screenshot_example" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. diff --git a/example/lib/main.dart b/example/lib/main.dart index 8782baa..bed57bb 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -35,21 +35,21 @@ class _MyAppState extends State { child: const Text('Press to toggle screenshot'), onPressed: () async { final result = await _noScreenshot.toggleScreenshot(); - print(result); + debugPrint(result.toString()); }, ), ElevatedButton( child: const Text('Press to turn off screenshot'), onPressed: () async { final result = await _noScreenshot.screenshotOff(); - print(result); + debugPrint(result.toString()); }, ), ElevatedButton( child: const Text('Press to turn on screenshot'), onPressed: () async { final result = await _noScreenshot.screenshotOn(); - print(result); + debugPrint(result.toString()); }, ), ], diff --git a/example/pubspec.lock b/example/pubspec.lock index 712900e..76c0646 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,49 +5,56 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.18.0" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" flutter: @@ -59,7 +66,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" source: hosted version: "2.0.1" flutter_test: @@ -67,34 +75,62 @@ packages: description: flutter source: sdk version: "0.0.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + url: "https://pub.dev" + source: hosted + version: "10.0.4" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" source: hosted version: "2.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.8.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.12.0" no_screenshot: dependency: "direct main" description: @@ -106,14 +142,16 @@ packages: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.9.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + url: "https://pub.dev" source: hosted version: "2.1.3" sky_engine: @@ -125,51 +163,66 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.7.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + url: "https://pub.dev" + source: hosted + version: "14.2.1" sdks: - dart: ">=2.18.2 <3.0.0" - flutter: ">=2.5.0" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/test/no_screenshot_test.dart b/test/no_screenshot_test.dart new file mode 100644 index 0000000..084e66b --- /dev/null +++ b/test/no_screenshot_test.dart @@ -0,0 +1,50 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:no_screenshot/no_screenshot_platform_interface.dart'; +import 'package:no_screenshot/no_screenshot_method_channel.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +class MockNoScreenshotPlatform + with MockPlatformInterfaceMixin + implements NoScreenshotPlatform { + @override + Future screenshotOff() async { + // Mock implementation or return a fixed value + return Future.value(true); + } + + @override + Future screenshotOn() async { + // Mock implementation or return a fixed value + return Future.value(true); + } + + @override + Future toggleScreenshot() async { + // Mock implementation or return a fixed value + return Future.value(true); + } +} + +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + final NoScreenshotPlatform initialPlatform = NoScreenshotPlatform.instance; + MockNoScreenshotPlatform fakePlatform = MockNoScreenshotPlatform(); + + test('$MethodChannelNoScreenshot is the default instance', () { + expect(initialPlatform, isInstanceOf()); + }); + + test('screenshotOn', () async { + expect(await fakePlatform.screenshotOn(), true); + }); + // screenshotOff + test('screenshotOff', () async { + expect(await fakePlatform.screenshotOff(), true); + }); + + // toggleScreenshot + test('toggleScreenshot', () async { + expect(await fakePlatform.toggleScreenshot(), true); + }); +} diff --git a/test_driver/app.dart b/test_driver/app.dart index 446df9e..f7cb2aa 100644 --- a/test_driver/app.dart +++ b/test_driver/app.dart @@ -1,5 +1,4 @@ import 'package:flutter_driver/driver_extension.dart'; -import 'app_test.dart'; import '../example/lib/main.dart' as app; void main() { diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index 021a285..675e696 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -13,7 +13,9 @@ void main() { setUp(() async { driver = await FlutterDriver.connect(); - channel.setMockMethodCallHandler((MethodCall methodCall) async { + // Updated deprecated method usage + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (MethodCall methodCall) async { switch (methodCall.method) { case screenShotOffConst: break; @@ -71,7 +73,9 @@ void main() { }); }); tearDown(() { - channel.setMockMethodCallHandler(null); + // Updated deprecated method usage + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, null); driver.close(); }); } diff --git a/test_driver/no_screenshot_test.dart b/test_driver/no_screenshot_test.dart deleted file mode 100644 index 6329351..0000000 --- a/test_driver/no_screenshot_test.dart +++ /dev/null @@ -1,41 +0,0 @@ -// import 'package:flutter_test/flutter_test.dart'; -// import 'package:no_screenshot/no_screenshot.dart'; -// import 'package:no_screenshot/no_screenshot_platform_interface.dart'; -// import 'package:no_screenshot/no_screenshot_method_channel.dart'; -// import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -// import 'package:screenshots/screenshots.dart'; - -// class MockNoScreenshotPlatform -// with MockPlatformInterfaceMixin -// implements NoScreenshotPlatform { - -// @override -// Future screenshotOff() { - -// } - -// @override -// Future screenshotOn() { -// } - -// @override -// Future toggleScreenshot() { - -// } -// } - -// void main() { -// final NoScreenshotPlatform initialPlatform = NoScreenshotPlatform.instance; - -// test('$MethodChannelNoScreenshot is the default instance', () { -// expect(initialPlatform, isInstanceOf()); -// }); - -// test('getPlatformVersion', () async { -// NoScreenshot noScreenshotPlugin = NoScreenshot(); -// MockNoScreenshotPlatform fakePlatform = MockNoScreenshotPlatform(); -// NoScreenshotPlatform.instance = fakePlatform; - -// expect(await noScreenshotPlugin.getPlatformVersion(), '42'); -// }); -// }