@qusaieilouti99/call-manager 0.1.98 → 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,15 +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
7
|
import android.graphics.BitmapFactory
|
|
8
8
|
import android.graphics.Color
|
|
9
9
|
import android.graphics.RenderEffect
|
|
10
10
|
import android.graphics.Shader
|
|
11
|
-
import android.graphics.
|
|
11
|
+
import android.graphics.Typeface
|
|
12
12
|
import android.graphics.drawable.GradientDrawable
|
|
13
|
+
import android.graphics.drawable.RippleDrawable
|
|
13
14
|
import android.os.Build
|
|
14
15
|
import android.os.Bundle
|
|
15
16
|
import android.os.Handler
|
|
@@ -24,19 +25,20 @@ import android.widget.FrameLayout
|
|
|
24
25
|
import android.widget.ImageView
|
|
25
26
|
import android.widget.LinearLayout
|
|
26
27
|
import android.widget.TextView
|
|
27
|
-
import androidx.core.content.ContextCompat
|
|
28
28
|
import java.net.HttpURLConnection
|
|
29
29
|
import java.net.URL
|
|
30
30
|
|
|
31
31
|
class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
32
32
|
|
|
33
|
-
private enum class FinishReason {
|
|
34
|
-
|
|
33
|
+
private enum class FinishReason {
|
|
34
|
+
ANSWER, DECLINE, TIMEOUT, MANUAL_DISMISS, EXTERNAL_END
|
|
35
|
+
}
|
|
35
36
|
private var finishReason: FinishReason? = null
|
|
36
|
-
private var callId
|
|
37
|
-
private var callType
|
|
37
|
+
private var callId = ""
|
|
38
|
+
private var callType = "Audio"
|
|
39
|
+
|
|
38
40
|
private val timeoutMs = 60_000L
|
|
39
|
-
private val
|
|
41
|
+
private val uiHandler = Handler(Looper.getMainLooper())
|
|
40
42
|
private val timeoutRunnable = Runnable {
|
|
41
43
|
finishReason = FinishReason.TIMEOUT
|
|
42
44
|
CallEngine.stopRingtone()
|
|
@@ -47,24 +49,31 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
47
49
|
|
|
48
50
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
49
51
|
super.onCreate(savedInstanceState)
|
|
52
|
+
// Samsung lock‐screen bypass flag
|
|
50
53
|
val isSamsungBypass = intent.getBooleanExtra(
|
|
51
54
|
"SAMSUNG_LOCK_SCREEN_BYPASS", false
|
|
52
55
|
)
|
|
53
56
|
setupLockScreenBypass(isSamsungBypass)
|
|
54
57
|
|
|
55
58
|
// Read params
|
|
56
|
-
callId
|
|
57
|
-
callType
|
|
59
|
+
callId = intent.getStringExtra("callId") ?: ""
|
|
60
|
+
callType = intent.getStringExtra("callType") ?: "Audio"
|
|
58
61
|
val callerName = intent.getStringExtra("callerName") ?: "Unknown"
|
|
59
62
|
val avatarUrl = intent.getStringExtra("callerAvatar")
|
|
60
63
|
|
|
64
|
+
// Register for external hang‐up
|
|
61
65
|
CallEngine.registerCallEndListener(this)
|
|
66
|
+
|
|
67
|
+
// Build all‐code UI
|
|
62
68
|
buildUi(callerName, avatarUrl)
|
|
63
|
-
|
|
69
|
+
|
|
70
|
+
// Auto‐timeout
|
|
71
|
+
uiHandler.postDelayed(timeoutRunnable, timeoutMs)
|
|
64
72
|
Log.d(TAG, "CallActivity setup complete for callId=$callId")
|
|
65
73
|
}
|
|
66
74
|
|
|
67
75
|
private fun buildUi(name: String, avatarUrl: String?) {
|
|
76
|
+
// Root container
|
|
68
77
|
val root = FrameLayout(this).apply {
|
|
69
78
|
layoutParams = ViewGroup.LayoutParams(
|
|
70
79
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
@@ -72,14 +81,16 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
72
81
|
)
|
|
73
82
|
}
|
|
74
83
|
|
|
75
|
-
//
|
|
84
|
+
//
|
|
85
|
+
// 1) Background ImageView + blur
|
|
86
|
+
//
|
|
76
87
|
val bg = ImageView(this).apply {
|
|
77
88
|
layoutParams = FrameLayout.LayoutParams(
|
|
78
89
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
79
90
|
ViewGroup.LayoutParams.MATCH_PARENT
|
|
80
91
|
)
|
|
81
92
|
scaleType = ImageView.ScaleType.CENTER_CROP
|
|
82
|
-
// apply RenderEffect blur
|
|
93
|
+
// On API 31+ apply live RenderEffect blur
|
|
83
94
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
84
95
|
setRenderEffect(
|
|
85
96
|
RenderEffect.createBlurEffect(
|
|
@@ -91,7 +102,9 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
91
102
|
root.addView(bg)
|
|
92
103
|
loadAndBlurBackground(bg, avatarUrl)
|
|
93
104
|
|
|
94
|
-
//
|
|
105
|
+
//
|
|
106
|
+
// 2) Semi-transparent scrim
|
|
107
|
+
//
|
|
95
108
|
root.addView(View(this).apply {
|
|
96
109
|
layoutParams = FrameLayout.LayoutParams(
|
|
97
110
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
@@ -100,12 +113,14 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
100
113
|
setBackgroundColor(Color.parseColor("#80000000"))
|
|
101
114
|
})
|
|
102
115
|
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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"
|
|
109
124
|
setTextColor(Color.WHITE)
|
|
110
125
|
setTextSize(TypedValue.COMPLEX_UNIT_SP, 18f)
|
|
111
126
|
gravity = Gravity.CENTER
|
|
@@ -114,55 +129,42 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
114
129
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
115
130
|
).apply {
|
|
116
131
|
gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
|
|
117
|
-
topMargin = dp(
|
|
132
|
+
topMargin = dp(32)
|
|
118
133
|
}
|
|
119
134
|
}
|
|
120
|
-
root.addView(
|
|
135
|
+
root.addView(typeLabel)
|
|
121
136
|
|
|
122
|
-
//
|
|
123
|
-
|
|
137
|
+
//
|
|
138
|
+
// 4) Avatar + Name (in top half)
|
|
139
|
+
//
|
|
140
|
+
val avatarSection = LinearLayout(this).apply {
|
|
124
141
|
orientation = LinearLayout.VERTICAL
|
|
125
142
|
gravity = Gravity.CENTER_HORIZONTAL
|
|
126
143
|
layoutParams = FrameLayout.LayoutParams(
|
|
127
144
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
128
145
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
129
146
|
).apply {
|
|
130
|
-
gravity = Gravity.
|
|
131
|
-
topMargin = dp(
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Profile circle
|
|
136
|
-
val profile = ImageView(this).apply {
|
|
137
|
-
val sz = dp(140)
|
|
138
|
-
layoutParams = LinearLayout.LayoutParams(sz, sz)
|
|
139
|
-
scaleType = ImageView.ScaleType.CENTER_CROP
|
|
140
|
-
background = GradientDrawable().apply {
|
|
141
|
-
shape = GradientDrawable.OVAL
|
|
142
|
-
setColor(Color.LTGRAY)
|
|
147
|
+
gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
|
|
148
|
+
topMargin = dp(100)
|
|
143
149
|
}
|
|
144
|
-
// enable clipping to our oval background
|
|
145
|
-
clipToOutline = true
|
|
146
150
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
// Caller name
|
|
151
|
-
centerCol.addView(TextView(this).apply {
|
|
151
|
+
avatarSection.addView(createAvatarView(name, avatarUrl))
|
|
152
|
+
avatarSection.addView(TextView(this).apply {
|
|
152
153
|
text = name
|
|
153
154
|
setTextColor(Color.WHITE)
|
|
154
155
|
setTextSize(TypedValue.COMPLEX_UNIT_SP, 28f)
|
|
155
|
-
typeface =
|
|
156
|
+
typeface = Typeface.DEFAULT_BOLD
|
|
156
157
|
gravity = Gravity.CENTER
|
|
157
158
|
layoutParams = LinearLayout.LayoutParams(
|
|
158
159
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
159
160
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
160
|
-
).apply { topMargin = dp(
|
|
161
|
+
).apply { topMargin = dp(16) }
|
|
161
162
|
})
|
|
163
|
+
root.addView(avatarSection)
|
|
162
164
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
//
|
|
165
|
+
//
|
|
166
|
+
// 5) Bottom Answer/Decline Buttons
|
|
167
|
+
//
|
|
166
168
|
val actions = LinearLayout(this).apply {
|
|
167
169
|
orientation = LinearLayout.HORIZONTAL
|
|
168
170
|
gravity = Gravity.CENTER
|
|
@@ -174,30 +176,89 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
174
176
|
bottomMargin = dp(48)
|
|
175
177
|
}
|
|
176
178
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
val answerBtn = createCircleButton(
|
|
184
|
-
android.R.drawable.ic_menu_call,
|
|
185
|
-
Color.parseColor("#4CAF50")
|
|
186
|
-
).apply { setOnClickListener { onAnswer() } }
|
|
187
|
-
|
|
188
|
-
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
|
+
)
|
|
189
185
|
actions.addView(View(this).apply {
|
|
190
186
|
layoutParams = LinearLayout.LayoutParams(dp(60), 0)
|
|
191
187
|
})
|
|
192
|
-
actions.addView(
|
|
188
|
+
actions.addView(
|
|
189
|
+
createCircleButton(
|
|
190
|
+
android.R.drawable.ic_menu_call,
|
|
191
|
+
Color.parseColor("#4CAF50")
|
|
192
|
+
).apply { setOnClickListener { onAnswer() } }
|
|
193
|
+
)
|
|
193
194
|
root.addView(actions)
|
|
194
195
|
|
|
195
196
|
setContentView(root)
|
|
196
197
|
}
|
|
197
198
|
|
|
198
|
-
|
|
199
|
-
private fun
|
|
200
|
-
|
|
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) {
|
|
201
262
|
Thread {
|
|
202
263
|
try {
|
|
203
264
|
val conn = URL(url).openConnection() as HttpURLConnection
|
|
@@ -208,25 +269,51 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
208
269
|
}.start()
|
|
209
270
|
}
|
|
210
271
|
|
|
211
|
-
|
|
272
|
+
/** Downloads bg image (remote or fallback), applies blur if needed. */
|
|
212
273
|
private fun loadAndBlurBackground(iv: ImageView, url: String?) {
|
|
213
|
-
if (url.isNullOrEmpty()) return
|
|
214
274
|
Thread {
|
|
215
|
-
try {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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) }
|
|
221
303
|
}.start()
|
|
222
304
|
}
|
|
223
305
|
|
|
224
|
-
|
|
306
|
+
/** Big round button with circular ripple. */
|
|
307
|
+
private fun createCircleButton(
|
|
308
|
+
iconRes: Int,
|
|
309
|
+
bgColor: Int
|
|
310
|
+
): FrameLayout {
|
|
225
311
|
val size = dp(70)
|
|
226
312
|
return FrameLayout(this).apply {
|
|
227
313
|
layoutParams = LinearLayout.LayoutParams(size, size)
|
|
228
|
-
isClickable = true
|
|
229
|
-
|
|
314
|
+
isClickable = true
|
|
315
|
+
isFocusable = true
|
|
316
|
+
foreground = makeCircleRipple()
|
|
230
317
|
// colored circle
|
|
231
318
|
addView(View(context).apply {
|
|
232
319
|
layoutParams = FrameLayout.LayoutParams(
|
|
@@ -248,12 +335,18 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
248
335
|
}
|
|
249
336
|
}
|
|
250
337
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
|
255
349
|
)
|
|
256
|
-
return ContextCompat.getDrawable(this, tv.resourceId)
|
|
257
350
|
}
|
|
258
351
|
|
|
259
352
|
private fun onAnswer() {
|
|
@@ -263,7 +356,6 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
263
356
|
CallEngine.answerCall(callId)
|
|
264
357
|
finishCallActivity()
|
|
265
358
|
}
|
|
266
|
-
|
|
267
359
|
private fun onDecline() {
|
|
268
360
|
finishReason = FinishReason.DECLINE
|
|
269
361
|
CallEngine.stopRingtone()
|
|
@@ -272,14 +364,10 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
272
364
|
finishCallActivity()
|
|
273
365
|
}
|
|
274
366
|
|
|
275
|
-
private fun dp(v: Int): Int = TypedValue.applyDimension(
|
|
276
|
-
TypedValue.COMPLEX_UNIT_DIP, v.toFloat(),
|
|
277
|
-
resources.displayMetrics
|
|
278
|
-
).toInt()
|
|
279
|
-
|
|
280
367
|
private fun setupLockScreenBypass(isSamsung: Boolean) {
|
|
281
368
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
|
282
|
-
setShowWhenLocked(true)
|
|
369
|
+
setShowWhenLocked(true)
|
|
370
|
+
setTurnScreenOn(true)
|
|
283
371
|
} else {
|
|
284
372
|
window.addFlags(
|
|
285
373
|
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
|
|
@@ -294,19 +382,17 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
294
382
|
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
|
|
295
383
|
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
|
296
384
|
)
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
300
|
-
km.requestDismissKeyguard(this,
|
|
385
|
+
(getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager)
|
|
386
|
+
.requestDismissKeyguard(this,
|
|
301
387
|
object : KeyguardManager.KeyguardDismissCallback() {
|
|
302
388
|
override fun onDismissSucceeded() {
|
|
303
389
|
Log.d(TAG, "Samsung keyguard dismissed")
|
|
304
390
|
}
|
|
305
391
|
override fun onDismissError() {
|
|
306
|
-
Log.w(TAG, "
|
|
392
|
+
Log.w(TAG, "Keyguard dismiss error")
|
|
307
393
|
}
|
|
308
|
-
}
|
|
309
|
-
|
|
394
|
+
}
|
|
395
|
+
)
|
|
310
396
|
}
|
|
311
397
|
}
|
|
312
398
|
|
|
@@ -328,7 +414,7 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
328
414
|
override fun onDestroy() {
|
|
329
415
|
super.onDestroy()
|
|
330
416
|
CallEngine.unregisterCallEndListener(this)
|
|
331
|
-
|
|
417
|
+
uiHandler.removeCallbacks(timeoutRunnable)
|
|
332
418
|
if (finishReason != FinishReason.ANSWER) {
|
|
333
419
|
CallEngine.stopRingtone()
|
|
334
420
|
CallEngine.cancelIncomingCallUI()
|
|
@@ -344,6 +430,11 @@ class CallActivity : Activity(), CallEngine.CallEndListener {
|
|
|
344
430
|
}
|
|
345
431
|
}
|
|
346
432
|
|
|
433
|
+
private fun dp(v: Int): Int = TypedValue.applyDimension(
|
|
434
|
+
TypedValue.COMPLEX_UNIT_DIP, v.toFloat(),
|
|
435
|
+
resources.displayMetrics
|
|
436
|
+
).toInt()
|
|
437
|
+
|
|
347
438
|
companion object {
|
|
348
439
|
private const val TAG = "CallActivity"
|
|
349
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
|