@qusaieilouti99/call-manager 0.1.97 → 0.1.99
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
// File: CallActivity.kt
|
|
2
1
|
package com.margelo.nitro.qusaieilouti99.callmanager
|
|
3
2
|
|
|
4
3
|
import android.app.Activity
|
|
5
4
|
import android.app.KeyguardManager
|
|
6
5
|
import android.content.Context
|
|
6
|
+
import android.graphics.Bitmap
|
|
7
|
+
import android.graphics.BitmapFactory
|
|
7
8
|
import android.graphics.Color
|
|
8
9
|
import android.graphics.RenderEffect
|
|
9
10
|
import android.graphics.Shader
|
|
10
|
-
import android.graphics.
|
|
11
|
+
import android.graphics.Typeface
|
|
11
12
|
import android.graphics.drawable.GradientDrawable
|
|
13
|
+
import android.graphics.drawable.RippleDrawable
|
|
12
14
|
import android.os.Build
|
|
13
15
|
import android.os.Bundle
|
|
14
16
|
import android.os.Handler
|
|
@@ -23,17 +25,20 @@ import android.widget.FrameLayout
|
|
|
23
25
|
import android.widget.ImageView
|
|
24
26
|
import android.widget.LinearLayout
|
|
25
27
|
import android.widget.TextView
|
|
26
|
-
import
|
|
27
|
-
import
|
|
28
|
+
import java.net.HttpURLConnection
|
|
29
|
+
import java.net.URL
|
|
28
30
|
|
|
29
31
|
class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
|
|
33
|
+
private enum class FinishReason {
|
|
34
|
+
ANSWER, DECLINE, TIMEOUT, MANUAL_DISMISS, EXTERNAL_END
|
|
35
|
+
}
|
|
32
36
|
private var finishReason: FinishReason? = null
|
|
33
|
-
private var callId
|
|
34
|
-
private var callType
|
|
37
|
+
private var callId = ""
|
|
38
|
+
private var callType = "Audio"
|
|
39
|
+
|
|
35
40
|
private val timeoutMs = 60_000L
|
|
36
|
-
private val
|
|
41
|
+
private val uiHandler = Handler(Looper.getMainLooper())
|
|
37
42
|
private val timeoutRunnable = Runnable {
|
|
38
43
|
finishReason = FinishReason.TIMEOUT
|
|
39
44
|
CallEngine.stopRingtone()
|
|
@@ -44,24 +49,31 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
44
49
|
|
|
45
50
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
46
51
|
super.onCreate(savedInstanceState)
|
|
52
|
+
// Samsung lock‐screen bypass flag
|
|
47
53
|
val isSamsungBypass = intent.getBooleanExtra(
|
|
48
54
|
"SAMSUNG_LOCK_SCREEN_BYPASS", false
|
|
49
55
|
)
|
|
50
56
|
setupLockScreenBypass(isSamsungBypass)
|
|
51
57
|
|
|
52
58
|
// Read params
|
|
53
|
-
callId
|
|
59
|
+
callId = intent.getStringExtra("callId") ?: ""
|
|
54
60
|
callType = intent.getStringExtra("callType") ?: "Audio"
|
|
55
61
|
val callerName = intent.getStringExtra("callerName") ?: "Unknown"
|
|
56
62
|
val avatarUrl = intent.getStringExtra("callerAvatar")
|
|
57
63
|
|
|
64
|
+
// Register for external hang‐up
|
|
58
65
|
CallEngine.registerCallEndListener(this)
|
|
66
|
+
|
|
67
|
+
// Build all‐code UI
|
|
59
68
|
buildUi(callerName, avatarUrl)
|
|
60
|
-
|
|
61
|
-
|
|
69
|
+
|
|
70
|
+
// Auto‐timeout
|
|
71
|
+
uiHandler.postDelayed(timeoutRunnable, timeoutMs)
|
|
72
|
+
Log.d(TAG, "CallActivity setup complete for callId=$callId")
|
|
62
73
|
}
|
|
63
74
|
|
|
64
75
|
private fun buildUi(name: String, avatarUrl: String?) {
|
|
76
|
+
// Root container
|
|
65
77
|
val root = FrameLayout(this).apply {
|
|
66
78
|
layoutParams = ViewGroup.LayoutParams(
|
|
67
79
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
@@ -69,27 +81,30 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
69
81
|
)
|
|
70
82
|
}
|
|
71
83
|
|
|
72
|
-
//
|
|
84
|
+
//
|
|
85
|
+
// 1) Background ImageView + blur
|
|
86
|
+
//
|
|
73
87
|
val bg = ImageView(this).apply {
|
|
74
88
|
layoutParams = FrameLayout.LayoutParams(
|
|
75
89
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
76
90
|
ViewGroup.LayoutParams.MATCH_PARENT
|
|
77
91
|
)
|
|
78
92
|
scaleType = ImageView.ScaleType.CENTER_CROP
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
RenderEffect.createBlurEffect(25f, 25f, Shader.TileMode.CLAMP)
|
|
88
|
-
)
|
|
93
|
+
// On API 31+ apply live RenderEffect blur
|
|
94
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
95
|
+
setRenderEffect(
|
|
96
|
+
RenderEffect.createBlurEffect(
|
|
97
|
+
25f, 25f, Shader.TileMode.CLAMP
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
}
|
|
89
101
|
}
|
|
90
102
|
root.addView(bg)
|
|
103
|
+
loadAndBlurBackground(bg, avatarUrl)
|
|
91
104
|
|
|
92
|
-
//
|
|
105
|
+
//
|
|
106
|
+
// 2) Semi-transparent scrim
|
|
107
|
+
//
|
|
93
108
|
root.addView(View(this).apply {
|
|
94
109
|
layoutParams = FrameLayout.LayoutParams(
|
|
95
110
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
@@ -98,12 +113,14 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
98
113
|
setBackgroundColor(Color.parseColor("#80000000"))
|
|
99
114
|
})
|
|
100
115
|
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
116
|
+
//
|
|
117
|
+
// 3) Top “Incoming … call” label
|
|
118
|
+
//
|
|
119
|
+
val typeLabel = TextView(this).apply {
|
|
120
|
+
text = if (callType.equals("video", true))
|
|
121
|
+
"Incoming video call"
|
|
122
|
+
else
|
|
123
|
+
"Incoming audio call"
|
|
107
124
|
setTextColor(Color.WHITE)
|
|
108
125
|
setTextSize(TypedValue.COMPLEX_UNIT_SP, 18f)
|
|
109
126
|
gravity = Gravity.CENTER
|
|
@@ -112,55 +129,42 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
112
129
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
113
130
|
).apply {
|
|
114
131
|
gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
|
|
115
|
-
topMargin = dp(
|
|
132
|
+
topMargin = dp(32)
|
|
116
133
|
}
|
|
117
134
|
}
|
|
118
|
-
root.addView(
|
|
135
|
+
root.addView(typeLabel)
|
|
119
136
|
|
|
120
|
-
//
|
|
121
|
-
|
|
137
|
+
//
|
|
138
|
+
// 4) Avatar + Name (in top half)
|
|
139
|
+
//
|
|
140
|
+
val avatarSection = LinearLayout(this).apply {
|
|
122
141
|
orientation = LinearLayout.VERTICAL
|
|
123
142
|
gravity = Gravity.CENTER_HORIZONTAL
|
|
124
143
|
layoutParams = FrameLayout.LayoutParams(
|
|
125
144
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
126
145
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
127
146
|
).apply {
|
|
128
|
-
gravity = Gravity.
|
|
129
|
-
topMargin = dp(
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
// Profile circle
|
|
133
|
-
val profile = ImageView(this).apply {
|
|
134
|
-
val sz = dp(140)
|
|
135
|
-
layoutParams = LinearLayout.LayoutParams(sz, sz)
|
|
136
|
-
scaleType = ImageView.ScaleType.CENTER_CROP
|
|
137
|
-
background = GradientDrawable().apply {
|
|
138
|
-
shape = GradientDrawable.OVAL
|
|
139
|
-
setColor(Color.LTGRAY)
|
|
147
|
+
gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
|
|
148
|
+
topMargin = dp(100)
|
|
140
149
|
}
|
|
141
|
-
clipToOutline = true
|
|
142
|
-
}
|
|
143
|
-
if (!avatarUrl.isNullOrEmpty()) {
|
|
144
|
-
Glide.with(this).load(avatarUrl).circleCrop().into(profile)
|
|
145
150
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// Caller name
|
|
149
|
-
centerCol.addView(TextView(this).apply {
|
|
151
|
+
avatarSection.addView(createAvatarView(name, avatarUrl))
|
|
152
|
+
avatarSection.addView(TextView(this).apply {
|
|
150
153
|
text = name
|
|
151
154
|
setTextColor(Color.WHITE)
|
|
152
155
|
setTextSize(TypedValue.COMPLEX_UNIT_SP, 28f)
|
|
153
|
-
typeface =
|
|
156
|
+
typeface = Typeface.DEFAULT_BOLD
|
|
154
157
|
gravity = Gravity.CENTER
|
|
155
158
|
layoutParams = LinearLayout.LayoutParams(
|
|
156
159
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
157
160
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
158
|
-
).apply { topMargin = dp(
|
|
161
|
+
).apply { topMargin = dp(16) }
|
|
159
162
|
})
|
|
163
|
+
root.addView(avatarSection)
|
|
160
164
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
//
|
|
165
|
+
//
|
|
166
|
+
// 5) Bottom Answer/Decline Buttons
|
|
167
|
+
//
|
|
164
168
|
val actions = LinearLayout(this).apply {
|
|
165
169
|
orientation = LinearLayout.HORIZONTAL
|
|
166
170
|
gravity = Gravity.CENTER
|
|
@@ -172,34 +176,145 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
172
176
|
bottomMargin = dp(48)
|
|
173
177
|
}
|
|
174
178
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
val answerBtn = createCircleButton(
|
|
182
|
-
android.R.drawable.ic_menu_call,
|
|
183
|
-
Color.parseColor("#4CAF50")
|
|
184
|
-
).apply { setOnClickListener { onAnswer() } }
|
|
185
|
-
|
|
186
|
-
actions.addView(declineBtn)
|
|
179
|
+
actions.addView(
|
|
180
|
+
createCircleButton(
|
|
181
|
+
android.R.drawable.ic_menu_close_clear_cancel,
|
|
182
|
+
Color.parseColor("#F44336")
|
|
183
|
+
).apply { setOnClickListener { onDecline() } }
|
|
184
|
+
)
|
|
187
185
|
actions.addView(View(this).apply {
|
|
188
186
|
layoutParams = LinearLayout.LayoutParams(dp(60), 0)
|
|
189
187
|
})
|
|
190
|
-
actions.addView(
|
|
188
|
+
actions.addView(
|
|
189
|
+
createCircleButton(
|
|
190
|
+
android.R.drawable.ic_menu_call,
|
|
191
|
+
Color.parseColor("#4CAF50")
|
|
192
|
+
).apply { setOnClickListener { onAnswer() } }
|
|
193
|
+
)
|
|
191
194
|
root.addView(actions)
|
|
192
195
|
|
|
193
196
|
setContentView(root)
|
|
194
197
|
}
|
|
195
198
|
|
|
196
|
-
|
|
199
|
+
/** Creates the top avatar circle: remote image or default + initials. */
|
|
200
|
+
private fun createAvatarView(
|
|
201
|
+
name: String,
|
|
202
|
+
url: String?
|
|
203
|
+
): FrameLayout {
|
|
204
|
+
val size = dp(140)
|
|
205
|
+
val container = FrameLayout(this).apply {
|
|
206
|
+
layoutParams = LinearLayout.LayoutParams(size, size)
|
|
207
|
+
background = GradientDrawable().apply {
|
|
208
|
+
shape = GradientDrawable.OVAL
|
|
209
|
+
setColor(Color.parseColor("#DDFFFFFF"))
|
|
210
|
+
}
|
|
211
|
+
clipToOutline = true
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ImageView for remote or default avatar
|
|
215
|
+
val iv = ImageView(this).apply {
|
|
216
|
+
layoutParams = FrameLayout.LayoutParams(
|
|
217
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
218
|
+
ViewGroup.LayoutParams.MATCH_PARENT
|
|
219
|
+
)
|
|
220
|
+
scaleType = ImageView.ScaleType.CENTER_CROP
|
|
221
|
+
}
|
|
222
|
+
container.addView(iv)
|
|
223
|
+
|
|
224
|
+
// Initials overlay
|
|
225
|
+
val initials = TextView(this).apply {
|
|
226
|
+
layoutParams = FrameLayout.LayoutParams(
|
|
227
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
228
|
+
ViewGroup.LayoutParams.MATCH_PARENT
|
|
229
|
+
)
|
|
230
|
+
gravity = Gravity.CENTER
|
|
231
|
+
setTextColor(Color.WHITE)
|
|
232
|
+
setTextSize(TypedValue.COMPLEX_UNIT_SP, 32f)
|
|
233
|
+
typeface = Typeface.DEFAULT_BOLD
|
|
234
|
+
text = getInitials(name)
|
|
235
|
+
}
|
|
236
|
+
container.addView(initials)
|
|
237
|
+
|
|
238
|
+
if (url.isNullOrEmpty()) {
|
|
239
|
+
// No remote → show default vector + initials
|
|
240
|
+
iv.setImageResource(R.drawable.ic_default_avatar)
|
|
241
|
+
initials.visibility = View.VISIBLE
|
|
242
|
+
} else {
|
|
243
|
+
// Remote → load + hide initials
|
|
244
|
+
initials.visibility = View.GONE
|
|
245
|
+
loadAvatar(iv, url)
|
|
246
|
+
}
|
|
247
|
+
return container
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private fun getInitials(fullName: String): String {
|
|
251
|
+
val parts = fullName.trim().split("\\s+".toRegex())
|
|
252
|
+
return when (parts.size) {
|
|
253
|
+
0 -> ""
|
|
254
|
+
1 -> parts[0].substring(0,1).uppercase()
|
|
255
|
+
else -> (parts[0][0].toString() + parts[1][0].toString())
|
|
256
|
+
.uppercase()
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** Downloads an image + sets it on the ImageView. */
|
|
261
|
+
private fun loadAvatar(iv: ImageView, url: String) {
|
|
262
|
+
Thread {
|
|
263
|
+
try {
|
|
264
|
+
val conn = URL(url).openConnection() as HttpURLConnection
|
|
265
|
+
conn.doInput = true; conn.connect()
|
|
266
|
+
val bmp = BitmapFactory.decodeStream(conn.inputStream)
|
|
267
|
+
runOnUiThread { iv.setImageBitmap(bmp) }
|
|
268
|
+
} catch (_: Exception) { /* ignore */ }
|
|
269
|
+
}.start()
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Downloads bg image (remote or fallback), applies blur if needed. */
|
|
273
|
+
private fun loadAndBlurBackground(iv: ImageView, url: String?) {
|
|
274
|
+
Thread {
|
|
275
|
+
val bmp: Bitmap? = try {
|
|
276
|
+
if (!url.isNullOrEmpty()) {
|
|
277
|
+
val c = URL(url).openConnection() as HttpURLConnection
|
|
278
|
+
c.doInput = true; c.connect()
|
|
279
|
+
BitmapFactory.decodeStream(c.inputStream)
|
|
280
|
+
} else {
|
|
281
|
+
// your fallback background
|
|
282
|
+
BitmapFactory.decodeResource(
|
|
283
|
+
resources, R.drawable.default_call_bg
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
} catch (_: Exception) {
|
|
287
|
+
null
|
|
288
|
+
}
|
|
289
|
+
bmp ?: return@Thread
|
|
290
|
+
|
|
291
|
+
val finalBmp = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
|
292
|
+
// quick blur: down/up-scale
|
|
293
|
+
val factor = 8
|
|
294
|
+
val w = bmp.width / factor
|
|
295
|
+
val h = bmp.height / factor
|
|
296
|
+
val small = Bitmap.createScaledBitmap(bmp, w, h, true)
|
|
297
|
+
Bitmap.createScaledBitmap(small, bmp.width, bmp.height, true)
|
|
298
|
+
} else {
|
|
299
|
+
bmp
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
runOnUiThread { iv.setImageBitmap(finalBmp) }
|
|
303
|
+
}.start()
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** Big round button with circular ripple. */
|
|
307
|
+
private fun createCircleButton(
|
|
308
|
+
iconRes: Int,
|
|
309
|
+
bgColor: Int
|
|
310
|
+
): FrameLayout {
|
|
197
311
|
val size = dp(70)
|
|
198
312
|
return FrameLayout(this).apply {
|
|
199
313
|
layoutParams = LinearLayout.LayoutParams(size, size)
|
|
200
|
-
isClickable = true
|
|
201
|
-
|
|
202
|
-
|
|
314
|
+
isClickable = true
|
|
315
|
+
isFocusable = true
|
|
316
|
+
foreground = makeCircleRipple()
|
|
317
|
+
// colored circle
|
|
203
318
|
addView(View(context).apply {
|
|
204
319
|
layoutParams = FrameLayout.LayoutParams(
|
|
205
320
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
@@ -220,12 +335,18 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
220
335
|
}
|
|
221
336
|
}
|
|
222
337
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
338
|
+
/** Circular RippleDrawable. */
|
|
339
|
+
private fun makeCircleRipple(): RippleDrawable {
|
|
340
|
+
val mask = GradientDrawable().apply {
|
|
341
|
+
shape = GradientDrawable.OVAL
|
|
342
|
+
setColor(Color.WHITE)
|
|
343
|
+
}
|
|
344
|
+
val clr = Color.parseColor("#33FFFFFF")
|
|
345
|
+
return RippleDrawable(
|
|
346
|
+
android.content.res.ColorStateList.valueOf(clr),
|
|
347
|
+
null,
|
|
348
|
+
mask
|
|
227
349
|
)
|
|
228
|
-
return ContextCompat.getDrawable(this, tv.resourceId)
|
|
229
350
|
}
|
|
230
351
|
|
|
231
352
|
private fun onAnswer() {
|
|
@@ -235,7 +356,6 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
235
356
|
CallEngine.answerCall(callId)
|
|
236
357
|
finishCallActivity()
|
|
237
358
|
}
|
|
238
|
-
|
|
239
359
|
private fun onDecline() {
|
|
240
360
|
finishReason = FinishReason.DECLINE
|
|
241
361
|
CallEngine.stopRingtone()
|
|
@@ -244,14 +364,10 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
244
364
|
finishCallActivity()
|
|
245
365
|
}
|
|
246
366
|
|
|
247
|
-
private fun dp(v: Int): Int = TypedValue.applyDimension(
|
|
248
|
-
TypedValue.COMPLEX_UNIT_DIP, v.toFloat(),
|
|
249
|
-
resources.displayMetrics
|
|
250
|
-
).toInt()
|
|
251
|
-
|
|
252
367
|
private fun setupLockScreenBypass(isSamsung: Boolean) {
|
|
253
368
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
|
254
|
-
setShowWhenLocked(true)
|
|
369
|
+
setShowWhenLocked(true)
|
|
370
|
+
setTurnScreenOn(true)
|
|
255
371
|
} else {
|
|
256
372
|
window.addFlags(
|
|
257
373
|
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
|
|
@@ -266,19 +382,17 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
266
382
|
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
|
|
267
383
|
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
|
268
384
|
)
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
272
|
-
km.requestDismissKeyguard(this,
|
|
385
|
+
(getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager)
|
|
386
|
+
.requestDismissKeyguard(this,
|
|
273
387
|
object : KeyguardManager.KeyguardDismissCallback() {
|
|
274
|
-
override fun onDismissSucceeded()
|
|
388
|
+
override fun onDismissSucceeded() {
|
|
275
389
|
Log.d(TAG, "Samsung keyguard dismissed")
|
|
276
390
|
}
|
|
277
391
|
override fun onDismissError() {
|
|
278
|
-
Log.w(TAG, "
|
|
392
|
+
Log.w(TAG, "Keyguard dismiss error")
|
|
279
393
|
}
|
|
280
|
-
}
|
|
281
|
-
|
|
394
|
+
}
|
|
395
|
+
)
|
|
282
396
|
}
|
|
283
397
|
}
|
|
284
398
|
|
|
@@ -300,7 +414,7 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
300
414
|
override fun onDestroy() {
|
|
301
415
|
super.onDestroy()
|
|
302
416
|
CallEngine.unregisterCallEndListener(this)
|
|
303
|
-
|
|
417
|
+
uiHandler.removeCallbacks(timeoutRunnable)
|
|
304
418
|
if (finishReason != FinishReason.ANSWER) {
|
|
305
419
|
CallEngine.stopRingtone()
|
|
306
420
|
CallEngine.cancelIncomingCallUI()
|
|
@@ -316,6 +430,11 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
316
430
|
}
|
|
317
431
|
}
|
|
318
432
|
|
|
433
|
+
private fun dp(v: Int): Int = TypedValue.applyDimension(
|
|
434
|
+
TypedValue.COMPLEX_UNIT_DIP, v.toFloat(),
|
|
435
|
+
resources.displayMetrics
|
|
436
|
+
).toInt()
|
|
437
|
+
|
|
319
438
|
companion object {
|
|
320
439
|
private const val TAG = "CallActivity"
|
|
321
440
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
android:width="24dp"
|
|
3
|
+
android:height="24dp"
|
|
4
|
+
android:viewportWidth="24"
|
|
5
|
+
android:viewportHeight="24">
|
|
6
|
+
<path
|
|
7
|
+
android:fillColor="#BDBDBD"
|
|
8
|
+
android:pathData="
|
|
9
|
+
M12,12c2.21,0 4,-1.79 4,-4
|
|
10
|
+
s-1.79,-4 -4,-4
|
|
11
|
+
s-4,1.79 -4,4
|
|
12
|
+
s1.79,4 4,4z
|
|
13
|
+
M6,20
|
|
14
|
+
c0,-3.31 2.69,-6 6,-6
|
|
15
|
+
s6,2.69 6,6
|
|
16
|
+
v1
|
|
17
|
+
H6v-1z"/>
|
|
18
|
+
</vector>
|
|
Binary file
|