从UI 开始讲解:
说起通话,就避免不了谈起InCallActivity.java, 这是通话中的UI 主界面,通过解析其布局文件
Incall_screen.xml
<fragment android:name="com.android.incallui.CallCardFragment"
android:id="@+id/callCardFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true" />
使用自定义fragment CallCardFragment, fragment ui 创建接口onCreateView
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.call_card_content, container, false);
}
分析call_card_content.xml
<fragment android:name="com.android.incallui.CallButtonFragment"
android:layout_alignParentBottom="true"
android:id="@+id/callButtonFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
再次使用自定义fragment CallButtonFragment
其布局文件
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View parent = inflater.inflate(R.layout.call_button_fragment, container, false);
call_button_fragment.xml
<com.android.incallui.LeuiCallButton
android:id="@+id/audioButton"
style="@style/InCallCompoundButton"
android:layout_marginLeft="@dimen/call_button_margin_side"
android:layout_marginRight="@dimen/call_button_margin_center"
leui:ButtonSelecter="@drawable/leui_ic_call_audio"
leui:ButtonText="@string/audio"
leui:contentDescription="@string/onscreenAudioText" />
ok, 到这了就能看到通话ui中的音频切换的button,切换流程将从这里的onclick事件开始分析:回头CallButtonFragment
public void onClick(View view) {
int id = view.getId();
int mode = AudioState.ROUTE_WIRED_OR_EARPIECE;
Log.d(this, "onClick(View " + view + ", id " + id + ")...");
switch(id) {
case R.id.audioButton:
onAudioButtonClicked();
}
private void onAudioButtonClicked() {
if (isSupported(AudioState.ROUTE_BLUETOOTH)) {
showAudioModePopup();
} else {
getPresenter().toggleSpeakerphone();
}
}
CallButtonPresenter.java
public void toggleSpeakerphone() {
setAudioMode(newMode);
}
public void setAudioMode(int mode) {
TelecomAdapter.getInstance().setAudioRoute(mode);
}
Phone.java
public final void setAudioRoute(int route) {
mInCallAdapter.setAudioRoute(route);
}
InCallAdapter.java
public void setAudioRoute(int route) {
mHandler.obtainMessage(MSG_SET_AUDIO_ROUTE, route, 0).sendToTarget();
}
private final class InCallAdapterHandler extends Handler {
@Override
public void handleMessage(Message msg) {
case MSG_SET_AUDIO_ROUTE:
mCallsManager.setAudioRoute(msg.arg1);
break;
}
CallsManager.java
void setAudioRoute(int route) {
mCallAudioManager.setAudioRoute(route);
}
ok, 经过系列转换,终于见到曙光了。
CallAudioManager.java
void setAudioRoute(int route) {
setSystemAudioState(mAudioState.isMuted(), newRoute,
mAudioState.getSupportedRouteMask());
}
private void turnOnSpeaker(boolean on) {
// Wired headset and earpiece work the same way
if (mAudioManager.isSpeakerphoneOn() != on) {
Log.i(this, "turning speaker phone %s", on);
mAudioManager.setSpeakerphoneOn(on);
}
}
终于调用到AudioManager. 这才是系统提供的api。
audiomanager 通过binder 机制调用Audioservice。省去中间简单传递过程,直接从audioservice分析
private void setForceUse(int usage, int config) {
AudioSystem.setForceUse(usage, config);
}
通过audiosystem 以jni 机制调用native方法。 android_media_AudioSystem.cpp
static jint
android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
{
return (jint) check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <audio_policy_force_use_t>(usage),
static_cast <audio_policy_forced_cfg_t>(config)));
}
AudioSystem.cpp
status_t AudioSystem::setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
return aps->setForceUse(usage, config);
}
IAudioPolicyService.cpp
virtual status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
data.writeInt32(static_cast <uint32_t>(usage));
data.writeInt32(static_cast <uint32_t>(config));
remote()->transact(SET_FORCE_USE, data, &reply);
return static_cast <status_t> (reply.readInt32());
}
AudioPolicyInterfaceImpl.cpp
status_t AudioPolicyService::setForceUse(audio_policy_force_use_t usage,
audio_policy_forced_cfg_t config)
{
Mutex::Autolock _l(mLock);
mAudioPolicyManager->setForceUse(usage, config);
return NO_ERROR;
}
AudioPolicyManager.cpp
void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage,
audio_policy_forced_cfg_t config)
{
applyStreamVolumes(output, newDevice, 0, true);
}
void AudioPolicyManager::applyStreamVolumes(audio_io_handle_t output,
audio_devices_t device,
int delayMs,
bool force)
{
checkAndSetVolume((audio_stream_type_t)stream,
mStreams[stream].getVolumeIndex(device),
output,
device,
delayMs,
force);
}
}
status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
int index,
audio_io_handle_t output,
audio_devices_t device,
int delayMs,
bool force)
{
}
后续基本流程
AudioPolicyClientImpl.cpp
AudioPolicyService.cpp
AudioFlinger.cpp