@ -0,0 +1,80 @@
|
||||
{
|
||||
"configVersion": 2,
|
||||
"packages": [
|
||||
{
|
||||
"name": "characters",
|
||||
"rootUri": "file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "collection",
|
||||
"rootUri": "file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/collection-1.16.0",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "flutter",
|
||||
"rootUri": "file:///Users/datang/fvm/versions/3.0.0/packages/flutter",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "flutter_lints",
|
||||
"rootUri": "file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "lints",
|
||||
"rootUri": "file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "material_color_utilities",
|
||||
"rootUri": "file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/material_color_utilities-0.1.4",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.13"
|
||||
},
|
||||
{
|
||||
"name": "meta",
|
||||
"rootUri": "file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "permission_handler_platform_interface",
|
||||
"rootUri": "file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/permission_handler_platform_interface-3.7.0",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.14"
|
||||
},
|
||||
{
|
||||
"name": "plugin_platform_interface",
|
||||
"rootUri": "file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-2.1.2",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "sky_engine",
|
||||
"rootUri": "file:///Users/datang/fvm/versions/3.0.0/bin/cache/pkg/sky_engine",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "vector_math",
|
||||
"rootUri": "file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.2",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.14"
|
||||
},
|
||||
{
|
||||
"name": "permission_handler_android",
|
||||
"rootUri": "../",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.15"
|
||||
}
|
||||
],
|
||||
"generated": "2022-07-29T09:47:41.527304Z",
|
||||
"generator": "pub",
|
||||
"generatorVersion": "2.17.0"
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
characters
|
||||
2.12
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib/
|
||||
collection
|
||||
2.12
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/collection-1.16.0/
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/collection-1.16.0/lib/
|
||||
flutter_lints
|
||||
2.12
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib/
|
||||
lints
|
||||
2.12
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib/
|
||||
material_color_utilities
|
||||
2.13
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/material_color_utilities-0.1.4/
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/material_color_utilities-0.1.4/lib/
|
||||
meta
|
||||
2.12
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib/
|
||||
permission_handler_platform_interface
|
||||
2.14
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/permission_handler_platform_interface-3.7.0/
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/permission_handler_platform_interface-3.7.0/lib/
|
||||
plugin_platform_interface
|
||||
2.12
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-2.1.2/
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-2.1.2/lib/
|
||||
vector_math
|
||||
2.14
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.2/
|
||||
file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.2/lib/
|
||||
permission_handler_android
|
||||
2.15
|
||||
file:///Users/datang/Downloads/flutter-permission-handler-master/permission_handler_android/
|
||||
file:///Users/datang/Downloads/flutter-permission-handler-master/permission_handler_android/lib/
|
||||
sky_engine
|
||||
2.12
|
||||
file:///Users/datang/fvm/versions/3.0.0/bin/cache/pkg/sky_engine/
|
||||
file:///Users/datang/fvm/versions/3.0.0/bin/cache/pkg/sky_engine/lib/
|
||||
flutter
|
||||
2.12
|
||||
file:///Users/datang/fvm/versions/3.0.0/packages/flutter/
|
||||
file:///Users/datang/fvm/versions/3.0.0/packages/flutter/lib/
|
||||
2
|
@ -0,0 +1 @@
|
||||
3.0.0
|
@ -0,0 +1,300 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Dart Packages" type="DartPackagesLibraryType">
|
||||
<properties>
|
||||
<option name="packageNameToDirsMap">
|
||||
<entry key="async">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="baseflow_plugin_template">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/git/baseflow_plugin_template-0695ef43c098d75efffe5fd6212390b853f05bf7//lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="boolean_selector">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="characters">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="charcode">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/charcode-1.3.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="clock">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="collection">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/collection-1.16.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="fake_async">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/fake_async-1.3.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="flutter">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/fvm/versions/3.0.0/packages/flutter/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="flutter_lints">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="flutter_test">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/fvm/versions/3.0.0/packages/flutter_test/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="flutter_web_plugins">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/fvm/versions/3.0.0/packages/flutter_web_plugins/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="js">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/js-0.6.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="lints">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="matcher">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.11/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="material_color_utilities">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/material_color_utilities-0.1.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="meta">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="path">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/path-1.8.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="permission_handler_platform_interface">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/permission_handler_platform_interface-3.7.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="plugin_platform_interface">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-2.1.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="sky_engine">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/fvm/versions/3.0.0/bin/cache/pkg/sky_engine/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="source_span">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="stack_trace">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="stream_channel">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="string_scanner">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="term_glyph">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="test_api">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test_api-0.4.9/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.1.5/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher_android">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher_ios">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher_linux">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher_macos">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher_platform_interface">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_platform_interface-2.1.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher_web">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="url_launcher_windows">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="vector_math">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
</option>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="file://$USER_HOME$/.pub-cache/git/baseflow_plugin_template-0695ef43c098d75efffe5fd6212390b853f05bf7//lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/charcode-1.3.1/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/collection-1.16.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/fake_async-1.3.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/js-0.6.4/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.11/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/material_color_utilities-0.1.4/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/path-1.8.1/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/permission_handler_platform_interface-3.7.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-2.1.2/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.2/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test_api-0.4.9/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.1.5/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.17/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.17/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.1/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.1/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_platform_interface-2.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.12/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.1/lib" />
|
||||
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.2/lib" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/bin/cache/pkg/sky_engine/lib" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/packages/flutter/lib" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/packages/flutter_test/lib" />
|
||||
<root url="file://$USER_HOME$/fvm/versions/3.0.0/packages/flutter_web_plugins/lib" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
@ -0,0 +1,27 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Dart SDK">
|
||||
<CLASSES>
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/async" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/cli" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/collection" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/convert" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/core" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/developer" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/ffi" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/html" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/indexed_db" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/io" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/isolate" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/js" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/js_util" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/math" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/mirrors" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/svg" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/typed_data" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/web_audio" />
|
||||
<root url="file://$USER_HOME$/fvm/default/bin/cache/dart-sdk/lib/web_gl" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
@ -0,0 +1,7 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Flutter Plugins" type="FlutterPluginsLibraryType">
|
||||
<CLASSES />
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/permission_handler_android.iml" filepath="$PROJECT_DIR$/.idea/permission_handler_android.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/build" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/example/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,18 @@
|
||||
# This file is deprecated. Tools should instead consume
|
||||
# `.dart_tool/package_config.json`.
|
||||
#
|
||||
# For more info see: https://dart.dev/go/dot-packages-deprecation
|
||||
#
|
||||
# Generated by pub on 2022-07-29 17:47:41.517101.
|
||||
characters:file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib/
|
||||
collection:file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/collection-1.16.0/lib/
|
||||
flutter:file:///Users/datang/fvm/versions/3.0.0/packages/flutter/lib/
|
||||
flutter_lints:file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib/
|
||||
lints:file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib/
|
||||
material_color_utilities:file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/material_color_utilities-0.1.4/lib/
|
||||
meta:file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib/
|
||||
permission_handler_platform_interface:file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/permission_handler_platform_interface-3.7.0/lib/
|
||||
plugin_platform_interface:file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/plugin_platform_interface-2.1.2/lib/
|
||||
sky_engine:file:///Users/datang/fvm/versions/3.0.0/bin/cache/pkg/sky_engine/lib/
|
||||
vector_math:file:///Users/datang/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.2/lib/
|
||||
permission_handler_android:lib/
|
@ -0,0 +1,8 @@
|
||||
|
||||
# Below is a list of people and organizations that have contributed
|
||||
# to the Flutter project. Names should be added to the list like so:
|
||||
#
|
||||
# Name/Organization <email address>
|
||||
|
||||
Baseflow <hello@baseflow.com>
|
||||
Maurits van Beusekom <maurits@baseflow.com>
|
@ -0,0 +1,12 @@
|
||||
## 10.0.0
|
||||
|
||||
* __BREAKING CHANGE__: Updated Android `compileSdkVersion` to `33` to handle the new `POST_NOTIFICATIONS` permission.
|
||||
> When updating to version 10.0.0 make sure to update the `android/app/build.gradle` file and set the `compileSdkVersion` to `33`.
|
||||
|
||||
## 9.0.2+1
|
||||
|
||||
* Undoes PR [#765](https://github.com/baseflow/flutter-permission-handler/pull/765) which by mistake requests write_external_storage permission based on the target SDK instead of the actual SDK of the Android device.
|
||||
|
||||
## 9.0.2
|
||||
|
||||
* Moves Android implementation into its own package.
|
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Baseflow
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/"/>
|
||||
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
|
||||
<classpathentry kind="output" path="bin/default"/>
|
||||
</classpath>
|
@ -0,0 +1,13 @@
|
||||
arguments=
|
||||
auto.sync=false
|
||||
build.scans.enabled=false
|
||||
connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(7.1.1))
|
||||
connection.project.dir=
|
||||
eclipse.preferences.version=1
|
||||
gradle.user.home=
|
||||
java.home=/Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home
|
||||
jvm.arguments=
|
||||
offline.mode=false
|
||||
override.workspace.settings=true
|
||||
show.console.view=true
|
||||
show.executions.view=true
|
@ -0,0 +1,40 @@
|
||||
group 'com.baseflow.permissionhandler'
|
||||
version '1.0'
|
||||
def args = ["-Xlint:deprecation","-Xlint:unchecked","-Werror"]
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
project.getTasks().withType(JavaCompile){
|
||||
options.compilerArgs.addAll(args)
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 33
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.useAndroidX=true
|
@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
@ -0,0 +1 @@
|
||||
rootProject.name = 'permission_handler'
|
@ -0,0 +1,3 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.baseflow.permissionhandler">
|
||||
</manifest>
|
@ -0,0 +1,39 @@
|
||||
package com.baseflow.permissionhandler;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
final class AppSettingsManager {
|
||||
@FunctionalInterface
|
||||
interface OpenAppSettingsSuccessCallback {
|
||||
void onSuccess(boolean appSettingsOpenedSuccessfully);
|
||||
}
|
||||
|
||||
void openAppSettings(
|
||||
Context context,
|
||||
OpenAppSettingsSuccessCallback successCallback,
|
||||
ErrorCallback errorCallback) {
|
||||
if(context == null) {
|
||||
Log.d(PermissionConstants.LOG_TAG, "Context cannot be null.");
|
||||
errorCallback.onError("PermissionHandler.AppSettingsManager", "Android context cannot be null.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Intent settingsIntent = new Intent();
|
||||
settingsIntent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
settingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
settingsIntent.setData(android.net.Uri.parse("package:" + context.getPackageName()));
|
||||
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
|
||||
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||
|
||||
context.startActivity(settingsIntent);
|
||||
|
||||
successCallback.onSuccess(true);
|
||||
} catch (Exception ex) {
|
||||
successCallback.onSuccess(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.baseflow.permissionhandler;
|
||||
|
||||
@FunctionalInterface
|
||||
interface ErrorCallback {
|
||||
void onError(String errorCode, String errorDescription);
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package com.baseflow.permissionhandler;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
import io.flutter.plugin.common.MethodChannel.Result;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {
|
||||
private final Context applicationContext;
|
||||
private final AppSettingsManager appSettingsManager;
|
||||
private final PermissionManager permissionManager;
|
||||
private final ServiceManager serviceManager;
|
||||
|
||||
MethodCallHandlerImpl(
|
||||
Context applicationContext,
|
||||
AppSettingsManager appSettingsManager,
|
||||
PermissionManager permissionManager,
|
||||
ServiceManager serviceManager) {
|
||||
this.applicationContext = applicationContext;
|
||||
this.appSettingsManager = appSettingsManager;
|
||||
this.permissionManager = permissionManager;
|
||||
this.serviceManager = serviceManager;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Activity activity;
|
||||
|
||||
public void setActivity(@Nullable Activity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result)
|
||||
{
|
||||
switch (call.method) {
|
||||
case "checkServiceStatus": {
|
||||
@PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString());
|
||||
serviceManager.checkServiceStatus(
|
||||
permission,
|
||||
applicationContext,
|
||||
result::success,
|
||||
(String errorCode, String errorDescription) -> result.error(
|
||||
errorCode,
|
||||
errorDescription,
|
||||
null));
|
||||
|
||||
break;
|
||||
}
|
||||
case "checkPermissionStatus": {
|
||||
@PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString());
|
||||
permissionManager.checkPermissionStatus(
|
||||
permission,
|
||||
applicationContext,
|
||||
result::success);
|
||||
break;
|
||||
}
|
||||
case "requestPermissions":
|
||||
final List<Integer> permissions = call.arguments();
|
||||
permissionManager.requestPermissions(
|
||||
permissions,
|
||||
activity,
|
||||
result::success,
|
||||
(String errorCode, String errorDescription) -> result.error(
|
||||
errorCode,
|
||||
errorDescription,
|
||||
null));
|
||||
|
||||
break;
|
||||
case "shouldShowRequestPermissionRationale": {
|
||||
@PermissionConstants.PermissionGroup final int permission = Integer.parseInt(call.arguments.toString());
|
||||
permissionManager.shouldShowRequestPermissionRationale(
|
||||
permission,
|
||||
activity,
|
||||
result::success,
|
||||
(String errorCode, String errorDescription) -> result.error(
|
||||
errorCode,
|
||||
errorDescription,
|
||||
null));
|
||||
|
||||
break;
|
||||
}
|
||||
case "openAppSettings":
|
||||
appSettingsManager.openAppSettings(
|
||||
applicationContext,
|
||||
result::success,
|
||||
(String errorCode, String errorDescription) -> result.error(
|
||||
errorCode,
|
||||
errorDescription,
|
||||
null));
|
||||
|
||||
break;
|
||||
default:
|
||||
result.notImplemented();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package com.baseflow.permissionhandler;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
final class PermissionConstants {
|
||||
static final String LOG_TAG = "permissions_handler";
|
||||
static final int PERMISSION_CODE = 24;
|
||||
static final int PERMISSION_CODE_IGNORE_BATTERY_OPTIMIZATIONS = 209;
|
||||
static final int PERMISSION_CODE_MANAGE_EXTERNAL_STORAGE = 210;
|
||||
static final int PERMISSION_CODE_SYSTEM_ALERT_WINDOW = 211;
|
||||
static final int PERMISSION_CODE_REQUEST_INSTALL_PACKAGES = 212;
|
||||
static final int PERMISSION_CODE_ACCESS_NOTIFICATION_POLICY = 213;
|
||||
|
||||
//PERMISSION_GROUP
|
||||
static final int PERMISSION_GROUP_CALENDAR = 0;
|
||||
static final int PERMISSION_GROUP_CAMERA = 1;
|
||||
static final int PERMISSION_GROUP_CONTACTS = 2;
|
||||
static final int PERMISSION_GROUP_LOCATION = 3;
|
||||
static final int PERMISSION_GROUP_LOCATION_ALWAYS = 4;
|
||||
static final int PERMISSION_GROUP_LOCATION_WHEN_IN_USE = 5;
|
||||
static final int PERMISSION_GROUP_MEDIA_LIBRARY = 6;
|
||||
static final int PERMISSION_GROUP_MICROPHONE = 7;
|
||||
static final int PERMISSION_GROUP_PHONE = 8;
|
||||
static final int PERMISSION_GROUP_PHOTOS = 9;
|
||||
static final int PERMISSION_GROUP_PHOTOS_ADD_ONLY = 10;
|
||||
static final int PERMISSION_GROUP_REMINDERS = 11;
|
||||
static final int PERMISSION_GROUP_SENSORS = 12;
|
||||
static final int PERMISSION_GROUP_SMS = 13;
|
||||
static final int PERMISSION_GROUP_SPEECH = 14;
|
||||
static final int PERMISSION_GROUP_STORAGE = 15;
|
||||
static final int PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS = 16;
|
||||
static final int PERMISSION_GROUP_NOTIFICATION = 17;
|
||||
static final int PERMISSION_GROUP_ACCESS_MEDIA_LOCATION = 18;
|
||||
static final int PERMISSION_GROUP_ACTIVITY_RECOGNITION = 19;
|
||||
static final int PERMISSION_GROUP_UNKNOWN = 20;
|
||||
static final int PERMISSION_GROUP_BLUETOOTH = 21;
|
||||
static final int PERMISSION_GROUP_MANAGE_EXTERNAL_STORAGE = 22;
|
||||
static final int PERMISSION_GROUP_SYSTEM_ALERT_WINDOW = 23;
|
||||
static final int PERMISSION_GROUP_REQUEST_INSTALL_PACKAGES = 24;
|
||||
static final int PERMISSION_GROUP_APP_TRACK_TRANSPARENCY = 25;
|
||||
static final int PERMISSION_GROUP_CRITICAL_ALERTS = 26;
|
||||
static final int PERMISSION_GROUP_ACCESS_NOTIFICATION_POLICY = 27;
|
||||
static final int PERMISSION_GROUP_BLUETOOTH_SCAN = 28;
|
||||
static final int PERMISSION_GROUP_BLUETOOTH_ADVERTISE = 29;
|
||||
static final int PERMISSION_GROUP_BLUETOOTH_CONNECT = 30;
|
||||
static final int PERMISSION_GROUP_CALL_LOG = 31;
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
PERMISSION_GROUP_CALENDAR,
|
||||
PERMISSION_GROUP_CAMERA,
|
||||
PERMISSION_GROUP_CONTACTS,
|
||||
PERMISSION_GROUP_LOCATION,
|
||||
PERMISSION_GROUP_LOCATION_ALWAYS,
|
||||
PERMISSION_GROUP_LOCATION_WHEN_IN_USE,
|
||||
PERMISSION_GROUP_MEDIA_LIBRARY,
|
||||
PERMISSION_GROUP_MICROPHONE,
|
||||
PERMISSION_GROUP_PHONE,
|
||||
PERMISSION_GROUP_PHOTOS,
|
||||
PERMISSION_GROUP_REMINDERS,
|
||||
PERMISSION_GROUP_SENSORS,
|
||||
PERMISSION_GROUP_SMS,
|
||||
PERMISSION_GROUP_SPEECH,
|
||||
PERMISSION_GROUP_STORAGE,
|
||||
PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS,
|
||||
PERMISSION_GROUP_NOTIFICATION,
|
||||
PERMISSION_GROUP_ACCESS_MEDIA_LOCATION,
|
||||
PERMISSION_GROUP_ACTIVITY_RECOGNITION,
|
||||
PERMISSION_GROUP_UNKNOWN,
|
||||
PERMISSION_GROUP_BLUETOOTH,
|
||||
PERMISSION_GROUP_MANAGE_EXTERNAL_STORAGE,
|
||||
PERMISSION_GROUP_SYSTEM_ALERT_WINDOW,
|
||||
PERMISSION_GROUP_REQUEST_INSTALL_PACKAGES,
|
||||
PERMISSION_GROUP_ACCESS_NOTIFICATION_POLICY,
|
||||
PERMISSION_GROUP_BLUETOOTH_SCAN,
|
||||
PERMISSION_GROUP_BLUETOOTH_ADVERTISE,
|
||||
PERMISSION_GROUP_BLUETOOTH_CONNECT,
|
||||
PERMISSION_GROUP_CALL_LOG
|
||||
})
|
||||
@interface PermissionGroup {
|
||||
}
|
||||
|
||||
//PERMISSION_STATUS
|
||||
static final int PERMISSION_STATUS_DENIED = 0;
|
||||
static final int PERMISSION_STATUS_GRANTED = 1;
|
||||
static final int PERMISSION_STATUS_RESTRICTED = 2;
|
||||
static final int PERMISSION_STATUS_LIMITED = 3;
|
||||
static final int PERMISSION_STATUS_NEVER_ASK_AGAIN = 4;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
PERMISSION_STATUS_DENIED,
|
||||
PERMISSION_STATUS_GRANTED,
|
||||
PERMISSION_STATUS_RESTRICTED,
|
||||
PERMISSION_STATUS_LIMITED,
|
||||
PERMISSION_STATUS_NEVER_ASK_AGAIN
|
||||
})
|
||||
@interface PermissionStatus {
|
||||
}
|
||||
|
||||
//SERVICE_STATUS
|
||||
static final int SERVICE_STATUS_DISABLED = 0;
|
||||
static final int SERVICE_STATUS_ENABLED = 1;
|
||||
static final int SERVICE_STATUS_NOT_APPLICABLE = 2;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
SERVICE_STATUS_DISABLED,
|
||||
SERVICE_STATUS_ENABLED,
|
||||
SERVICE_STATUS_NOT_APPLICABLE
|
||||
})
|
||||
@interface ServiceStatus {
|
||||
}
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
package com.baseflow.permissionhandler;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
|
||||
import io.flutter.plugin.common.BinaryMessenger;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
|
||||
/**
|
||||
* Platform implementation of the permission_handler Flutter plugin.
|
||||
*
|
||||
* <p>Instantiate this in an add to app scenario to gracefully handle activity and context changes.
|
||||
* See {@code com.example.permissionhandlerexample.MainActivity} for an example.
|
||||
*
|
||||
* <p>Call {@link #registerWith(io.flutter.plugin.common.PluginRegistry.Registrar)} to register an
|
||||
* implementation of this that uses the stable {@code io.flutter.plugin.common} package.
|
||||
*/
|
||||
public final class PermissionHandlerPlugin implements FlutterPlugin, ActivityAware {
|
||||
|
||||
private final PermissionManager permissionManager;
|
||||
private MethodChannel methodChannel;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Nullable private io.flutter.plugin.common.PluginRegistry.Registrar pluginRegistrar;
|
||||
|
||||
@Nullable private ActivityPluginBinding pluginBinding;
|
||||
|
||||
@Nullable
|
||||
private MethodCallHandlerImpl methodCallHandler;
|
||||
|
||||
public PermissionHandlerPlugin() {
|
||||
this.permissionManager = new PermissionManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a plugin implementation that uses the stable {@code io.flutter.plugin.common}
|
||||
* package.
|
||||
*
|
||||
* <p>Calling this automatically initializes the plugin. However plugins initialized this way
|
||||
* won't react to changes in activity or context, unlike {@link PermissionHandlerPlugin}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) {
|
||||
final PermissionHandlerPlugin plugin = new PermissionHandlerPlugin();
|
||||
|
||||
plugin.pluginRegistrar = registrar;
|
||||
plugin.registerListeners();
|
||||
|
||||
plugin.startListening(registrar.context(), registrar.messenger());
|
||||
|
||||
if (registrar.activeContext() instanceof Activity) {
|
||||
plugin.startListeningToActivity(
|
||||
registrar.activity()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
|
||||
startListening(
|
||||
binding.getApplicationContext(),
|
||||
binding.getBinaryMessenger()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
|
||||
stopListening();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
|
||||
startListeningToActivity(
|
||||
binding.getActivity()
|
||||
);
|
||||
|
||||
this.pluginBinding = binding;
|
||||
registerListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
|
||||
onAttachedToActivity(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromActivity() {
|
||||
stopListeningToActivity();
|
||||
|
||||
deregisterListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromActivityForConfigChanges() {
|
||||
onDetachedFromActivity();
|
||||
}
|
||||
|
||||
|
||||
private void startListening(Context applicationContext, BinaryMessenger messenger) {
|
||||
methodChannel = new MethodChannel(
|
||||
messenger,
|
||||
"flutter.baseflow.com/permissions/methods");
|
||||
|
||||
methodCallHandler = new MethodCallHandlerImpl(
|
||||
applicationContext,
|
||||
new AppSettingsManager(),
|
||||
this.permissionManager,
|
||||
new ServiceManager()
|
||||
);
|
||||
|
||||
methodChannel.setMethodCallHandler(methodCallHandler);
|
||||
}
|
||||
|
||||
private void stopListening() {
|
||||
methodChannel.setMethodCallHandler(null);
|
||||
methodChannel = null;
|
||||
methodCallHandler = null;
|
||||
}
|
||||
|
||||
private void startListeningToActivity(
|
||||
Activity activity
|
||||
) {
|
||||
if (methodCallHandler != null) {
|
||||
methodCallHandler.setActivity(activity);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopListeningToActivity() {
|
||||
if (methodCallHandler != null) {
|
||||
methodCallHandler.setActivity(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerListeners() {
|
||||
if (this.pluginRegistrar != null) {
|
||||
this.pluginRegistrar.addActivityResultListener(this.permissionManager);
|
||||
this.pluginRegistrar.addRequestPermissionsResultListener(this.permissionManager);
|
||||
} else if (pluginBinding != null) {
|
||||
this.pluginBinding.addActivityResultListener(this.permissionManager);
|
||||
this.pluginBinding.addRequestPermissionsResultListener(this.permissionManager);
|
||||
}
|
||||
}
|
||||
|
||||
private void deregisterListeners() {
|
||||
if (this.pluginBinding != null) {
|
||||
this.pluginBinding.removeActivityResultListener(this.permissionManager);
|
||||
this.pluginBinding.removeRequestPermissionsResultListener(this.permissionManager);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,497 @@
|
||||
package com.baseflow.permissionhandler;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.flutter.plugin.common.PluginRegistry;
|
||||
|
||||
final class PermissionManager implements PluginRegistry.ActivityResultListener, PluginRegistry.RequestPermissionsResultListener {
|
||||
|
||||
@Nullable
|
||||
private RequestPermissionsSuccessCallback successCallback;
|
||||
|
||||
@Nullable
|
||||
private Activity activity;
|
||||
|
||||
private Map<Integer, Integer> requestResults;
|
||||
|
||||
@Override
|
||||
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode != PermissionConstants.PERMISSION_CODE_IGNORE_BATTERY_OPTIMIZATIONS &&
|
||||
requestCode != PermissionConstants.PERMISSION_CODE_MANAGE_EXTERNAL_STORAGE &&
|
||||
requestCode != PermissionConstants.PERMISSION_CODE_SYSTEM_ALERT_WINDOW &&
|
||||
requestCode != PermissionConstants.PERMISSION_CODE_REQUEST_INSTALL_PACKAGES &&
|
||||
requestCode != PermissionConstants.PERMISSION_CODE_ACCESS_NOTIFICATION_POLICY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = resultCode == Activity.RESULT_OK
|
||||
? PermissionConstants.PERMISSION_STATUS_GRANTED
|
||||
: PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
|
||||
int permission;
|
||||
|
||||
if (requestCode == PermissionConstants.PERMISSION_CODE_IGNORE_BATTERY_OPTIMIZATIONS) {
|
||||
permission = PermissionConstants.PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS;
|
||||
} else if (requestCode == PermissionConstants.PERMISSION_CODE_MANAGE_EXTERNAL_STORAGE) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
status = Environment.isExternalStorageManager()
|
||||
? PermissionConstants.PERMISSION_STATUS_GRANTED
|
||||
: PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
permission = PermissionConstants.PERMISSION_GROUP_MANAGE_EXTERNAL_STORAGE;
|
||||
} else if (requestCode == PermissionConstants.PERMISSION_CODE_SYSTEM_ALERT_WINDOW) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
status = Settings.canDrawOverlays(activity)
|
||||
? PermissionConstants.PERMISSION_STATUS_GRANTED
|
||||
: PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
permission = PermissionConstants.PERMISSION_GROUP_SYSTEM_ALERT_WINDOW;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (requestCode == PermissionConstants.PERMISSION_CODE_REQUEST_INSTALL_PACKAGES) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
status = activity.getPackageManager().canRequestPackageInstalls()
|
||||
? PermissionConstants.PERMISSION_STATUS_GRANTED
|
||||
: PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
permission = PermissionConstants.PERMISSION_GROUP_REQUEST_INSTALL_PACKAGES;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (requestCode == PermissionConstants.PERMISSION_CODE_ACCESS_NOTIFICATION_POLICY) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
NotificationManager notificationManager = (NotificationManager) activity.getSystemService(Application.NOTIFICATION_SERVICE);
|
||||
status = notificationManager.isNotificationPolicyAccessGranted()
|
||||
? PermissionConstants.PERMISSION_STATUS_GRANTED
|
||||
: PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
permission = PermissionConstants.PERMISSION_GROUP_ACCESS_NOTIFICATION_POLICY;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
HashMap<Integer, Integer> results = new HashMap<>();
|
||||
results.put(permission, status);
|
||||
successCallback.onSuccess(results);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
if (requestCode != PermissionConstants.PERMISSION_CODE) {
|
||||
ongoing = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (requestResults == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < permissions.length; i++) {
|
||||
final String permissionName = permissions[i];
|
||||
|
||||
@PermissionConstants.PermissionGroup final int permission =
|
||||
PermissionUtils.parseManifestName(permissionName);
|
||||
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_UNKNOWN)
|
||||
continue;
|
||||
|
||||
final int result = grantResults[i];
|
||||
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_MICROPHONE) {
|
||||
if (!requestResults.containsKey(PermissionConstants.PERMISSION_GROUP_MICROPHONE)) {
|
||||
requestResults.put(
|
||||
PermissionConstants.PERMISSION_GROUP_MICROPHONE,
|
||||
PermissionUtils.toPermissionStatus(this.activity, permissionName, result));
|
||||
}
|
||||
if (!requestResults.containsKey(PermissionConstants.PERMISSION_GROUP_SPEECH)) {
|
||||
requestResults.put(
|
||||
PermissionConstants.PERMISSION_GROUP_SPEECH,
|
||||
PermissionUtils.toPermissionStatus(this.activity, permissionName, result));
|
||||
}
|
||||
if (!requestResults.containsKey(PermissionConstants.PERMISSION_GROUP_CALL_LOG)) {
|
||||
requestResults.put(
|
||||
PermissionConstants.PERMISSION_GROUP_CALL_LOG,
|
||||
PermissionUtils.toPermissionStatus(this.activity, permissionName, result));
|
||||
}
|
||||
} else if (permission == PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS) {
|
||||
@PermissionConstants.PermissionStatus int permissionStatus =
|
||||
PermissionUtils.toPermissionStatus(this.activity, permissionName, result);
|
||||
|
||||
if (!requestResults.containsKey(PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS)) {
|
||||
requestResults.put(PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS, permissionStatus);
|
||||
}
|
||||
} else if (permission == PermissionConstants.PERMISSION_GROUP_LOCATION) {
|
||||
@PermissionConstants.PermissionStatus int permissionStatus =
|
||||
PermissionUtils.toPermissionStatus(this.activity, permissionName, result);
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
if (!requestResults.containsKey(PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS)) {
|
||||
requestResults.put(
|
||||
PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS,
|
||||
permissionStatus);
|
||||
}
|
||||
}
|
||||
|
||||
if (!requestResults.containsKey(PermissionConstants.PERMISSION_GROUP_LOCATION_WHEN_IN_USE)) {
|
||||
requestResults.put(
|
||||
PermissionConstants.PERMISSION_GROUP_LOCATION_WHEN_IN_USE,
|
||||
permissionStatus);
|
||||
}
|
||||
|
||||
requestResults.put(permission, permissionStatus);
|
||||
} else if (!requestResults.containsKey(permission)) {
|
||||
requestResults.put(
|
||||
permission,
|
||||
PermissionUtils.toPermissionStatus(this.activity, permissionName, result));
|
||||
}
|
||||
|
||||
PermissionUtils.updatePermissionShouldShowStatus(this.activity, permission);
|
||||
}
|
||||
|
||||
this.successCallback.onSuccess(requestResults);
|
||||
ongoing = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface RequestPermissionsSuccessCallback {
|
||||
void onSuccess(Map<Integer, Integer> results);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface CheckPermissionsSuccessCallback {
|
||||
void onSuccess(@PermissionConstants.PermissionStatus int permissionStatus);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface ShouldShowRequestPermissionRationaleSuccessCallback {
|
||||
void onSuccess(boolean shouldShowRequestPermissionRationale);
|
||||
}
|
||||
|
||||
private boolean ongoing = false;
|
||||
|
||||
void checkPermissionStatus(
|
||||
@PermissionConstants.PermissionGroup int permission,
|
||||
Context context,
|
||||
CheckPermissionsSuccessCallback successCallback) {
|
||||
|
||||
successCallback.onSuccess(determinePermissionStatus(
|
||||
permission,
|
||||
context));
|
||||
}
|
||||
|
||||
void requestPermissions(
|
||||
List<Integer> permissions,
|
||||
Activity activity,
|
||||
RequestPermissionsSuccessCallback successCallback,
|
||||
ErrorCallback errorCallback) {
|
||||
if (ongoing) {
|
||||
errorCallback.onError(
|
||||
"PermissionHandler.PermissionManager",
|
||||
"A request for permissions is already running, please wait for it to finish before doing another request (note that you can request multiple permissions at the same time).");
|
||||
return;
|
||||
}
|
||||
|
||||
if (activity == null) {
|
||||
Log.d(PermissionConstants.LOG_TAG, "Unable to detect current Activity.");
|
||||
|
||||
errorCallback.onError(
|
||||
"PermissionHandler.PermissionManager",
|
||||
"Unable to detect current Android Activity.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.successCallback = successCallback;
|
||||
this.activity = activity;
|
||||
this.requestResults = new HashMap<>();
|
||||
|
||||
ArrayList<String> permissionsToRequest = new ArrayList<>();
|
||||
for (Integer permission : permissions) {
|
||||
@PermissionConstants.PermissionStatus final int permissionStatus = determinePermissionStatus(permission, activity);
|
||||
if (permissionStatus == PermissionConstants.PERMISSION_STATUS_GRANTED) {
|
||||
if (!requestResults.containsKey(permission)) {
|
||||
requestResults.put(permission, PermissionConstants.PERMISSION_STATUS_GRANTED);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
final List<String> names = PermissionUtils.getManifestNames(activity, permission);
|
||||
|
||||
// check to see if we can find manifest names
|
||||
// if we can't add as unknown and continue
|
||||
if (names == null || names.isEmpty()) {
|
||||
if (!requestResults.containsKey(permission)) {
|
||||
// On Android below M, the android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS flag in AndroidManifest.xml
|
||||
// may be ignored and not visible to the App as it's a new permission setting as a whole.
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
requestResults.put(permission, PermissionConstants.PERMISSION_STATUS_RESTRICTED);
|
||||
} else {
|
||||
requestResults.put(permission, PermissionConstants.PERMISSION_STATUS_DENIED);
|
||||
}
|
||||
// On Android below R, the android.permission.MANAGE_EXTERNAL_STORAGE flag in AndroidManifest.xml
|
||||
// may be ignored and not visible to the App as it's a new permission setting as a whole.
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_MANAGE_EXTERNAL_STORAGE && Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
requestResults.put(permission, PermissionConstants.PERMISSION_STATUS_RESTRICTED);
|
||||
} else {
|
||||
requestResults.put(permission, PermissionConstants.PERMISSION_STATUS_DENIED);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permission == PermissionConstants.PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS) {
|
||||
executeIntent(
|
||||
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
|
||||
PermissionConstants.PERMISSION_CODE_IGNORE_BATTERY_OPTIMIZATIONS);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && permission == PermissionConstants.PERMISSION_GROUP_MANAGE_EXTERNAL_STORAGE) {
|
||||
executeIntent(
|
||||
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
|
||||
PermissionConstants.PERMISSION_CODE_MANAGE_EXTERNAL_STORAGE);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permission == PermissionConstants.PERMISSION_GROUP_SYSTEM_ALERT_WINDOW) {
|
||||
executeIntent(
|
||||
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
||||
PermissionConstants.PERMISSION_CODE_SYSTEM_ALERT_WINDOW);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && permission == PermissionConstants.PERMISSION_GROUP_REQUEST_INSTALL_PACKAGES) {
|
||||
executeIntent(
|
||||
Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
|
||||
PermissionConstants.PERMISSION_CODE_REQUEST_INSTALL_PACKAGES);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permission == PermissionConstants.PERMISSION_GROUP_ACCESS_NOTIFICATION_POLICY) {
|
||||
executeSimpleIntent(
|
||||
Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS,
|
||||
PermissionConstants.PERMISSION_CODE_ACCESS_NOTIFICATION_POLICY);
|
||||
} else {
|
||||
permissionsToRequest.addAll(names);
|
||||
}
|
||||
}
|
||||
|
||||
final String[] requestPermissions = permissionsToRequest.toArray(new String[0]);
|
||||
if (permissionsToRequest.size() > 0) {
|
||||
ongoing = true;
|
||||
|
||||
ActivityCompat.requestPermissions(
|
||||
activity,
|
||||
requestPermissions,
|
||||
PermissionConstants.PERMISSION_CODE);
|
||||
} else {
|
||||
ongoing = false;
|
||||
if (requestResults.size() > 0) {
|
||||
successCallback.onSuccess(requestResults);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PermissionConstants.PermissionStatus
|
||||
private int determinePermissionStatus(
|
||||
@PermissionConstants.PermissionGroup int permission,
|
||||
Context context) {
|
||||
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_NOTIFICATION) {
|
||||
return checkNotificationPermissionStatus(context);
|
||||
}
|
||||
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_BLUETOOTH) {
|
||||
return checkBluetoothPermissionStatus(context);
|
||||
}
|
||||
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_BLUETOOTH_CONNECT
|
||||
|| permission == PermissionConstants.PERMISSION_GROUP_BLUETOOTH_SCAN
|
||||
|| permission == PermissionConstants.PERMISSION_GROUP_BLUETOOTH_ADVERTISE){
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||
return checkBluetoothPermissionStatus(context);
|
||||
}
|
||||
}
|
||||
|
||||
final List<String> names = PermissionUtils.getManifestNames(context, permission);
|
||||
|
||||
if (names == null) {
|
||||
Log.d(PermissionConstants.LOG_TAG, "No android specific permissions needed for: " + permission);
|
||||
|
||||
return PermissionConstants.PERMISSION_STATUS_GRANTED;
|
||||
}
|
||||
|
||||
//if no permissions were found then there is an issue and permission is not set in Android manifest
|
||||
if (names.size() == 0) {
|
||||
Log.d(PermissionConstants.LOG_TAG, "No permissions found in manifest for: " + names + permission);
|
||||
|
||||
// On Android below M, the android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS flag in AndroidManifest.xml
|
||||
// may be ignored and not visible to the App as it's a new permission setting as a whole.
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
return PermissionConstants.PERMISSION_STATUS_RESTRICTED;
|
||||
}
|
||||
}
|
||||
|
||||
// On Android below R, the android.permission.MANAGE_EXTERNAL_STORAGE flag in AndroidManifest.xml
|
||||
// may be ignored and not visible to the App as it's a new permission setting as a whole.
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_MANAGE_EXTERNAL_STORAGE) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
return PermissionConstants.PERMISSION_STATUS_RESTRICTED;
|
||||
}
|
||||
}
|
||||
|
||||
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M
|
||||
? PermissionConstants.PERMISSION_STATUS_GRANTED
|
||||
: PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
}
|
||||
|
||||
final boolean targetsMOrHigher = context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.M;
|
||||
|
||||
for (String name : names) {
|
||||
// Only handle them if the client app actually targets a API level greater than M.
|
||||
if (targetsMOrHigher) {
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS) {
|
||||
String packageName = context.getPackageName();
|
||||
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
// PowerManager.isIgnoringBatteryOptimizations has been included in Android M first.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (pm != null && pm.isIgnoringBatteryOptimizations(packageName)) {
|
||||
return PermissionConstants.PERMISSION_STATUS_GRANTED;
|
||||
} else {
|
||||
return PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
}
|
||||
} else {
|
||||
return PermissionConstants.PERMISSION_STATUS_RESTRICTED;
|
||||
}
|
||||
}
|
||||
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_MANAGE_EXTERNAL_STORAGE) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
return PermissionConstants.PERMISSION_STATUS_RESTRICTED;
|
||||
}
|
||||
|
||||
return Environment.isExternalStorageManager()
|
||||
? PermissionConstants.PERMISSION_STATUS_GRANTED
|
||||
: PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
}
|
||||
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_SYSTEM_ALERT_WINDOW) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return Settings.canDrawOverlays(context)
|
||||
? PermissionConstants.PERMISSION_STATUS_GRANTED
|
||||
: PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_REQUEST_INSTALL_PACKAGES) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
return context.getPackageManager().canRequestPackageInstalls()
|
||||
? PermissionConstants.PERMISSION_STATUS_GRANTED
|
||||
: PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_ACCESS_NOTIFICATION_POLICY) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Application.NOTIFICATION_SERVICE);
|
||||
return notificationManager.isNotificationPolicyAccessGranted()
|
||||
? PermissionConstants.PERMISSION_STATUS_GRANTED
|
||||
: PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
final int permissionStatus = ContextCompat.checkSelfPermission(context, name);
|
||||
if (permissionStatus != PackageManager.PERMISSION_GRANTED) {
|
||||
return PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PermissionConstants.PERMISSION_STATUS_GRANTED;
|
||||
}
|
||||
|
||||
private void executeIntent(String action, int requestCode) {
|
||||
String packageName = activity.getPackageName();
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(action);
|
||||
intent.setData(Uri.parse("package:" + packageName));
|
||||
activity.startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
private void executeSimpleIntent(String action, int requestCode) {
|
||||
activity.startActivityForResult(new Intent(action), requestCode);
|
||||
}
|
||||
|
||||
void shouldShowRequestPermissionRationale(
|
||||
int permission,
|
||||
Activity activity,
|
||||
ShouldShowRequestPermissionRationaleSuccessCallback successCallback,
|
||||
ErrorCallback errorCallback) {
|
||||
if (activity == null) {
|
||||
Log.d(PermissionConstants.LOG_TAG, "Unable to detect current Activity.");
|
||||
|
||||
errorCallback.onError(
|
||||
"PermissionHandler.PermissionManager",
|
||||
"Unable to detect current Android Activity.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> names = PermissionUtils.getManifestNames(activity, permission);
|
||||
|
||||
// if isn't an android specific group then go ahead and return false;
|
||||
if (names == null) {
|
||||
Log.d(PermissionConstants.LOG_TAG, "No android specific permissions needed for: " + permission);
|
||||
successCallback.onSuccess(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (names.isEmpty()) {
|
||||
Log.d(PermissionConstants.LOG_TAG, "No permissions found in manifest for: " + permission + " no need to show request rationale");
|
||||
successCallback.onSuccess(false);
|
||||
return;
|
||||
}
|
||||
|
||||
successCallback.onSuccess(ActivityCompat.shouldShowRequestPermissionRationale(activity, names.get(0)));
|
||||
}
|
||||
|
||||
private int checkNotificationPermissionStatus(Context context) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
NotificationManagerCompat manager = NotificationManagerCompat.from(context);
|
||||
boolean isGranted = manager.areNotificationsEnabled();
|
||||
if (isGranted) {
|
||||
return PermissionConstants.PERMISSION_STATUS_GRANTED;
|
||||
}
|
||||
return PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
}
|
||||
|
||||
return context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
|
||||
? PermissionConstants.PERMISSION_STATUS_GRANTED
|
||||
: PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
}
|
||||
|
||||
private int checkBluetoothPermissionStatus(Context context) {
|
||||
List<String> names = PermissionUtils.getManifestNames(context, PermissionConstants.PERMISSION_GROUP_BLUETOOTH);
|
||||
boolean missingInManifest = names == null || names.isEmpty();
|
||||
if (missingInManifest) {
|
||||
Log.d(PermissionConstants.LOG_TAG, "Bluetooth permission missing in manifest");
|
||||
return PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
}
|
||||
return PermissionConstants.PERMISSION_STATUS_GRANTED;
|
||||
}
|
||||
}
|
@ -0,0 +1,407 @@
|
||||
package com.baseflow.permissionhandler;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class PermissionUtils {
|
||||
|
||||
@PermissionConstants.PermissionGroup
|
||||
static int parseManifestName(String permission) {
|
||||
switch (permission) {
|
||||
case Manifest.permission.READ_CALENDAR:
|
||||
case Manifest.permission.WRITE_CALENDAR:
|
||||
return PermissionConstants.PERMISSION_GROUP_CALENDAR;
|
||||
case Manifest.permission.CAMERA:
|
||||
return PermissionConstants.PERMISSION_GROUP_CAMERA;
|
||||
case Manifest.permission.READ_CONTACTS:
|
||||
case Manifest.permission.WRITE_CONTACTS:
|
||||
case Manifest.permission.GET_ACCOUNTS:
|
||||
return PermissionConstants.PERMISSION_GROUP_CONTACTS;
|
||||
case Manifest.permission.ACCESS_BACKGROUND_LOCATION:
|
||||
return PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS;
|
||||
case Manifest.permission.ACCESS_COARSE_LOCATION:
|
||||
case Manifest.permission.ACCESS_FINE_LOCATION:
|
||||
return PermissionConstants.PERMISSION_GROUP_LOCATION;
|
||||
case Manifest.permission.RECORD_AUDIO:
|
||||
return PermissionConstants.PERMISSION_GROUP_MICROPHONE;
|
||||
case Manifest.permission.READ_PHONE_STATE:
|
||||
case Manifest.permission.READ_PHONE_NUMBERS:
|
||||
case Manifest.permission.CALL_PHONE:
|
||||
case Manifest.permission.ADD_VOICEMAIL:
|
||||
case Manifest.permission.USE_SIP:
|
||||
case Manifest.permission.BIND_CALL_REDIRECTION_SERVICE:
|
||||
return PermissionConstants.PERMISSION_GROUP_PHONE;
|
||||
case Manifest.permission.BODY_SENSORS:
|
||||
return PermissionConstants.PERMISSION_GROUP_SENSORS;
|
||||
case Manifest.permission.SEND_SMS:
|
||||
case Manifest.permission.RECEIVE_SMS:
|
||||
case Manifest.permission.READ_SMS:
|
||||
case Manifest.permission.RECEIVE_WAP_PUSH:
|
||||
case Manifest.permission.RECEIVE_MMS:
|
||||
return PermissionConstants.PERMISSION_GROUP_SMS;
|
||||
case Manifest.permission.READ_EXTERNAL_STORAGE:
|
||||
case Manifest.permission.WRITE_EXTERNAL_STORAGE:
|
||||
return PermissionConstants.PERMISSION_GROUP_STORAGE;
|
||||
case Manifest.permission.ACCESS_MEDIA_LOCATION:
|
||||
return PermissionConstants.PERMISSION_GROUP_ACCESS_MEDIA_LOCATION;
|
||||
case Manifest.permission.ACTIVITY_RECOGNITION:
|
||||
return PermissionConstants.PERMISSION_GROUP_ACTIVITY_RECOGNITION;
|
||||
case Manifest.permission.MANAGE_EXTERNAL_STORAGE:
|
||||
return PermissionConstants.PERMISSION_GROUP_MANAGE_EXTERNAL_STORAGE;
|
||||
case Manifest.permission.SYSTEM_ALERT_WINDOW:
|
||||
return PermissionConstants.PERMISSION_GROUP_SYSTEM_ALERT_WINDOW;
|
||||
case Manifest.permission.REQUEST_INSTALL_PACKAGES:
|
||||
return PermissionConstants.PERMISSION_GROUP_REQUEST_INSTALL_PACKAGES;
|
||||
case Manifest.permission.ACCESS_NOTIFICATION_POLICY:
|
||||
return PermissionConstants.PERMISSION_GROUP_ACCESS_NOTIFICATION_POLICY;
|
||||
case Manifest.permission.BLUETOOTH_SCAN:
|
||||
return PermissionConstants.PERMISSION_GROUP_BLUETOOTH_SCAN;
|
||||
case Manifest.permission.BLUETOOTH_ADVERTISE:
|
||||
return PermissionConstants.PERMISSION_GROUP_BLUETOOTH_ADVERTISE;
|
||||
case Manifest.permission.BLUETOOTH_CONNECT:
|
||||
return PermissionConstants.PERMISSION_GROUP_BLUETOOTH_CONNECT;
|
||||
case Manifest.permission.POST_NOTIFICATIONS:
|
||||
return PermissionConstants.PERMISSION_GROUP_NOTIFICATION;
|
||||
case Manifest.permission.READ_CALL_LOG:
|
||||
case Manifest.permission.WRITE_CALL_LOG:
|
||||
return PermissionConstants.PERMISSION_GROUP_CALL_LOG;
|
||||
default:
|
||||
return PermissionConstants.PERMISSION_GROUP_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static List<String> getManifestNames(Context context, @PermissionConstants.PermissionGroup int permission) {
|
||||
final ArrayList<String> permissionNames = new ArrayList<>();
|
||||
|
||||
switch (permission) {
|
||||
case PermissionConstants.PERMISSION_GROUP_CALENDAR:
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_CALENDAR))
|
||||
permissionNames.add(Manifest.permission.READ_CALENDAR);
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.WRITE_CALENDAR))
|
||||
permissionNames.add(Manifest.permission.WRITE_CALENDAR);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_CAMERA:
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.CAMERA))
|
||||
permissionNames.add(Manifest.permission.CAMERA);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_CONTACTS:
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_CONTACTS))
|
||||
permissionNames.add(Manifest.permission.READ_CONTACTS);
|
||||
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.WRITE_CONTACTS))
|
||||
permissionNames.add(Manifest.permission.WRITE_CONTACTS);
|
||||
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.GET_ACCOUNTS))
|
||||
permissionNames.add(Manifest.permission.GET_ACCOUNTS);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS:
|
||||
// Note that the LOCATION_ALWAYS will deliberately fallthrough to the LOCATION
|
||||
// case on pre Android Q devices. The ACCESS_BACKGROUND_LOCATION permission was only
|
||||
// introduced in Android Q, before it should be treated as the ACCESS_COARSE_LOCATION or
|
||||
// ACCESS_FINE_LOCATION.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.ACCESS_BACKGROUND_LOCATION))
|
||||
permissionNames.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
|
||||
break;
|
||||
}
|
||||
case PermissionConstants.PERMISSION_GROUP_LOCATION_WHEN_IN_USE:
|
||||
case PermissionConstants.PERMISSION_GROUP_LOCATION:
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.ACCESS_COARSE_LOCATION))
|
||||
permissionNames.add(Manifest.permission.ACCESS_COARSE_LOCATION);
|
||||
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.ACCESS_FINE_LOCATION))
|
||||
permissionNames.add(Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
break;
|
||||
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_SPEECH:
|
||||
case PermissionConstants.PERMISSION_GROUP_MICROPHONE:
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.RECORD_AUDIO))
|
||||
permissionNames.add(Manifest.permission.RECORD_AUDIO);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_PHONE:
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_PHONE_STATE))
|
||||
permissionNames.add(Manifest.permission.READ_PHONE_STATE);
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.Q && hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_PHONE_NUMBERS)) {
|
||||
permissionNames.add(Manifest.permission.READ_PHONE_NUMBERS);
|
||||
}
|
||||
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.CALL_PHONE))
|
||||
permissionNames.add(Manifest.permission.CALL_PHONE);
|
||||
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.ADD_VOICEMAIL))
|
||||
permissionNames.add(Manifest.permission.ADD_VOICEMAIL);
|
||||
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.USE_SIP))
|
||||
permissionNames.add(Manifest.permission.USE_SIP);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && hasPermissionInManifest(context, permissionNames, Manifest.permission.BIND_CALL_REDIRECTION_SERVICE))
|
||||
permissionNames.add(Manifest.permission.BIND_CALL_REDIRECTION_SERVICE);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && hasPermissionInManifest(context, permissionNames, Manifest.permission.ANSWER_PHONE_CALLS))
|
||||
permissionNames.add(Manifest.permission.ANSWER_PHONE_CALLS);
|
||||
|
||||
break;
|
||||
case PermissionConstants.PERMISSION_GROUP_CALL_LOG:
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_CALL_LOG))
|
||||
permissionNames.add(Manifest.permission.READ_CALL_LOG);
|
||||
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.WRITE_CALL_LOG))
|
||||
permissionNames.add(Manifest.permission.WRITE_CALL_LOG);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_SENSORS:
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.BODY_SENSORS)) {
|
||||
permissionNames.add(Manifest.permission.BODY_SENSORS);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_SMS:
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.SEND_SMS))
|
||||
permissionNames.add(Manifest.permission.SEND_SMS);
|
||||
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.RECEIVE_SMS))
|
||||
permissionNames.add(Manifest.permission.RECEIVE_SMS);
|
||||
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_SMS))
|
||||
permissionNames.add(Manifest.permission.READ_SMS);
|
||||
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.RECEIVE_WAP_PUSH))
|
||||
permissionNames.add(Manifest.permission.RECEIVE_WAP_PUSH);
|
||||
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.RECEIVE_MMS))
|
||||
permissionNames.add(Manifest.permission.RECEIVE_MMS);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_STORAGE:
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.READ_EXTERNAL_STORAGE))
|
||||
permissionNames.add(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q && Environment.isExternalStorageLegacy())) {
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.WRITE_EXTERNAL_STORAGE))
|
||||
permissionNames.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS:
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && hasPermissionInManifest(context, permissionNames, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS))
|
||||
permissionNames.add(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_ACCESS_MEDIA_LOCATION:
|
||||
// The ACCESS_MEDIA_LOCATION permission is introduced in Android Q, meaning we should
|
||||
// not handle permissions on pre Android Q devices.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
|
||||
return null;
|
||||
|
||||
if(hasPermissionInManifest(context, permissionNames, Manifest.permission.ACCESS_MEDIA_LOCATION))
|
||||
permissionNames.add(Manifest.permission.ACCESS_MEDIA_LOCATION);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_ACTIVITY_RECOGNITION:
|
||||
// The ACTIVITY_RECOGNITION permission is introduced in Android Q, meaning we should
|
||||
// not handle permissions on pre Android Q devices.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
|
||||
return null;
|
||||
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.ACTIVITY_RECOGNITION))
|
||||
permissionNames.add(Manifest.permission.ACTIVITY_RECOGNITION);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_BLUETOOTH:
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.BLUETOOTH))
|
||||
permissionNames.add(Manifest.permission.BLUETOOTH);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_MANAGE_EXTERNAL_STORAGE:
|
||||
// The MANAGE_EXTERNAL_STORAGE permission is introduced in Android R, meaning we should
|
||||
// not handle permissions on pre Android R devices.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && hasPermissionInManifest(context, permissionNames, Manifest.permission.MANAGE_EXTERNAL_STORAGE ))
|
||||
permissionNames.add(Manifest.permission.MANAGE_EXTERNAL_STORAGE);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_SYSTEM_ALERT_WINDOW:
|
||||
if (hasPermissionInManifest(context, permissionNames, Manifest.permission.SYSTEM_ALERT_WINDOW ))
|
||||
permissionNames.add(Manifest.permission.SYSTEM_ALERT_WINDOW);
|
||||
break;
|
||||
|
||||
case PermissionConstants.PERMISSION_GROUP_REQUEST_INSTALL_PACKAGES:
|
||||
// The REQUEST_INSTALL_PACKAGES permission is introduced in Android M, meaning we should
|
||||
// not handle permissions on pre Android M devices.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && hasPermissionInManifest(context, permissionNames, Manifest.permission.REQUEST_INSTALL_PACKAGES ))
|
||||
permissionNames.add(Manifest.permission.REQUEST_INSTALL_PACKAGES);
|
||||
break;
|
||||
case PermissionConstants.PERMISSION_GROUP_ACCESS_NOTIFICATION_POLICY:
|
||||
// The REQUEST_NOTIFICATION_POLICY permission is introduced in Android M, meaning we should
|
||||
// not handle permissions on pre Android M devices.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && hasPermissionInManifest(context, permissionNames, Manifest.permission.ACCESS_NOTIFICATION_POLICY ))
|
||||
permissionNames.add(Manifest.permission.ACCESS_NOTIFICATION_POLICY);
|
||||
break;
|
||||
case PermissionConstants.PERMISSION_GROUP_BLUETOOTH_SCAN: {
|
||||
// The BLUETOOTH_SCAN permission is introduced in Android S, meaning we should
|
||||
// not handle permissions on pre Android S devices.
|
||||
String result = determineBluetoothPermission(context, Manifest.permission.BLUETOOTH_SCAN);
|
||||
|
||||
if (result != null) {
|
||||
permissionNames.add(result);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PermissionConstants.PERMISSION_GROUP_BLUETOOTH_ADVERTISE: {
|
||||
// The BLUETOOTH_ADVERTISE permission is introduced in Android S, meaning we should
|
||||
// not handle permissions on pre Android S devices.
|
||||
String result = determineBluetoothPermission(context, Manifest.permission.BLUETOOTH_ADVERTISE);
|
||||
|
||||
if (result != null) {
|
||||
permissionNames.add(result);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PermissionConstants.PERMISSION_GROUP_BLUETOOTH_CONNECT: {
|
||||
// The BLUETOOTH_CONNECT permission is introduced in Android S, meaning we should
|
||||
// not handle permissions on pre Android S devices.
|
||||
String result = determineBluetoothPermission(context, Manifest.permission.BLUETOOTH_CONNECT);
|
||||
|
||||
if (result != null) {
|
||||
permissionNames.add(result);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PermissionConstants.PERMISSION_GROUP_NOTIFICATION:
|
||||
// The POST_NOTIFICATIONS permission is introduced in Android 13, meaning we should
|
||||
// not handle permissions on pre Android 13 devices.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && hasPermissionInManifest(context, permissionNames, Manifest.permission.POST_NOTIFICATIONS ))
|
||||
permissionNames.add(Manifest.permission.POST_NOTIFICATIONS);
|
||||
break;
|
||||
case PermissionConstants.PERMISSION_GROUP_MEDIA_LIBRARY:
|
||||
case PermissionConstants.PERMISSION_GROUP_PHOTOS:
|
||||
case PermissionConstants.PERMISSION_GROUP_REMINDERS:
|
||||
case PermissionConstants.PERMISSION_GROUP_UNKNOWN:
|
||||
return null;
|
||||
}
|
||||
|
||||
return permissionNames;
|
||||
}
|
||||
|
||||
private static boolean hasPermissionInManifest(Context context, ArrayList<String> confirmedPermissions, String permission) {
|
||||
try {
|
||||
if (confirmedPermissions != null) {
|
||||
for (String r : confirmedPermissions) {
|
||||
if (r.equals(permission)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context == null) {
|
||||
Log.d(PermissionConstants.LOG_TAG, "Unable to detect current Activity or App Context.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PackageInfo info = getPackageInfo(context);
|
||||
|
||||
if (info == null) {
|
||||
Log.d(PermissionConstants.LOG_TAG, "Unable to get Package info, will not be able to determine permissions to request.");
|
||||
return false;
|
||||
}
|
||||
|
||||
confirmedPermissions = new ArrayList<>(Arrays.asList(info.requestedPermissions));
|
||||
for (String r : confirmedPermissions) {
|
||||
if (r.equals(permission)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.d(PermissionConstants.LOG_TAG, "Unable to check manifest for permission: ", ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@PermissionConstants.PermissionStatus
|
||||
static int toPermissionStatus(final Activity activity, final String permissionName, int grantResult) {
|
||||
if (grantResult == PackageManager.PERMISSION_DENIED) {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && PermissionUtils.isNeverAskAgainSelected(activity, permissionName)
|
||||
? PermissionConstants.PERMISSION_STATUS_NEVER_ASK_AGAIN
|
||||
: PermissionConstants.PERMISSION_STATUS_DENIED;
|
||||
}
|
||||
|
||||
return PermissionConstants.PERMISSION_STATUS_GRANTED;
|
||||
}
|
||||
|
||||
static void updatePermissionShouldShowStatus(final Activity activity, @PermissionConstants.PermissionGroup int permission) {
|
||||
if (activity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> names = getManifestNames(activity, permission);
|
||||
|
||||
if (names == null || names.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
static boolean isNeverAskAgainSelected(final Activity activity, final String name) {
|
||||
if (activity == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean shouldShowRequestPermissionRationale = ActivityCompat.shouldShowRequestPermissionRationale(activity, name);
|
||||
return !shouldShowRequestPermissionRationale;
|
||||
}
|
||||
|
||||
private static String determineBluetoothPermission(Context context, String permission) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && hasPermissionInManifest(context, null, permission )) {
|
||||
return permission;
|
||||
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
if(hasPermissionInManifest(context, null, Manifest.permission.ACCESS_FINE_LOCATION)){
|
||||
return Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
} else if (hasPermissionInManifest(context, null, Manifest.permission.ACCESS_COARSE_LOCATION)){
|
||||
return Manifest.permission.ACCESS_COARSE_LOCATION;
|
||||
}
|
||||
|
||||
return null;
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && hasPermissionInManifest(context, null, Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||
return Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Suppress deprecation warnings since its purpose is to support to be backwards compatible with
|
||||
// pre TIRAMISU versions of Android
|
||||
@SuppressWarnings("deprecation")
|
||||
private static PackageInfo getPackageInfo(Context context) throws PackageManager.NameNotFoundException {
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
return pm.getPackageInfo(context.getPackageName(), PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS));
|
||||
} else {
|
||||
return pm.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
package com.baseflow.permissionhandler;
|
||||
|
||||
import static android.content.Context.BLUETOOTH_SERVICE;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.location.LocationManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
final class ServiceManager {
|
||||
@FunctionalInterface
|
||||
interface SuccessCallback {
|
||||
void onSuccess(@PermissionConstants.ServiceStatus int serviceStatus);
|
||||
}
|
||||
|
||||
void checkServiceStatus(
|
||||
int permission,
|
||||
Context context,
|
||||
SuccessCallback successCallback,
|
||||
ErrorCallback errorCallback) {
|
||||
if(context == null) {
|
||||
Log.d(PermissionConstants.LOG_TAG, "Context cannot be null.");
|
||||
errorCallback.onError("PermissionHandler.ServiceManager", "Android context cannot be null.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_LOCATION ||
|
||||
permission == PermissionConstants.PERMISSION_GROUP_LOCATION_ALWAYS ||
|
||||
permission == PermissionConstants.PERMISSION_GROUP_LOCATION_WHEN_IN_USE) {
|
||||
final int serviceStatus = isLocationServiceEnabled(context)
|
||||
? PermissionConstants.SERVICE_STATUS_ENABLED
|
||||
: PermissionConstants.SERVICE_STATUS_DISABLED;
|
||||
|
||||
successCallback.onSuccess(serviceStatus);
|
||||
return;
|
||||
}
|
||||
if(permission == PermissionConstants.PERMISSION_GROUP_BLUETOOTH){
|
||||
final int serviceStatus = isBluetoothServiceEnabled(context)
|
||||
? PermissionConstants.SERVICE_STATUS_ENABLED
|
||||
: PermissionConstants.SERVICE_STATUS_DISABLED;
|
||||
|
||||
successCallback.onSuccess(serviceStatus);
|
||||
}
|
||||
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_PHONE) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
|
||||
successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
TelephonyManager telephonyManager = (TelephonyManager) context
|
||||
.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
|
||||
if (telephonyManager == null || telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE) {
|
||||
successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
List<ResolveInfo> callAppsList = getCallAppsList(pm);
|
||||
|
||||
if (callAppsList.isEmpty()) {
|
||||
successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (telephonyManager.getSimState() != TelephonyManager.SIM_STATE_READY) {
|
||||
successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_DISABLED);
|
||||
return;
|
||||
}
|
||||
|
||||
successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_ENABLED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (permission == PermissionConstants.PERMISSION_GROUP_IGNORE_BATTERY_OPTIMIZATIONS) {
|
||||
final int serviceStatus = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
? PermissionConstants.SERVICE_STATUS_ENABLED
|
||||
: PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE;
|
||||
successCallback.onSuccess(serviceStatus);
|
||||
return;
|
||||
}
|
||||
|
||||
successCallback.onSuccess(PermissionConstants.SERVICE_STATUS_NOT_APPLICABLE);
|
||||
}
|
||||
|
||||
private boolean isLocationServiceEnabled(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
final LocationManager locationManager = context.getSystemService(LocationManager.class);
|
||||
if (locationManager == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return locationManager.isLocationEnabled();
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
return isLocationServiceEnabledKitKat(context);
|
||||
} else {
|
||||
return isLocationServiceEnablePreKitKat(context);
|
||||
}
|
||||
}
|
||||
|
||||
// Suppress deprecation warnings since its purpose is to support to be backwards compatible with
|
||||
// pre Pie versions of Android.
|
||||
@SuppressWarnings("deprecation")
|
||||
private static boolean isLocationServiceEnabledKitKat(Context context)
|
||||
{
|
||||
if (Build.VERSION.SDK_INT < VERSION_CODES.KITKAT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int locationMode;
|
||||
|
||||
try {
|
||||
locationMode = Settings.Secure.getInt(
|
||||
context.getContentResolver(),
|
||||
Settings.Secure.LOCATION_MODE);
|
||||
} catch (Settings.SettingNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
return locationMode != Settings.Secure.LOCATION_MODE_OFF;
|
||||
}
|
||||
|
||||
// Suppress deprecation warnings since its purpose is to support to be backwards compatible with
|
||||
// pre KitKat versions of Android.
|
||||
@SuppressWarnings("deprecation")
|
||||
private static boolean isLocationServiceEnablePreKitKat(Context context)
|
||||
{
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT)
|
||||
return false;
|
||||
|
||||
final String locationProviders = Settings.Secure.getString(
|
||||
context.getContentResolver(),
|
||||
Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
|
||||
return !TextUtils.isEmpty(locationProviders);
|
||||
}
|
||||
// Suppress deprecation warnings since its purpose is to support to be backwards compatible with
|
||||
// pre S versions of Android
|
||||
@SuppressWarnings("deprecation")
|
||||
private boolean isBluetoothServiceEnabled(Context context) {
|
||||
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
return BluetoothAdapter.getDefaultAdapter().isEnabled();
|
||||
}
|
||||
|
||||
BluetoothManager manager = (BluetoothManager) context.getSystemService(BLUETOOTH_SERVICE);
|
||||
final BluetoothAdapter adapter = manager.getAdapter();
|
||||
return adapter.isEnabled();
|
||||
}
|
||||
|
||||
// Suppress deprecation warnings since its purpose is to support to be backwards compatible with
|
||||
// pre TIRAMISU versions of Android
|
||||
@SuppressWarnings("deprecation")
|
||||
private List<ResolveInfo> getCallAppsList(PackageManager pm) {
|
||||
Intent callIntent = new Intent(Intent.ACTION_CALL);
|
||||
callIntent.setData(Uri.parse("tel:123123"));
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
return pm.queryIntentActivities(callIntent, PackageManager.ResolveInfoFlags.of(0));
|
||||
} else {
|
||||
return pm.queryIntentActivities(callIntent, 0);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: 06b979c4d5e1b499745422269f01a00341257058
|
||||
channel: master
|
||||
|
||||
project_type: app
|
@ -0,0 +1,16 @@
|
||||
# permission_handler_example
|
||||
|
||||
Demonstrates how to use the permission_handler plugin.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This project is a starting point for a Flutter application.
|
||||
|
||||
A few resources to get you started if this is your first Flutter project:
|
||||
|
||||
- [Lab: Write your first Flutter app](https://flutter.io/docs/get-started/codelab)
|
||||
- [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook)
|
||||
|
||||
For help getting started with Flutter, view our
|
||||
[online documentation](https://flutter.io/docs), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
@ -0,0 +1,13 @@
|
||||
arguments=
|
||||
auto.sync=false
|
||||
build.scans.enabled=false
|
||||
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
|
||||
connection.project.dir=
|
||||
eclipse.preferences.version=1
|
||||
gradle.user.home=
|
||||
java.home=/Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home
|
||||
jvm.arguments=
|
||||
offline.mode=false
|
||||
override.workspace.settings=true
|
||||
show.console.view=true
|
||||
show.executions.view=true
|
@ -0,0 +1,55 @@
|
||||
def localProperties = new Properties()
|
||||
def localPropertiesFile = rootProject.file('local.properties')
|
||||
if (localPropertiesFile.exists()) {
|
||||
localPropertiesFile.withReader('UTF-8') { reader ->
|
||||
localProperties.load(reader)
|
||||
}
|
||||
}
|
||||
|
||||
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
||||
if (flutterRoot == null) {
|
||||
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
||||
}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||
if (flutterVersionCode == null) {
|
||||
flutterVersionCode = '1'
|
||||
}
|
||||
|
||||
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
||||
if (flutterVersionName == null) {
|
||||
flutterVersionName = '1.0'
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
android {
|
||||
compileSdkVersion 33
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "com.baseflow.permissionhandler.example"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 33
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source '../..'
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.baseflow.permissionhandler.example">
|
||||
<!-- Flutter needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
@ -0,0 +1,103 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.baseflow.permissionhandler.example">
|
||||
|
||||
<!--
|
||||
Internet permissions do not affect the `permission_handler` plugin, but are required if your app needs access to
|
||||
the internet.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<!-- Permissions options for the `contacts` group -->
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
|
||||
|
||||
<!-- Permissions options for the `storage` group -->
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<!-- Permissions options for the `camera` group -->
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
|
||||
<!-- Permissions options for the `sms` group -->
|
||||
<uses-permission android:name="android.permission.SEND_SMS"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
|
||||
<uses-permission android:name="android.permission.READ_SMS"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
|
||||
|
||||
<!-- Permissions options for the `phone` group -->
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
|
||||
<uses-permission android:name="android.permission.CALL_PHONE"/>
|
||||
<uses-permission android:name="android.permission.ADD_VOICEMAIL"/>
|
||||
<uses-permission android:name="android.permission.USE_SIP"/>
|
||||
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
|
||||
|
||||
<!-- Permissions options for the `calendar` group -->
|
||||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||||
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
|
||||
|
||||
<!-- Permissions options for the `location` group -->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||
|
||||
<!-- Permissions options for the `microphone` or `speech` group -->
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
|
||||
<!-- Permissions options for the `sensors` group -->
|
||||
<uses-permission android:name="android.permission.BODY_SENSORS" />
|
||||
|
||||
<!-- Permissions options for the `accessMediaLocation` group -->
|
||||
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
|
||||
|
||||
<!-- Permissions options for the `activityRecognition` group -->
|
||||
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
|
||||
|
||||
<!-- Permissions options for the `ignoreBatteryOptimizations` group -->
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
|
||||
<!-- Permissions options for the `bluetooth` group -->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
|
||||
<!-- Permissions options for the `manage external storage` group -->
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||
|
||||
<!-- Permissions options for the `system alert windows` group -->
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
|
||||
<!-- Permissions options for the `request install packages` group -->
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
||||
<!-- Permissions options for the `access notification policy` group -->
|
||||
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>
|
||||
|
||||
<application
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="permission_handler_example"
|
||||
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
|
||||
|
||||
<activity android:name="io.flutter.embedding.android.FlutterActivity"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@android:style/Theme.Black.NoTitleBar"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
</manifest>
|
@ -0,0 +1,6 @@
|
||||
package com.example.example
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity: FlutterActivity() {
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
After Width: | Height: | Size: 544 B |
After Width: | Height: | Size: 442 B |
After Width: | Height: | Size: 721 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
Flutter draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
Flutter draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
</resources>
|
@ -0,0 +1,52 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.permissionhandlerexample">
|
||||
<!-- Flutter needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<!-- Permissions options for the `contacts` group -->
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
|
||||
|
||||
<!-- Permissions options for the `storage` group -->
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<!-- Permissions options for the `camera` group -->
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
|
||||
<!-- Permissions options for the `sms` group -->
|
||||
<uses-permission android:name="android.permission.SEND_SMS"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
|
||||
<uses-permission android:name="android.permission.READ_SMS"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
|
||||
|
||||
<!-- Permissions options for the `phone` group -->
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
|
||||
<uses-permission android:name="android.permission.CALL_PHONE"/>
|
||||
<uses-permission android:name="android.permission.ADD_VOICEMAIL"/>
|
||||
<uses-permission android:name="android.permission.USE_SIP"/>
|
||||
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
|
||||
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
|
||||
|
||||
<!-- Permissions options for the `calendar` group -->
|
||||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||||
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
|
||||
|
||||
<!-- Permissions options for the `location` group -->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
|
||||
<!-- Permissions options for the `microphone` or `speech` group -->
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
|
||||
<!-- Permissions options for the `sensors` group -->
|
||||
<uses-permission android:name="android.permission.BODY_SENSORS" />
|
||||
|
||||
<!-- Permissions options for the `access notification policy` group -->
|
||||
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>
|
||||
</manifest>
|
@ -0,0 +1,27 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.buildDir = '../build'
|
||||
subprojects {
|
||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||
project.evaluationDependsOn(':app')
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
@ -0,0 +1,6 @@
|
||||
#Fri Jun 23 08:50:38 CEST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
|
@ -0,0 +1,15 @@
|
||||
include ':app'
|
||||
|
||||
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
|
||||
|
||||
def plugins = new Properties()
|
||||
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
|
||||
if (pluginsFile.exists()) {
|
||||
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
|
||||
}
|
||||
|
||||
plugins.each { name, path ->
|
||||
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
|
||||
include ":$name"
|
||||
project(":$name").projectDir = pluginDirectory
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
import 'package:baseflow_plugin_template/baseflow_plugin_template.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart';
|
||||
|
||||
void main() {
|
||||
runApp(BaseflowPluginExample(
|
||||
pluginName: 'Permission Handler',
|
||||
githubURL: 'https://github.com/Baseflow/flutter-permission-handler',
|
||||
pubDevURL: 'https://pub.dev/packages/permission_handler',
|
||||
pages: [PermissionHandlerWidget.createPage()]));
|
||||
}
|
||||
|
||||
///Defines the main theme color
|
||||
final MaterialColor themeMaterialColor =
|
||||
BaseflowPluginExample.createMaterialColor(
|
||||
const Color.fromRGBO(48, 49, 60, 1));
|
||||
|
||||
/// A Flutter application demonstrating the functionality of this plugin
|
||||
class PermissionHandlerWidget extends StatefulWidget {
|
||||
/// Create a page containing the functionality of this plugin
|
||||
static ExamplePage createPage() {
|
||||
return ExamplePage(
|
||||
Icons.location_on, (context) => PermissionHandlerWidget());
|
||||
}
|
||||
|
||||
@override
|
||||
_PermissionHandlerWidgetState createState() =>
|
||||
_PermissionHandlerWidgetState();
|
||||
}
|
||||
|
||||
class _PermissionHandlerWidgetState extends State<PermissionHandlerWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: ListView(
|
||||
children: Permission.values
|
||||
.where((permission) {
|
||||
return permission != Permission.unknown &&
|
||||
permission != Permission.mediaLibrary &&
|
||||
permission != Permission.photos &&
|
||||
permission != Permission.photosAddOnly &&
|
||||
permission != Permission.reminders &&
|
||||
permission != Permission.appTrackingTransparency &&
|
||||
permission != Permission.criticalAlerts;
|
||||
})
|
||||
.map((permission) => PermissionWidget(permission))
|
||||
.toList()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Permission widget containing information about the passed [Permission]
|
||||
class PermissionWidget extends StatefulWidget {
|
||||
/// Constructs a [PermissionWidget] for the supplied [Permission]
|
||||
const PermissionWidget(this._permission);
|
||||
|
||||
final Permission _permission;
|
||||
|
||||
@override
|
||||
_PermissionState createState() => _PermissionState(_permission);
|
||||
}
|
||||
|
||||
class _PermissionState extends State<PermissionWidget> {
|
||||
_PermissionState(this._permission);
|
||||
|
||||
final Permission _permission;
|
||||
final PermissionHandlerPlatform _permissionHandler =
|
||||
PermissionHandlerPlatform.instance;
|
||||
PermissionStatus _permissionStatus = PermissionStatus.denied;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_listenForPermissionStatus();
|
||||
}
|
||||
|
||||
void _listenForPermissionStatus() async {
|
||||
final status = await _permissionHandler.checkPermissionStatus(_permission);
|
||||
setState(() => _permissionStatus = status);
|
||||
}
|
||||
|
||||
Color getPermissionColor() {
|
||||
switch (_permissionStatus) {
|
||||
case PermissionStatus.denied:
|
||||
return Colors.red;
|
||||
case PermissionStatus.granted:
|
||||
return Colors.green;
|
||||
case PermissionStatus.limited:
|
||||
return Colors.orange;
|
||||
default:
|
||||
return Colors.grey;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
title: Text(
|
||||
_permission.toString(),
|
||||
style: Theme.of(context).textTheme.bodyText1,
|
||||
),
|
||||
subtitle: Text(
|
||||
_permissionStatus.toString(),
|
||||
style: TextStyle(color: getPermissionColor()),
|
||||
),
|
||||
trailing: (_permission is PermissionWithService)
|
||||
? IconButton(
|
||||
icon: const Icon(
|
||||
Icons.info,
|
||||
color: Colors.white,
|
||||
),
|
||||
onPressed: () {
|
||||
checkServiceStatus(
|
||||
context, _permission as PermissionWithService);
|
||||
})
|
||||
: null,
|
||||
onTap: () {
|
||||
requestPermission(_permission);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void checkServiceStatus(
|
||||
BuildContext context, PermissionWithService permission) async {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text(
|
||||
(await _permissionHandler.checkServiceStatus(permission)).toString()),
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> requestPermission(Permission permission) async {
|
||||
final status = await _permissionHandler.requestPermissions([permission]);
|
||||
|
||||
setState(() {
|
||||
print(status);
|
||||
_permissionStatus = status[permission] ?? PermissionStatus.denied;
|
||||
print(_permissionStatus);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,245 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.8.2"
|
||||
baseflow_plugin_template:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "v2.1.0"
|
||||
resolved-ref: "0695ef43c098d75efffe5fd6212390b853f05bf7"
|
||||
url: "https://github.com/Baseflow/baseflow_plugin_template.git"
|
||||
source: git
|
||||
version: "2.1.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.16.0"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.4"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.11"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.4"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.1"
|
||||
permission_handler_android:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "10.0.0"
|
||||
permission_handler_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.7.0"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.9"
|
||||
url_launcher:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: url_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.5"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.17"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.17"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
url_launcher_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.12"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
sdks:
|
||||
dart: ">=2.17.0-0 <3.0.0"
|
||||
flutter: ">=2.10.0"
|
@ -0,0 +1,37 @@
|
||||
name: permission_handler_android_example
|
||||
description: Demonstrates how to use the permission_handler_android plugin.
|
||||
|
||||
environment:
|
||||
sdk: ">=2.15.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
baseflow_plugin_template:
|
||||
git:
|
||||
url: https://github.com/Baseflow/baseflow_plugin_template.git
|
||||
ref: v2.1.0
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
permission_handler_android:
|
||||
# When depending on this package from a real application you should use:
|
||||
# permission_handler_android: ^x.y.z
|
||||
# See https://dart.dev/tools/pub/dependencies#version-constraints
|
||||
# The example app is bundled with the plugin so we use a path dependency on
|
||||
# the parent directory to use the current plugin's version.
|
||||
path: ../
|
||||
|
||||
url_launcher: ^6.0.12
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
||||
assets:
|
||||
- res/images/baseflow_logo_def_light-02.png
|
||||
- res/images/poweredByBaseflowLogoLight@3x.png
|
||||
- packages/baseflow_plugin_template/logo.png
|
||||
- packages/baseflow_plugin_template/poweredByBaseflow.png
|
||||
|
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 17 KiB |
@ -0,0 +1,79 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.16.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: lints
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.4"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
permission_handler_platform_interface:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: permission_handler_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.7.0"
|
||||
plugin_platform_interface:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
sdks:
|
||||
dart: ">=2.15.0 <3.0.0"
|
||||
flutter: ">=2.8.0"
|
@ -0,0 +1,25 @@
|
||||
name: permission_handler_android
|
||||
description: Permission plugin for Flutter. This plugin provides the Android API to request and check permissions.
|
||||
version: 10.0.0
|
||||
homepage: https://github.com/baseflow/flutter-permission-handler
|
||||
|
||||
environment:
|
||||
sdk: ">=2.15.0 <3.0.0"
|
||||
flutter: ">=2.8.0"
|
||||
|
||||
flutter:
|
||||
plugin:
|
||||
implements: permission_handler
|
||||
platforms:
|
||||
android:
|
||||
package: com.baseflow.permissionhandler
|
||||
pluginClass: PermissionHandlerPlugin
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
permission_handler_platform_interface: ^3.7.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^1.0.4
|
||||
plugin_platform_interface: ^2.0.0
|