코틀린 팀플3-연락처 어플 만들기

알람, 권한 부여, 애니매이션, 착발신 기록 가져오기

songyooho 2024. 7. 24. 21:50

1. 알람

1) 알람 추가 다이얼로그

mainFbtnAddalarm.setOnClickListener {
    val builder = AlertDialog.Builder(this@MainActivity)
    builder.setTitle("알림 추가")
    builder.setIcon(R.mipmap.ic_launcher)

    val bindingDialog = DialogAlarmBinding.inflate(layoutInflater)
    val items = arrayOf("없음","5분","15분","30분")
    val adapter = ArrayAdapter(this@MainActivity,android.R.layout.simple_spinner_dropdown_item,items)
    bindingDialog.dialongSpinnerTime.adapter=adapter
    builder.setView(bindingDialog.root)

    val listener = DialogInterface.OnClickListener { _,_->
        val selected=bindingDialog.dialongSpinnerTime.selectedItemPosition
        val time=when(selected){
            0 -> 0
            1 -> 5
            2 -> 15
            else -> 30
        }
        showNotification(bindingDialog.dialogEtName.text.toString(), time)
    }

    builder.setPositiveButton("확인",listener)
    builder.setNegativeButton("취소",null)

    builder.show()
}

 

2)알람 채널 생성- 이부분은 onCreate()에서 메소드 실행

private fun createNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Android 8.0
        val channel = NotificationChannel(
            channelID, "default channel",
            NotificationManager.IMPORTANCE_DEFAULT
        )
        channel.description = "call alarm"
        val notificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }
}

 

3)알람 띄우기

private fun showNotification(str:String, time:Int) {
    val builder = NotificationCompat.Builder(this, channelID)
        .setSmallIcon(R.mipmap.ic_launcher)
        .setContentTitle("연락처 알림")
        .setContentText(str+"에게 연락할 시간입니다.")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
    if (ActivityCompat.checkSelfPermission(
            this,
            Manifest.permission.POST_NOTIFICATIONS
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        getPermission()
        return
    }
    Thread{
        Thread.sleep((60*1000*time).toLong())
        NotificationManagerCompat.from(this).notify(myNotificationID, builder.build())
    }.start()

}

-알람띄우기까지 시간을 기다리는걸 Thread.sleep을 이용

 

 

2. 권한 부여

1)AndroidManifest에 권한 추가

<uses-feature
    android:name="android.hardware.telephony"
    android:required="false" />

<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />

 

2)권한 체크 후 권한 받아오기- 권한을 모두 받은 상태일 경우 뷰 초기화 시작

fun getPermission(){
    if(Build.VERSION.SDK_INT < 33){
        val permissions = arrayOf(android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.CALL_PHONE,
            android.Manifest.permission.SEND_SMS,
            android.Manifest.permission.INTERNET, android.Manifest.permission.READ_CALL_LOG)
        var flag=false
        for(i in permissions){
            if(checkSelfPermission(i) == PackageManager.PERMISSION_DENIED){
                flag=true
            }
        }
        if(flag) requestPermissions(permissions,0)
        else initView()
    }else{
        val permissions = arrayOf(android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.CALL_PHONE,
            android.Manifest.permission.POST_NOTIFICATIONS,android.Manifest.permission.SEND_SMS,
            android.Manifest.permission.INTERNET, android.Manifest.permission.READ_CALL_LOG)
        var flag=false
        for(i in permissions){
            if(checkSelfPermission(i) == PackageManager.PERMISSION_DENIED){
                flag=true
            }
        }
        if(flag) requestPermissions(permissions,0)
        else initView()
    }

-알림 권한은 SDK 버전 33부터 받아야 하므로 if문으로 나눠서 다르게 받음

 

3)권한 받아왔을때 모든 권한을 받았으면 뷰 초기화 시작

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if(requestCode ==0){
        var flag=true
        for(i in grantResults){
            if(i==PackageManager.PERMISSION_DENIED) flag=false

        }
        if(flag) initView()
    }
}

 

 

3. 애니메이션 상태 체크해서 변수 설정하기

listLlGridlist.setOnClickListener{
    mainViewWhitebtn.callOnClick()
    listMlGridlist.setTransitionListener(object :MotionLayout.TransitionListener{
        override fun onTransitionStarted(
            motionLayout: MotionLayout?,
            startId: Int,
            endId: Int
        ) {
            return
        }

        override fun onTransitionChange(
            motionLayout: MotionLayout?,
            startId: Int,
            endId: Int,
            progress: Float
        ) {
            return
        }

        override fun onTransitionCompleted(
            motionLayout: MotionLayout?,
            currentId: Int
        ) {
            isGrid = motionLayout!!.currentState==motionLayout!!.startState
            println(isGrid)
        }

        override fun onTransitionTrigger(
            motionLayout: MotionLayout?,
            triggerId: Int,
            positive: Boolean,
            progress: Float
        ) {
            return
        }

    })
}

-애니메이션이 동작 완료되었을때 체크해서 어느상태인지 확인 후 변수 설정

 

4. 착발신 기록 가져오기

1)착발신 기록 데이터 구조

data class CallLogEntity(
    var name: String?,
    val type: String,
    val number: String,
    val date: String,
    val Duration: Int
)

 

2)착발신 기록 가져오기

fun callHistory(context: Context):ArrayList<CallLogEntity>{
    val logs=ArrayList<CallLogEntity>()
    val callSet= arrayOf(CallLog.Calls.TYPE, CallLog.Calls.NUMBER, CallLog.Calls.DATE, CallLog.Calls.DURATION)
    val cursor = context.contentResolver.query(CallLog.Calls.CONTENT_URI,callSet,null,null,null)
        ?: return logs
    while(cursor.moveToNext()){
        val typeidx=cursor.getColumnIndex(callSet[0])
        val numberidx=cursor.getColumnIndex(callSet[1])
        val dateidx=cursor.getColumnIndex(callSet[2])
        val durationidx=cursor.getColumnIndex(callSet[3])

        val type=if(cursor.getInt(typeidx)==CallLog.Calls.INCOMING_TYPE) "착신" else "발신"
        val number = cursor.getString(numberidx)
        val date=SimpleDateFormat("yyyy-MM-dd").format(Date(cursor.getLong(dateidx)))
        val duration =cursor.getDouble(durationidx).toInt()
        logs+=CallLogEntity(null,type,number,date,duration)
    }
    return logs
}

 

3)ContactDataSource에서 by lazy로 변수 선언

val CallLogEntities by lazy { callHistory(application) }

 

4)ContactRepositoryImpl에서 전화기록에 저장된 연락처를 가지고 이름 데이터 붙여 가져오기

override fun getCallLogs(): ArrayList<CallLogEntity> {
    val map=contactDataSource.ContactEntities.associate { it.num to it.name }
    val callLogs=contactDataSource.CallLogEntities
    for(i in callLogs){
        i.name = map.getOrDefault(i.number,i.number)
    }
    return callLogs
}