couple improvements to flashlight toggling

This commit is contained in:
tibbi 2017-11-06 11:44:36 +01:00
parent 739e1219c4
commit 7f38f2aa3a
7 changed files with 216 additions and 251 deletions

View File

@ -52,7 +52,6 @@ class MainActivity : SimpleActivity() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
mCameraImpl!!.handleCameraSetup() mCameraImpl!!.handleCameraSetup()
mCameraImpl!!.checkFlashlight()
bright_display_btn.beVisibleIf(config.brightDisplay) bright_display_btn.beVisibleIf(config.brightDisplay)
stroboscope_btn.beVisibleIf(config.stroboscope) stroboscope_btn.beVisibleIf(config.stroboscope)
@ -105,7 +104,7 @@ class MainActivity : SimpleActivity() {
} }
private fun setupCameraImpl() { private fun setupCameraImpl() {
mCameraImpl = MyCameraImpl(this) mCameraImpl = MyCameraImpl.newInstance(this)
mCameraImpl!!.enableFlashlight() mCameraImpl!!.enableFlashlight()
} }

View File

@ -1,6 +1,23 @@
package com.simplemobiletools.flashlight.extensions package com.simplemobiletools.flashlight.extensions
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent
import com.simplemobiletools.flashlight.R
import com.simplemobiletools.flashlight.helpers.Config import com.simplemobiletools.flashlight.helpers.Config
import com.simplemobiletools.flashlight.helpers.MyWidgetProvider
val Context.config: Config get() = Config.newInstance(this) val Context.config: Config get() = Config.newInstance(this)
fun Context.updateWidgets() {
val widgetsCnt = AppWidgetManager.getInstance(this).getAppWidgetIds(ComponentName(this, MyWidgetProvider::class.java))
if (widgetsCnt.isNotEmpty()) {
val ids = intArrayOf(R.xml.widget_info)
Intent(this, MyWidgetProvider::class.java).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
sendBroadcast(this)
}
}
}

View File

@ -12,7 +12,7 @@ import com.squareup.otto.Bus
@TargetApi(Build.VERSION_CODES.LOLLIPOP) @TargetApi(Build.VERSION_CODES.LOLLIPOP)
internal class MarshmallowCamera constructor(val context: Context) { internal class MarshmallowCamera constructor(val context: Context) {
private val manager: CameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager private val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
private var cameraId: String? = null private var cameraId: String? = null
init { init {

View File

@ -1,15 +1,14 @@
package com.simplemobiletools.flashlight.helpers package com.simplemobiletools.flashlight.helpers
import android.annotation.TargetApi
import android.content.Context import android.content.Context
import android.graphics.SurfaceTexture import android.graphics.SurfaceTexture
import android.hardware.Camera import android.hardware.Camera
import android.os.Build
import android.os.Handler import android.os.Handler
import com.simplemobiletools.commons.extensions.isMarshmallowPlus import com.simplemobiletools.commons.extensions.isMarshmallowPlus
import com.simplemobiletools.commons.extensions.isNougatPlus import com.simplemobiletools.commons.extensions.isNougatPlus
import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.flashlight.R import com.simplemobiletools.flashlight.R
import com.simplemobiletools.flashlight.extensions.updateWidgets
import com.simplemobiletools.flashlight.models.Events import com.simplemobiletools.flashlight.models.Events
import com.squareup.otto.Bus import com.squareup.otto.Bus
import java.io.IOException import java.io.IOException
@ -17,20 +16,173 @@ import java.io.IOException
class MyCameraImpl(val context: Context) { class MyCameraImpl(val context: Context) {
var stroboFrequency = 1000 var stroboFrequency = 1000
companion object {
private var camera: Camera? = null private var camera: Camera? = null
private var mParams: Camera.Parameters? = null private var params: Camera.Parameters? = null
private var bus: Bus? = null private var bus: Bus? = null
private var mIsFlashlightOn = false private var isFlashlightOn = false
private var mIsMarshmallow = false private var isMarshmallow = false
private var mShouldEnableFlashlight = false private var shouldEnableFlashlight = false
}
private var marshmallowCamera: MarshmallowCamera? = null private var marshmallowCamera: MarshmallowCamera? = null
@Volatile private var shouldStroboscopeStop = false @Volatile private var shouldStroboscopeStop = false
@Volatile private var isStroboscopeRunning = false @Volatile private var isStroboscopeRunning = false
companion object {
fun newInstance(context: Context) = MyCameraImpl(context)
}
init {
isMarshmallow = context.isMarshmallowPlus()
if (bus == null) {
bus = BusProvider.instance
bus!!.register(this)
}
handleCameraSetup()
}
fun toggleFlashlight() {
isFlashlightOn = !isFlashlightOn
checkFlashlight()
}
fun toggleStroboscope(): Boolean {
if (!isStroboscopeRunning) {
disableFlashlight()
}
if (!context.isNougatPlus()) {
if (camera == null) {
initCamera()
}
if (camera == null) {
context.toast(R.string.camera_error)
return false
}
}
if (isStroboscopeRunning) {
stopStroboscope()
} else {
Thread(stroboscope).start()
}
return true
}
fun stopStroboscope() {
shouldStroboscopeStop = true
}
fun handleCameraSetup() {
if (isMarshmallow) {
setupMarshmallowCamera()
} else {
setupCamera()
}
}
private fun setupMarshmallowCamera() {
if (marshmallowCamera == null) {
marshmallowCamera = MarshmallowCamera(context)
}
}
private fun setupCamera() {
if (isMarshmallow)
return
if (camera == null) {
initCamera()
}
}
private fun initCamera() {
try {
camera = Camera.open()
params = camera!!.parameters
params!!.flashMode = Camera.Parameters.FLASH_MODE_OFF
camera!!.parameters = params
} catch (e: Exception) {
bus!!.post(Events.CameraUnavailable())
}
}
private fun checkFlashlight() {
if (isFlashlightOn) {
enableFlashlight()
} else {
disableFlashlight()
}
}
fun enableFlashlight() {
shouldStroboscopeStop = true
if (isStroboscopeRunning) {
shouldEnableFlashlight = true
return
}
if (isMarshmallow) {
toggleMarshmallowFlashlight(true)
} else {
if (camera == null || params == null) {
return
}
params!!.flashMode = Camera.Parameters.FLASH_MODE_TORCH
camera!!.parameters = params
camera!!.startPreview()
}
val mainRunnable = Runnable { stateChanged(true) }
Handler(context.mainLooper).post(mainRunnable)
}
private fun disableFlashlight() {
if (isStroboscopeRunning) {
return
}
if (isMarshmallow) {
toggleMarshmallowFlashlight(false)
} else {
if (camera == null || params == null) {
return
}
params!!.flashMode = Camera.Parameters.FLASH_MODE_OFF
camera!!.parameters = params
}
stateChanged(false)
}
private fun stateChanged(isEnabled: Boolean) {
isFlashlightOn = isEnabled
bus!!.post(Events.StateChanged(isEnabled))
context.updateWidgets()
}
private fun toggleMarshmallowFlashlight(enable: Boolean) {
marshmallowCamera!!.toggleMarshmallowFlashlight(bus!!, enable)
}
fun releaseCamera() {
if (isFlashlightOn) {
disableFlashlight()
}
camera?.release()
camera = null
bus?.unregister(this)
isFlashlightOn = false
shouldStroboscopeStop = true
}
private val stroboscope = Runnable { private val stroboscope = Runnable {
if (isStroboscopeRunning) { if (isStroboscopeRunning) {
return@Runnable return@Runnable
@ -46,9 +198,7 @@ class MyCameraImpl(val context: Context) {
Thread.sleep(stroboFrequency.toLong()) Thread.sleep(stroboFrequency.toLong())
marshmallowCamera!!.toggleMarshmallowFlashlight(bus!!, false) marshmallowCamera!!.toggleMarshmallowFlashlight(bus!!, false)
Thread.sleep(stroboFrequency.toLong()) Thread.sleep(stroboFrequency.toLong())
} catch (ignored: InterruptedException) { } catch (e: Exception) {
shouldStroboscopeStop = true
} catch (ignored: RuntimeException) {
shouldStroboscopeStop = true shouldStroboscopeStop = true
} }
@ -77,18 +227,14 @@ class MyCameraImpl(val context: Context) {
Thread.sleep(stroboFrequency.toLong()) Thread.sleep(stroboFrequency.toLong())
camera!!.parameters = torchOff camera!!.parameters = torchOff
Thread.sleep(stroboFrequency.toLong()) Thread.sleep(stroboFrequency.toLong())
} catch (ignored: InterruptedException) { } catch (e: Exception) {
shouldStroboscopeStop = true
} catch (ignored: RuntimeException) {
shouldStroboscopeStop = true
} }
} }
try { try {
if (camera != null) { if (camera != null) {
camera!!.parameters = torchOff camera!!.parameters = torchOff
if (!mShouldEnableFlashlight || mIsMarshmallow) { if (!shouldEnableFlashlight || isMarshmallow) {
camera!!.release() camera!!.release()
camera = null camera = null
} }
@ -100,157 +246,9 @@ class MyCameraImpl(val context: Context) {
isStroboscopeRunning = false isStroboscopeRunning = false
shouldStroboscopeStop = false shouldStroboscopeStop = false
if (mShouldEnableFlashlight) { if (shouldEnableFlashlight) {
enableFlashlight() enableFlashlight()
mShouldEnableFlashlight = false shouldEnableFlashlight = false
} }
} }
init {
mIsMarshmallow = context.isMarshmallowPlus()
if (bus == null) {
bus = BusProvider.instance
bus!!.register(this)
}
handleCameraSetup()
checkFlashlight()
}
fun toggleFlashlight() {
mIsFlashlightOn = !mIsFlashlightOn
handleCameraSetup()
}
fun toggleStroboscope(): Boolean {
if (!isStroboscopeRunning)
disableFlashlight()
if (!context.isNougatPlus()) {
if (camera == null) {
initCamera()
}
if (camera == null) {
context.toast(R.string.camera_error)
return false
}
}
if (isStroboscopeRunning) {
stopStroboscope()
} else {
Thread(stroboscope).start()
}
return true
}
fun stopStroboscope() {
shouldStroboscopeStop = true
}
fun handleCameraSetup() {
if (mIsMarshmallow) {
setupMarshmallowCamera()
} else {
setupCamera()
}
checkFlashlight()
}
private fun setupMarshmallowCamera() {
if (marshmallowCamera == null) {
marshmallowCamera = MarshmallowCamera(context)
}
}
private fun setupCamera() {
if (mIsMarshmallow)
return
if (camera == null) {
initCamera()
}
}
private fun initCamera() {
try {
camera = Camera.open()
mParams = camera!!.parameters
mParams!!.flashMode = Camera.Parameters.FLASH_MODE_OFF
camera!!.parameters = mParams
} catch (e: Exception) {
bus!!.post(Events.CameraUnavailable())
}
}
fun checkFlashlight() {
if (mIsFlashlightOn) {
enableFlashlight()
} else {
disableFlashlight()
}
}
fun enableFlashlight() {
shouldStroboscopeStop = true
if (isStroboscopeRunning) {
mShouldEnableFlashlight = true
return
}
mIsFlashlightOn = true
if (mIsMarshmallow) {
toggleMarshmallowFlashlight(true)
} else {
if (camera == null || mParams == null) {
return
}
mParams!!.flashMode = Camera.Parameters.FLASH_MODE_TORCH
camera!!.parameters = mParams
camera!!.startPreview()
}
val mainRunnable = Runnable { bus!!.post(Events.StateChanged(true)) }
Handler(context.mainLooper).post(mainRunnable)
}
private fun disableFlashlight() {
if (isStroboscopeRunning) {
return
}
mIsFlashlightOn = false
if (mIsMarshmallow) {
toggleMarshmallowFlashlight(false)
} else {
if (camera == null || mParams == null) {
return
}
mParams!!.flashMode = Camera.Parameters.FLASH_MODE_OFF
camera!!.parameters = mParams
}
bus!!.post(Events.StateChanged(false))
}
private fun toggleMarshmallowFlashlight(enable: Boolean) {
marshmallowCamera!!.toggleMarshmallowFlashlight(bus!!, enable)
}
fun releaseCamera() {
if (mIsFlashlightOn) {
disableFlashlight()
}
camera?.release()
camera = null
bus?.unregister(this)
mIsFlashlightOn = false
shouldStroboscopeStop = true
}
} }

View File

@ -9,24 +9,24 @@ import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.hardware.camera2.CameraAccessException
import android.hardware.camera2.CameraManager
import android.os.Build
import android.support.annotation.RequiresApi
import android.util.Log
import android.widget.RemoteViews import android.widget.RemoteViews
import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.isMarshmallowPlus
import com.simplemobiletools.flashlight.R import com.simplemobiletools.flashlight.R
import com.simplemobiletools.flashlight.extensions.config import com.simplemobiletools.flashlight.extensions.config
import com.simplemobiletools.flashlight.models.Events import com.simplemobiletools.flashlight.models.Events
import com.squareup.otto.Bus
import com.squareup.otto.Subscribe import com.squareup.otto.Subscribe
class MyWidgetProvider : AppWidgetProvider() { class MyWidgetProvider : AppWidgetProvider() {
private val TOGGLE = "toggle" private val TOGGLE = "toggle"
companion object { companion object {
private var mCameraImpl: MyCameraImpl? = null
private var mRemoteViews: RemoteViews? = null
private var mColoredBmp: Bitmap? = null private var mColoredBmp: Bitmap? = null
private var mWhiteBmp: Bitmap? = null private var mWhiteBmp: Bitmap? = null
private var mBus: Bus? = null
private var mContext: Context? = null
} }
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
@ -34,77 +34,70 @@ class MyWidgetProvider : AppWidgetProvider() {
} }
private fun performUpdate(context: Context) { private fun performUpdate(context: Context) {
mContext = context
val appWidgetManager = AppWidgetManager.getInstance(context) val appWidgetManager = AppWidgetManager.getInstance(context)
appWidgetManager.getAppWidgetIds(getComponentName(context)).forEach { appWidgetManager.getAppWidgetIds(getComponentName(context)).forEach {
val views = RemoteViews(context.packageName, R.layout.widget)
val intent = Intent(context, MyWidgetProvider::class.java) val intent = Intent(context, MyWidgetProvider::class.java)
intent.action = TOGGLE intent.action = TOGGLE
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0) val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0)
mRemoteViews = RemoteViews(context.packageName, R.layout.widget) views.setOnClickPendingIntent(R.id.toggle_btn, pendingIntent)
mRemoteViews!!.setOnClickPendingIntent(R.id.toggle_btn, pendingIntent)
mCameraImpl = MyCameraImpl(context)
val selectedColor = context.config.widgetBgColor val selectedColor = context.config.widgetBgColor
val alpha = Color.alpha(selectedColor) val alpha = Color.alpha(selectedColor)
mColoredBmp = getColoredCircles(selectedColor, alpha) mColoredBmp = getColoredCircles(context, selectedColor, alpha)
mWhiteBmp = getColoredCircles(Color.WHITE, alpha) mWhiteBmp = getColoredCircles(context, Color.WHITE, alpha)
mRemoteViews!!.setImageViewBitmap(R.id.toggle_btn, mWhiteBmp) views.setImageViewBitmap(R.id.toggle_btn, mWhiteBmp)
if (mBus == null) { appWidgetManager.updateAppWidget(it, views)
mBus = BusProvider.instance
}
registerBus()
} }
} }
private fun getComponentName(context: Context) = ComponentName(context, MyWidgetProvider::class.java) private fun getComponentName(context: Context) = ComponentName(context, MyWidgetProvider::class.java)
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
Log.e("DEBUG", "received action ${intent.action}")
when (intent.action) { when (intent.action) {
TOGGLE -> toggleFlashlight(context) //TOGGLE -> toggleFlashlight(context)
else -> super.onReceive(context, intent) else -> super.onReceive(context, intent)
} }
} }
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun toggleFlashlight(context: Context) { private fun toggleFlashlight(context: Context) {
if (mCameraImpl == null || mBus == null) { if (context.isMarshmallowPlus()) {
performUpdate(context) val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
try {
val cameraId = manager.cameraIdList[0]
//manager.setTorchMode(cameraId!!, enable)
} catch (ignored: CameraAccessException) {
}
}
} }
mCameraImpl!!.toggleFlashlight() private fun getColoredCircles(context: Context, color: Int, alpha: Int): Bitmap {
} val drawable = context.resources.getDrawable(R.drawable.circles_small)
private fun getColoredCircles(color: Int, alpha: Int): Bitmap {
val drawable = mContext!!.resources.getDrawable(R.drawable.circles_small)
drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_ATOP) drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
drawable.mutate().alpha = alpha drawable.mutate().alpha = alpha
return Utils.drawableToBitmap(drawable) return Utils.drawableToBitmap(drawable)
} }
private fun enableFlashlight() { private fun enableFlashlight() {
mRemoteViews!!.setImageViewBitmap(R.id.toggle_btn, mColoredBmp) //mRemoteViews!!.setImageViewBitmap(R.id.toggle_btn, mColoredBmp)
/*for (widgetId in mWidgetIds!!) { /*for (widgetId in mWidgetIds!!) {
mWidgetManager!!.updateAppWidget(widgetId, mRemoteViews) mWidgetManager!!.updateAppWidget(widgetId, mRemoteViews)
}*/ }*/
} }
private fun disableFlashlight() { private fun disableFlashlight() {
mRemoteViews!!.setImageViewBitmap(R.id.toggle_btn, mWhiteBmp) //mRemoteViews!!.setImageViewBitmap(R.id.toggle_btn, mWhiteBmp)
/*for (widgetId in mWidgetIds!!) { /*for (widgetId in mWidgetIds!!) {
mWidgetManager!!.updateAppWidget(widgetId, mRemoteViews) mWidgetManager!!.updateAppWidget(widgetId, mRemoteViews)
}*/ }*/
} }
@Subscribe
fun cameraUnavailable(event: Events.CameraUnavailable) {
if (mContext != null) {
mContext!!.toast(R.string.camera_error)
disableFlashlight()
}
}
@Subscribe @Subscribe
fun stateChangedEvent(event: Events.StateChanged) { fun stateChangedEvent(event: Events.StateChanged) {
if (event.isEnabled) { if (event.isEnabled) {
@ -113,34 +106,4 @@ class MyWidgetProvider : AppWidgetProvider() {
disableFlashlight() disableFlashlight()
} }
} }
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
super.onDeleted(context, appWidgetIds)
unregisterBus()
releaseCamera(context)
}
private fun releaseCamera(context: Context) {
if (mCameraImpl == null) {
performUpdate(context)
}
mCameraImpl!!.releaseCamera()
}
private fun registerBus() {
try {
mBus!!.register(this)
} catch (ignored: Exception) {
}
}
private fun unregisterBus() {
try {
mBus!!.unregister(this)
} catch (ignored: Exception) {
}
}
} }

View File

@ -1,19 +1,7 @@
package com.simplemobiletools.flashlight.models package com.simplemobiletools.flashlight.models
class Events { class Events {
class StateChanged(isEnabled: Boolean) { class StateChanged(val isEnabled: Boolean)
val isEnabled: Boolean
get() = mIsEnabled
init {
mIsEnabled = isEnabled
}
companion object {
private var mIsEnabled: Boolean = false
}
}
class CameraUnavailable class CameraUnavailable
} }

View File

@ -22,7 +22,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/activity_margin" android:layout_marginBottom="@dimen/activity_margin"
android:layout_marginTop="@dimen/buttons_margin" android:layout_marginTop="@dimen/buttons_margin"
android:background="@mipmap/ic_bright_display" android:background="@drawable/ic_bright_display"
android:padding="@dimen/activity_margin"/> android:padding="@dimen/activity_margin"/>
<ImageView <ImageView
@ -30,7 +30,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/buttons_margin" android:layout_marginTop="@dimen/buttons_margin"
android:background="@mipmap/ic_stroboscope" android:background="@drawable/ic_stroboscope"
android:padding="@dimen/activity_margin"/> android:padding="@dimen/activity_margin"/>
<com.simplemobiletools.commons.views.MySeekBar <com.simplemobiletools.commons.views.MySeekBar