上一章我们了解了FM主activity:FMRadio.java,若没查看的,请打开链接Android FM模块学习之四源码解析(一)
查看fmradio.java源码注释。接下来我们来看看FM重要的一个类:FMRadioService.java
由上一章我们已经知道,打开FM时,在OnStart函数中会bindToService来开启服务,
public boolean bindToService(Context context, ServiceConnection callback) { Log.e(LOGTAG, "bindToService: Context with serviceconnection callback"); context.startService(new Intent(context, FMRadioService.class)); ServiceBinder sb = new ServiceBinder(callback); sConnectionMap.put(context, sb); return context.bindService((new Intent()).setClass(context, FMRadioService.class), sb, 0); }
开启了服务,就会去做一些FM的操作和响应。我们进入到类FMRadioSerivce.java中
在publicvoid onCreate() 方法里初始化数据
mPrefs = new FmSharedPreferences(this);初始化存取数据
电话监听
TelephonyManager tmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE | PhoneStateListener.LISTEN_DATA_ACTIVITY);
保持CPU 运转,屏幕和键盘灯有可能是关闭的
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName()); mWakeLock.setReferenceCounted(false);
注册屏幕是否开启
registerScreenOnOffListener();
注册耳机
registerHeadsetListener();
registerSleepExpired();
registerRecordTimeout();
registerDelayedServiceStop();
registerFMRecordingStatus();
Activity销毁界面方法
public void onDestroy()
在onDestroy方法里mDelayedStopHandler.removeCallbacksAndMessages(null); 移除回调handler信息
关闭警铃cancelAlarms()
将声音设为音乐焦点
//release the audio focus listener AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); if (isMuted()) { mMuted = false; audioManager.setStreamMute(AudioManager.STREAM_MUSIC,false); } audioManager.abandonAudioFocus(mAudioFocusListener);
遗弃音频管理监听
audioManager.abandonAudioFocus(mAudioFocusListener);
在onDestroy方法里卸载注册
/* Remove the Screen On/off listener */ if (mScreenOnOffReceiver != null) { unregisterReceiver(mScreenOnOffReceiver); mScreenOnOffReceiver = null; } /* Unregister the headset Broadcase receiver */ if (mAirplaneModeReceiver != null) { unregisterReceiver(mAirplaneModeReceiver); mAirplaneModeReceiver = null; } if (mHeadsetReceiver != null) {unregisterReceiver(mHeadsetReceiver); mHeadsetReceiver = null; } if( mMusicCommandListener != null ) { unregisterReceiver(mMusicCommandListener); mMusicCommandListener = null; } if( mFmMediaButtonListener != null ) { unregisterReceiver(mFmMediaButtonListener); mFmMediaButtonListener = null; } if (mAudioBecomeNoisyListener != null) { unregisterReceiver(mAudioBecomeNoisyListener); mAudioBecomeNoisyListener = null; } if (mSleepExpiredListener != null ) { unregisterReceiver(mSleepExpiredListener); mSleepExpiredListener = null; } if (mRecordTimeoutListener != null) { unregisterReceiver(mRecordTimeoutListener); mRecordTimeoutListener = null; } if (mDelayedServiceStopListener != null) { unregisterReceiver(mDelayedServiceStopListener); mDelayedServiceStopListener = null; } if (mFmRecordingStatus != null ) { unregisterReceiver(mFmRecordingStatus); mFmRecordingStatus = null; }
关闭收音机fmOff();关掉调频:禁用调频主机和硬件。
TelephonyManager tmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); tmgr.listen(mPhoneStateListener, 0); Log.d(LOGTAG, "onDestroy: unbindFromService completed"); //unregisterReceiver(mIntentReceiver); mWakeLock.release();
mWakeLock.release();<span style="font-family:KaiTi_GB2312;"> </span>释放唤醒锁
在onDestroy方法里设置电话监听参数0失去监听来电状态
tmgr.listen(mPhoneStateListener, 0);
public void registerFMRecordingStatus()控制
private void stop() 卸载FMMediaButtonIntentReceiver类的注册
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
ComponentName fmRadio = new ComponentName(this.getPackageName(),
FMMediaButtonIntentReceiver.class.getName());
mAudioManager.unregisterMediaButtonEventReceiver(fmRadio);
stop()方法调用gotoIdleState()方法删除mDelayedStopHandler空消息,关闭警铃
private void gotoIdleState() mDelayedStopHandler.removeCallbacksAndMessages(null); cancelAlarms(); setAlarmDelayedServiceStop(); stopForeground(true);
public IBinder onBind(Intent intent)绑定service
mDelayedStopHandler.removeCallbacksAndMessages(null);
cancelAlarms();关闭,警铃
mServiceInUse = true; 服务可以使用
/* Application/UI is attached, so get out of lower power mode */
setLowPowerMode(false);
public void onRebind(Intent intent)重新捆绑service
public void onStart(Intent intent, intstartId) StartService启动方法
public boolean onUnbind(Intent intent) 解绑service
获得进程名字方法private String getProcessName()
private void sendRecordIntent(int action) 发送录音无序广播在注册录音广播接收方法中
private void sendRecordServiceIntent(intaction) 发送录音状态无序广播
private void startFM()启动FM方法:
if(true == mAppShutdown) { // not to sendintent to AudioManager in Shutdown if (isCallActive()) { // when Call is activenever let audio playback if ( true == mPlaybackInProgress ) // no needto resend event
请求音频声音焦点
AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE); int granted = audioManager.requestAudioFocus(mAudioFocusListener,AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
判断是否请求声音焦点成功
if(granted !=AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { Log.d(LOGTAG, "audio focuss couldnot be granted"); return; }
/**
*请求改变焦点失败
*/
public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
/**
*请求改变焦点成功 */
public static final intAUDIOFOCUS_REQUEST_GRANTED = 1;
实现audioManager类的焦点监听接口
private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() { public void onAudioFocusChange(int focusChange) { mDelayedStopHandler.obtainMessage(FOCUSCHANGE, focusChange, 0).sendToTarget(); } };
请求声音焦点当music响起fm短时间暂停,music关闭后fm继续播放private void requestFocus()
mAudioManager.registerMediaButtonEventReceiver(fmRadio);注册多媒体按钮事件监听
mStoppedOnFocusLoss = false;停止声音焦值为false
停止fm使用
private void stopFM(){ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,AudioSystem.DEVICE_STATE_UNAVAILABLE,""); }
重新设置fm
private void resetFM() { AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM, AudioSystem.DEVICE_STATE_UNAVAILABLE, "") }
mA2dpDeviceState.isDeviceAvailable()蓝牙耳机设备可用是否可用
mOverA2DP全局变量是用来表示蓝牙是否可用
public boolean mute()静音模式 mMute 全局变量作为是否开启静音模式做判断
AudioManager audioManager =(AudioManager) getSystemService(Context.AUDIO_SERVICE);
设置静音audioManager.setStreamMute(AudioManager.STREAM_MUSIC,false);
public booleanisWiredHeadsetAvailable()耳机可用
public boolean isCallActive()通话中,调用getCallState()方法返回0为空闲没有通话,返回1是通话状态。
public void stopRecording()停止录音
private void fmActionOnCallState(int state ) 通话活动状态在进入fm方法privateboolean fmOn()中调用此方法,会用到通话监听获取state值。
public boolean startA2dpPlayback()启动蓝牙播放方法,
final Runnable mHeadsetPluginHandler= new Runnable()方法当耳机被拔出就关闭fm
final Runnable mHeadsetPluginHandler = new Runnable() { public void run() { /* Update the UI based on the state change of the headset/antenna*/ if(!isAntennaAvailable()) { // if (!isFmOn()) // return; /* Disable FM and let the UI know */ fmOff(); try { /* Notify the UI/Activity, only if the service is "bound" by an activity and if Callbacks are registered */ if((mServiceInUse) && (mCallbacks != null) ) { mCallbacks.onDisabled(); } } catch (RemoteException e) { e.printStackTrace(); } }else { /* headset is plugged back in, So turn on FM if: - FM is not already ON. - If the FM UI/Activity is in the foreground (the service is "bound" by an activity and if Callbacks are registered) */ if ((!isFmOn()) && (mServiceInUse) && (mCallbacks != null)) { if( true != fmOn() ) { return; } try { mCallbacks.onEnabled(); } catch (RemoteException e) { e.printStackTrace(); } } } } };
public void clearStationInfo()清除fm状态信息
FmRxEvCallbacksAdaptor fmCallbacks= new FmRxEvCallbacksAdaptor() 广播接收类详解
public void FmRxEvEnableReceiver()可用接收
public voidFmRxEvDisableReceiver() 失去接收功能
public void FmRxEvRadioReset()收音机从新设置
调整fm频率并保持
FmSharedPreferences.setTunedFrequency(frequency);
mPrefs.Save();
enableStereo(FmSharedPreferences.getAudioOutputMode());获取立体声音是否可用
更新状态栏的通知信息
startNotification();设计fm在后台播放,service不被杀死,挂一个前台通知,在停止FMRadioService停止前台通知:
startForeground(FMRADIOSERVICE_STATUS,status);
在gotoIdleState()转到fm空闲状态的时候就停止前警铃,后警铃后台服务,前台通知栏等关闭。
mDelayedStopHandler.removeCallbacksAndMessages(null);
cancelAlarms();
setAlarmDelayedServiceStop();
stopForeground(true);
readInternalAntennaAvailable() 读的调频的内部天线可用状态
private booleansetAudioPath(boolean analogMode) 安装判断铃声路径
/*
*打开调频:调频硬件启动,并初始化调频模块
* @return返回值为真:如果调频使api调用成功,
假:如果api失败了。
* /
private boolean fmOn()
mReceiver = newFmReceiver(FMRADIO_DEVICE_FD_STRING, fmCallbacks);
从调频堆栈接收回调函数
FmRxEvCallbacksAdaptor fmCallbacks = newFmRxEvCallbacksAdaptor()
mReceiver.setRawRdsGrpMask();
FmSharedPreferences.clearTags();清除Tag
Fm重新设置
public void FmRxEvRadioReset()
fmRadioReset();
调整屏幕状态
public void FmRxEvRadioTuneStatus(intfrequency)
FmSharedPreferences.setTunedFrequency(frequency);
mPrefs.Save();
清除状态信息
if(mReceiver != null) {
clearStationInfo();
}
更新状态栏通知
startNotification();
判断RDSS支持
public void FmRxEvRdsLockStatus(booleanbRDSSupported)
mCallbacks.onStationRDSSupported(bRDSSupported);
更新警铃立体声状态
public void FmRxEvStereoStatus(booleanstereo)
mCallbacks.onAudioUpdate(stereo);
public void FmRxEvServiceAvailable(booleansignal)
fm搜索完成
public void FmRxEvSearchComplete(intfrequency)
FmSharedPreferences.setTunedFrequency(frequency);
clearStationInfo();
startNotification();
mWakeLock.acquire(10*1000);唤醒锁屏超时10*1000就释放唤醒对象
电话不是在空闲状态换回false
if ( TelephonyManager.CALL_STATE_IDLE !=getCallState() ) {
return bStatus;
}
正常进入fm
if (isFmOn()) { /* FM Is already on,*/ bStatus = true; Log.d(LOGTAG, "mReceiver.already enabled"); }
获取fm配置
FmConfig config =FmSharedPreferences.getFMConfiguration();
广播接收获取FM配置状态
bStatus =mReceiver.enable(FmSharedPreferences.getFMConfiguration());
扬声器可用设置boolean值
if (isSpeakerEnabled()) { setAudioPath(false); } else { setAudioPath(true); }
真正启动fm播放声音是AudioSystem.setDeviceConnectionState(); 设置fm设备启动,设置fm耳机播放还是扬声器播放(核心代码)
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM, AudioSystem.DEVICE_STATE_AVAILABLE, ""); if (isSpeakerEnabled()) { mSpeakerPhoneOn = true; Log.d(LOGTAG, "Audio source set it as speaker"); AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_SPEAKER); } else { Log.d(LOGTAG, "Audio source set it as headset"); AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE); }
audio焦点监听事件
AudioManager.OnAudioFocusChangeListener是申请成功之后监听AudioFocus使用情况的Listener,后续如果有别的程序要竞争AudioFocus,都是通过这个Listener的onAudioFocusChange()方法来通知这个AudioFocus的使用者的。
请求audio焦点属性
指示申请得到的AudioFocus不知道会持续多久,一般是长期占有;
指示要申请的AudioFocus是暂时性的,会很快用完释放的;
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK不但说要申请的AudioFocus是暂时性的,还指示当前正在使用AudioFocus的可以继续播放,只是要“duck”一下(降低音量)。
AUDIOFOCUS_REQUEST_GRANTED:申请成功;
AUDIOFOCUS_REQUEST_FAILED:申请失败。
抢夺焦点
AUDIOFOCUS_GAIN:获得了Audio
Focus;
AUDIOFOCUS_LOSS:失去了Audio
Focus,并将会持续很长的时间。这里因为可能会停掉很长时间,所以不仅仅要停止Audio的播放,最好直接释放掉Media资源。而因为停止播放Audio的时间会很长,如果程序因为这个原因而失去AudioFocus,最好不要让它再次自动获得AudioFocus而继续播放,不然突然冒出来的声音会让用户感觉莫名其妙,感受很不好。这里直接放弃AudioFocus,当然也不用再侦听远程播放控制【如下面代码的处理】。要再次播放,除非用户再在界面上点击开始播放,才重新初始化Media,进行播放。
AUDIOFOCUS_LOSS_TRANSIENT:暂时失去Audio
Focus,并会很快再次获得。必须停止Audio的播放,但是因为可能会很快再次获得AudioFocus,这里可以不释放Media资源;
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:暂时失去AudioFocus,但是可以继续播放,不过要在降低音量。