前一章咱們瞭解了FM手動調頻,接下來咱們要分析FM模塊用到的源碼。此源碼是基於高通平臺的,別的平臺都大同小異,只不過是平臺本身做了些小改動而已。java
首先要看的固然是主activity,android
FMRadio.javaapi
fmradio類啓動FMRadioService.java類調用FmSharedPreferences類進行存儲數據,PresetStation調整頻率緩存
setVolumeControlStream(AudioManager.STREAM_MUSIC);音樂回放即媒體音量函數
LoadedDataAndState加載數據狀態佈局
HorizontalNumberPicker水平刻度盤類繼承LinearLayoutpost
mPicker.setTextSize(mDisplayWidth/ TEXTSIZE_PARAMETER_FOR_NUMBER_PICKER);設置字體的大小,屏幕寬度除以20字體
mPicker.setDensity(outMetrics.densityDpi);設置控件密度動畫
mPicker.setOnValueChangedListener設置監聽事件ui
valueToFrequency(newVal);刻度滑動選中的值,上升降低調整限制值FmConfig配置文件裏setLowerLimit(int lowLimit)在設置裏選中地區時候的頻率取值範圍
mPrefs.getFrequencyStepSize(),得到設置的步長大小
mHandler.post(mRadioChangeFrequency);更新在刻度盤上顯示頻率信息、
tuneRadio(int frequency)調整fm頻率
FMRadioService.java類isFmOn()方法:
registerCallbacks註冊回調IFMRadioServiceCallbacks的對象、
ServiceStub繼承IFMRadioService.Stub使用到WeakReferenc弱引用,WeakReference是弱於 SoftReference 的引用類型。弱引用的特性和基本與軟引用類似,區別就在於弱引用所指向的對象只要進行系統垃圾回收,無論內存使用狀況如何,永遠對其進行回收(get() 方法返回 null)。
IBindermBinder = new ServiceStub(this); bindService IBinder等於serviceStub對象。
fmOn()部分代碼:
/**
*當來電話不是閒置的時候就返回false
*/
if (TelephonyManager.CALL_STATE_IDLE != getCallState() ) {
return bStatus;
}
mReceiver= new FmReceiver(FMRADIO_DEVICE_FD_STRING, fmCallbacks);
FmReceiver接受廣播類繼承FmTransceiver
/ * *
*構造函數接收方對象,路徑
*電臺和事件回調。
* < p >
* @param devicePath調頻設備路徑字符串。
* @param回調事件回調處理
從調頻接收機*事件。
*
* /
public FmReceiver(String devicePath,FmRxEvCallbacksAdaptorcallback) throws InstantiationException {
mControl = new FmRxControls();
mRxEvents = new FmRxEventListner();
//registerClient(callback);
mCallback = callback;
}
得到FM如今的狀態
public int getFMState()
{
/* Current State of FM device */
int currFMState =FmTransceiver.getFMPowerState();
return currFMState;
}
滑動刻度盤動畫效果:
mAnimation= AnimationUtils.loadAnimation(this,R.anim.preset_select);
靜音控件監聽,點擊控件有聲無聲切換。
mMuteButton.setOnClickListener(mMuteModeClickListener);
喇叭與耳機監聽切換
mSpeakerButton.setOnClickListener(mSpeakerClickListener);
開啓關閉fm控件切換
mOnOffButton.setOnClickListener(mTurnOnOffClickListener);
向右調頻控件監聽
mForwardButton.setOnClickListener(mForwardClickListener);
mForwardButton.setOnLongClickListener(mForwardLongClickListener);
向左調頻控件監聽
mBackButton.setOnClickListener(mBackClickListener);
mBackButton.setOnLongClickListener(mBackLongClickListener);
單擊收藏按鈕把收藏頻率定位調頻到刻度盤上,長期按鈕將刻度盤頻率收藏到按鈕上存儲到data分區下的fmradio_prefs.xml文件 key是tation_name0x1
頻率顯示控件
mTuneStationFrequencyTV= (TextView)findViewById(R.id.prog_frequency_tv);
長按頻率顯示控件監聽方法:
mTuneStationFrequencyTV.setOnLongClickListener(mFrequencyViewClickListener);
錄音視圖顯示與監聽事件
mRecordingMsgTV= (TextView)findViewById(R.id.record_msg_tv);
if (mRecordingMsgTV != null) {
mRecordingMsgTV.setOnClickListener(mRecordButtonListener);
}
自動關掉FM時間顯示
mSleepMsgTV= (TextView)findViewById(R.id.sleep_msg_tv);
fm信號強度
mRSSI =(ImageView)findViewById(R.id.signal_level);
if (mRSSI != null) {
mRSSI.setVisibility(View.INVISIBLE);
}
顯示控件顯示信息等數據顯示
protectedvoid setDisplayvalue()
onRestart()
獲取 IFMRadioService請求焦點
onStop中方法調用private boolean isSleepTimerActive()是不是睡眠。
if(isSleepTimerActive()){
mSleepUpdateHandlerThread.interrupt();
}
若是是睡眠活動就睡眠更新線程中斷線程
當錄音開始,走onStop()方法時候就中止錄音更新線程
private boolean isRecording()
if (null!= mRecordUpdateHandlerThread) {
mRecordUpdateHandlerThread.interrupt();
}
public void onStart()
用戶選擇高清晰多媒體顯示建立命令失敗.
一、若是未保存則調用onCreateDialog(int),而後再調用onPrepareDialog(int, Dialog)
(2)若是保存了對話框對象,則直接調用onPrepareDialog(int,Dialog),不會再去create,因此有時候當你再輸入框裏不管如何輸入什麼內容,對話框的內容都是第一次產生的。
removeDialog(int)是用來清除Activity保存下來的Dialog對象,若是不加removeDialog將會致使不管在對話框裏輸入什麼內容,
彈出來的對話框始終都是第一次保留下來的,這裏因此要加上它
建立搜索dialog
createSearchDlg(id,dlgBuilder)
FMConfig.java類
public int getRdsStd () {
return mRdsStd;
}
registerFMSettingListner();註冊收音機設置配置文件
mPrefs.Load();調用FmSharedPreferences的Load()方法獲取fmradio_prefs.xml數據
碰見bug:將設置地區自動選擇印度(外單項目)
/* LoadConfiguration */
if(Locale.getDefault().equals(Locale.CHINA)) {
setCountry(sp.getInt(FMCONFIG_COUNTRY,REGIONAL_BAND_CHINA));
} else {
setCountry(sp.getInt(FMCONFIG_COUNTRY, REGIONAL_BAND_NORTH_AMERICA));
}
/* Last list the user was navigating */
Local.getDafault()在第一次刷機後設置本地語言後
protected void onPause()的時候,將信息保存mPrefs.Save();
ScrollerText控件繼承Handler、
/ * *
*移動一個字符留下的文字和文章
*SCROLLER_UPDATE_DELAY_MS後延遲下更新消息。
*若是滾動整個字符串,而後它會顯示整個字符串
*並等待SCROLLER_RESTART_DELAY_MS滾動重啓
* /
voidupdateText()更新錄音時間
中止錄音時間跟新
void stopScroll() {
mStatus = SCROLLER_STOPPED;
removeMessages(SCROLLER_MSG_TICK);
removeMessages(SCROLLER_MSG_RESTART);
removeMessages(SCROLLER_MSG_START);
resetScroll();
}
從新設置錄音時間顯示
private void resetScroll()
啓動錄音時間
void startScroll() {
初始化搜索
private void initiateSearch(int pty)
resetSearch()從新收索
private void cancelSearch()關閉收索
初始化搜索列表
private void initiateSearchList()
初始化睡眠定時器
private void initiateSleepTimer(long seconds) {
mSleepAtPhoneTime =(SystemClock.elapsedRealtime()) + (seconds * 1000);
Log.d(LOGTAG, "Sleep in seconds:" + seconds);
initiateSleepThread();
}
初始化睡眠線程
private void initiateSleepThread()
在
Intent launchPreferencesIntent = new Intent().setClass(this,
Settings.class);
launchPreferencesIntent.putExtra(Settings.RX_MODE,true);
startActivityForResult(launchPreferencesIntent,
ACTIVITY_RESULT_SETTINGS);
private void enableSpeaker() 揚聲器可用
private void updateExpiredRecordTime()更新錄音時間
private Runnable doRecordProcessing = new Runnable()錄音進度
public void onResume()
mService.registerCallbacks(mServiceCallbacks);註冊回調service
mService.cancelDelayedStop(FMRadioService.STOP_SERVICE);延遲關閉FMRadioService
public boolean bindToService(Context context,ServiceConnection callback)啓動在FMRadio的onStart()方法判斷條件啓動FMRadioService
if((mService == null ) && (false == bindToService(this, osc)))
onDestroy()方法中解綁nRegisterReceiver(mFmSettingReceiver);
boolean isWiredHeadsetAvailable()判斷耳機是否可用,在FMRadioService類裏添加public void registerHeadsetListener()註冊耳機監聽事件,mHeadsetPlugged = (intent.getIntExtra("state", 0) == 1);狀態監聽
Intent裏的public static final String ACTION_HEADSET_PLUG =
"android.intent.action.HEADSET_PLUG";耳機靜態常量定義。
再啓動FMRadioService監聽 registerHeadsetListener();耳機
/ * *肯定是否一個內部天線。
* FMOn返回緩存的值初始化。
*
* @return真正的若是內部天線可用或連線
*耳機插入,若是內部天線是錯誤的
*沒有和有線耳機不是插入。
* /
public boolean isAntennaAvailable()FMRadioService類
public void readInternalAntennaAvailable()肯定是否有內部天線,調用類FMReceivce的父類FMTransceiver類發送接收信號類
public boolean getInternalAntenna()方法,經過FmReceiverJNI類調用getControlNative方法。
恢復設置默認地區設置private voidRestoreDefaults()
當天線能夠用的時候就調用UI界面可用顯示
private void enableRadioOnOffUI() {
boolean bEnable = isFmOn();
/* Disable if no antenna/headset isavailable */
if (!isAntennaAvailable()) {
bEnable = false;
}
enableRadioOnOffUI(bEnable);
}
調用此方法private void enableRadioOnOffUI(boolean bEnable)顯示FMRadio.java UI界面
boolean isCallActive()電話呼叫活動,FMRadioService類isCallActive當狀態不爲零表示在通話中
public boolean isCallActive()
{
//Non-zero: Call state is RINGING orOFFHOOK on the available subscriptions
//zero: Call state is IDLE on all theavailable subscriptions
if(0 != getCallState()) return true;
return false;
}
private void enableRadio()可以使用收音機
private void disableRadio()不可用收音機
private void resetRadio()從新設置收音機
public void clearStationList()清除電臺列表信息
public boolean fmConfigure()收音機配置
/ *設置調頻模塊自動切換到另外一個頻率
*站若是一個頻率的信號強度比
*目前調諧頻率。
*
*布爾bEnable:真:自動切換到更強的交替頻率。
*假:不要切換到備用頻率。
*
* @return真實若是設置自動對焦模式api調用成功,錯誤若是api失敗了。
*注:回調FmRxEvRadioTuneStatus時將調用
*完成不一樣的頻率。
* /
調用FMRadioService類 publicboolean enableAutoAF(boolean bEnable)方法。
public void fmAudioOutputMode()輸出立體聲音
private void startRecording()錄音開始
private void setRecordingStopImage()錄音中止圖片設置
private void setRecordingStartImage()錄音開始圖片設置、
private void startRecordingTimer()錄音啓動的時間
private void stopRecording()中止錄音
private boolean isRecording()判斷是否在錄音
private boolean isSpeakerEnabled()判斷揚聲器是可用
private boolean stationExists(PresetStationstation )長按收藏按鈕式電臺頻率是都存在
private void addToPresets()添加電臺頻率顯示到按鈕上
FmSharedPreferences.addStation(selectedStation.getName(),selectedStation
.getFrequency(),currentList);
setupPresetLayout();
調用FmSharedPreferences類的addStation方法添加到mListOfPlists列表裏
private void resetSearchProgress()重置搜索進度
updateSearchProgress()更新搜索進度
setupPresetLayout()安裝頻率佈局,收藏頻率至按鈕上初始化
updateStationInfoToUI()更新電臺信息界面信息
private boolean isFmOn()收音機是否開啓
/*若是啓用了模擬路徑返回true */
public boolean isAnalogModeEnabled() {
return misAnalogPathEnabled;
}
/ *返回調頻(Soc)音頻硬件是否有限。
*
* @return真若是調頻音頻是柔和的,假若是不低調。
*
* /
public boolean isMuted() {
return mMuted;
}
private boolean isScanActive()掃描活動布爾值
private boolean isSeekActive()查找活動布爾值
private boolean isSearchActive()搜索活動布爾值
public PresetStation getCurrentTunedStation()得到如今調整電臺
private void SeekNextStation()在搜索查找下一個頻率
private void initiateSearch(int pty)初始化搜索
/** SEEK Station with the matching PI */
private void initiatePISearch(int pi)需找匹配的頻率
private void resetSearch()重新搜索
private void cancelSearch()關閉搜索
private void initiateSearchList()初始化搜索列表
private void initiateSleepTimer(long seconds) 初始化睡眠計時器
private void initiateSleepThread()初始化睡眠線程
private void endSleepTimer()結束睡眠計時器時間
private boolean hasSleepTimerExpired()睡眠計時器中止
private boolean isSleepTimerActive()睡眠計時器活動是否活動
private void updateExpiredSleepTime()更新中止睡眠時間
private String makeTimeString(long secs)時間格式字符串
private void tuneRadio(int frequency)調整收音機頻率
private void resetFMStationInfoUI()重新設置收音機電臺顯示界面信息
IFMRadioServiceCallbacks類回調時候
Runnable mRadioEnabled = new Runnable()收音機可用
Runnable mRadioDisabled = new Runnable()收音機不可用
Runnable mRadioReset = new Runnable()收音機從新設置
Runnable mUpdateStationInfo = new Runnable()跟新收音機電臺信息
Runnable mOnMute = new Runnable()收音機靜音設置
Runnable mOnStereo = new Runnable()立體聲音
Runnable mUpdateRadioText = new Runnable()更新收音機文本信息
Runnable mRadioChangeFrequency = newRunnable()調整頻率
Runnable mUpdateExtenRadioText = newRunnable()更新延伸收音機文本信息
Runnable mUpdateProgramService = newRunnable()跟新service進度
private void DebugToasts(String str, intduration)彈出提示信息
private void registerFMSettingListner() 註冊設置改變監聽
private void unRegisterReceiver(BroadcastReceiver myReceiver)卸載註冊避免重複註冊報異常