gpt4 book ai didi

android - 检测拨出电话何时开始播放回铃音

转载 作者:行者123 更新时间:2023-12-03 13:25:28 25 4
gpt4 key购买 nike

当它开始播放回铃音时,我正在尝试检测拨出电话的状态。我尝试了各种方法来检测这种状态。这里是其中的一些:
1.使用PhoneStateListener :
(Cannot detect when outgoing call is answered in Android)

import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;

public class CustomPhoneStateListener extends PhoneStateListener {

public void onCallStateChanged(int state, String num) {
Log.d(CallStatusPlugin.TAG, ">>>state changed" + state);
}
}
但是像 TelephonyManager.CALL_STATE_IDLE 这样的状态, TelephonyManager.CALL_STATE_OFFHOOK 没有给我们这些状态。
2.使用 READ_PRECISE_PHONE_STATE :
将方法添加到上述相同的电话状态监听器
public void onPreciseCallStateChanged() {
Log.d(CallStatusPlugin.TAG, "onPreciseCallStateChanged");
}
但根据我的研究,读取精确状态要求应用程序必须是系统应用程序。
3. 使用 NotificationListener :
public class CustomNotificationListener extends NotificationListenerService {

public static final String TAG = "CallStatusPlugin";

public CustomNotificationListener() {
Log.v(TAG, ">>> CustomNotificationListener");
}

public void onNotificationPosted(StatusBarNotification sbn) {
Log.i(TAG, "New Notification");

Bundle extras = sbn.getNotification().extras;

if ("Ongoing call".equals(extras.getString(Notification.EXTRA_TEXT))) {
Log.v(TAG, "outgoing call");
} else if ("Dialing".equals(extras.getString(Notification.EXTRA_TEXT))) {
Log.v(TAG, "dialling call");
}
}
}
但这无济于事,因为当拨出电话开始播放回铃音时,操作系统不会更改通知。
4. 使用 BroadcastReceiver :
public class CallBroadcastReceiver extends BroadcastReceiver {

public static final String TAG = "CallStatusPlugin";

public void onReceive(Context context, Intent intent) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);

Log.i(TAG, "CallBroadcastReceiver state: " + state);

// TelephonyManager.EXTRA_FOREGROUND_CALL_STATE = "foreground_state"
Log.d(TAG, "new state >>>>" + intent.getIntExtra("foreground_state", -2));
}
}
但也没有帮助。
5. 使用反射:
我还尝试使用反射获取默认拨号程序的实例,但没有成功:
    //com.samsung.android.incallui
Reflections reflections = new Reflections("com.samsung.android.contacts", new SubTypesScanner(false));

final ClassLoader classLoader = this.getClass().getClassLoader();
ClassLoader[] loaders = { classLoader };

ConfigurationBuilder configurationBuilder = (ConfigurationBuilder) reflections.getConfiguration();
configurationBuilder.setClassLoaders(loaders);

Log.d(TAG, "cl" + classLoader.toString());
Set<Class<? extends Object>> allClasses = reflections.getSubTypesOf(Object.class);
Log.d(TAG, "allclasses" + allClasses.toString());
我无法上课(也许我没有正确使用反射)
6. 使用 InCallService :
通过用自定义拨号器替换默认拨号器(我不想使用)来获得 Call状态。
import android.os.Bundle;
import android.telecom.Call;
import android.telecom.InCallService;
import android.util.Log;

public class CustomInCallService extends InCallService {

public static final String TAG = "CallStatusPlugin";

@Override
public void onCallAdded(Call call) {
Log.d(TAG, "onCallAdded: " + call.getState());

call.registerCallback(
new Call.Callback() {
@Override
public void onConnectionEvent (Call call, String event, Bundle extras) {
Log.d(TAG, "Call.Callback.onConnectionEvent: " + event + ", " + call.getState());
}

@Override
public void onStateChanged (Call call, int state) {
Log.d(TAG, "Call.Callback.onStateChanged: " + state + ", " + call.getState());
}
}
);
}
}
onStateChanged最后给了我一些东西:
调用状态 -> 9 ( STATE_CONNECTING ) -> 1 ( STATE_DIALING ) -> 4 ( STATE_ACTIVE )(回答时)-> 7 ( STATE_DISCONNECTING )
但是通话状态也变成了 STATE_DIALING当拨出电话出现问题时,例如调用的号码无法接通或电话已关闭。所以这意味着我们不能说 DIALING state 是呼出调用开始播放回铃音的状态。
7. 使用 CallManager 从反射:
( 添加于 2018 年 8 月 3 日 )
public class OutCallLogger extends BroadcastReceiver {

public static final String TAG = "CallStatusPlugin";

public OutCallLogger() {
Log.e(TAG, "\n\n\nOutCallLogger Instance Created\n\n\n");
}

@Override
public void onReceive(Context context, Intent intent) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
Log.i(TAG, "OutCallLogger state: " + state);

String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.i(TAG, "Outgoing Number: " + number);

// TelephonyManager.EXTRA_FOREGROUND_CALL_STATE = "foreground_state"
Log.d(TAG, "new state >>>>" + intent.getIntExtra("foreground_state", -2));
Log.d(TAG, "new state >>>>" + intent.getIntExtra("ringing_state", -2));
Log.d(TAG, "new state >>>>" + intent.getIntExtra("background_state", -2));
Log.d(TAG, "new state >>>>" + intent.getIntExtra("disconnect_cause", -2));

final ClassLoader classLoader = this.getClass().getClassLoader();

try {
Class<?> callManagerClass = classLoader.loadClass("com.android.internal.telephony.CallManager");
Log.e(TAG, "CallManager: Class loaded " + callManagerClass.toString());

Method[] methods = callManagerClass.getDeclaredMethods();
for (Method m : methods) {
Log.e(TAG, "Methods: " + m.getName());
}

Method getInstanceMethod = callManagerClass.getDeclaredMethod("getInstance");
getInstanceMethod.setAccessible(true);
Log.e(TAG, "CallManager: Method loaded " + getInstanceMethod.getName());

Object callManagerObject = getInstanceMethod.invoke(null);
Log.e(TAG, "CallManager: Object loaded " + callManagerObject.getClass().getName());

Method getAllPhonesMethod = callManagerClass.getDeclaredMethod("getAllPhones");
Log.e(TAG, "CallManager: Method loaded " + getAllPhonesMethod.getName());

Method getForegroundCallsMethod = callManagerClass.getDeclaredMethod("getForegroundCalls");
Log.e(TAG, "CallManager: Method loaded " + getForegroundCallsMethod.getName());
List foregroundCalls = (List) getForegroundCallsMethod.invoke(callManagerObject);
Log.e(TAG, "Foreground calls: " + foregroundCalls + ", " + foregroundCalls.size());

Method getBackgroundCallsMethod = callManagerClass.getDeclaredMethod("getBackgroundCalls");
Log.e(TAG, "CallManager: Method loaded " + getForegroundCallsMethod.getName());
List backgroundCalls = (List) getBackgroundCallsMethod.invoke(callManagerObject);
Log.e(TAG, "Background calls: " + backgroundCalls + ", " + backgroundCalls.size());

Timer timer = new Timer();

// keep printing all the for 20 seconds to check if we got one
TimerTask doAsynchronousTask = new TimerTask() {
long t0 = System.currentTimeMillis();

@Override
public void run() {
// cancel the timer after 20 seconds
if (System.currentTimeMillis() - t0 > 20 * 1000) {
cancel();
return;
}

try {
List phonesObject = (List) getAllPhonesMethod.invoke(callManagerObject);
Log.e(TAG, "All phones " + phonesObject + ", " + phonesObject.size());

List foregroundCalls = (List) getForegroundCallsMethod.invoke(callManagerObject);
Log.e(TAG, "Foreground calls: " + foregroundCalls + ", " + foregroundCalls.size());

Object backgroundCalls = getBackgroundCallsMethod.invoke(callManagerObject);
Log.e(TAG, "Background calls: " + backgroundCalls);

String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
Log.i(TAG, "New state: " + state);
} catch (Exception e) {
Log.e(TAG, ">>>1. " + e.getMessage());
}
}
};

timer.schedule(doAsynchronousTask, 0, 1000); //execute in every 1000 ms
} catch (ClassNotFoundException e) {
Log.e(TAG, ">>>2. " + e.getMessage());
} catch (NoSuchMethodException e) {
Log.e(TAG, ">>>3. " + e.getMessage());
} catch (InvocationTargetException e) {
Log.e(TAG, ">>>4. " + e.getMessage());
} catch (IllegalAccessException e) {
Log.e(TAG, ">>>5. " + e.getMessage());
}
}
}
但我将所有后台/前台调用和电话作为 emty 结果:
08-03 15:19:22.638  2586  4636 E CallStatusPlugin: All phones [], 0
08-03 15:19:22.639 2586 4636 E CallStatusPlugin: Foreground calls: [], 0
08-03 15:19:22.639 2586 4636 E CallStatusPlugin: Background calls: []
不确定操作系统是否使用 CallManager或不。
经过2-3周的研究,我了解到:
  • 隐藏的 API 为我们提供了与操作系统更深层次的集成(但 Google may remove access to hidden API in Android P )
  • Ringing sound of an outgoing call == Ringback tone
  • State dialing !== State of playing ringback tone
  • 但是我没有得出结论,我可以说这是我们可以获得拨出调用开始播放回铃音的状态的方式

  • 我通过阅读 adb logcat '*:V' 的所有操作系统日志来继续调试。并看到当我听到回铃音( adb logcat -b system '*:V' )时正在打印日志:
    07-31 13:34:13.487  3738 29960 I Telephony: AsyncConnectTonePlayer : play
    07-31 13:34:13.784 3273 7999 D SSRM:p : SIOP:: AP = 330, PST = 313 (W:26), BAT = 294, USB = 0, CHG = 0
    07-31 13:34:13.902 3738 29960 I Telephony: AsyncConnectTonePlayer : onCompletion
    07-31 13:34:14.304 3273 15438 D CustomFrequencyManagerService: releaseDVFSLockLocked : Getting Lock type frm List : DVFS_MIN_LIMIT frequency : 1352000 uid : 1000 pid : 3273 tag : com.samsung.android.incallui@2
    07-31 13:34:14.639 3273 7999 D AudioService: getStreamVolume 0 index 10
    07-31 13:34:16.449 4175 4175 D io_stats: !@ 179,0 r 264349 9232882 w 465999 10111332 d 42634 3418440 f 235485 235449 iot 468730 459107 th 51200 0 0 pt 0 inp 0 0 104823.814
    然后我开始搜索与 相关的内容。 io 统计事件 android & gsm 连接事件 但我无法想出任何方法来获得拨出电话的特定状态,其中调用开始播放回铃音。
    我查看了各种 Android 代码以找出一些提示:
  • TelephonyConnection
  • GsmConnection

  • 我应该寻求实现这一目标的任何提示或方向?与 GSM 连接一样, ConnectionService , ConnectivityManager , ConnectionService ConnectionRequest 任何事物?
    编辑1:
    阅读更多日志将我引向 SipManager我读到了 SIP Basic Call Flow Examples我认为,Android 用于调用或接听电话。
    07-31 16:29:55.335  4076  5081 I reSIProcate: INFO | RESIP:TRANSACTION | TuSelector.cxx:131 | Start add(alm)
    07-31 16:29:55.335 4076 5081 I reSIProcate: INFO | RESIP:TRANSACTION | TuSelector.cxx:138 | AlarmMsg is not null
    07-31 16:29:55.335 4076 5081 I reSIProcate: INFO | RESIP:TRANSACTION | TuSelector.cxx:140 | Sending AlarmMessage 0 to TUs
    07-31 16:29:55.335 4076 5081 I reSIProcate: INFO | RESIP:TRANSACTION | TuSelector.cxx:145 | End add(alm)
    07-31 16:29:55.335 4076 5081 I reSIProcate: INFO | RESIP:DNS | DnsResult.cxx:240 | Whitelisting 2405:200:380:1581::42(28): 2405:200:380:1581::42
    07-31 16:29:55.335 4076 5081 I reSIProcate: INFO | RESIP:DNS | RRVip.cxx:128 | updating an existing vip: 2405:200:380:1581::42 with 2405:200:380:1581::42
    07-31 16:29:55.335 4076 5081 I reSIProcate: INFO | RESIP:TRANSACTION | TuSelector.cxx:71 | Send to TU: TU: CALL-SESSION(8) size=0
    07-31 16:29:55.335 4076 5081 I reSIProcate:
    07-31 16:29:55.335 4076 5081 I reSIProcate: SipResp: 180 tid=935e2afa889bdcad cseq=1 INVITE contact=xxxx@10.56.68.219:5070 / 1 from(wire)
    07-31 16:29:55.336 4076 5081 D StackIF : readMessage: messageType 2 tid 0 pduLength 920
    07-31 16:29:55.336 4076 5081 D SECIMSJ[0]: [UNSL]< NOTIFY_SIP_MESSAGE
    07-31 16:29:55.336 4076 5081 D StackIF[0]: processNotify: id NOTIFY_SIP_MESSAGE
    07-31 16:29:55.340 4076 5081 D SIPMSG[0]: [<--] SIP/2.0 180 Ringing [CSeq: 1 INVITE]
    07-31 16:29:55.340 4076 4896 D ResipRawSipHandler: handleMessage: event: 100
    07-31 16:29:55.340 4076 5082 D OpenApiServiceModule: handleMessage: what 100
    07-31 16:29:55.341 4076 4896 D ResipVolteHandler: handleMessage: evt 114
    07-31 16:29:55.341 4076 5081 D CpAudioEngineClient: SAE_NotiInfo: SAE_NotiInfo string: 16:29:55.341<180 Ringing:1 INVITE
    07-31 16:29:55.341 4076 5081 D VoIpEngineProxy: NotiInfo:Sending IPC_IMS_INFO Noti
    那会有用吗?

    最佳答案

    现在在 Android R 中,我们拥有 public api 的权限。

    READ_PRECISE_PHONE_STATE

    Allows read only access to precise phone state. Allows reading of detailed information about phone state for special-use applications such as dialers, carrier applications, or ims applications.



    也许你现在可以用它来精确的通话状态,我已经在自定义Android系统中得到了精确的通话状态。

    关于android - 检测拨出电话何时开始播放回铃音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51611240/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com