第2回 カメラを使ってみよう


カメラ実装用アクティビティ追加

(1) メニューから「ファイル」-「新規」-「アクティビティー」-「空のアクティビティー」を選択します。

(2) 以下を入力し、完了ボタンをクリックします。

  • アクティビティー名                        :LiveCamera
  • レイアウト・ファイルを生成する      :チェックする
  • ソース言語                                   :Kotlin
  • ターゲット・ソース・セット            :main

ページトップ

MainActivityのレイアウト変更

(1) プロジェクトツリーから app/res/layout/activity_main.xml をダブルクリックします。

(2) パレットの「Buttons」を選択、「Button」を画面上にドラッグします。
※この画面が表示されていないときは「※ここをクリック!」をクリックしてください。
以下を設定してください。

  • id     :takeVideoBtn
  • text  : カメラ起動

(3) コンポーネント・ツリーの「takeVideoBtn」にエラー表示のアイコンがあるとき、画面上部の①のアイコンをクリックし、エラーを除去します。
Ctrl+sで保存します。

ページトップ

LiveCameraActivityのレイアウト変更

(1) プロジェクトツリーから app/res/layout/activity_live_camera.xml をダブルクリックします。

(2) 画面右上の「コード」アイコンをクリックします。

(3) 以下のコードを入力し、Ctrl+sで保存します。

<?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=".LiveCamera">

    <VideoView
        android:id="@+id/videoView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginBottom="57dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
ページトップ

プログラム修正

(1) プロジェクトツリーから app/manifests/AndroidManifest.xml をダブルクリックします。

(2) 以下のコードを入力し、Ctrl+sで保存します。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.livecamera">

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.hardware.camera.autofocus" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity
            android:name=".LiveCamera"
            android:parentActivityName=".MainActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".MainActivity" />
        </activity>

        <meta-data
            android:name="com.google.firebase.ml.vision.DEPENDENCIES"
            android:value="face" />

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

(3) プロジェクトツリーから app/java/com.example.livecamera/MainActivity をダブルクリックします。

(4) 以下のコードを入力し、Ctrl+sで保存します。

package com.example.livecamera

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat

class MainActivity : AppCompatActivity() {
    companion object {
        const val CAMERA_PERMISSION_REQUEST_CODE = 2
    }

    private lateinit var takeVideoBtn: Button

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

        takeVideoBtn = findViewById(R.id.takeVideoBtn)
    }

    override fun onResume(){
        super.onResume()
        takeVideoBtn.setOnClickListener{
            // カメラ機能を実装したアプリが存在するかチェック
            val intent = Intent(applicationContext, LiveCamera::class.java)
            intent.resolveActivity(packageManager)?.let {
                if (checkCameraPermission()) {
                    startActivity(intent)
                } else {
                    grantCameraPermission()
                }
            } ?: Toast.makeText(this, "カメラを扱うアプリがありません", Toast.LENGTH_LONG).show()
        }
    }

    private fun grantCameraPermission() =
            ActivityCompat.requestPermissions(this,
                    arrayOf(Manifest.permission.CAMERA),
                    CAMERA_PERMISSION_REQUEST_CODE)

    private fun checkCameraPermission() = PackageManager.PERMISSION_GRANTED ==
            ContextCompat.checkSelfPermission(applicationContext, Manifest.permission.CAMERA)
}

(5) プロジェクトツリーから app/java/com.example.livecamera/LiveCamera をダブルクリックします。

(6) 以下のコードを入力し、Ctrl+sで保存します。

package com.example.livecamera

import android.content.Intent
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment.DIRECTORY_MOVIES
import android.provider.MediaStore
import android.widget.VideoView
import java.io.File
import java.io.IOException

class LiveCamera : AppCompatActivity() {

    private lateinit var videoView: VideoView
    private var capturedUri: Uri? = null

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_live_camera)

    videoView =  findViewById(R.id.videoView)
    takeVideo()
  }

    private fun takeVideo(){
            dispatchTakeVideoIntent()
            videoView.setVideoURI(intent.data)
            videoView.start()
    }

    private fun dispatchTakeVideoIntent() {
        val takeVideoIntent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
        takeVideoIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        if (takeVideoIntent.resolveActivity(packageManager) != null) {
            try {
                takeVideoIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10)
                takeVideoIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1)
                val videoFile: File = createMediaFile()
            println("=============>videoFile = $videoFile")
                capturedUri = Uri.fromFile(videoFile)

                takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, capturedUri)
                startActivityForResult(takeVideoIntent, 200)
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }

    private fun createMediaFile(): File {
        // Create an image file name
        val fileName = "VID_"
        val directory:File = File(System.getProperty("java.io.tmpdir", ".") + "/" +  DIRECTORY_MOVIES)

        if (!directory.exists())
            directory.mkdir()

        return File("$directory/$fileName${System.currentTimeMillis()}.mp4")
    }
}
ページトップ

実行

(1) メニューの「ビルド」-「プロジェクトの再ビルド」をクリックします。

(2) ステータスバーに進行状況が表示され、「ビルド出力」と「イベント・ログ」でビルドエラーなどの確認ができます。

(3) ビルドが終了するとステータスバーに「Gradleビルドが完了しました」が表示されます。
「ビルド出力」に BUILD SUCCESSFUL が表示されていることを確認します。

(4) デバッグする実機が「SHARP SH-05G」であることを確認し、「実行」アイコンをクリックします。

(5) ステータスが以下の順に表示され、実機にインストールされます。

(6) 実機で作成したアプリが実行されています。

ページトップ

個人的感想

分かったこと

  • Activity の命名を「~Activity」にしなかったため、プロジェクト名なのかアクティビティなのか分からなくなった
  • Activity から Intent を生成して 別Activityを呼び出す
  • Intentしてカメラを使う
  • 表示するものと用途によってViewを使い分ける必要がある
  • onResumeなど、割り込み関係を overrideする
  • ローカルストレージのアクセス方法
  • Toastが楽しい!

分からなかったこと

  • Manifest の 中身
  • permissionが正しく出来ているのかわからない
  • カメラ制御が古いロジック?(camera2でない)
  • androidバージョン違いの他の端末で動くのか?
  • カメラ終了してないので、最初の画面に戻らずハングったりする。
    端末再起動しないとカメラが使えなくなる。
ページトップ