Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@

A plugin to enable or disable the torch of a device that works both on Android (including Android 4.x) and ioS.

## NOTE: For older Android devices

Some older Android devices have been [known to crash](https://stackoverflow.com/questions/36259930/which-permissions-are-required-for-flashlight) when requesting access to the device torch. This is the result of a bug on those devices requiring full camera access in order to control the camera flash.

This plugin by default only requests `android.permission.FLASHLIGHT`, but if you need your app to be compatible with more devices, you can add the following lines to your application's `AndroidManifest.xml`

```xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera.flash" />
```



## Getting started
### 1) Dependency setup

Expand All @@ -24,4 +39,4 @@ import 'package:torch_compat/torch_compat.dart';
```dart
TorchCompat.turnOn();
TorchCompat.turnOff();
```
```
23 changes: 14 additions & 9 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,46 @@ buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:3.5.1'
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

rootProject.allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
compileSdkVersion 28
compileSdkVersion 30

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = '1.8'
}

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}

defaultConfig {
minSdkVersion 16
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
}
}

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "androidx.annotation:annotation:1.1.0"
}
3 changes: 2 additions & 1 deletion android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
org.gradle.jvmargs=-Xmx1536M

android.useAndroidX=true
android.enableJetifier=true
2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
9 changes: 1 addition & 8 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="fr.g123k.torch_compat">

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera.flash" />

package="fr.g123k.torch_compat">
</manifest>
142 changes: 92 additions & 50 deletions android/src/main/kotlin/fr/g123k/torch_compat/TorchCompatPlugin.kt
Original file line number Diff line number Diff line change
@@ -1,67 +1,109 @@
package fr.g123k.torch_compat

import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import fr.g123k.torch_compat.impl.BaseTorch
import fr.g123k.torch_compat.impl.TorchCamera2Impl
import fr.g123k.torch_compat.impl.TorchCamera1Impl
import fr.g123k.torch_compat.utils.ActivityLifecycleCallbacks
import androidx.annotation.NonNull

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar

@Suppress("JoinDeclarationAndAssignment")
class TorchCompatPlugin(activity: Activity) : MethodCallHandler {
import fr.g123k.torch_compat.impl.BaseTorch
import fr.g123k.torch_compat.impl.TorchCamera2Impl
import fr.g123k.torch_compat.impl.TorchCamera1Impl

import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding

private val hasLamp = activity.applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)
private val torchImpl: BaseTorch

init {
torchImpl = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> TorchCamera2Impl(activity)
else -> TorchCamera1Impl(activity)
}
/** TorchCompatPlugin */
class TorchCompatPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel : MethodChannel

activity.application.registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks() {
override fun onActivityStopped(activity: Activity?) {
torchImpl.dispose()
}
})
}
private lateinit var context: Context
private lateinit var activity: Activity

companion object {
@JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "g123k/torch_compat")
channel.setMethodCallHandler(TorchCompatPlugin(registrar.activity()))
}
}
private var hasLamp: Boolean = false
private lateinit var torchImpl: BaseTorch

override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "turnOn") {
if (!hasLamp) {
result.error("NOTORCH", "This device does not have a torch", null)
} else {
torchImpl.turnOn()
result.success(true)
}
} else if (call.method == "turnOff") {
if (!hasLamp) {
result.error("NOTORCH", "This device does not have a torch", null)
} else {
torchImpl.turnOff()
result.success(true)
}
} else if (call.method == "hasTorch") {
result.success(hasLamp)
} else if (call.method == "dispose") {
torchImpl.dispose()
result.success(true)
} else {
result.notImplemented()
}
private fun attach(binding: ActivityPluginBinding) {
activity = binding.activity
hasLamp = activity.applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)
torchImpl = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> TorchCamera2Impl(activity)
else -> TorchCamera1Impl(activity)
}

// activity.application.registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks() {
// override fun onActivityStopped(activity: Activity?) {
// torchImpl.dispose()
// }
// })
}

private fun detach() {
torchImpl.dispose()
}

override fun onDetachedFromActivity() {
detach()
}

override fun onDetachedFromActivityForConfigChanges() {
detach()
}

override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
attach(binding)
}

override fun onAttachedToActivity(binding: ActivityPluginBinding) {
attach(binding)
}


override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "g123k/torch_compat")
channel.setMethodCallHandler(this)
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformVersion") {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still needed?

result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else if (call.method == "turnOn") {
if (!hasLamp) {
result.error("NOTORCH", "This device does not have a torch", null)
} else {
torchImpl.turnOn()
result.success(true)
}
} else if (call.method == "turnOff") {
if (!hasLamp) {
result.error("NOTORCH", "This device does not have a torch", null)
} else {
torchImpl.turnOff()
result.success(true)
}
} else if (call.method == "hasTorch") {
result.success(hasLamp)
} else if (call.method == "dispose") {
torchImpl.dispose()
result.success(true)
} else {
result.notImplemented()
}
}

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
torchImpl.dispose()
}
}

This file was deleted.

53 changes: 13 additions & 40 deletions example/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,52 +22,25 @@

# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/

# Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
# Web related
lib/generated_plugin_registrant.dart

# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/Flutter/flutter_export_environment.sh
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# Symbolication related
app.*.symbols

# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
# Obfuscation related
app.*.map.json

# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
2 changes: 1 addition & 1 deletion example/.metadata
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.

version:
revision: 68587a0916366e9512a78df22c44163d041dd5f3
revision: ffb2ecea5223acdd139a5039be2f9c796962833d
channel: stable

project_type: app
Loading