UI 변경 진행 중

메뉴 버튼 팝업 처리 추가
This commit is contained in:
ritoseo 2025-04-02 10:54:23 +09:00
parent 600e6c5007
commit 3bb1079674
15 changed files with 307 additions and 10 deletions

View File

@ -47,6 +47,11 @@ android {
'proguard-rules.pro' 'proguard-rules.pro'
} }
} }
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "ritosip-${defaultConfig.versionName}.apk"
}
}
buildFeatures { buildFeatures {
viewBinding true viewBinding true
dataBinding true dataBinding true

View File

@ -1705,6 +1705,16 @@ JNIEXPORT void JNICALL Java_com_tutpro_baresip_plus_Api_call_1set_1video_1direct
re_thread_leave(); re_thread_leave();
} }
JNIEXPORT void JNICALL Java_com_tutpro_baresip_plus_Api_call_1set_1video_1mute(
JNIEnv *env, jobject obj, jlong call, jboolean mute)
{
(void)env;
(void)obj;
re_thread_enter();
video_set_source_mute(call_video((struct call *)call), (bool)mute);
re_thread_leave();
}
JNIEXPORT void JNICALL Java_com_tutpro_baresip_plus_Api_call_1set_1media_1direction( JNIEXPORT void JNICALL Java_com_tutpro_baresip_plus_Api_call_1set_1media_1direction(
JNIEnv *env, jobject obj, jlong call, jint adir, jint vdir) JNIEnv *env, jobject obj, jlong call, jint adir, jint vdir)
{ {

View File

@ -964,7 +964,9 @@ JNIEXPORT void JNICALL Java_com_tutpro_baresip_plus_VideoView_set_1surfaceSelf(
} }
} else { } else {
LOGW("[SELF] Releasing windowSelf"); LOGW("[SELF] Releasing windowSelf");
ANativeWindow_release(window_self); if(window_self) {
ANativeWindow_release(window_self);
}
window_self = NULL; window_self = NULL;
} }
} }

View File

@ -99,6 +99,7 @@ object Api {
external fun call_has_video(callp: Long): Boolean external fun call_has_video(callp: Long): Boolean
external fun call_set_video_source(callp: Long, front: Boolean): Int external fun call_set_video_source(callp: Long, front: Boolean): Int
external fun call_set_video_direction(callp: Long, dir: Int) external fun call_set_video_direction(callp: Long, dir: Int)
external fun call_set_video_mute(callp: Long, mute: Boolean) // added by ritoseo
external fun call_set_media_direction(callp: Long, adir: Int, vdir: Int) external fun call_set_media_direction(callp: Long, adir: Int, vdir: Int)
external fun call_disable_video_stream(callp: Long, disable: Boolean) external fun call_disable_video_stream(callp: Long, disable: Boolean)
external fun call_video_enabled(callp: Long): Boolean external fun call_video_enabled(callp: Long): Boolean

View File

@ -395,6 +395,36 @@ class BaresipService: Service() {
} else if(req == "audio_unmute") { } else if(req == "audio_unmute") {
Api.calls_mute(false) Api.calls_mute(false)
isMicMuted = false isMicMuted = false
} else if(req == "video_mute") {
if(uas.size > 0) {
val ua = uas[0]
val call = ua.currentCall()
call?.setVideoMute(true)
isVideoMuted = true
}
} else if(req == "video_unmute") {
if(uas.size > 0) {
val ua = uas[0]
val call = ua.currentCall()
call?.setVideoMute(false)
isVideoMuted = false
}
} else if(req == "audio_source") {
val param = intent?.getStringExtra("param")
if(param != null) {
try {
val json = JSONObject(param)
var device = "usb"
val source_target = json.getString("target")
if(source_target == "aux") {
device = "codec"
}
Utils.setAudioSourceDevice(device)
audioInputDevice = device
} catch(e : Exception) {
e.printStackTrace()
}
}
} else if(req == "set_account") { } else if(req == "set_account") {
UserAgent.deleteAllUas() UserAgent.deleteAllUas()
val param = intent?.getStringExtra("param") val param = intent?.getStringExtra("param")
@ -422,9 +452,13 @@ class BaresipService: Service() {
Api.account_set_auth_pass(acc.accp, password) Api.account_set_auth_pass(acc.accp, password)
acc.authPass = Api.account_auth_pass(acc.accp) acc.authPass = Api.account_auth_pass(acc.accp)
Api.account_set_answermode(acc.accp, Api.ANSWERMODE_AUTO) if(BaresipService.callAnswerMode == "manual") {
acc.answerMode = Api.ANSWERMODE_AUTO Api.account_set_answermode(acc.accp, Api.ANSWERMODE_MANUAL)
acc.answerMode = Api.ANSWERMODE_MANUAL
} else {
Api.account_set_answermode(acc.accp, Api.ANSWERMODE_AUTO)
acc.answerMode = Api.ANSWERMODE_AUTO
}
/* /*
Api.log_level_set(0) Api.log_level_set(0)
@ -773,9 +807,13 @@ class BaresipService: Service() {
if (call != null) { if (call != null) {
callExist = true callExist = true
var audioMute = "unmute" var audioMute = "unmute"
var videoMute = "unmute"
if(isMicMuted) if(isMicMuted)
audioMute = "mute" audioMute = "mute"
if(isVideoMuted)
videoMute = "mute"
Utils.propertySet("sys.ritosip.call.mute.audio", audioMute) Utils.propertySet("sys.ritosip.call.mute.audio", audioMute)
Utils.propertySet("sys.ritosip.call.mute.video", videoMute)
Utils.propertySet("sys.ritosip.call.status", "calling") Utils.propertySet("sys.ritosip.call.status", "calling")
Utils.propertySet("sys.ritosip.call.number", call.peerUri) Utils.propertySet("sys.ritosip.call.number", call.peerUri)
@ -899,6 +937,18 @@ class BaresipService: Service() {
Utils.propertySet("sys.ritosip.media.input", "content") Utils.propertySet("sys.ritosip.media.input", "content")
} }
val usbMicExist = Utils.checkUsbMicrophone()
if(usbMicExist) {
Utils.propertySet("sys.ritosip.usb.microphone", "connected")
if(audioInputDevice == "usb") {
Utils.propertySet("sys.rito.audio.input.device", "usb")
} else {
Utils.propertySet("sys.rito.audio.input.device", "codec")
}
} else {
Utils.propertySet("sys.ritosip.usb.microphone", "disconnected")
}
delay(100) // 1초마다 실행 delay(100) // 1초마다 실행
val now = LocalDateTime.now() val now = LocalDateTime.now()
@ -2341,6 +2391,7 @@ class BaresipService: Service() {
var callActionUri = "" var callActionUri = ""
var isMainVisible = false var isMainVisible = false
var isMicMuted = false var isMicMuted = false
var isVideoMuted = false
var isRecOn = false var isRecOn = false
var toneCountry = "us" var toneCountry = "us"
var videoSize = Size(0, 0) var videoSize = Size(0, 0)
@ -2392,6 +2443,8 @@ class BaresipService: Service() {
var preferTransport = "udp" var preferTransport = "udp"
var videoFormatHeight = 480 var videoFormatHeight = 480
var connectedDisplayCount = 0 var connectedDisplayCount = 0
var callAnswerMode = "auto"
var audioInputDevice = "usb"
var useDisplaySplitMode = false var useDisplaySplitMode = false
var displaySplitMode = DISPLAY_SPLIT_MODE_원거리_최대_근거리_우하단 var displaySplitMode = DISPLAY_SPLIT_MODE_원거리_최대_근거리_우하단
var farViewDisplayId = 1 var farViewDisplayId = 1

View File

@ -96,6 +96,10 @@ class Call(val callp: Long, val ua: UserAgent, val peerUri: String, val dir: Str
Api.call_set_video_direction(callp, vdir) Api.call_set_video_direction(callp, vdir)
} }
fun setVideoMute(mute: Boolean) { // added by ritoseo
Api.call_set_video_mute(callp, mute)
}
fun setMediaDirection(adir: Int, vdir: Int) { fun setMediaDirection(adir: Int, vdir: Int) {
Api.call_set_media_direction(callp, adir, vdir) Api.call_set_media_direction(callp, adir, vdir)
} }

View File

@ -269,6 +269,12 @@ object Config {
BaresipService.preferTransport = "udp" BaresipService.preferTransport = "udp"
config = "${config}prefer_transport ${BaresipService.preferTransport}\n" config = "${config}prefer_transport ${BaresipService.preferTransport}\n"
val answerMode = previousVariable("answer_mode")
if (answerMode != "")
BaresipService.callAnswerMode = answerMode
else
BaresipService.callAnswerMode = "auto"
config = "${config}answer_mode ${BaresipService.callAnswerMode}\n"
save() save()
BaresipService.isConfigInitialized = true BaresipService.isConfigInitialized = true

View File

@ -34,12 +34,14 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.widget.AppCompatButton
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -127,6 +129,9 @@ class MainActivity : AppCompatActivity() {
private lateinit var comDevChangedListener: AudioManager.OnCommunicationDeviceChangedListener private lateinit var comDevChangedListener: AudioManager.OnCommunicationDeviceChangedListener
private lateinit var permissions: Array<String> private lateinit var permissions: Array<String>
private lateinit var dialogImgBtn1: AppCompatButton
private lateinit var dialogImgBtn2: AppCompatButton
private var callHandler: Handler = Handler(Looper.getMainLooper()) private var callHandler: Handler = Handler(Looper.getMainLooper())
private var callRunnable: Runnable? = null private var callRunnable: Runnable? = null
private var downloadsInputUri: Uri? = null private var downloadsInputUri: Uri? = null
@ -238,6 +243,12 @@ class MainActivity : AppCompatActivity() {
dialpadButton = binding.dialpadButton dialpadButton = binding.dialpadButton
swipeRefresh = binding.swipeRefresh swipeRefresh = binding.swipeRefresh
dialogImgBtn1 = binding.dialogButtonImg1
dialogImgBtn1.setOnClickListener {
}
dialogImgBtn2 = binding.dialogButtonImg2
BaresipService.supportedCameras = Utils.supportedCameras(applicationContext).isNotEmpty() BaresipService.supportedCameras = Utils.supportedCameras(applicationContext).isNotEmpty()
imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
@ -1876,7 +1887,10 @@ class MainActivity : AppCompatActivity() {
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
val BTN_MISC = 188 val BTN_MISC = 188
//val BTN_MENU = 58
val SCANCODE_OPTION = 357 //MENU키 -> OPTION키로 매핑
//println("onKeyDown : ${keyCode}") //println("onKeyDown : ${keyCode}")
//println("onKeyDown2 : ${event?.scanCode}")
val stream = if (am.mode == AudioManager.MODE_RINGTONE) val stream = if (am.mode == AudioManager.MODE_RINGTONE)
AudioManager.STREAM_RING AudioManager.STREAM_RING
else else
@ -1892,13 +1906,40 @@ class MainActivity : AppCompatActivity() {
return true return true
} }
KeyEvent.KEYCODE_BACK -> { KeyEvent.KEYCODE_BACK -> {
callVideoButton.requestFocus() //callVideoButton.requestFocus()
return true return true
} }
KeyEvent.KEYCODE_0, KeyEvent.KEYCODE_1, KeyEvent.KEYCODE_2, KeyEvent.KEYCODE_3, KeyEvent.KEYCODE_4, KeyEvent.KEYCODE_5, KeyEvent.KEYCODE_6,
KeyEvent.KEYCODE_7, KeyEvent.KEYCODE_8, KeyEvent.KEYCODE_9
-> {
callUri.setText(callUri.text.toString() + (keyCode - KeyEvent.KEYCODE_0).toString())
}
KeyEvent.KEYCODE_DEL -> {
val editable = callUri.text
val length = editable.length
if (length > 0) {
editable.delete(length - 1, length)
}
}
BTN_MISC -> { BTN_MISC -> {
return true return true
} }
} }
when (event?.scanCode) {
SCANCODE_OPTION -> {
val dialog = findViewById<FrameLayout>(R.id.dialogLayout)
if(dialog.isVisible) {
dialog.visibility = View.INVISIBLE
} else {
dialog.visibility = View.VISIBLE
findViewById<AppCompatButton>(R.id.dialogButtonImg1).requestFocus()
}
// val dialog = findViewById<FrameLayout>(R.id.dialogBase)
// val customButton = LayoutInflater.from(this).inflate(R.layout.image_button, null)
// dialog.addView(customButton)
return true
}
}
return super.onKeyDown(keyCode, event) return super.onKeyDown(keyCode, event)
@ -2184,7 +2225,10 @@ class MainActivity : AppCompatActivity() {
this.setShowWhenLocked(false) this.setShowWhenLocked(false)
switchVideoLayout(false) switchVideoLayout(false)
callVideoButton.requestFocus() //callVideoButton.requestFocus()
BaresipService.isMicMuted = false
BaresipService.isVideoMuted = false
} }
"message", "message show", "message reply" -> { "message", "message show", "message reply" -> {
val i = Intent(applicationContext, ChatActivity::class.java) val i = Intent(applicationContext, ChatActivity::class.java)
@ -2959,7 +3003,8 @@ class MainActivity : AppCompatActivity() {
callButton.visibility = View.VISIBLE callButton.visibility = View.VISIBLE
callButton.isEnabled = true callButton.isEnabled = true
} }
callVideoButton.visibility = View.VISIBLE //callVideoButton.visibility = View.VISIBLE
callVideoButton.visibility = View.INVISIBLE // modified by ritoseo
callVideoButton.isEnabled = true callVideoButton.isEnabled = true
hangupButton.visibility = View.INVISIBLE hangupButton.visibility = View.INVISIBLE
hangupButton.isEnabled = false hangupButton.isEnabled = false
@ -2993,7 +3038,8 @@ class MainActivity : AppCompatActivity() {
callButton.isEnabled = true callButton.isEnabled = true
} }
callVideoButton.visibility = View.VISIBLE //callVideoButton.visibility = View.VISIBLE
callVideoButton.visibility = View.INVISIBLE // modified by ritoseo
callVideoButton.isEnabled = true callVideoButton.isEnabled = true
hangupButton.visibility = View.INVISIBLE hangupButton.visibility = View.INVISIBLE
answerButton.visibility = View.INVISIBLE answerButton.visibility = View.INVISIBLE

View File

@ -30,6 +30,7 @@ import android.net.wifi.WifiManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.os.Process
import android.provider.DocumentsContract import android.provider.DocumentsContract
import android.provider.MediaStore import android.provider.MediaStore
import android.provider.OpenableColumns import android.provider.OpenableColumns
@ -1259,6 +1260,15 @@ object Utils {
} }
} }
fun setAudioSourceDevice(dev : String) {
propertySet("sys.rito.audio.input.device", dev)
//val process = Runtime.getRuntime().exec("ritosysc shell-order=killall audioserver")
val process = Runtime.getRuntime().exec("ritosysc shell-order=killall android.hardware.audio.service")
//val process = Runtime.getRuntime().exec("ritosysc shell-order=service call audio 11 i32 1 i32 3")
process.waitFor()
process.destroy()
}
fun checkDisplayConnection(idx : Int): String { fun checkDisplayConnection(idx : Int): String {
val connId = idx + 1 val connId = idx + 1
val file = File("/sys/class/drm/card0-HDMI-A-${connId}/status") // 파일 경로 설정 val file = File("/sys/class/drm/card0-HDMI-A-${connId}/status") // 파일 경로 설정
@ -1268,6 +1278,20 @@ object Utils {
} }
} }
fun checkUsbMicrophone(): Boolean {
var found = false
val file = File("/proc/asound/cards") // 파일 경로 설정
file.bufferedReader().use { reader ->
reader.lineSequence().forEach { line ->
if(line.contains("USB")) {
found = true
}
}
}
return found
}
fun checkCameraConnection(idx : Int): String { fun checkCameraConnection(idx : Int): String {
if(idx == 0) { if(idx == 0) {
val file = File("/d/hdmirx/status") // 파일 경로 설정 val file = File("/d/hdmirx/status") // 파일 경로 설정

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true">
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="#FFFFFF" />
<solid android:color="#FF9800" /> <!-- 포커스 배경 (주황색 강조) -->
<corners android:radius="16dp" />
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="#FFFFFF" />
<solid android:color="#FFA726" /> <!-- 포커스 배경 (주황색 강조) -->
<corners android:radius="16dp" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<stroke android:width="2dp" android:color="#88FFFFFF" />
<solid android:color="#424242" /> <!-- 포커스 배경 (회색) -->
<corners android:radius="16dp" />
</shape>
</item>
</selector>

View File

@ -98,6 +98,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:background="@color/cardview_shadow_start_color" android:background="@color/cardview_shadow_start_color"
android:clickable="false"
android:gravity="center_vertical" android:gravity="center_vertical"
android:popupBackground="@color/colorSpinnerDropdown" android:popupBackground="@color/colorSpinnerDropdown"
android:spinnerMode="dropdown" /> android:spinnerMode="dropdown" />
@ -145,10 +146,12 @@
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:background="@drawable/custom_borer" android:background="@drawable/custom_border"
android:enabled="false"
android:hint="@string/callee" android:hint="@string/callee"
android:inputType="textEmailAddress" android:inputType="textEmailAddress"
android:textColorHint="@color/colorSecondaryDark" android:textColorHint="@color/colorSecondaryDark"
android:textColor="#FF000000"
android:textSize="34sp"> android:textSize="34sp">
<!-- <requestFocus /> --> <!-- <requestFocus /> -->
</AutoCompleteTextView> </AutoCompleteTextView>
@ -229,7 +232,8 @@
android:background="@null" android:background="@null"
android:contentDescription="@string/video_call" android:contentDescription="@string/video_call"
android:padding="0dp" android:padding="0dp"
android:src="@drawable/call_video"></ImageButton> android:src="@drawable/call_video"
android:visibility="invisible"></ImageButton>
<ImageButton <ImageButton
android:id="@+id/hangupButton" android:id="@+id/hangupButton"
@ -507,4 +511,92 @@
android:visibility="invisible" > android:visibility="invisible" >
</RelativeLayout> </RelativeLayout>
<FrameLayout
android:id="@+id/dialogLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
tools:visibility="visible">
<FrameLayout
android:id="@+id/dialogBase"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginHorizontal="150px"
android:layout_marginVertical="150px"
android:background="@drawable/custom_border">
<!--
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/dialogButton1"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="250px"
android:layout_marginTop="250px"
android:background="@drawable/bg_button_selector"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center"
android:padding="16dp"
android:text="전화걸기"
android:textColor="@color/colorWhite"
android:textSize="30sp"
android:textStyle="bold" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/dialogButton2"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="700px"
android:layout_marginTop="250px"
android:background="@drawable/bg_button_selector"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center"
android:padding="16dp"
android:text="설정"
android:textColor="@color/colorWhite"
android:textSize="30sp"
android:textStyle="bold" />
-->
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/dialogButtonImg1"
android:layout_width="220px"
android:layout_height="wrap_content"
android:layout_marginLeft="400px"
android:layout_marginTop="250px"
android:background="@drawable/bg_button_selector"
android:drawableTop="@drawable/callbutton2"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center"
android:padding="16dp"
android:drawablePadding="25px"
android:text="전화걸기"
android:textColor="@color/colorWhite"
android:textSize="30sp"
android:textStyle="bold" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/dialogButtonImg2"
android:layout_width="220px"
android:layout_height="wrap_content"
android:layout_marginLeft="950px"
android:layout_marginTop="250px"
android:background="@drawable/bg_button_selector"
android:drawableTop="@drawable/setting"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center"
android:padding="16dp"
android:drawablePadding="25px"
android:text="설정"
android:textColor="@color/colorWhite"
android:textSize="30sp"
android:textStyle="bold" />
</FrameLayout>
</FrameLayout>
</RelativeLayout> </RelativeLayout>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/imageButton"
android:layout_width="128px"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:background="@drawable/bg_button_selector"
android:focusable="true"
android:clickable="true"
android:focusableInTouchMode="true"
android:padding="16dp">
<ImageView
android:id="@+id/buttonImage"
android:layout_width="128px"
android:layout_height="128px"
android:src="@drawable/callbutton"
android:layout_marginBottom="8dp" />
<TextView
android:id="@+id/buttonText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="전화걸기?"
android:textColor="@color/colorWhite"
android:textSize="24sp"
android:textAlignment="center" />
</LinearLayout>

View File

@ -1468,6 +1468,7 @@ struct stream *video_strm(const struct video *v);
const struct vidcodec *video_codec(const struct video *vid, bool tx); const struct vidcodec *video_codec(const struct video *vid, bool tx);
void video_sdp_attr_decode(struct video *v); void video_sdp_attr_decode(struct video *v);
void video_req_keyframe(struct video *vid); void video_req_keyframe(struct video *vid);
void video_set_source_mute(struct video *vid, bool mute); // added by ritoseo
double video_calc_seconds(uint64_t rtp_ts); double video_calc_seconds(uint64_t rtp_ts);
double video_timestamp_to_seconds(uint64_t timestamp); double video_timestamp_to_seconds(uint64_t timestamp);