【2022年】簡単な懐中電灯アプリを実装してみる

# 前置き

使ってる懐中電灯アプリが、なぜかライトつけるだけなのに長いローディング画面があったり
広告があったりで、「もー本当クソクソクソクソですわ～（私の中のお姫様）」って感じだったのですが
そういや、自分が鬱病で腐った元プログラマーだった事を思い出したので
自分が理想とする懐中電灯アプリを作ってみては？と思い、作るに至りました

# そもそもAndroidデフォルトの機能で懐中電灯あるのでは？

お黙りなさい

# 参考

https://qiita.com/L_A_P_119611/items/826f3f0e96fe0de1d23b

こいつのワンタップで点灯機能とか不要な機能を切った、簡潔なバージョンを作ります

# プロジェクト作成

Empty Activityで作成
今回はbuild.gradle等には触らない

# main_activity.xml

Hello worldを表示するTextViewを消して、単純なボタンのみにする

~~~ main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        android:onClick="onClick_lightSwitch"/>
    
</androidx.constraintlayout.widget.ConstraintLayout>
~~~

# MainActivity.kt

最初に全文を載せる　個々の説明はそのあとに

~~~ MainActivity.kt
package com.flashligt.simpleflashloight

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.hardware.camera2.CameraManager
import android.view.View
import android.os.Handler
import android.content.Context

class MainActivity : AppCompatActivity() {

    lateinit var manager: CameraManager
    lateinit var cameraId : String
    var lightSwitch : Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        getCameraId()
    }

    private fun getCameraId()
    {
        manager =
            getSystemService(Context.CAMERA_SERVICE) as CameraManager
        try {
            // トーチモードのコールバックを登録する
            manager.registerTorchCallback(object : CameraManager.TorchCallback() {
                override fun onTorchModeChanged(id: String, enabled: Boolean) {
                    super.onTorchModeChanged(id, enabled)
                    // 前面カメラのみ有効
                    if(id != "0") return
                    // カメラidと状態を保存する
                    cameraId = id
                }
            }, Handler())
        } catch (e: Exception) {
            //例外握りつぶしはよくないが、今回の処理では必要ないため握りつぶす
        }
    }



    fun onClick_lightSwitch( view : View)
    {
        manager.setTorchMode(cameraId, !lightSwitch)
        lightSwitch = !lightSwitch
    }

}
~~~

たぶんソースみればわかると思うけど、一応個々の説明をする

~~~ MainActivity.kt

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.hardware.camera2.CameraManager
import android.view.View
import android.os.Handler
import android.content.Context
~~~

必要なものをimportしてるだけ
脳死で記述していい
gradleに特段記述しなくてもimportできるはず


~~~ MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        getCameraId()
    }
~~~

ただの初期化。独自に用意したgetCameraId()関数以外は、自動生成されるソース

~~~ MainActivity.kt
private fun getCameraId()
    {
        manager =
            getSystemService(Context.CAMERA_SERVICE) as CameraManager
        try {
            // トーチモードのコールバックを登録する
            manager.registerTorchCallback(object : CameraManager.TorchCallback() {
                override fun onTorchModeChanged(id: String, enabled: Boolean) {
                    super.onTorchModeChanged(id, enabled)
                    // 前面カメラのみ有効
                    if(id != "0") return
                    // カメラidと状態を保存する
                    cameraId = id
                }
            }, Handler())
        } catch (e: Exception) {
            //例外握りつぶしはよくないが、今回の処理では必要ないため握りつぶす
        }
    }
~~~

カメラを取得する処理
カメラとライトが連動してるらしい
処理を見るに、カメラが複数ある端末にも対応できるらしいが
そんなケース殆ど無いと思われる

本来は例外処理を書かないといけないが、めんどくさいんで握りつぶす


（よい子はなるべく真似しないように）

~~~ MainActivity.kt
    fun onClick_lightSwitch( view : View)
    {
        manager.setTorchMode(cameraId, lightSwitch)
        lightSwitch = !lightSwitch
    }
~~~

main_activity.xmlで配置したbuttonのクリックイベントの結び付け先
単純にCameraManagerにライトの点灯or消灯命令を下し
内部に保有してるライトの点灯情報を切り替えてるだけ

# とりあえずこれで起動はできる

ボタンを押せばライトが点灯と消灯を繰り返すはず

# 課題

・アプリ起動時にライトが点灯しない（ソースの簡略化のためにわざと切ってる）
・ライトを点灯した状態でアプリをバックグラウンドにしたり終了してもライトつけっぱなし
・画面の縦横切り替え等でライトの点灯フラグが初期化されておかしくなる
・UIの見た目でライトのOn/Offの判断ができない

上記問題点を解決した懐中電灯アプリを作る

https://qiita.com/princess114514/items/71a1b0c65ebcf104509d


# その他

### パーミッション設定が必要そうだけど必要ないのか？

俺もカメラにアクセスするから必要かと思ったが、いらないようだ
あのへんの処理マジでだるい記憶しかないから助かる