上一章咱们了解了FM主activity:FMRadio.java,若没查看的,请打开连接Android FM模块学习之四源码解析(一)java
查看fmradio.java源码注释。接下来咱们来看看FM重要的一个类:FMRadioService.javaapi
由上一章咱们已经知道,打开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中ui
在publicvoid onCreate() 方法里初始化数据this
mPrefs = new FmSharedPreferences(this);初始化存取数据设计
电话监听
TelephonyManager tmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE |
PhoneStateListener.LISTEN_DATA_ACTIVITY);对象
保持CPU 运转,屏幕和键盘灯有多是关闭的blog
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();//释放唤醒锁
在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_GAIN
指示申请获得的AudioFocus不知道会持续多久,通常是长期占有;
AUDIOFOCUS_GAIN_TRANSIENT
指示要申请的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,可是能够继续播放,不过要在下降音量。