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

View File

@ -1,6 +1,23 @@
package com.simplemobiletools.flashlight.extensions
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import com.simplemobiletools.flashlight.R
import com.simplemobiletools.flashlight.helpers.Config
import com.simplemobiletools.flashlight.helpers.MyWidgetProvider
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)
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
init {

View File

@ -1,15 +1,14 @@
package com.simplemobiletools.flashlight.helpers
import android.annotation.TargetApi
import android.content.Context
import android.graphics.SurfaceTexture
import android.hardware.Camera
import android.os.Build
import android.os.Handler
import com.simplemobiletools.commons.extensions.isMarshmallowPlus
import com.simplemobiletools.commons.extensions.isNougatPlus
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.flashlight.R
import com.simplemobiletools.flashlight.extensions.updateWidgets
import com.simplemobiletools.flashlight.models.Events
import com.squareup.otto.Bus
import java.io.IOException
@ -17,20 +16,173 @@ import java.io.IOException
class MyCameraImpl(val context: Context) {
var stroboFrequency = 1000
companion object {
private var camera: Camera? = null
private var mParams: Camera.Parameters? = null
private var params: Camera.Parameters? = null
private var bus: Bus? = null
private var mIsFlashlightOn = false
private var mIsMarshmallow = false
private var mShouldEnableFlashlight = false
}
private var isFlashlightOn = false
private var isMarshmallow = false
private var shouldEnableFlashlight = false
private var marshmallowCamera: MarshmallowCamera? = null
@Volatile private var shouldStroboscopeStop = 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 {
if (isStroboscopeRunning) {
return@Runnable
@ -46,9 +198,7 @@ class MyCameraImpl(val context: Context) {
Thread.sleep(stroboFrequency.toLong())
marshmallowCamera!!.toggleMarshmallowFlashlight(bus!!, false)
Thread.sleep(stroboFrequency.toLong())
} catch (ignored: InterruptedException) {
shouldStroboscopeStop = true
} catch (ignored: RuntimeException) {
} catch (e: Exception) {
shouldStroboscopeStop = true
}
@ -77,18 +227,14 @@ class MyCameraImpl(val context: Context) {
Thread.sleep(stroboFrequency.toLong())
camera!!.parameters = torchOff
Thread.sleep(stroboFrequency.toLong())
} catch (ignored: InterruptedException) {
shouldStroboscopeStop = true
} catch (ignored: RuntimeException) {
shouldStroboscopeStop = true
} catch (e: Exception) {
}
}
try {
if (camera != null) {
camera!!.parameters = torchOff
if (!mShouldEnableFlashlight || mIsMarshmallow) {
if (!shouldEnableFlashlight || isMarshmallow) {
camera!!.release()
camera = null
}
@ -100,157 +246,9 @@ class MyCameraImpl(val context: Context) {
isStroboscopeRunning = false
shouldStroboscopeStop = false
if (mShouldEnableFlashlight) {
if (shouldEnableFlashlight) {
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.Color
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 com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.extensions.isMarshmallowPlus
import com.simplemobiletools.flashlight.R
import com.simplemobiletools.flashlight.extensions.config
import com.simplemobiletools.flashlight.models.Events
import com.squareup.otto.Bus
import com.squareup.otto.Subscribe
class MyWidgetProvider : AppWidgetProvider() {
private val TOGGLE = "toggle"
companion object {
private var mCameraImpl: MyCameraImpl? = null
private var mRemoteViews: RemoteViews? = null
private var mColoredBmp: 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) {
@ -34,77 +34,70 @@ class MyWidgetProvider : AppWidgetProvider() {
}
private fun performUpdate(context: Context) {
mContext = context
val appWidgetManager = AppWidgetManager.getInstance(context)
appWidgetManager.getAppWidgetIds(getComponentName(context)).forEach {
val views = RemoteViews(context.packageName, R.layout.widget)
val intent = Intent(context, MyWidgetProvider::class.java)
intent.action = TOGGLE
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0)
mRemoteViews = RemoteViews(context.packageName, R.layout.widget)
mRemoteViews!!.setOnClickPendingIntent(R.id.toggle_btn, pendingIntent)
mCameraImpl = MyCameraImpl(context)
views.setOnClickPendingIntent(R.id.toggle_btn, pendingIntent)
val selectedColor = context.config.widgetBgColor
val alpha = Color.alpha(selectedColor)
mColoredBmp = getColoredCircles(selectedColor, alpha)
mWhiteBmp = getColoredCircles(Color.WHITE, alpha)
mRemoteViews!!.setImageViewBitmap(R.id.toggle_btn, mWhiteBmp)
mColoredBmp = getColoredCircles(context, selectedColor, alpha)
mWhiteBmp = getColoredCircles(context, Color.WHITE, alpha)
views.setImageViewBitmap(R.id.toggle_btn, mWhiteBmp)
if (mBus == null) {
mBus = BusProvider.instance
}
registerBus()
appWidgetManager.updateAppWidget(it, views)
}
}
private fun getComponentName(context: Context) = ComponentName(context, MyWidgetProvider::class.java)
override fun onReceive(context: Context, intent: Intent) {
Log.e("DEBUG", "received action ${intent.action}")
when (intent.action) {
TOGGLE -> toggleFlashlight(context)
//TOGGLE -> toggleFlashlight(context)
else -> super.onReceive(context, intent)
}
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun toggleFlashlight(context: Context) {
if (mCameraImpl == null || mBus == null) {
performUpdate(context)
if (context.isMarshmallowPlus()) {
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(color: Int, alpha: Int): Bitmap {
val drawable = mContext!!.resources.getDrawable(R.drawable.circles_small)
private fun getColoredCircles(context: Context, color: Int, alpha: Int): Bitmap {
val drawable = context.resources.getDrawable(R.drawable.circles_small)
drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
drawable.mutate().alpha = alpha
return Utils.drawableToBitmap(drawable)
}
private fun enableFlashlight() {
mRemoteViews!!.setImageViewBitmap(R.id.toggle_btn, mColoredBmp)
//mRemoteViews!!.setImageViewBitmap(R.id.toggle_btn, mColoredBmp)
/*for (widgetId in mWidgetIds!!) {
mWidgetManager!!.updateAppWidget(widgetId, mRemoteViews)
}*/
}
private fun disableFlashlight() {
mRemoteViews!!.setImageViewBitmap(R.id.toggle_btn, mWhiteBmp)
//mRemoteViews!!.setImageViewBitmap(R.id.toggle_btn, mWhiteBmp)
/*for (widgetId in mWidgetIds!!) {
mWidgetManager!!.updateAppWidget(widgetId, mRemoteViews)
}*/
}
@Subscribe
fun cameraUnavailable(event: Events.CameraUnavailable) {
if (mContext != null) {
mContext!!.toast(R.string.camera_error)
disableFlashlight()
}
}
@Subscribe
fun stateChangedEvent(event: Events.StateChanged) {
if (event.isEnabled) {
@ -113,34 +106,4 @@ class MyWidgetProvider : AppWidgetProvider() {
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
class Events {
class StateChanged(isEnabled: Boolean) {
val isEnabled: Boolean
get() = mIsEnabled
init {
mIsEnabled = isEnabled
}
companion object {
private var mIsEnabled: Boolean = false
}
}
class StateChanged(val isEnabled: Boolean)
class CameraUnavailable
}

View File

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