diff --git a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ActivityHostApiImpl.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ActivityHostApiImpl.java
index 871bdc953..694b6a8d3 100644
--- a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ActivityHostApiImpl.java
+++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ActivityHostApiImpl.java
@@ -2,6 +2,7 @@
import android.app.Activity;
import android.content.Intent;
+import android.os.PowerManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -53,6 +54,8 @@ public class ActivityHostApiImpl implements
private final InstanceManager instanceManager;
+ private final PowerManagerFlutterApiImpl powerManagerFlutterApi;
+
/**
* Callbacks to complete a pending permission request.
*
@@ -62,7 +65,7 @@ public class ActivityHostApiImpl implements
private final Map> pendingPermissionsRequestMap = new HashMap<>();
/**
- * Callback to complete a pending activity-for-result request.
+ * Callbacks to complete a pending activity-for-result request.
*
* These callbacks are set in {@link this#startActivityForResult(String, String, Long, Result)},
* and are completed in {@link this#onActivityResult(int, int, Intent)}.
@@ -76,9 +79,11 @@ public class ActivityHostApiImpl implements
* @param instanceManager maintains instances stored to communicate with attached Dart objects
*/
public ActivityHostApiImpl(
+ @NonNull PowerManagerFlutterApiImpl powerManagerFlutterApi,
@NonNull BinaryMessenger binaryMessenger,
@NonNull InstanceManager instanceManager
) {
+ this.powerManagerFlutterApi = powerManagerFlutterApi;
this.binaryMessenger = binaryMessenger;
this.instanceManager = instanceManager;
}
@@ -219,4 +224,22 @@ public boolean onActivityResult(
return true;
}
+
+ @Override
+ @NonNull public String getSystemService(
+ @NonNull String instanceId,
+ @NonNull String name
+ ) {
+ final UUID instanceUuid = UUID.fromString(instanceId);
+ final Activity activity = instanceManager.getInstance(instanceUuid);
+
+ final Object systemService = activity.getSystemService(name);
+
+ if (systemService instanceof PowerManager) {
+ powerManagerFlutterApi.create((PowerManager) systemService);
+ }
+
+ final UUID systemServiceUuid = instanceManager.getIdentifierForStrongReference(systemService);
+ return systemServiceUuid.toString();
+ }
}
diff --git a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/BuildVersionHostApiImpl.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/BuildVersionHostApiImpl.java
new file mode 100644
index 000000000..8bff93500
--- /dev/null
+++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/BuildVersionHostApiImpl.java
@@ -0,0 +1,21 @@
+package com.baseflow.permissionhandler;
+
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+
+import com.baseflow.permissionhandler.PermissionHandlerPigeon.BuildVersionHostApi;
+
+/**
+ * Host API implementation for `Build.VERSION`.
+ *
+ *
This class may handle instantiating and adding native object instances that are attached to a
+ * Dart instance or handle method calls on the associated native class or an instance of the class.
+ */
+public class BuildVersionHostApiImpl implements BuildVersionHostApi {
+ @NonNull
+ @Override
+ public Long sdkInt() {
+ return (long) Build.VERSION.SDK_INT;
+ }
+}
diff --git a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ContextHostApiImpl.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ContextHostApiImpl.java
index 6a96dbb94..c15644750 100644
--- a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ContextHostApiImpl.java
+++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/ContextHostApiImpl.java
@@ -2,6 +2,7 @@
import android.content.Context;
import android.content.Intent;
+import android.os.PowerManager;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
@@ -26,6 +27,8 @@ public class ContextHostApiImpl implements ContextHostApi {
private final InstanceManager instanceManager;
+ private final PowerManagerFlutterApiImpl powerManagerFlutterApi;
+
/**
* Constructs an {@link ContextHostApiImpl}.
*
@@ -33,9 +36,11 @@ public class ContextHostApiImpl implements ContextHostApi {
* @param instanceManager maintains instances stored to communicate with attached Dart objects
*/
public ContextHostApiImpl(
+ @NonNull PowerManagerFlutterApiImpl powerManagerFlutterApi,
@NonNull BinaryMessenger binaryMessenger,
@NonNull InstanceManager instanceManager
) {
+ this.powerManagerFlutterApi = powerManagerFlutterApi;
this.binaryMessenger = binaryMessenger;
this.instanceManager = instanceManager;
}
@@ -74,4 +79,22 @@ public void startActivity(
return context.getPackageName();
}
+
+ @Override
+ @NonNull public String getSystemService(
+ @NonNull String instanceId,
+ @NonNull String name
+ ) {
+ final UUID instanceUuid = UUID.fromString(instanceId);
+ final Context context = instanceManager.getInstance(instanceUuid);
+
+ final Object systemService = context.getSystemService(name);
+
+ if (systemService instanceof PowerManager) {
+ powerManagerFlutterApi.create((PowerManager) systemService);
+ }
+
+ final UUID systemServiceUuid = instanceManager.getIdentifierForStrongReference(systemService);
+ return systemServiceUuid.toString();
+ }
}
diff --git a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPigeon.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPigeon.java
index b402b5f4f..a753a32fa 100644
--- a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPigeon.java
+++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPigeon.java
@@ -340,6 +340,17 @@ public interface ActivityHostApi {
*/
@NonNull
String getPackageName(@NonNull String instanceId);
+ /**
+ * Return the handle to a system-level service by name.
+ *
+ * The class of the returned object varies by the requested name.
+ *
+ * Returns the instance ID of the service.
+ *
+ * See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String).
+ */
+ @NonNull
+ String getSystemService(@NonNull String instanceId, @NonNull String name);
/**
* Start an activity for which the application would like a result when it finished.
*
@@ -473,6 +484,31 @@ public void error(Throwable error) {
String output = api.getPackageName(instanceIdArg);
wrapped.add(0, output);
}
+ catch (Throwable exception) {
+ ArrayList wrappedError = wrapError(exception);
+ wrapped = wrappedError;
+ }
+ reply.reply(wrapped);
+ });
+ } else {
+ channel.setMessageHandler(null);
+ }
+ }
+ {
+ BasicMessageChannel channel =
+ new BasicMessageChannel<>(
+ binaryMessenger, "dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getSystemService", getCodec());
+ if (api != null) {
+ channel.setMessageHandler(
+ (message, reply) -> {
+ ArrayList wrapped = new ArrayList();
+ ArrayList args = (ArrayList) message;
+ String instanceIdArg = (String) args.get(0);
+ String nameArg = (String) args.get(1);
+ try {
+ String output = api.getSystemService(instanceIdArg, nameArg);
+ wrapped.add(0, output);
+ }
catch (Throwable exception) {
ArrayList wrappedError = wrapError(exception);
wrapped = wrappedError;
@@ -594,6 +630,17 @@ public interface ContextHostApi {
*/
@NonNull
String getPackageName(@NonNull String instanceId);
+ /**
+ * Return the handle to a system-level service by name.
+ *
+ * The class of the returned object varies by the requested name.
+ *
+ * Returns the instance ID of the service.
+ *
+ * See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String).
+ */
+ @NonNull
+ String getSystemService(@NonNull String instanceId, @NonNull String name);
/** The codec used by ContextHostApi. */
static @NonNull MessageCodec getCodec() {
@@ -665,6 +712,31 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable ContextHos
String output = api.getPackageName(instanceIdArg);
wrapped.add(0, output);
}
+ catch (Throwable exception) {
+ ArrayList wrappedError = wrapError(exception);
+ wrapped = wrappedError;
+ }
+ reply.reply(wrapped);
+ });
+ } else {
+ channel.setMessageHandler(null);
+ }
+ }
+ {
+ BasicMessageChannel channel =
+ new BasicMessageChannel<>(
+ binaryMessenger, "dev.flutter.pigeon.permission_handler_android.ContextHostApi.getSystemService", getCodec());
+ if (api != null) {
+ channel.setMessageHandler(
+ (message, reply) -> {
+ ArrayList wrapped = new ArrayList();
+ ArrayList args = (ArrayList) message;
+ String instanceIdArg = (String) args.get(0);
+ String nameArg = (String) args.get(1);
+ try {
+ String output = api.getSystemService(instanceIdArg, nameArg);
+ wrapped.add(0, output);
+ }
catch (Throwable exception) {
ArrayList wrappedError = wrapError(exception);
wrapped = wrappedError;
@@ -992,4 +1064,165 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable IntentHost
}
}
}
+ /**
+ * Host API for `PowerManager`.
+ *
+ * This class may handle instantiating and adding native object instances that
+ * are attached to a Dart instance or handle method calls on the associated
+ * native class or an instance of the class.
+ *
+ * See https://developer.android.com/reference/android/os/PowerManager.
+ *
+ * Generated interface from Pigeon that represents a handler of messages from Flutter.
+ */
+ public interface PowerManagerHostApi {
+ /**
+ * Returns whether the given application package name is on the device's power allowlist.
+ *
+ * Apps can be placed on the allowlist through the settings UI invoked by
+ * [Settings.actionRequestIgnoreBatteryOptimizations].
+ *
+ * Being on the power allowlist means that the system will not apply most
+ * power saving features to the app. Guardrails for extreme cases may still
+ * be applied.
+ *
+ * See https://developer.android.com/reference/android/os/PowerManager#isIgnoringBatteryOptimizations(java.lang.String).
+ */
+ @NonNull
+ Boolean isIgnoringBatteryOptimizations(@NonNull String instanceId, @NonNull String packageName);
+
+ /** The codec used by PowerManagerHostApi. */
+ static @NonNull MessageCodec getCodec() {
+ return new StandardMessageCodec();
+ }
+ /**Sets up an instance of `PowerManagerHostApi` to handle messages through the `binaryMessenger`. */
+ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable PowerManagerHostApi api) {
+ {
+ BasicMessageChannel channel =
+ new BasicMessageChannel<>(
+ binaryMessenger, "dev.flutter.pigeon.permission_handler_android.PowerManagerHostApi.isIgnoringBatteryOptimizations", getCodec());
+ if (api != null) {
+ channel.setMessageHandler(
+ (message, reply) -> {
+ ArrayList wrapped = new ArrayList();
+ ArrayList args = (ArrayList) message;
+ String instanceIdArg = (String) args.get(0);
+ String packageNameArg = (String) args.get(1);
+ try {
+ Boolean output = api.isIgnoringBatteryOptimizations(instanceIdArg, packageNameArg);
+ wrapped.add(0, output);
+ }
+ catch (Throwable exception) {
+ ArrayList wrappedError = wrapError(exception);
+ wrapped = wrappedError;
+ }
+ reply.reply(wrapped);
+ });
+ } else {
+ channel.setMessageHandler(null);
+ }
+ }
+ }
+ }
+ /**
+ * Flutter API for `PowerManager`.
+ *
+ * This class may handle instantiating and adding Dart instances that are
+ * attached to a native instance or receiving callback methods from an
+ * overridden native class.
+ *
+ * See https://developer.android.com/reference/android/os/PowerManager.
+ *
+ * Generated class from Pigeon that represents Flutter messages that can be called from Java.
+ */
+ public static class PowerManagerFlutterApi {
+ private final @NonNull BinaryMessenger binaryMessenger;
+
+ public PowerManagerFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) {
+ this.binaryMessenger = argBinaryMessenger;
+ }
+
+ /** Public interface for sending reply. */
+ @SuppressWarnings("UnknownNullness")
+ public interface Reply {
+ void reply(T reply);
+ }
+ /** The codec used by PowerManagerFlutterApi. */
+ static @NonNull MessageCodec getCodec() {
+ return new StandardMessageCodec();
+ }
+ /** Create a new Dart instance and add it to the `InstanceManager`. */
+ public void create(@NonNull String instanceIdArg, @NonNull Reply callback) {
+ BasicMessageChannel channel =
+ new BasicMessageChannel<>(
+ binaryMessenger, "dev.flutter.pigeon.permission_handler_android.PowerManagerFlutterApi.create", getCodec());
+ channel.send(
+ new ArrayList(Collections.singletonList(instanceIdArg)),
+ channelReply -> callback.reply(null));
+ }
+ /** Dispose of the Dart instance and remove it from the `InstanceManager`. */
+ public void dispose(@NonNull String instanceIdArg, @NonNull Reply callback) {
+ BasicMessageChannel channel =
+ new BasicMessageChannel<>(
+ binaryMessenger, "dev.flutter.pigeon.permission_handler_android.PowerManagerFlutterApi.dispose", getCodec());
+ channel.send(
+ new ArrayList(Collections.singletonList(instanceIdArg)),
+ channelReply -> callback.reply(null));
+ }
+ }
+ /**
+ * Host API for `BuildVersion`.
+ *
+ * This class may handle instantiating and adding native object instances that
+ * are attached to a Dart instance or handle method calls on the associated
+ * native class or an instance of the class.
+ *
+ * See https://developer.android.com/reference/android/os/Build.VERSION.
+ *
+ * Generated interface from Pigeon that represents a handler of messages from Flutter.
+ */
+ public interface BuildVersionHostApi {
+ /**
+ * The SDK version of the software currently running on this hardware device.
+ *
+ * This value never changes while a device is booted, but it may increase
+ * when the hardware manufacturer provides an OTA update.
+ *
+ * Possible values are defined in [Build.versionCodes].
+ *
+ * See https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT.
+ */
+ @NonNull
+ Long sdkInt();
+
+ /** The codec used by BuildVersionHostApi. */
+ static @NonNull MessageCodec getCodec() {
+ return new StandardMessageCodec();
+ }
+ /**Sets up an instance of `BuildVersionHostApi` to handle messages through the `binaryMessenger`. */
+ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable BuildVersionHostApi api) {
+ {
+ BasicMessageChannel channel =
+ new BasicMessageChannel<>(
+ binaryMessenger, "dev.flutter.pigeon.permission_handler_android.BuildVersionHostApi.sdkInt", getCodec());
+ if (api != null) {
+ channel.setMessageHandler(
+ (message, reply) -> {
+ ArrayList wrapped = new ArrayList();
+ try {
+ Long output = api.sdkInt();
+ wrapped.add(0, output);
+ }
+ catch (Throwable exception) {
+ ArrayList wrappedError = wrapError(exception);
+ wrapped = wrappedError;
+ }
+ reply.reply(wrapped);
+ });
+ } else {
+ channel.setMessageHandler(null);
+ }
+ }
+ }
+ }
}
diff --git a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPlugin.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPlugin.java
index 692a6237b..e8c2ab094 100644
--- a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPlugin.java
+++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PermissionHandlerPlugin.java
@@ -11,8 +11,10 @@
import com.baseflow.instancemanager.InstanceManagerPigeon.InstanceManagerHostApi;
import com.baseflow.instancemanager.JavaObjectHostApiImpl;
import com.baseflow.permissionhandler.PermissionHandlerPigeon.ActivityHostApi;
+import com.baseflow.permissionhandler.PermissionHandlerPigeon.BuildVersionHostApi;
import com.baseflow.permissionhandler.PermissionHandlerPigeon.ContextHostApi;
import com.baseflow.permissionhandler.PermissionHandlerPigeon.IntentHostApi;
+import com.baseflow.permissionhandler.PermissionHandlerPigeon.PowerManagerHostApi;
import com.baseflow.permissionhandler.PermissionHandlerPigeon.UriHostApi;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
@@ -50,19 +52,34 @@ private void setUp(
final JavaObjectHostApi javaObjectHostApi = new JavaObjectHostApiImpl(instanceManager);
JavaObjectHostApi.setup(binaryMessenger, javaObjectHostApi);
+ final UriHostApi uriHostApi = new UriHostApiImpl(binaryMessenger, instanceManager);
+ UriHostApi.setup(binaryMessenger, uriHostApi);
+
+ final IntentHostApi intentHostApi = new IntentHostApiImpl(binaryMessenger, instanceManager);
+ IntentHostApi.setup(binaryMessenger, intentHostApi);
+
+ final PowerManagerFlutterApiImpl powerManagerFlutterApi = new PowerManagerFlutterApiImpl(binaryMessenger, instanceManager);
+ final PowerManagerHostApi powerManagerHostApi = new PowerManagerHostApiImpl(binaryMessenger, instanceManager);
+ PowerManagerHostApi.setup(binaryMessenger, powerManagerHostApi);
+
activityFlutterApi = new ActivityFlutterApiImpl(binaryMessenger, instanceManager);
- activityHostApi = new ActivityHostApiImpl(binaryMessenger, instanceManager);
+ activityHostApi = new ActivityHostApiImpl(
+ powerManagerFlutterApi,
+ binaryMessenger,
+ instanceManager
+ );
ActivityHostApi.setup(binaryMessenger, activityHostApi);
contextFlutterApi = new ContextFlutterApiImpl(binaryMessenger, instanceManager);
- final ContextHostApiImpl contextHostApi = new ContextHostApiImpl(binaryMessenger, instanceManager);
+ final ContextHostApiImpl contextHostApi = new ContextHostApiImpl(
+ powerManagerFlutterApi,
+ binaryMessenger,
+ instanceManager
+ );
ContextHostApi.setup(binaryMessenger, contextHostApi);
- final UriHostApi uriHostApi = new UriHostApiImpl(binaryMessenger, instanceManager);
- UriHostApi.setup(binaryMessenger, uriHostApi);
-
- final IntentHostApi intentHostApi = new IntentHostApiImpl(binaryMessenger, instanceManager);
- IntentHostApi.setup(binaryMessenger, intentHostApi);
+ final BuildVersionHostApi buildVersionHostApi = new BuildVersionHostApiImpl();
+ BuildVersionHostApi.setup(binaryMessenger, buildVersionHostApi);
}
@Override
diff --git a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PowerManagerFlutterApiImpl.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PowerManagerFlutterApiImpl.java
new file mode 100644
index 000000000..306f36155
--- /dev/null
+++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PowerManagerFlutterApiImpl.java
@@ -0,0 +1,66 @@
+package com.baseflow.permissionhandler;
+
+import android.os.PowerManager;
+
+import androidx.annotation.NonNull;
+
+import com.baseflow.instancemanager.InstanceManager;
+import com.baseflow.permissionhandler.PermissionHandlerPigeon.PowerManagerFlutterApi;
+
+import java.util.UUID;
+
+import io.flutter.plugin.common.BinaryMessenger;
+
+/**
+ * Flutter API implementation for `PowerManager`.
+ *
+ * This class may handle adding native instances that are attached to a Dart instance or passing
+ * arguments of callbacks methods to a Dart instance.
+ */
+public class PowerManagerFlutterApiImpl {
+ // To ease adding additional methods, this value is added prematurely.
+ @SuppressWarnings({"unused", "FieldCanBeLocal"})
+ private final BinaryMessenger binaryMessenger;
+
+ private final InstanceManager instanceManager;
+
+ private final PowerManagerFlutterApi api;
+
+ /**
+ * Constructs a {@link PowerManagerFlutterApiImpl}.
+ *
+ * @param binaryMessenger used to communicate with Dart over asynchronous messages
+ * @param instanceManager maintains instances stored to communicate with attached Dart objects
+ */
+ public PowerManagerFlutterApiImpl(
+ @NonNull BinaryMessenger binaryMessenger,
+ @NonNull InstanceManager instanceManager
+ ) {
+ this.binaryMessenger = binaryMessenger;
+ this.instanceManager = instanceManager;
+ api = new PowerManagerFlutterApi(binaryMessenger);
+ }
+
+ /**
+ * Stores the `PowerManager` instance and notifies Dart to create and store a new `PowerManager`
+ * instance that is attached to this one. If `instance` has already been added, this method does
+ * nothing.
+ */
+ public void create(@NonNull PowerManager instance) {
+ if (!instanceManager.containsInstance(instance)) {
+ final UUID powerManagerInstanceUuid = instanceManager.addHostCreatedInstance(instance);
+ api.create(powerManagerInstanceUuid.toString(), reply -> {});
+ }
+ }
+
+ /**
+ * Disposes of the `PowerManager` instance in the instance manager and notifies Dart to do the
+ * same. If `instance` was already disposed, this method does nothing.
+ */
+ public void dispose(PowerManager instance) {
+ final UUID powerManagerInstanceUuid = instanceManager.getIdentifierForStrongReference(instance);
+ if (powerManagerInstanceUuid != null) {
+ api.dispose(powerManagerInstanceUuid.toString(), reply -> {});
+ }
+ }
+}
diff --git a/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PowerManagerHostApiImpl.java b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PowerManagerHostApiImpl.java
new file mode 100644
index 000000000..3c6936126
--- /dev/null
+++ b/permission_handler_android/android/src/main/java/com/baseflow/permissionhandler/PowerManagerHostApiImpl.java
@@ -0,0 +1,52 @@
+package com.baseflow.permissionhandler;
+
+import android.os.Build;
+import android.os.PowerManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+
+import com.baseflow.instancemanager.InstanceManager;
+import com.baseflow.permissionhandler.PermissionHandlerPigeon.PowerManagerHostApi;
+
+import java.util.UUID;
+
+import io.flutter.plugin.common.BinaryMessenger;
+
+/**
+ * Host API implementation for `PowerManager`.
+ *
+ *
This class may handle instantiating and adding native object instances that are attached to a
+ * Dart instance or handle method calls on the associated native class or an instance of the class.
+ */
+public class PowerManagerHostApiImpl implements PowerManagerHostApi {
+ // To ease adding additional methods, this value is added prematurely.
+ @SuppressWarnings({"unused", "FieldCanBeLocal"})
+ private final BinaryMessenger binaryMessenger;
+
+ private final InstanceManager instanceManager;
+
+ /**
+ * Constructs an {@link PowerManagerHostApiImpl}.
+ *
+ * @param binaryMessenger used to communicate with Dart over asynchronous messages
+ * @param instanceManager maintains instances stored to communicate with attached Dart objects
+ */
+ public PowerManagerHostApiImpl(
+ @NonNull BinaryMessenger binaryMessenger,
+ @NonNull InstanceManager instanceManager
+ ) {
+ this.binaryMessenger = binaryMessenger;
+ this.instanceManager = instanceManager;
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.M)
+ @NonNull
+ @Override
+ public Boolean isIgnoringBatteryOptimizations(@NonNull String instanceId, @NonNull String packageName) {
+ final UUID instanceUuid = UUID.fromString(instanceId);
+ final PowerManager powerManager = instanceManager.getInstance(instanceUuid);
+
+ return powerManager.isIgnoringBatteryOptimizations(packageName);
+ }
+}
diff --git a/permission_handler_android/lib/permission_handler_android.dart b/permission_handler_android/lib/permission_handler_android.dart
index e806932db..efce2d675 100644
--- a/permission_handler_android/lib/permission_handler_android.dart
+++ b/permission_handler_android/lib/permission_handler_android.dart
@@ -1,13 +1,14 @@
export 'src/android_object_mirrors/activity.dart';
+export 'src/android_object_mirrors/build.dart';
export 'src/android_object_mirrors/context.dart';
export 'src/android_object_mirrors/intent.dart';
export 'src/android_object_mirrors/manifest.dart';
export 'src/android_object_mirrors/package_manager.dart';
+export 'src/android_object_mirrors/power_manager.dart';
export 'src/android_object_mirrors/settings.dart';
export 'src/android_object_mirrors/uri.dart';
export 'src/activity_aware.dart';
export 'src/activity_manager.dart';
export 'src/extensions.dart';
-export 'src/missing_activity_exception.dart';
export 'src/permission_handler_android.dart';
diff --git a/permission_handler_android/lib/src/android_object_mirrors/activity.dart b/permission_handler_android/lib/src/android_object_mirrors/activity.dart
index 2b7ac957e..30ecda27a 100644
--- a/permission_handler_android/lib/src/android_object_mirrors/activity.dart
+++ b/permission_handler_android/lib/src/android_object_mirrors/activity.dart
@@ -116,6 +116,22 @@ class Activity extends JavaObject {
requestCode,
);
}
+
+ /// Return the handle to a system-level service by name.
+ ///
+ /// The class of the returned object varies by the requested name.
+ ///
+ /// Returns the instance ID of the service.
+ ///
+ /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String).
+ Future getSystemService(
+ String name,
+ ) {
+ return _hostApi.getSystemServiceFromInstance(
+ this,
+ name,
+ );
+ }
}
/// Result of an activity-for-result request.
diff --git a/permission_handler_android/lib/src/android_object_mirrors/build.dart b/permission_handler_android/lib/src/android_object_mirrors/build.dart
new file mode 100644
index 000000000..53ed428d2
--- /dev/null
+++ b/permission_handler_android/lib/src/android_object_mirrors/build.dart
@@ -0,0 +1,362 @@
+import '../android_permission_handler_api_impls.dart';
+
+/// Information about the current build, extracted from system properties.
+///
+/// See https://developer.android.com/reference/android/os/Build
+class Build {
+ Build._();
+
+ /// Various version strings.
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION
+ static _Version get version => _version;
+ static const _Version _version = _Version();
+
+ /// Enumeration of the currently known SDK version codes.
+ ///
+ /// These are the values that can be found in VERSION#SDK. Version numbers
+ /// increment monotonically with each official platform release.
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES
+ static _VersionCodes get versionCodes => _versionCodes;
+ static const _VersionCodes _versionCodes = _VersionCodes();
+}
+
+/// Various version strings.
+///
+/// See https://developer.android.com/reference/android/os/Build.VERSION
+class _Version {
+ const _Version();
+
+ /// The SDK version of the software currently running on this hardware device.
+ ///
+ /// This value never changes while a device is booted, but it may increase
+ /// when the hardware manufacturer provides an OTA update.
+ ///
+ /// Possible values are defined in [Build.versionCodes].
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT.
+ Future get sdkInt async => await _hostApi.sdkInt();
+
+ static final BuildVersionHostApiImpl _hostApi = BuildVersionHostApiImpl();
+}
+
+/// Enumeration of the currently known SDK version codes.
+///
+/// These are the values that can be found in VERSION#SDK_INT. Version numbers
+/// increment monotonically with each official platform release.
+///
+/// See https://developer.android.com/reference/android/os/Build.VERSION_CODES
+class _VersionCodes {
+ const _VersionCodes();
+
+ /// The original, first, version of Android. Yay!
+ ///
+ /// Released publicly as Android 1.0 in September 2008.
+ ///
+ /// Constant Value: 1 (0x00000001).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#BASE
+ int get base => 1;
+
+ /// First Android update.
+ ///
+ /// Released publicly as Android 1.1 in February 2009.
+ ///
+ /// Constant Value: 2 (0x00000002).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#BASE_1_1
+ int get base1_1 => 2;
+
+ /// C.
+ ///
+ /// Released publicly as Android 1.5 in April 2009.
+ ///
+ /// Constant Value: 3 (0x00000003).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#CUPCAKE
+ int get cupcake => 3;
+
+ /// CUR_DEVELOPMENT.
+ ///
+ /// Magic version number for a current development build, which has not yet
+ /// turned into an official release.
+ ///
+ /// Constant Value: 10000 (0x00002710).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#CUR_DEVELOPMENT
+ int get curDevelopment => 10000;
+
+ /// D.
+ ///
+ /// Released publicly as Android 1.6 in September 2009.
+ ///
+ /// Constant Value: 4 (0x00000004).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#DONUT
+ int get donut => 4;
+
+ /// E.
+ ///
+ /// Released publicly as Android 2.0 in October 2009.
+ ///
+ /// Constant Value: 5 (0x00000005).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#ECLAIR
+ int get eclair => 5;
+
+ /// E incremental update.
+ ///
+ /// Released publicly as Android 2.0.1 in December 2009.
+ ///
+ /// Constant Value: 6 (0x00000006).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#ECLAIR_0_1
+ int get eclair0_1 => 6;
+
+ /// E MR1.
+ ///
+ /// Released publicly as Android 2.1 in January 2010.
+ ///
+ /// Constant Value: 7 (0x00000007).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#ECLAIR_MR1
+ int get eclairMR1 => 7;
+
+ /// F.
+ ///
+ /// Released publicly as Android 2.2 in May 2010.
+ ///
+ /// Constant Value: 8 (0x00000008).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#FROYO
+ int get froyo => 8;
+
+ /// G.
+ ///
+ /// Released publicly as Android 2.3 in December 2010.
+ ///
+ /// Constant Value: 9 (0x00000009).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#GINGERBREAD
+ int get gingerbread => 9;
+
+ /// G MR1.
+ ///
+ /// Released publicly as Android 2.3.3 in February 2011.
+ ///
+ /// Constant Value: 10 (0x0000000a).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#GINGERBREAD_MR1
+ int get gingerbreadMR1 => 10;
+
+ /// H.
+ ///
+ /// Released publicly as Android 3.0 in February 2011.
+ ///
+ /// Constant Value: 11 (0x0000000b).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#HONEYCOMB
+ int get honeycomb => 11;
+
+ /// H MR1.
+ ///
+ /// Released publicly as Android 3.1 in May 2011.
+ ///
+ /// Constant Value: 12 (0x0000000c).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#HONEYCOMB_MR1
+ int get honeycombMR1 => 12;
+
+ /// H MR2.
+ ///
+ /// Released publicly as Android 3.2 in July 2011.
+ ///
+ /// Constant Value: 13 (0x0000000d).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#HONEYCOMB_MR2
+ int get honeycombMR2 => 13;
+
+ /// I.
+ ///
+ /// Released publicly as Android 4.0 in October 2011.
+ ///
+ /// Constant Value: 14 (0x0000000e).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#ICE_CREAM_SANDWICH
+ int get iceCreamSandwich => 14;
+
+ /// I MR1.
+ ///
+ /// Released publicly as Android 4.0.3 in December 2011.
+ ///
+ /// Constant Value: 15 (0x0000000f).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1
+ int get iceCreamSandwichMR1 => 15;
+
+ /// J.
+ ///
+ /// Released publicly as Android 4.1 in July 2012.
+ ///
+ /// Constant Value: 16 (0x00000010).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#JELLY_BEAN
+ int get jellyBean => 16;
+
+ /// J MR1.
+ ///
+ /// Released publicly as Android 4.2 in November 2012.
+ ///
+ /// Constant Value: 17 (0x00000011).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#JELLY_BEAN_MR1
+ int get jellyBeanMR1 => 17;
+
+ /// J MR2.
+ ///
+ /// Released publicly as Android 4.3 in July 2013.
+ ///
+ /// Constant Value: 18 (0x00000012).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#JELLY_BEAN_MR2
+ int get jellyBeanMR2 => 18;
+
+ /// K.
+ ///
+ /// Released publicly as Android 4.4 in October 2013.
+ ///
+ /// Constant Value: 19 (0x00000013).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#KITKAT
+ int get kitKat => 19;
+
+ /// K for watches.
+ ///
+ /// Released publicly as Android 4.4W in June 2014.
+ ///
+ /// Constant Value: 20 (0x00000014).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#KITKAT_WATCH
+ int get kitKatWatch => 20;
+
+ /// L.
+ ///
+ /// Released publicly as Android 5.0 in November 2014.
+ ///
+ /// Constant Value: 21 (0x00000015).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#LOLLIPOP
+ int get lollipop => 21;
+
+ /// L MR1.
+ ///
+ /// Released publicly as Android 5.1 in March 2015.
+ ///
+ /// Constant Value: 22 (0x00000016).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#LOLLIPOP_MR1
+ int get lollipopMR1 => 22;
+
+ /// M.
+ ///
+ /// Released publicly as Android 6.0 in October 2015.
+ ///
+ /// Constant Value: 23 (0x00000017).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#M
+ int get m => 23;
+
+ /// N.
+ ///
+ /// Released publicly as Android 7.0 in August 2016.
+ ///
+ /// Constant Value: 24 (0x00000018).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#N
+ int get n => 24;
+
+ /// N MR1.
+ ///
+ /// Released publicly as Android 7.1 in October 2016.
+ ///
+ /// Constant Value: 25 (0x00000019).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#N_MR1
+ int get nMR1 => 25;
+
+ /// O.
+ ///
+ /// Released publicly as Android 8.0 in August 2017.
+ ///
+ /// Constant Value: 26 (0x0000001a).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#O
+ int get o => 26;
+
+ /// O MR1.
+ ///
+ /// Released publicly as Android 8.1 in December 2017.
+ ///
+ /// Constant Value: 27 (0x0000001b).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#O_MR1
+ int get oMR1 => 27;
+
+ /// P.
+ ///
+ /// Released publicly as Android 9 in August 2018.
+ ///
+ /// Constant Value: 28 (0x0000001c).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#P
+ int get p => 28;
+
+ /// Q.
+ ///
+ /// Released publicly as Android 10 in September 2019.
+ ///
+ /// Constant Value: 29 (0x0000001d).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#Q
+ int get q => 29;
+
+ /// R.
+ ///
+ /// Released publicly as Android 11 in September 2020.
+ ///
+ /// Constant Value: 30 (0x0000001e).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#R
+ int get r => 30;
+
+ /// S.
+ ///
+ /// Constant Value: 31 (0x0000001f).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#S
+ int get s => 31;
+
+ /// S V2.
+ ///
+ /// Once more unto the breach, dear friends, once more.
+ ///
+ /// Constant Value: 32 (0x00000020).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#S_V2
+ int get sV2 => 32;
+
+ /// Tiramisu.
+ ///
+ /// Constant Value: 33 (0x00000021).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#TIRAMISU
+ int get tiramisu => 33;
+
+ /// Upside Down Cake.
+ ///
+ /// Constant Value: 34 (0x00000022).
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION_CODES#UPSIDE_DOWN_CAKE
+ int get upsideDownCake => 34;
+}
diff --git a/permission_handler_android/lib/src/android_object_mirrors/context.dart b/permission_handler_android/lib/src/android_object_mirrors/context.dart
index 2bb318e8b..742c83dd1 100644
--- a/permission_handler_android/lib/src/android_object_mirrors/context.dart
+++ b/permission_handler_android/lib/src/android_object_mirrors/context.dart
@@ -29,6 +29,11 @@ class Context extends JavaObject {
final ContextHostApiImpl _hostApi;
+ /// Use with [Context.getSystemService] to retrieve a [PowerManager] for
+ /// controlling power management, including "wake locks," which let you keep
+ /// the device on while you're running long tasks.
+ static const String powerService = 'power';
+
/// Determine whether the application has been granted a particular permission.
///
/// See https://developer.android.com/reference/android/content/Context#checkSelfPermission(java.lang.String).
@@ -61,4 +66,18 @@ class Context extends JavaObject {
this,
);
}
+
+ /// Return the handle to a system-level service by name.
+ ///
+ /// The class of the returned object varies by the requested name.
+ ///
+ /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String).
+ Future getSystemService(
+ String name,
+ ) {
+ return _hostApi.getSystemServiceFromInstance(
+ this,
+ name,
+ );
+ }
}
diff --git a/permission_handler_android/lib/src/android_object_mirrors/power_manager.dart b/permission_handler_android/lib/src/android_object_mirrors/power_manager.dart
new file mode 100644
index 000000000..e4c74ea87
--- /dev/null
+++ b/permission_handler_android/lib/src/android_object_mirrors/power_manager.dart
@@ -0,0 +1,47 @@
+import 'package:flutter/services.dart';
+import 'package:flutter_instance_manager/flutter_instance_manager.dart';
+import 'package:permission_handler_android/src/android_permission_handler_api_impls.dart';
+
+import 'build.dart';
+
+/// This class lets you query and request control of aspects of the device's power state.
+///
+/// See: https://developer.android.com/reference/android/os/PowerManager
+class PowerManager extends JavaObject {
+ /// Instantiates an [PowerManager] without creating and attaching to an
+ /// instance of the associated native class.
+ PowerManager.detached({
+ BinaryMessenger? binaryMessenger,
+ InstanceManager? instanceManager,
+ }) : _hostApi = PowerManagerHostApiImpl(
+ binaryMessenger: binaryMessenger,
+ instanceManager: instanceManager,
+ ),
+ super.detached();
+
+ final PowerManagerHostApiImpl _hostApi;
+
+ /// Returns whether the given application package name is on the device's power allowlist.
+ ///
+ /// Only works on Android M and above. Returns false on lower API levels.
+ ///
+ /// Apps can be placed on the allowlist through the settings UI invoked by
+ /// [Settings.actionRequestIgnoreBatteryOptimizations].
+ ///
+ /// Being on the power allowlist means that the system will not apply most
+ /// power saving features to the app. Guardrails for extreme cases may still
+ /// be applied.
+ ///
+ /// See https://developer.android.com/reference/android/os/PowerManager#isIgnoringBatteryOptimizations(java.lang.String).
+ Future isIgnoringBatteryOptimizations(String packageName) async {
+ final int sdkVersion = await Build.version.sdkInt;
+ if (sdkVersion < Build.versionCodes.m) {
+ return false;
+ }
+
+ return _hostApi.isIgnoringBatteryOptimizationsFromInstance(
+ this,
+ packageName,
+ );
+ }
+}
diff --git a/permission_handler_android/lib/src/android_permission_handler_api_impls.dart b/permission_handler_android/lib/src/android_permission_handler_api_impls.dart
index 2e80134c6..b75162d03 100644
--- a/permission_handler_android/lib/src/android_permission_handler_api_impls.dart
+++ b/permission_handler_android/lib/src/android_permission_handler_api_impls.dart
@@ -1,12 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_instance_manager/flutter_instance_manager.dart';
-import 'package:permission_handler_android/src/activity_aware.dart';
-
-import 'android_object_mirrors/activity.dart';
-import 'android_object_mirrors/context.dart';
-import 'android_object_mirrors/intent.dart';
-import 'android_object_mirrors/uri.dart';
+import 'package:permission_handler_android/permission_handler_android.dart';
import 'permission_handler.pigeon.dart';
/// Handles initialization of Flutter APIs for the Android permission handler.
@@ -15,9 +10,12 @@ class AndroidPermissionHandlerFlutterApis {
AndroidPermissionHandlerFlutterApis({
ActivityFlutterApiImpl? activityFlutterApi,
ContextFlutterApiImpl? contextFlutterApi,
+ PowerManagerFlutterApiImpl? powerManagerFlutterApi,
}) {
this.activityFlutterApi = activityFlutterApi ?? ActivityFlutterApiImpl();
this.contextFlutterApi = contextFlutterApi ?? ContextFlutterApiImpl();
+ this.powerManagerFlutterApi =
+ powerManagerFlutterApi ?? PowerManagerFlutterApiImpl();
}
static bool _haveBeenSetUp = false;
@@ -37,11 +35,15 @@ class AndroidPermissionHandlerFlutterApis {
/// Flutter API for [Context].
late final ContextFlutterApiImpl contextFlutterApi;
+ /// Flutter API for [PowerManager].
+ late final PowerManagerFlutterApiImpl powerManagerFlutterApi;
+
/// Ensures all the Flutter APIs have been setup to receive calls from native code.
void ensureSetUp() {
if (!_haveBeenSetUp) {
ActivityFlutterApi.setup(activityFlutterApi);
ContextFlutterApi.setup(contextFlutterApi);
+ PowerManagerFlutterApi.setup(powerManagerFlutterApi);
_haveBeenSetUp = true;
}
@@ -176,6 +178,23 @@ class ActivityHostApiImpl extends ActivityHostApi {
requestCode: requestCode,
);
}
+
+ /// Return the handle to a system-level service by name.
+ ///
+ /// Returns the instance ID of the service.
+ ///
+ /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String).
+ Future getSystemServiceFromInstance(
+ Activity activity,
+ String name,
+ ) async {
+ final String systemServiceId = await getSystemService(
+ instanceManager.getIdentifier(activity)!,
+ name,
+ );
+
+ return instanceManager.getInstanceWithWeakReference(systemServiceId);
+ }
}
/// Flutter API implementation of Activity.
@@ -258,6 +277,21 @@ class ContextHostApiImpl extends ContextHostApi {
instanceManager.getIdentifier(context)!,
);
}
+
+ /// Return the handle to a system-level service by name.
+ ///
+ /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String).
+ Future getSystemServiceFromInstance(
+ Context context,
+ String name,
+ ) async {
+ final String systemServiceId = await getSystemService(
+ instanceManager.getIdentifier(context)!,
+ name,
+ );
+
+ return instanceManager.getInstanceWithWeakReference(systemServiceId);
+ }
}
/// Flutter API implementation of Context.
@@ -413,3 +447,87 @@ class IntentHostApiImpl extends IntentHostApi {
);
}
}
+
+/// Host API implementation of PowerManager.
+class PowerManagerHostApiImpl extends PowerManagerHostApi {
+ /// Creates a new instance of [PowerManagerHostApiImpl].
+ PowerManagerHostApiImpl({
+ this.binaryMessenger,
+ InstanceManager? instanceManager,
+ }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager,
+ super(binaryMessenger: binaryMessenger);
+
+ /// Sends binary data across the Flutter platform barrier.
+ ///
+ /// If it is null, the default BinaryMessenger will be used which routes to
+ /// the host platform.
+ final BinaryMessenger? binaryMessenger;
+
+ /// Maintains instances stored to communicate with native language objects.
+ final InstanceManager instanceManager;
+
+ /// Returns whether the given application package name is on the device's power allowlist.
+ ///
+ /// Apps can be placed on the allowlist through the settings UI invoked by
+ /// [Settings.actionRequestIgnoreBatteryOptimizations].
+ ///
+ /// Being on the power allowlist means that the system will not apply most
+ /// power saving features to the app. Guardrails for extreme cases may still
+ /// be applied.
+ ///
+ /// See https://developer.android.com/reference/android/os/PowerManager#isIgnoringBatteryOptimizations(java.lang.String).
+ Future isIgnoringBatteryOptimizationsFromInstance(
+ PowerManager powerManager,
+ String packageName,
+ ) async {
+ return await Build.version.sdkInt >= Build.versionCodes.m &&
+ await isIgnoringBatteryOptimizations(
+ instanceManager.getIdentifier(powerManager)!,
+ packageName,
+ );
+ }
+}
+
+/// Flutter API implementation of PowerManager.
+class PowerManagerFlutterApiImpl extends PowerManagerFlutterApi {
+ /// Constructs a new instance of [PowerManagerFlutterApiImpl].
+ PowerManagerFlutterApiImpl({
+ InstanceManager? instanceManager,
+ }) : _instanceManager = instanceManager ?? JavaObject.globalInstanceManager;
+
+ /// Maintains instances stored to communicate with native language objects.
+ final InstanceManager _instanceManager;
+
+ @override
+ void create(String instanceId) {
+ final PowerManager powerManager = PowerManager.detached();
+ _instanceManager.addHostCreatedInstance(
+ powerManager,
+ instanceId,
+ );
+ }
+
+ @override
+ void dispose(String instanceId) {
+ _instanceManager.remove(instanceId);
+ }
+}
+
+/// Host API implementation of Build.Version.
+class BuildVersionHostApiImpl extends BuildVersionHostApi {
+ /// Creates a new instance of [BuildVersionHostApiImpl].
+ BuildVersionHostApiImpl({
+ this.binaryMessenger,
+ InstanceManager? instanceManager,
+ }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager,
+ super(binaryMessenger: binaryMessenger);
+
+ /// Sends binary data across the Flutter platform barrier.
+ ///
+ /// If it is null, the default BinaryMessenger will be used which routes to
+ /// the host platform.
+ final BinaryMessenger? binaryMessenger;
+
+ /// Maintains instances stored to communicate with native language objects.
+ final InstanceManager instanceManager;
+}
diff --git a/permission_handler_android/lib/src/extensions.dart b/permission_handler_android/lib/src/extensions.dart
index da29678f3..2cbb2e1ed 100644
--- a/permission_handler_android/lib/src/extensions.dart
+++ b/permission_handler_android/lib/src/extensions.dart
@@ -19,6 +19,8 @@ extension PermissionToManifestStrings on Permission {
return [Manifest.permission.writeCalendar];
} else if (this == Permission.camera) {
return [Manifest.permission.camera];
+ } else if (this == Permission.ignoreBatteryOptimizations) {
+ return [Manifest.permission.requestIgnoreBatteryOptimizations];
}
throw UnimplementedError(
diff --git a/permission_handler_android/lib/src/missing_activity_exception.dart b/permission_handler_android/lib/src/missing_activity_exception.dart
deleted file mode 100644
index 8899289b5..000000000
--- a/permission_handler_android/lib/src/missing_activity_exception.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-import 'android_object_mirrors/activity.dart';
-
-/// An exception thrown when no [Activity] is attached.
-///
-/// This can happen if the app is running in the background, for example.
-class MissingActivityException implements Exception {
- /// Creates a new instance of [MissingActivityException].
- const MissingActivityException();
-
- @override
- String toString() =>
- 'MissingActivityException: There is no attached activity';
-}
diff --git a/permission_handler_android/lib/src/permission_handler.pigeon.dart b/permission_handler_android/lib/src/permission_handler.pigeon.dart
index bba1b1c8c..3f6ca1d0e 100644
--- a/permission_handler_android/lib/src/permission_handler.pigeon.dart
+++ b/permission_handler_android/lib/src/permission_handler.pigeon.dart
@@ -94,9 +94,9 @@ class _ActivityHostApiCodec extends StandardMessageCodec {
@override
Object? readValueOfType(int type, ReadBuffer buffer) {
switch (type) {
- case 128:
+ case 128:
return ActivityResultPigeon.decode(readValue(buffer)!);
- case 129:
+ case 129:
return PermissionRequestResult.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
@@ -124,14 +124,12 @@ class ActivityHostApi {
/// Gets whether the application should show UI with rationale before requesting a permission.
///
/// See https://developer.android.com/reference/android/app/Activity#shouldShowRequestPermissionRationale(java.lang.String).
- Future shouldShowRequestPermissionRationale(
- String arg_instanceId, String arg_permission) async {
+ Future shouldShowRequestPermissionRationale(String arg_instanceId, String arg_permission) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.shouldShowRequestPermissionRationale',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.shouldShowRequestPermissionRationale', codec,
binaryMessenger: _binaryMessenger);
- final List? replyList = await channel
- .send([arg_instanceId, arg_permission]) as List?;
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_permission]) as List?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@@ -156,14 +154,12 @@ class ActivityHostApi {
/// Determine whether the application has been granted a particular permission.
///
/// See https://developer.android.com/reference/android/app/Activity#checkSelfPermission(java.lang.String).
- Future checkSelfPermission(
- String arg_instanceId, String arg_permission) async {
+ Future checkSelfPermission(String arg_instanceId, String arg_permission) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.checkSelfPermission',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.checkSelfPermission', codec,
binaryMessenger: _binaryMessenger);
- final List? replyList = await channel
- .send([arg_instanceId, arg_permission]) as List?;
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_permission]) as List?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@@ -191,15 +187,12 @@ class ActivityHostApi {
/// https://developer.android.com/reference/android/app/Activity#requestPermissions(java.lang.String[],%20int)
/// and
/// https://developer.android.com/reference/android/app/Activity#onRequestPermissionsResult(int,%20java.lang.String[],%20int[]).
- Future requestPermissions(String arg_instanceId,
- List arg_permissions, int? arg_requestCode) async {
+ Future requestPermissions(String arg_instanceId, List arg_permissions, int? arg_requestCode) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.requestPermissions',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.requestPermissions', codec,
binaryMessenger: _binaryMessenger);
- final List? replyList = await channel
- .send([arg_instanceId, arg_permissions, arg_requestCode])
- as List?;
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_permissions, arg_requestCode]) as List?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@@ -224,15 +217,12 @@ class ActivityHostApi {
/// Launch a new activity.
///
/// See https://developer.android.com/reference/android/content/Context#startActivity(android.content.Intent).
- Future startActivity(
- String arg_instanceId, String arg_intentInstanceId) async {
+ Future startActivity(String arg_instanceId, String arg_intentInstanceId) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.startActivity',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.startActivity', codec,
binaryMessenger: _binaryMessenger);
final List? replyList =
- await channel.send([arg_instanceId, arg_intentInstanceId])
- as List?;
+ await channel.send([arg_instanceId, arg_intentInstanceId]) as List?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@@ -254,8 +244,7 @@ class ActivityHostApi {
/// See https://developer.android.com/reference/android/content/Context#getPackageName().
Future getPackageName(String arg_instanceId) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getPackageName',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getPackageName', codec,
binaryMessenger: _binaryMessenger);
final List? replyList =
await channel.send([arg_instanceId]) as List?;
@@ -280,18 +269,49 @@ class ActivityHostApi {
}
}
+ /// Return the handle to a system-level service by name.
+ ///
+ /// The class of the returned object varies by the requested name.
+ ///
+ /// Returns the instance ID of the service.
+ ///
+ /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String).
+ Future getSystemService(String arg_instanceId, String arg_name) async {
+ final BasicMessageChannel channel = BasicMessageChannel(
+ 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.getSystemService', codec,
+ binaryMessenger: _binaryMessenger);
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_name]) as List?;
+ if (replyList == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyList.length > 1) {
+ throw PlatformException(
+ code: replyList[0]! as String,
+ message: replyList[1] as String?,
+ details: replyList[2],
+ );
+ } else if (replyList[0] == null) {
+ throw PlatformException(
+ code: 'null-error',
+ message: 'Host platform returned null value for non-null return value.',
+ );
+ } else {
+ return (replyList[0] as String?)!;
+ }
+ }
+
/// Start an activity for which the application would like a result when it finished.
///
/// See https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int).
- Future startActivityForResult(String arg_instanceId,
- String arg_intentInstanceId, int? arg_requestCode) async {
+ Future startActivityForResult(String arg_instanceId, String arg_intentInstanceId, int? arg_requestCode) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.startActivityForResult',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.startActivityForResult', codec,
binaryMessenger: _binaryMessenger);
- final List? replyList = await channel.send(
- [arg_instanceId, arg_intentInstanceId, arg_requestCode])
- as List?;
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_intentInstanceId, arg_requestCode]) as List?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@@ -330,19 +350,17 @@ abstract class ActivityFlutterApi {
/// Dispose of the Dart instance and remove it from the `InstanceManager`.
void dispose(String instanceId);
- static void setup(ActivityFlutterApi? api,
- {BinaryMessenger? binaryMessenger}) {
+ static void setup(ActivityFlutterApi? api, {BinaryMessenger? binaryMessenger}) {
{
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ActivityFlutterApi.create',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ActivityFlutterApi.create', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object? message) async {
assert(message != null,
- 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityFlutterApi.create was null.');
+ 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityFlutterApi.create was null.');
final List args = (message as List?)!;
final String? arg_instanceId = (args[0] as String?);
assert(arg_instanceId != null,
@@ -354,15 +372,14 @@ abstract class ActivityFlutterApi {
}
{
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ActivityFlutterApi.dispose',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ActivityFlutterApi.dispose', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object? message) async {
assert(message != null,
- 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityFlutterApi.dispose was null.');
+ 'Argument for dev.flutter.pigeon.permission_handler_android.ActivityFlutterApi.dispose was null.');
final List args = (message as List?)!;
final String? arg_instanceId = (args[0] as String?);
assert(arg_instanceId != null,
@@ -395,14 +412,12 @@ class ContextHostApi {
/// Determine whether the application has been granted a particular permission.
///
/// See https://developer.android.com/reference/android/content/Context#checkSelfPermission(java.lang.String).
- Future checkSelfPermission(
- String arg_instanceId, String arg_permission) async {
+ Future checkSelfPermission(String arg_instanceId, String arg_permission) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ContextHostApi.checkSelfPermission',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ContextHostApi.checkSelfPermission', codec,
binaryMessenger: _binaryMessenger);
- final List? replyList = await channel
- .send([arg_instanceId, arg_permission]) as List?;
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_permission]) as List?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@@ -427,15 +442,12 @@ class ContextHostApi {
/// Launch a new activity.
///
/// See https://developer.android.com/reference/android/content/Context#startActivity(android.content.Intent).
- Future startActivity(
- String arg_instanceId, String arg_intentInstanceId) async {
+ Future startActivity(String arg_instanceId, String arg_intentInstanceId) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ContextHostApi.startActivity',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ContextHostApi.startActivity', codec,
binaryMessenger: _binaryMessenger);
final List? replyList =
- await channel.send([arg_instanceId, arg_intentInstanceId])
- as List?;
+ await channel.send([arg_instanceId, arg_intentInstanceId]) as List?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@@ -457,8 +469,7 @@ class ContextHostApi {
/// See https://developer.android.com/reference/android/content/Context#getPackageName().
Future getPackageName(String arg_instanceId) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ContextHostApi.getPackageName',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ContextHostApi.getPackageName', codec,
binaryMessenger: _binaryMessenger);
final List? replyList =
await channel.send([arg_instanceId]) as List?;
@@ -482,6 +493,40 @@ class ContextHostApi {
return (replyList[0] as String?)!;
}
}
+
+ /// Return the handle to a system-level service by name.
+ ///
+ /// The class of the returned object varies by the requested name.
+ ///
+ /// Returns the instance ID of the service.
+ ///
+ /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String).
+ Future getSystemService(String arg_instanceId, String arg_name) async {
+ final BasicMessageChannel channel = BasicMessageChannel(
+ 'dev.flutter.pigeon.permission_handler_android.ContextHostApi.getSystemService', codec,
+ binaryMessenger: _binaryMessenger);
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_name]) as List?;
+ if (replyList == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyList.length > 1) {
+ throw PlatformException(
+ code: replyList[0]! as String,
+ message: replyList[1] as String?,
+ details: replyList[2],
+ );
+ } else if (replyList[0] == null) {
+ throw PlatformException(
+ code: 'null-error',
+ message: 'Host platform returned null value for non-null return value.',
+ );
+ } else {
+ return (replyList[0] as String?)!;
+ }
+ }
}
/// Flutter API for `Context`.
@@ -500,19 +545,17 @@ abstract class ContextFlutterApi {
/// Dispose of the Dart instance and remove it from the `InstanceManager`.
void dispose(String instanceId);
- static void setup(ContextFlutterApi? api,
- {BinaryMessenger? binaryMessenger}) {
+ static void setup(ContextFlutterApi? api, {BinaryMessenger? binaryMessenger}) {
{
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ContextFlutterApi.create',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ContextFlutterApi.create', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object? message) async {
assert(message != null,
- 'Argument for dev.flutter.pigeon.permission_handler_android.ContextFlutterApi.create was null.');
+ 'Argument for dev.flutter.pigeon.permission_handler_android.ContextFlutterApi.create was null.');
final List args = (message as List?)!;
final String? arg_instanceId = (args[0] as String?);
assert(arg_instanceId != null,
@@ -524,15 +567,14 @@ abstract class ContextFlutterApi {
}
{
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ContextFlutterApi.dispose',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ContextFlutterApi.dispose', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object? message) async {
assert(message != null,
- 'Argument for dev.flutter.pigeon.permission_handler_android.ContextFlutterApi.dispose was null.');
+ 'Argument for dev.flutter.pigeon.permission_handler_android.ContextFlutterApi.dispose was null.');
final List args = (message as List?)!;
final String? arg_instanceId = (args[0] as String?);
assert(arg_instanceId != null,
@@ -571,8 +613,8 @@ class UriHostApi {
final BasicMessageChannel channel = BasicMessageChannel(
'dev.flutter.pigeon.permission_handler_android.UriHostApi.parse', codec,
binaryMessenger: _binaryMessenger);
- final List? replyList = await channel
- .send([arg_instanceId, arg_uriString]) as List?;
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_uriString]) as List?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@@ -599,8 +641,7 @@ class UriHostApi {
/// See https://developer.android.com/reference/android/net/Uri#toString().
Future toStringAsync(String arg_instanceId) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.UriHostApi.toStringAsync',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.UriHostApi.toStringAsync', codec,
binaryMessenger: _binaryMessenger);
final List? replyList =
await channel.send([arg_instanceId]) as List?;
@@ -648,8 +689,7 @@ class IntentHostApi {
/// See https://developer.android.com/reference/android/content/Intent#Intent().
Future create(String arg_instanceId) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.IntentHostApi.create',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.IntentHostApi.create', codec,
binaryMessenger: _binaryMessenger);
final List? replyList =
await channel.send([arg_instanceId]) as List?;
@@ -674,11 +714,10 @@ class IntentHostApi {
/// See https://developer.android.com/reference/android/content/Intent#setAction(java.lang.String).
Future setAction(String arg_instanceId, String arg_action) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.IntentHostApi.setAction',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.IntentHostApi.setAction', codec,
binaryMessenger: _binaryMessenger);
- final List? replyList = await channel
- .send([arg_instanceId, arg_action]) as List?;
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_action]) as List?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@@ -700,11 +739,10 @@ class IntentHostApi {
/// See https://developer.android.com/reference/android/content/Intent#setData(android.net.Uri).
Future setData(String arg_instanceId, String arg_uriInstanceId) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.IntentHostApi.setData',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.IntentHostApi.setData', codec,
binaryMessenger: _binaryMessenger);
- final List? replyList = await channel
- .send([arg_instanceId, arg_uriInstanceId]) as List?;
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_uriInstanceId]) as List?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@@ -730,11 +768,10 @@ class IntentHostApi {
/// See https://developer.android.com/reference/android/content/Intent#addCategory(java.lang.String).
Future addCategory(String arg_instanceId, String arg_category) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.IntentHostApi.addCategory',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.IntentHostApi.addCategory', codec,
binaryMessenger: _binaryMessenger);
- final List? replyList = await channel
- .send([arg_instanceId, arg_category]) as List?;
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_category]) as List?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@@ -756,11 +793,10 @@ class IntentHostApi {
/// See https://developer.android.com/reference/android/content/Intent#addFlags(int).
Future addFlags(String arg_instanceId, int arg_flags) async {
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.IntentHostApi.addFlags',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.IntentHostApi.addFlags', codec,
binaryMessenger: _binaryMessenger);
- final List? replyList = await channel
- .send([arg_instanceId, arg_flags]) as List?;
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_flags]) as List?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
@@ -777,3 +813,169 @@ class IntentHostApi {
}
}
}
+
+/// Host API for `PowerManager`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or handle method calls on the associated
+/// native class or an instance of the class.
+///
+/// See https://developer.android.com/reference/android/os/PowerManager.
+class PowerManagerHostApi {
+ /// Constructor for [PowerManagerHostApi]. The [binaryMessenger] named argument is
+ /// available for dependency injection. If it is left null, the default
+ /// BinaryMessenger will be used which routes to the host platform.
+ PowerManagerHostApi({BinaryMessenger? binaryMessenger})
+ : _binaryMessenger = binaryMessenger;
+ final BinaryMessenger? _binaryMessenger;
+
+ static const MessageCodec codec = StandardMessageCodec();
+
+ /// Returns whether the given application package name is on the device's power allowlist.
+ ///
+ /// Apps can be placed on the allowlist through the settings UI invoked by
+ /// [Settings.actionRequestIgnoreBatteryOptimizations].
+ ///
+ /// Being on the power allowlist means that the system will not apply most
+ /// power saving features to the app. Guardrails for extreme cases may still
+ /// be applied.
+ ///
+ /// See https://developer.android.com/reference/android/os/PowerManager#isIgnoringBatteryOptimizations(java.lang.String).
+ Future isIgnoringBatteryOptimizations(String arg_instanceId, String arg_packageName) async {
+ final BasicMessageChannel channel = BasicMessageChannel(
+ 'dev.flutter.pigeon.permission_handler_android.PowerManagerHostApi.isIgnoringBatteryOptimizations', codec,
+ binaryMessenger: _binaryMessenger);
+ final List? replyList =
+ await channel.send([arg_instanceId, arg_packageName]) as List?;
+ if (replyList == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyList.length > 1) {
+ throw PlatformException(
+ code: replyList[0]! as String,
+ message: replyList[1] as String?,
+ details: replyList[2],
+ );
+ } else if (replyList[0] == null) {
+ throw PlatformException(
+ code: 'null-error',
+ message: 'Host platform returned null value for non-null return value.',
+ );
+ } else {
+ return (replyList[0] as bool?)!;
+ }
+ }
+}
+
+/// Flutter API for `PowerManager`.
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+///
+/// See https://developer.android.com/reference/android/os/PowerManager.
+abstract class PowerManagerFlutterApi {
+ static const MessageCodec codec = StandardMessageCodec();
+
+ /// Create a new Dart instance and add it to the `InstanceManager`.
+ void create(String instanceId);
+
+ /// Dispose of the Dart instance and remove it from the `InstanceManager`.
+ void dispose(String instanceId);
+
+ static void setup(PowerManagerFlutterApi? api, {BinaryMessenger? binaryMessenger}) {
+ {
+ final BasicMessageChannel channel = BasicMessageChannel(
+ 'dev.flutter.pigeon.permission_handler_android.PowerManagerFlutterApi.create', codec,
+ binaryMessenger: binaryMessenger);
+ if (api == null) {
+ channel.setMessageHandler(null);
+ } else {
+ channel.setMessageHandler((Object? message) async {
+ assert(message != null,
+ 'Argument for dev.flutter.pigeon.permission_handler_android.PowerManagerFlutterApi.create was null.');
+ final List args = (message as List?)!;
+ final String? arg_instanceId = (args[0] as String?);
+ assert(arg_instanceId != null,
+ 'Argument for dev.flutter.pigeon.permission_handler_android.PowerManagerFlutterApi.create was null, expected non-null String.');
+ api.create(arg_instanceId!);
+ return;
+ });
+ }
+ }
+ {
+ final BasicMessageChannel channel = BasicMessageChannel(
+ 'dev.flutter.pigeon.permission_handler_android.PowerManagerFlutterApi.dispose', codec,
+ binaryMessenger: binaryMessenger);
+ if (api == null) {
+ channel.setMessageHandler(null);
+ } else {
+ channel.setMessageHandler((Object? message) async {
+ assert(message != null,
+ 'Argument for dev.flutter.pigeon.permission_handler_android.PowerManagerFlutterApi.dispose was null.');
+ final List args = (message as List?)!;
+ final String? arg_instanceId = (args[0] as String?);
+ assert(arg_instanceId != null,
+ 'Argument for dev.flutter.pigeon.permission_handler_android.PowerManagerFlutterApi.dispose was null, expected non-null String.');
+ api.dispose(arg_instanceId!);
+ return;
+ });
+ }
+ }
+ }
+}
+
+/// Host API for `BuildVersion`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or handle method calls on the associated
+/// native class or an instance of the class.
+///
+/// See https://developer.android.com/reference/android/os/Build.VERSION.
+class BuildVersionHostApi {
+ /// Constructor for [BuildVersionHostApi]. The [binaryMessenger] named argument is
+ /// available for dependency injection. If it is left null, the default
+ /// BinaryMessenger will be used which routes to the host platform.
+ BuildVersionHostApi({BinaryMessenger? binaryMessenger})
+ : _binaryMessenger = binaryMessenger;
+ final BinaryMessenger? _binaryMessenger;
+
+ static const MessageCodec codec = StandardMessageCodec();
+
+ /// The SDK version of the software currently running on this hardware device.
+ ///
+ /// This value never changes while a device is booted, but it may increase
+ /// when the hardware manufacturer provides an OTA update.
+ ///
+ /// Possible values are defined in [Build.versionCodes].
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT.
+ Future sdkInt() async {
+ final BasicMessageChannel channel = BasicMessageChannel(
+ 'dev.flutter.pigeon.permission_handler_android.BuildVersionHostApi.sdkInt', codec,
+ binaryMessenger: _binaryMessenger);
+ final List? replyList =
+ await channel.send(null) as List?;
+ if (replyList == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyList.length > 1) {
+ throw PlatformException(
+ code: replyList[0]! as String,
+ message: replyList[1] as String?,
+ details: replyList[2],
+ );
+ } else if (replyList[0] == null) {
+ throw PlatformException(
+ code: 'null-error',
+ message: 'Host platform returned null value for non-null return value.',
+ );
+ } else {
+ return (replyList[0] as int?)!;
+ }
+ }
+}
diff --git a/permission_handler_android/lib/src/permission_handler_android.dart b/permission_handler_android/lib/src/permission_handler_android.dart
index 874d6ccb2..b1d5bee7b 100644
--- a/permission_handler_android/lib/src/permission_handler_android.dart
+++ b/permission_handler_android/lib/src/permission_handler_android.dart
@@ -24,9 +24,13 @@ class PermissionHandlerAndroid extends PermissionHandlerPlatform {
/// however, only [PermissionStatus.granted] or [PermissionStatus.denied] will
/// be returned.
///
- /// TODO(jweener): handle special permissions.
+ /// TODO(jweener): handle all special permissions.
@override
Future checkPermissionStatus(Permission permission) async {
+ if (Permission.ignoreBatteryOptimizations == permission) {
+ return _checkIgnoreBatteryOptimizationStatus();
+ }
+
final Iterable statuses = await Future.wait(
permission.manifestStrings.map(
(String manifestString) async {
@@ -73,9 +77,11 @@ class PermissionHandlerAndroid extends PermissionHandlerPlatform {
return shouldShowRationales.any((bool shouldShow) => shouldShow);
}
- /// TODO(jweener): handle special permissions.
+ /// TODO(jweener): handle all special permissions.
@override
- Future requestPermission(Permission permission) async {
+ Future requestPermission(
+ Permission permission,
+ ) async {
final Activity? activity = _activityManager.activity;
if (activity == null) {
debugPrint(
@@ -83,8 +89,27 @@ class PermissionHandlerAndroid extends PermissionHandlerPlatform {
return PermissionStatus.denied;
}
+ if (Permission.ignoreBatteryOptimizations == permission) {
+ await _requestSpecialPermission(
+ action: Settings.actionRequestIgnoreBatteryOptimizations,
+ );
+ return _checkIgnoreBatteryOptimizationStatus();
+ }
+
+ return _requestNormalPermission(
+ activity: activity,
+ permission: permission,
+ );
+ }
+
+ Future _requestNormalPermission({
+ required Activity activity,
+ required Permission permission,
+ int? requestCode,
+ }) async {
final PermissionRequestResult result = await activity.requestPermissions(
permission.manifestStrings,
+ requestCode,
);
final List permissions =
@@ -106,6 +131,22 @@ class PermissionHandlerAndroid extends PermissionHandlerPlatform {
return statuses.strictest;
}
+ Future _requestSpecialPermission({
+ required String action,
+ int? requestCode,
+ }) async {
+ await _activityManager.activity?.startActivityForResult(
+ Intent()
+ ..setAction(action)
+ ..setData(
+ Uri.parse(
+ 'package:${await _activityManager.applicationContext.getPackageName()}',
+ ),
+ ),
+ requestCode,
+ );
+ }
+
/// TODO(jweener): return false if opening of the settings page fails.
@override
Future openAppSettings() async {
@@ -126,4 +167,18 @@ class PermissionHandlerAndroid extends PermissionHandlerPlatform {
return true;
}
+
+ Future _checkIgnoreBatteryOptimizationStatus() async {
+ final Context applicationContext = _activityManager.applicationContext;
+ final String packageName = await applicationContext.getPackageName();
+ final Object? systemService =
+ await applicationContext.getSystemService(Context.powerService);
+ assert(systemService is PowerManager,
+ 'Expected PowerManager, got $systemService');
+ final PowerManager powerManager = systemService as PowerManager;
+ final bool isIgnoring =
+ await powerManager.isIgnoringBatteryOptimizations(packageName);
+
+ return isIgnoring ? PermissionStatus.granted : PermissionStatus.denied;
+ }
}
diff --git a/permission_handler_android/pigeons/android_permission_handler.dart b/permission_handler_android/pigeons/android_permission_handler.dart
index d37bd53a5..fda46cac0 100644
--- a/permission_handler_android/pigeons/android_permission_handler.dart
+++ b/permission_handler_android/pigeons/android_permission_handler.dart
@@ -100,6 +100,18 @@ abstract class ActivityHostApi {
String instanceId,
);
+ /// Return the handle to a system-level service by name.
+ ///
+ /// The class of the returned object varies by the requested name.
+ ///
+ /// Returns the instance ID of the service.
+ ///
+ /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String).
+ String getSystemService(
+ String instanceId,
+ String name,
+ );
+
/// Start an activity for which the application would like a result when it finished.
///
/// See https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int).
@@ -158,6 +170,18 @@ abstract class ContextHostApi {
String getPackageName(
String instanceId,
);
+
+ /// Return the handle to a system-level service by name.
+ ///
+ /// The class of the returned object varies by the requested name.
+ ///
+ /// Returns the instance ID of the service.
+ ///
+ /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String).
+ String getSystemService(
+ String instanceId,
+ String name,
+ );
}
/// Flutter API for `Context`.
@@ -260,3 +284,64 @@ abstract class IntentHostApi {
int flags,
);
}
+
+/// Host API for `PowerManager`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or handle method calls on the associated
+/// native class or an instance of the class.
+///
+/// See https://developer.android.com/reference/android/os/PowerManager.
+@HostApi(dartHostTestHandler: 'PowerManagerTestHostApi')
+abstract class PowerManagerHostApi {
+ /// Returns whether the given application package name is on the device's power allowlist.
+ ///
+ /// Apps can be placed on the allowlist through the settings UI invoked by
+ /// [Settings.actionRequestIgnoreBatteryOptimizations].
+ ///
+ /// Being on the power allowlist means that the system will not apply most
+ /// power saving features to the app. Guardrails for extreme cases may still
+ /// be applied.
+ ///
+ /// See https://developer.android.com/reference/android/os/PowerManager#isIgnoringBatteryOptimizations(java.lang.String).
+ bool isIgnoringBatteryOptimizations(
+ String instanceId,
+ String packageName,
+ );
+}
+
+/// Flutter API for `PowerManager`.
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+///
+/// See https://developer.android.com/reference/android/os/PowerManager.
+@FlutterApi()
+abstract class PowerManagerFlutterApi {
+ /// Create a new Dart instance and add it to the `InstanceManager`.
+ void create(String instanceId);
+
+ /// Dispose of the Dart instance and remove it from the `InstanceManager`.
+ void dispose(String instanceId);
+}
+
+/// Host API for `BuildVersion`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or handle method calls on the associated
+/// native class or an instance of the class.
+///
+/// See https://developer.android.com/reference/android/os/Build.VERSION.
+@HostApi(dartHostTestHandler: 'BuildVersionTestHostApi')
+abstract class BuildVersionHostApi {
+ /// The SDK version of the software currently running on this hardware device.
+ ///
+ /// This value never changes while a device is booted, but it may increase
+ /// when the hardware manufacturer provides an OTA update.
+ ///
+ /// Possible values are defined in [Build.versionCodes].
+ ///
+ /// See https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT.
+ int sdkInt();
+}
diff --git a/permission_handler_android/test/test_permission_handler.pigeon.dart b/permission_handler_android/test/test_permission_handler.pigeon.dart
index f701f0971..6749de231 100644
--- a/permission_handler_android/test/test_permission_handler.pigeon.dart
+++ b/permission_handler_android/test/test_permission_handler.pigeon.dart
@@ -28,9 +28,9 @@ class _ActivityTestHostApiCodec extends StandardMessageCodec {
@override
Object? readValueOfType(int type, ReadBuffer buffer) {
switch (type) {
- case 128:
+ case 128:
return ActivityResultPigeon.decode(readValue(buffer)!);
- case 129:
+ case 129:
return PermissionRequestResult.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
@@ -46,15 +46,13 @@ class _ActivityTestHostApiCodec extends StandardMessageCodec {
///
/// See https://developer.android.com/reference/android/app/Activity.
abstract class ActivityTestHostApi {
- static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
- TestDefaultBinaryMessengerBinding.instance;
+ static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => TestDefaultBinaryMessengerBinding.instance;
static const MessageCodec codec = _ActivityTestHostApiCodec();
/// Gets whether the application should show UI with rationale before requesting a permission.
///
/// See https://developer.android.com/reference/android/app/Activity#shouldShowRequestPermissionRationale(java.lang.String).
- bool shouldShowRequestPermissionRationale(
- String instanceId, String permission);
+ bool shouldShowRequestPermissionRationale(String instanceId, String permission);
/// Determine whether the application has been granted a particular permission.
///
@@ -67,8 +65,7 @@ abstract class ActivityTestHostApi {
/// https://developer.android.com/reference/android/app/Activity#requestPermissions(java.lang.String[],%20int)
/// and
/// https://developer.android.com/reference/android/app/Activity#onRequestPermissionsResult(int,%20java.lang.String[],%20int[]).
- Future requestPermissions(
- String instanceId, List permissions, int? requestCode);
+ Future requestPermissions(String instanceId, List permissions, int? requestCode);
/// Launch a new activity.
///
@@ -80,28 +77,31 @@ abstract class ActivityTestHostApi {
/// See https://developer.android.com/reference/android/content/Context#getPackageName().
String getPackageName(String instanceId);
+ /// Return the handle to a system-level service by name.
+ ///
+ /// The class of the returned object varies by the requested name.
+ ///
+ /// Returns the instance ID of the service.
+ ///
+ /// See https://developer.android.com/reference/android/content/Context#getSystemService(java.lang.String).
+ String getSystemService(String instanceId, String name);
+
/// Start an activity for which the application would like a result when it finished.
///
/// See https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int).
- Future startActivityForResult(
- String instanceId, String intentInstanceId, int? requestCode);
+ Future startActivityForResult(String instanceId, String intentInstanceId, int? requestCode);
- static void setup(ActivityTestHostApi? api,
- {BinaryMessenger? binaryMessenger}) {
+ static void setup(ActivityTestHostApi? api, {BinaryMessenger? binaryMessenger}) {
{
final BasicMessageChannel channel = BasicMessageChannel(
- 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.shouldShowRequestPermissionRationale',
- codec,
+ 'dev.flutter.pigeon.permission_handler_android.ActivityHostApi.shouldShowRequestPermissionRationale', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
- _testBinaryMessengerBinding!.defaultBinaryMessenger
- .setMockDecodedMessageHandler(channel, null);
+ _testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler