개발새발 - IT 기술블로그
article thumbnail

안녕하세요. 이번 포스팅에서는 디바이스의 충전케이블 연결 여부배터리 잔량을 불러오는 기능에 대해 같이 알아보겠습니다.

진행 순서는 아래와 같습니다. 참고로 BatteryManager를 제외한 추가적인 학습이 필요한 기능의 사용을 최대한 지양하며 작성했습니다.

 

 

1. 배터리의 상태를 표시하는 레이아웃 생성

2. 암시적 인텐트로 BroadCast Receiver 호출

3. 뷰를 실시간으로 업데이트 하기 위한 BroadCast Receiver 생성

4. Manifest 파일에 BroadCast Receiver 등록하기

 

 

결과 GIF

 

 

 

 


 

 

 

배터리의 상태를 표시하는 레이아웃 생성

 

배터리의 상태에 따라 변화하는 ImageView와 TextView, 잔량을 표시할 TextView를 생성하였습니다.
배터리 상태는 1~6단계 + 위험충전중0%100% 총 10단계로 구분하였고, 아래 첨부된 이미지 파일을 사용하였습니다.

 

 

battery.zip
0.00MB

 

 

 

<activity_main.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"
    android:background="@color/black"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/batteryImg"
        android:layout_width="50dp"
        android:layout_height="50dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:tint="@color/white" />

    <TextView
        android:id="@+id/batteryValue"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:textColor="@color/white"
        android:textSize="16sp"
        app:layout_constraintEnd_toEndOf="@+id/batteryImg"
        app:layout_constraintStart_toStartOf="@+id/batteryImg"
        app:layout_constraintTop_toBottomOf="@+id/batteryImg" />

    <TextView
        android:id="@+id/batteryIsCharging"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="충전중"
        android:visibility="gone"
        android:textColor="#0aff00"
        android:textSize="13sp"
        app:layout_constraintEnd_toEndOf="@+id/batteryValue"
        app:layout_constraintStart_toStartOf="@+id/batteryValue"
        app:layout_constraintTop_toBottomOf="@+id/batteryValue" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

암시적 인텐트로 BroadCast Receiver 호출

 

여기서 배터리의 잔량을 받아오고 충전기 연결여부를 받아오는 BroadCastReceiver를 호출합니다.

 

<MainActivity.kt>

// 배터리 잔량 및 충전여부를 암시적 인텐트로 브로드캐스팅
private fun getBatteryState() {
    val ifilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
    val receiver = PowerConnectionReceiver(batteryImg, isChargingText)
    val batteryStatus: Intent? = registerReceiver(receiver, ifilter)
    batteryStatus?.let {
        val level = it.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
        val scale = it.getIntExtra(BatteryManager.EXTRA_SCALE, -1)

        batteryPct = level * 100 / scale.toFloat()
        val i: Int = batteryPct.toInt()
        if (i > -1) {
            Log.d("Battery", "Get Battery Status : $batteryPct")
            val s = "$i%"
            valueText.text = s
        }
    }
}

 

 

코드 설명

 

배터리의 상태(Value)가 변화하면 호출되는 액션입니다.

IntentFilter(Intent.ACTION_BATTERY_CHANGED)

 

배터리의 현재 잔량과 최대수치를 받아옵니다.

val level = it.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale = it.getIntExtra(BatteryManager.EXTRA_SCALE, -1)

 

배터리의 현재 잔량을 백분율로 나타내기 위해 Float 타입으로 계산해줍니다.

batteryPct = level * 100 / scale.toFloat()

 

 

 

뷰를 실시간으로 업데이트 하기 위한 BroadCast Receiver 생성

 

<MainActivity.kt>

 // 충전케이블 연결 여부를 불러 와 잔량을 표시하는 뷰를 업데이트
    class PowerConnectionReceiver(
        private val imgView: ImageView,
        private val isChargingText: TextView,
    ) : BroadcastReceiver() {
        @SuppressLint("UnsafeProtectedBroadcastReceiver")
        override fun onReceive(context: Context, intent: Intent) {
            val status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
            val isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING

            if (isCharging) {
                isChargingText.visibility = View.VISIBLE
                Log.i("Battery", "Charging")
            } else {
                isChargingText.visibility = View.GONE
                Log.i("Battery", "DisCharging")
            }

            if (batteryPct != -1f) {
                if (isCharging) {
                    setDrawable(context, R.drawable.battery_charging)
                } else if (batteryPct == 100f) {
                    setDrawable(context, R.drawable.battery_full)
                } else if (batteryPct < 100f && batteryPct > 84.5) {
                    setDrawable(context, R.drawable.battery_6)
                } else if (batteryPct < 84.5 && batteryPct > 67.5) {
                    setDrawable(context, R.drawable.battery_5)
                } else if (batteryPct < 67.5 && batteryPct > 50.5) {
                    setDrawable(context, R.drawable.battery_4)
                } else if (batteryPct < 50.5 && batteryPct > 33.5) {
                    setDrawable(context, R.drawable.battery_3)
                } else if (batteryPct < 33.5 && batteryPct > 16.5) {
                    setDrawable(context, R.drawable.battery_2)
                } else if (batteryPct < 16.5 && batteryPct > 5f) {
                    setDrawable(context, R.drawable.battery_1)
                } else if (batteryPct < 5f && batteryPct > 0f) {
                    setDrawable(context, R.drawable.battery_caution)
                } else {
                    setDrawable(context, R.drawable.battery_empty)
                }
            }
        }

        private fun setDrawable(context: Context, drawable: Int) {
            imgView.setImageDrawable(
                ResourcesCompat.getDrawable(
                    context.resources,
                    drawable,
                    null
                )
            )
        }
    }

 

 

코드 설명

 

인텐트로 호출하면 현재 배터리의 상태정보를 가져옵니다.

intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)

 

현재 디바이스에 충전케이블이 연결되었는지의 여부를 Boolean 타입으로 받아옵니다.

status == BatteryManager.BATTERY_STATUS_CHARGING

 

플래그 값이 true이면 충전중 메시지를 보여주고, false면 숨깁니다.

if (isCharging) {
    isChargingText.visibility = View.VISIBLE
} else {
    isChargingText.visibility = View.GONE
}

 

 

배터리의 상태값을 받아오는데 성공했다면(설정한 Default값이 아니라면) 조건문을 실행합니다.

if (batteryPct != -1f) {
…
}

 

Manifest 파일에 BroadCast Receiver 등록하기

마지막으로 생성한 리시버를 어플리케이션에 등록하는 작업을 진행합니다. 인텐트 필터로 전원 연결 및 해제를 등록합니다.

…
<receiver
    android:name="com.example.batteryexam.MainActivity$PowerConnectionReceiver"
    android:exported="true"
    tools:ignore="Instantiatable">
    <intent-filter>
        <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
        <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
    </intent-filter>
</receiver>
</application>

 

 

전체코드<MainAcitivity.kt>

더보기

 

package com.example.batteryexam

import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat

class MainActivity : AppCompatActivity() {
    companion object {
        var batteryPct = -1f
    }

    private lateinit var batteryImg: ImageView
    lateinit var valueText: TextView
    lateinit var isChargingText: TextView

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

        batteryImg = findViewById(R.id.batteryImg)
        valueText = findViewById(R.id.batteryValue)
        isChargingText = findViewById(R.id.batteryIsCharging)

        getBatteryState()
    }

    // 배터리 잔량 및 충전여부를 암시적 인텐트로 브로드캐스팅
    private fun getBatteryState() {
        val ifilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
        val receiver = PowerConnectionReceiver(batteryImg, isChargingText)
        val batteryStatus: Intent? = registerReceiver(receiver, ifilter)
        batteryStatus?.let {
            val level = it.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
            val scale = it.getIntExtra(BatteryManager.EXTRA_SCALE, -1)

            batteryPct = level * 100 / scale.toFloat()
            val i: Int = batteryPct.toInt()
            if (i > -1) {
                Log.d("Battery", "Get Battery Status : $batteryPct")
                val s = "$i%"
                valueText.text = s
            }
        }
    }

    // 충전케이블 연결 여부를 불러 와 잔량을 표시하는 뷰를 업데이트
    class PowerConnectionReceiver(
        private val imgView: ImageView,
        private val isChargingText: TextView,
    ) : BroadcastReceiver() {
        @SuppressLint("UnsafeProtectedBroadcastReceiver")
        override fun onReceive(context: Context, intent: Intent) {
            val status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
            val isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING

            if (isCharging) {
                isChargingText.visibility = View.VISIBLE
                Log.i("Battery", "Charging")
            } else {
                isChargingText.visibility = View.GONE
                Log.i("Battery", "DisCharging")
            }

            if (batteryPct != -1f) {
                if (isCharging) {
                    setDrawable(context, R.drawable.battery_charging)
                } else if (batteryPct == 100f) {
                    setDrawable(context, R.drawable.battery_full)
                } else if (batteryPct < 100f && batteryPct > 84.5) {
                    setDrawable(context, R.drawable.battery_6)
                } else if (batteryPct < 84.5 && batteryPct > 67.5) {
                    setDrawable(context, R.drawable.battery_5)
                } else if (batteryPct < 67.5 && batteryPct > 50.5) {
                    setDrawable(context, R.drawable.battery_4)
                } else if (batteryPct < 50.5 && batteryPct > 33.5) {
                    setDrawable(context, R.drawable.battery_3)
                } else if (batteryPct < 33.5 && batteryPct > 16.5) {
                    setDrawable(context, R.drawable.battery_2)
                } else if (batteryPct < 16.5 && batteryPct > 5f) {
                    setDrawable(context, R.drawable.battery_1)
                } else if (batteryPct < 5f && batteryPct > 0f) {
                    setDrawable(context, R.drawable.battery_caution)
                } else {
                    setDrawable(context, R.drawable.battery_empty)
                }
            }
        }

        private fun setDrawable(context: Context, drawable: Int) {
            imgView.setImageDrawable(
                ResourcesCompat.getDrawable(
                    context.resources,
                    drawable,
                    null
                )
            )
        }
    }
}

 

 

이렇게 핸드폰 충전상태 및 배터리 잔량을 받아오는 방법에 대해 알아보았습니다. 
감사합니다.

 

 

 

 

 

 

참조

https://developer.android.com/reference/android/os/BatteryManager

 

BatteryManager  |  Android Developers

 

developer.android.com

 

 

 

예제 소스

https://github.com/tekken5953/BatteryExam

 

GitHub - tekken5953/BatteryExam

Contribute to tekken5953/BatteryExam development by creating an account on GitHub.

github.com