Skip to content

Commit

Permalink
1. IncomingCallActivity 수신, 거절 버튼 기능 및 화면 전환 구현
Browse files Browse the repository at this point in the history
2. CallInProgressActivity UI 일부 구현 및 거절 버튼 기능 및 화면 전환
   구현
3. CallEndedActivity UI 구현
4. resource 수정 및 추가
  • Loading branch information
pse committed Aug 12, 2024
1 parent ff1c31b commit 179e37b
Show file tree
Hide file tree
Showing 17 changed files with 440 additions and 159 deletions.
38 changes: 29 additions & 9 deletions app/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
xmlns:tools="http://schemas.android.com/tools">

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

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.CALL_PHONE" />

<application
android:allowBackup="true"
Expand All @@ -12,27 +18,30 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Sibal"
tools:targetApi="31" >
android:theme="@style/Theme.Sibal">

<service
android:name=".MyInCallService"
android:permission="android.permission.BIND_INCALL_SERVICE"
android:exported="true">

<meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
<meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING"
android:exported="true"
android:permission="android.permission.BIND_INCALL_SERVICE">
<meta-data
android:name="android.telecom.IN_CALL_SERVICE_UI"
android:value="true" />
<meta-data
android:name="android.telecom.IN_CALL_SERVICE_RINGING"
android:value="true" />

<intent-filter>
<action android:name="android.telecom.InCallService" />
</intent-filter>
</service>

<activity
android:name=".MainActivity"
android:exported="true" >
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Expand All @@ -42,14 +51,25 @@
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.DIAL" />

<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DIAL" />

<category android:name="android.intent.category.DEFAULT" />

<data android:scheme="tel" />
</intent-filter>
</activity>

<activity
android:name=".CallInProgressActivity"
android:exported="false" />

<activity
android:name=".CallEndedActivity"
android:exported="false" />
</application>

</manifest>
22 changes: 12 additions & 10 deletions app/app/src/main/java/com/example/sibal/CallEndedActivity.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
package com.example.sibal

import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import android.os.Looper
import android.os.Handler
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.sibal.databinding.ActivityCallEndedBinding

class CallEndedActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_call_ended)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
Log.d("CallEndedActivity", "전화 종료 화면 실행")
val binding = ActivityCallEndedBinding.inflate(layoutInflater)
setContentView(binding.root)

Handler(Looper.getMainLooper()).postDelayed({
finish()
}, 2000)
}
}
45 changes: 36 additions & 9 deletions app/app/src/main/java/com/example/sibal/CallInProgressActivity.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,47 @@
package com.example.sibal

import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import android.telecom.TelecomManager
import android.util.Log
import android.view.MotionEvent
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.content.ContextCompat
import com.example.sibal.databinding.ActivityCallInProgressBinding

class CallInProgressActivity : AppCompatActivity() {
private lateinit var telecomManager: TelecomManager

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_call_progress)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
Log.d("CallInProgressActivity", "전화 수신 화면 실행")
val binding = ActivityCallInProgressBinding.inflate(layoutInflater)
setContentView(binding.root)

val declineButton: ImageView = binding.decline2
telecomManager = getSystemService(TELECOM_SERVICE) as TelecomManager

declineButton.setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
(v as ImageView).setColorFilter(Color.argb(150, 0, 0, 0)) // 어두운 색 적용
true
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ANSWER_PHONE_CALLS) == PackageManager.PERMISSION_GRANTED) {
Log.d("IncomingCallActivity", "전화 종료")
telecomManager.endCall()
val intent = Intent(this, CallEndedActivity::class.java)
startActivity(intent)
finish()
}
true
}
else -> false
}
}
}
}
97 changes: 91 additions & 6 deletions app/app/src/main/java/com/example/sibal/IncomingCallActivity.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,107 @@
package com.example.sibal

import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Resources
import android.os.Bundle
import android.os.Handler
import android.telecom.TelecomManager
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.example.sibal.databinding.ActivityIncomingCallBinding

class IncomingCallActivity : AppCompatActivity() {

private lateinit var binding: ActivityIncomingCallBinding
private var parentWidth: Int = 0
private lateinit var telecomManager: TelecomManager

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("IncomingCallActivity", "덮어 쓰기 화면 실행")
binding = ActivityIncomingCallBinding.inflate(layoutInflater)
Log.d("IncomingCallActivity", "전화가 걸려왔을 때 화면 실행")
val binding = ActivityIncomingCallBinding.inflate(layoutInflater)
setContentView(binding.root)

val acceptButton = binding.accept
val declineButton = binding.decline

setupButtonDrag(acceptButton, true)
setupButtonDrag(declineButton, false)

parentWidth = Resources.getSystem().displayMetrics.widthPixels
telecomManager = getSystemService(TELECOM_SERVICE) as TelecomManager
}

private fun setupButtonDrag(button: ImageView, isAcceptButton: Boolean) {
var dX = 0f
var initialX = 0f

button.setOnTouchListener { view, event ->
when (event.action) {
//버튼을 눌렀을 때
MotionEvent.ACTION_DOWN -> {
initialX = view.x //버튼의 초기 위치 저장
dX = view.x - event.rawX //버튼 이동 거리

view.animate()
.scaleX(1.3f)
.scaleY(1.3f)
.setDuration(0)
.start()
true
}

//버튼을 드래그 했을 때
MotionEvent.ACTION_MOVE -> {
view.animate()
.x(event.rawX + dX)
.setDuration(0)
.start()

//전화 수신 버튼을 화면의 오른쪽으로 충분히 이동 시켰을 경우 -> 전화 수신
if (isAcceptButton && view.x > parentWidth * 0.4) {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ANSWER_PHONE_CALLS) == PackageManager.PERMISSION_GRANTED) {
Log.d("IncomingCallActivity", "전화 수신")
telecomManager.acceptRingingCall()
val intent = Intent(this, CallInProgressActivity::class.java)
startActivity(intent)
finish()
}

//전화 거절 버튼을 화면의 왼쪽으로 충분히 이동 시켰을 경우 -> 전화 종료
} else if (!isAcceptButton && view.x < parentWidth * 0.6) {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ANSWER_PHONE_CALLS) == PackageManager.PERMISSION_GRANTED) {
Log.d("IncomingCallActivity", "전화 종료")
telecomManager.endCall()
val intent = Intent(this, CallEndedActivity::class.java)
startActivity(intent)
finish()
}
}
true
}

//버튼을 땟을 때 -> 버튼이 제자리로 돌아감
MotionEvent.ACTION_UP -> {
//버튼 위치를 원래대로 되돌리는 애니메이션
val moveBackAnim = ObjectAnimator.ofFloat(view, "x", initialX)

//버튼 크기를 원래대로 되돌리는 애니메이션
val scaleBackXAnim = ObjectAnimator.ofFloat(view, "scaleX", 1f)
val scaleBackYAnim = ObjectAnimator.ofFloat(view, "scaleY", 1f)

//애니메이션 동시 실행
val animatorSet = AnimatorSet()
animatorSet.playTogether(moveBackAnim, scaleBackXAnim, scaleBackYAnim)
animatorSet.duration - 300
animatorSet.start()
true
}
else -> false
}
}
}
}
15 changes: 13 additions & 2 deletions app/app/src/main/java/com/example/sibal/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.example.sibal

import android.Manifest
import android.Manifest.permission.ANSWER_PHONE_CALLS
import android.app.role.RoleManager
import android.content.Context.ROLE_SERVICE
import android.content.Context.TELECOM_SERVICE
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
Expand All @@ -15,12 +18,18 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.getSystemService

class MainActivity : AppCompatActivity() {
val permissions = arrayOf(
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.ANSWER_PHONE_CALLS,
Manifest.permission.CALL_PHONE
)

override fun onCreate(savedInstancestate: Bundle?) {
super.onCreate(savedInstancestate)
Log.d("메인 액티비티", "메인 액티비티 실행")

//퍼미션 런처 생성
val permissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
Expand All @@ -33,7 +42,9 @@ class MainActivity : AppCompatActivity() {
}
}
//퍼미션 런처 실행
permissionLauncher.launch("android.permission.READ_PHONE_STATE")
for(permission in permissions) {
permissionLauncher.launch(permission)
}

val telecomManager = getSystemService(TELECOM_SERVICE) as TelecomManager
val roleManager = getSystemService(ROLE_SERVICE) as RoleManager
Expand Down
4 changes: 0 additions & 4 deletions app/app/src/main/java/com/example/sibal/MyInCallService.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package com.example.sibal

import android.app.Service
import android.content.Intent
import android.net.wifi.rtt.CivicLocationKeys.STATE
import android.os.IBinder
import android.telecom.Call
import android.telecom.InCallService
import android.util.Log

class MyInCallService : InCallService() {

Expand Down
Binary file added app/app/src/main/res/drawable/accept.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/app/src/main/res/drawable/decline.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/app/src/main/res/drawable/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/app/src/main/res/drawable/logo_black.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/app/src/main/res/drawable/microphone_on.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions app/app/src/main/res/drawable/rounded_rectangle1.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="30dp" />
<solid android:color="#FFFFFF" />
<!-- 테두리 설정 -->
<stroke
android:width="1dp"
android:color="#808080" />
</shape>
9 changes: 9 additions & 0 deletions app/app/src/main/res/drawable/rounded_rectangle2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="30dp" />
<solid android:color="#D3D3D3" />
<!-- 테두리 설정 -->
<stroke
android:width="1dp"
android:color="#808080" />
</shape>
Binary file added app/app/src/main/res/drawable/speaker_off.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 179e37b

Please sign in to comment.