編輯:關於Android編程
上一篇大概分析了一下FM啟動流程,若不了解Fm啟動流程的,可以去打開前面的鏈接先了解FM啟動流程,接下來我們簡單分析一下FM的搜索頻率流程。
在了解源碼之前,我們先看一下流程圖:
其實從圖中可以看到,實現搜索頻率的功能是在底層CPP文件,java層只操作和更新一些界面(GUI),Java調用JNI實現功能。Java app基本核心,通過方法回調實現a類和b類方法,b類調a類方法信息交互相互控制融為一體。App實現一些JNI接口最終實現核心功能是cpp文件,最後通過Service類(耗時操作)調用New一個線程循環不斷的獲取cpp裡的信息,去更新UI界面活動狀態。
搜索流程簡單分析<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPqO6teO798vRy/ewtMWlo6zNqLn9u6W197e9t6ijrNfuuvO197W9Rk1SZWNlaXZlckpOScDg1tC1xLe9t6jKtc/WuabE3KGjzai5/UZNUnhFdmVudExpc3RuZXLA4LK7ts+78cihY3BwseTGtbXExrXCyqOsw7+78cih0ru0zsa1wsoo1rG1vca1wsrL0cv3zeqzyc2j1rm199PDKb7Nu9i190ZNUmFkaW9TZXJ2aWNlxNqyv0ZtUnhFdkNhbGxiYWNrc0FkYXB0b3K1xLe9t6jU2rvYtfe1vUZNUmFkaW/A4NbQt723qKOsvavGtcLKtObI60ZtU2hhcmVkUHJlZmVyZW5jZXPA4HhtbM7EtbXW0KOst6LLzUhhbmRsZXK4/NDCVUmjrLy0v8y2yMXMo6y21Luwv/KjrNfz09K8/c231tC85M/Uyr61xMa1wsrSu9bCzPi2r6GjPC9wPgo8cD4gICC908/CwLTP6s+4tPrC67fWzvajujxicj4KPC9wPgo8cD4gICAgRk1SYWRpb9bQtcSyy7Wly9HL97mmxNyjrG9uT3B0aW9uc0l0ZW1TZWxlY3RlZChNZW51SXRlbSBpdGVtKbzgzP3W0NffaW5pdGlhdGVTZWFyY2gobVNjYW5QdHlJbmRleCk7t723qKGjPC9wPgo8cD48aW1nIHNyYz0="/uploadfile/Collfiles/20141121/2014112108585517.jpg" alt="\">
調用FMRadioService的scan()方法(mService.scan(pty))進行掃描頻率
updateSearchProgress()裡加了同步方法對象鎖
調用了private Dialog createProgressDialog(int id)對話框進行搜索信息
標准耳機FmSharedPreferences.isRBDSStd()
private Dialog createProgressDialog(int id) { String msgStr = ""; String titleStr = ""; String []items; double frequency = mTunedStation.getFrequency() / 1000.0; boolean bSearchActive = false; if (isSeekActive()) { msgStr = getString(R.string.msg_seeking); bSearchActive = true; }else if (isScanActive()) { if(FmSharedPreferences.isRBDSStd()) {//標准耳機 items = getResources(). getStringArray(R.array.search_category_rbds_entries); }else { // if(FmSharedPreferences.isRDSStd()) items = getResources(). getStringArray(R.array.search_category_rds_entries); }String ptyStr = ""; if (items.length > mScanPtyIndex) ptyStr = items[mScanPtyIndex]; if (!TextUtils.isEmpty(ptyStr)) { msgStr = getString(R.string.msg_scanning_pty, ptyStr); }else { Log.d(LOGTAG, "pty is null\n"); msgStr = getString(R.string.msg_scanning); } titleStr = getString(R.string.msg_search_title, ("" + frequency)); bSearchActive=true; }else if (isSearchActive()) { msgStr = getString(R.string.msg_searching); titleStr = getString(R.string.msg_searching_title); bSearchActive = true; } if (bSearchActive) {mProgressDialog = new ProgressDialog(FMRadio.this); if (mProgressDialog != null) { mProgressDialog.setTitle(titleStr); mProgressDialog.setMessage(msgStr); mProgressDialog.setIcon(R.drawable.ic_launcher_fmradio); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); mProgressDialog.setCanceledOnTouchOutside(false); mProgressDialog.setButton(DialogInterface.BUTTON_POSITIVE, getText(R.string.button_text_stop), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { cancelSearch(); } }); mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { cancelSearch(); } }); mProgressDialog.setOnKeyListener(new OnKeyListener() { public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { Log.d(LOGTAG, "OnKeyListener event received in ProgressDialog" + keyCode); switch (keyCode) { case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: case 126: //KeyEvent.KEYCODE_MEDIA_PLAY: case 127: //KeyEvent.KEYCODE_MEDIA_PAUSE: case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: case KeyEvent.KEYCODE_MEDIA_NEXT: case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_REWIND: case KeyEvent.KEYCODE_MEDIA_STOP: return true; } return false; } }); } Message msg = new Message(); msg.what = TIMEOUT_PROGRESS_DLG; mSearchProgressHandler.sendMessageDelayed(msg, SHOWBUSY_TIMEOUT); } return mProgressDialog; }調用FMRadioService類中的Scan()方法掃描
調用 FMReceiver的searchStations()方法進行掃描
public boolean scan(int pty) { boolean bCommandSent=false; if (mReceiver != null) { Log.d(LOGTAG, "scan: PTY: " + pty); if(FmSharedPreferences.isRBDSStd()) { /* RBDS : Validate PTY value?? */ if( ((pty > 0) && (pty <= 23)) || ((pty >= 29) && (pty <= 31)) ) {bCommandSent = mReceiver.searchStations(FmReceiver.FM_RX_SRCHRDS_MODE_SCAN_PTY, FmReceiver.FM_RX_DWELL_PERIOD_2S, FmReceiver.FM_RX_SEARCHDIR_UP, pty, 0); } else { bCommandSent = mReceiver.searchStations(FmReceiver.FM_RX_SRCH_MODE_SCAN, FmReceiver.FM_RX_DWELL_PERIOD_2S, FmReceiver.FM_RX_SEARCHDIR_UP); }} else { /* RDS : Validate PTY value?? */ if( (pty > 0) && (pty <= 31) ) { bCommandSent = mReceiver.searchStations(FmReceiver.FM_RX_SRCHRDS_MODE_SCAN_PTY, FmReceiver.FM_RX_DWELL_PERIOD_2S, FmReceiver.FM_RX_SEARCHDIR_UP, pty, 0); } else{ bCommandSent = mReceiver.searchStations(FmReceiver.FM_RX_SRCH_MODE_SCAN, FmReceiver.FM_RX_DWELL_PERIOD_2S, FmReceiver.FM_RX_SEARCHDIR_UP); } } } return bCommandSent; }
FmReceiver類的public boolean searchStations (int mode,int dwellPeriod,intdirection,int pty,Int pi) 方法
獲得FMState狀態
int state = getFMState();
/ * 驗證參數* /
調用setSearchState(subSrchLevel_ScanInProg);
re = mControl.searchStations(sFd, mode,dwellPeriod, direction, pty, pi);
public boolean searchStations (int mode, int dwellPeriod, int direction){ int state = getFMState();//獲得FMState狀態 boolean bStatus = true; int re; /* Check current state of FM device */ if (state == FMState_Turned_Off || state == FMState_Srch_InProg) { Log.d(TAG, "searchStations: Device currently busy in executing another command."); return false; } Log.d (TAG, "Basic search..."); /* Validate the arguments */ if ( (mode != FM_RX_SRCH_MODE_SEEK) && (mode != FM_RX_SRCH_MODE_SCAN)) { Log.d (TAG, "Invalid search mode: " + mode ); bStatus = false; } if ( (dwellPeriod < FM_RX_DWELL_PERIOD_0S ) || (dwellPeriod > FM_RX_DWELL_PERIOD_7S)) { Log.d (TAG, "Invalid dwelling time: " + dwellPeriod); bStatus = false; } if ( (direction != FM_RX_SEARCHDIR_DOWN) && (direction != FM_RX_SEARCHDIR_UP)) { Log.d (TAG, "Invalid search direction: " + direction); bStatus = false; } if (bStatus) { Log.d (TAG, "searchStations: mode " + mode + "direction: " + direction); if (mode == FM_RX_SRCH_MODE_SEEK) setSearchState(subSrchLevel_SeekInPrg); else if (mode == FM_RX_SRCH_MODE_SCAN) setSearchState(subSrchLevel_ScanInProg); Log.v(TAG, "searchStations: CURRENT-STATE : FMRxOn ---> NEW-STATE : SearchInProg"); re = mControl.searchStations(sFd, mode, dwellPeriod, direction, 0, 0); if (re != 0) { Log.e(TAG, "search station failed"); if (getFMState() == FMState_Srch_InProg) setSearchState(subSrchLevel_SrchComplete); return false; } state = getFMState(); if (state == FMState_Turned_Off) { Log.d(TAG, "searchStations: CURRENT-STATE : FMState_Off (unexpected)"); return false; } } return bStatus; }
設置FM搜索電源狀態
static void setSearchState(int state) { mSearchState = state; switch(mSearchState) { case subSrchLevel_SeekInPrg: case subSrchLevel_ScanInProg: case subSrchLevel_SrchListInProg: setFMPowerState(FMState_Srch_InProg); break; case subSrchLevel_SrchComplete: /* Update the state of the FM device */ mSearchState = subSrchLevel_NoSearch; setFMPowerState(FMState_Rx_Turned_On); break; case subSrchLevel_SrchAbort: break; default: mSearchState = subSrchLevel_NoSearch; break; } }setFMPowerState(FMState_Rx_Turned_On); 是調用FmTransceiver類發射器類,FM電源狀態
/*============================================================== FUNCTION: setFMPowerState ==============================================================*/ /** * Sets the FM power state * ** This method sets the FM power state. * *
*/ static void setFMPowerState(int state) { FMState = state; }
調用FMRxControls.java類的
/ * 配置各種搜索參數,開始搜索* /
public int searchStations (int fd, int mode,int dwell, int dir, int pty, int pi)
設置一些參數
FmReceiverJNI.setControlNative();
設置的搜索模式
設置掃描居住的時間
設置的企業
設置PI
/* configure various search parameters and start search */ public int searchStations (int fd, int mode, int dwell, int dir, int pty, int pi){ int re = 0; Log.d(TAG, "Mode is " + mode + " Dwell is " + dwell); Log.d(TAG, "dir is " + dir + " PTY is " + pty); Log.d(TAG, "pi is " + pi + " id " + V4L2_CID_PRIVATE_TAVARUA_SRCHMODE); re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCHMODE, mode); if (re != 0) { Log.e(TAG, "setting of search mode failed"); return re; } re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SCANDWELL, dwell); if (re != 0) { Log.e(TAG, "setting of scan dwell time failed"); return re; } if (pty != 0) { re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY, pty); if (re != 0) { Log.e(TAG, "setting of PTY failed"); return re; } } if (pi != 0) { re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PI, pi); if (re != 0) { Log.e(TAG, "setting of PI failed"); return re; } } re = FmReceiverJNI.startSearchNative (fd, dir ); return re; }
啟動搜索 FmReceiverJNI.startSearchNative (fd, dir );
關閉搜索
FMRadio 調用 FMRadioService 的CancelSearch()方法
public boolean cancelSearch()
public boolean cancelSearch() { boolean bCommandSent=false; if (mReceiver != null) { Log.d(LOGTAG, "cancelSearch"); bCommandSent = mReceiver.cancelSearch(); } return bCommandSent; }調用FRReceiver的cancelSearch()
mReceiver.cancelSearch()
更新搜索 FMRadio.java中
updateSearchProgress();
private void updateSearchProgress() { boolean searchActive = isScanActive() || isSeekActive() || isSearchActive(); if (searchActive) { synchronized (this) { if(mProgressDialog == null) { showDialog(DIALOG_PROGRESS_PROGRESS); }else { Message msg = new Message(); msg.what = UPDATE_PROGRESS_DLG; mSearchProgressHandler.sendMessage(msg); } } }else { Message msg = new Message(); msg.what = END_PROGRESS_DLG; mSearchProgressHandler.sendMessage(msg); } }
調用FMRxControls類的public void cancelSearch (int fd)方法
最後調用FMReceiver類的cancelSearchNative()
/* cancel search in progress */ public void cancelSearch (int fd){ FmReceiverJNI.cancelSearchNative(fd); }最後發送一個mSearchProgressHandler
msg.what = END_PROGRESS_DLG;
mSearchProgressHandler.sendMessage(msg)
刪除handler發送消息關閉對話框
private Handler mSearchProgressHandler = new Handler() { public void handleMessage(Message msg) { if (msg.what == UPDATE_PROGRESS_DLG) { if(mProgressDialog != null) { double frequency = mTunedStation.getFrequency() / 1000.0; String titleStr = getString(R.string.msg_search_title, ("" + frequency)); mProgressDialog.setTitle(titleStr); } }else if (msg.what == END_PROGRESS_DLG) { mSearchProgressHandler.removeMessages(END_PROGRESS_DLG); mSearchProgressHandler.removeMessages(UPDATE_PROGRESS_DLG); mSearchProgressHandler.removeMessages(TIMEOUT_PROGRESS_DLG); removeDialog(DIALOG_PROGRESS_PROGRESS); mProgressDialog = null; }else if (msg.what == TIMEOUT_PROGRESS_DLG) { cancelSearch(); } } };
在搜索中更新FMRadioUI界面的監聽類FmRxEventListner.java
public void startListner (final int fd, final FmRxEvCallbacks cb) { /* start a thread and listen for messages */ mThread = new Thread(){ public void run(){ byte [] buff = new byte[STD_BUF_SIZE]; Log.d(TAG, "Starting listener " + fd); while ((!Thread.currentThread().isInterrupted())) { try { int index = 0; int state = 0; Arrays.fill(buff, (byte)0x00); int freq = 0; int eventCount = FmReceiverJNI.getBufferNative (fd, buff, EVENT_LISTEN); if (eventCount >= 0) Log.d(TAG, "Received event. Count: " + eventCount); for ( index = 0; index < eventCount; index++ ) { Log.d(TAG, "Received <" +buff[index]+ ">" ); switch(buff[index]){ case 0:Log.d(TAG, "Got READY_EVENT"); if(FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMRx_Starting) { /*Set the state as FMRxOn */ FmTransceiver.setFMPowerState(FmTransceiver.FMState_Rx_Turned_On); Log.v(TAG, "RxEvtList: CURRENT-STATE : FMRxStarting ---> NEW-STATE : FMRxOn"); cb.FmRxEvEnableReceiver(); } else if (FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMTurning_Off) { /*Set the state as FMOff */ FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off); Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff"); FmTransceiver.release("/dev/radio0"); cb.FmRxEvDisableReceiver(); Thread.currentThread().interrupt(); } break;case 1: Log.d(TAG, "Got TUNE_EVENT"); freq = FmReceiverJNI.getFreqNative(fd); state = FmReceiver.getSearchState(); switch(state) { case FmTransceiver.subSrchLevel_SeekInPrg : Log.v(TAG, "Current state is " + state); FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete); Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn"); cb.FmRxEvSearchComplete(freq); break; default: if (freq > 0) cb.FmRxEvRadioTuneStatus(freq); else Log.e(TAG, "get frequency command failed"); break; } break; case 2:Log.d(TAG, "Got SEEK_COMPLETE_EVENT"); state = FmReceiver.getSearchState(); switch(state) { case FmTransceiver.subSrchLevel_ScanInProg: Log.v(TAG, "Current state is " + state); FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete); Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn"); cb.FmRxEvSearchComplete(FmReceiverJNI.getFreqNative(fd)); break; case FmTransceiver.subSrchLevel_SrchAbort: Log.v(TAG, "Current state is SRCH_ABORTED"); Log.v(TAG, "Aborting on-going search command..."); FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete); Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn"); cb.FmRxEvSearchComplete(FmReceiverJNI.getFreqNative(fd)); break; } break; case 3:Log.d(TAG, "Got SCAN_NEXT_EVENT"); cb.FmRxEvSearchInProgress(); break; case 4: Log.d(TAG, "Got RAW_RDS_EVENT"); cb.FmRxEvRdsGroupData(); break; case 5: Log.d(TAG, "Got RT_EVENT"); cb.FmRxEvRdsRtInfo(); break; case 6: Log.d(TAG, "Got PS_EVENT"); cb.FmRxEvRdsPsInfo(); break; case 7: Log.d(TAG, "Got ERROR_EVENT"); break; case 8: Log.d(TAG, "Got BELOW_TH_EVENT"); cb.FmRxEvServiceAvailable (false); break; case 9:Log.d(TAG, "Got ABOVE_TH_EVENT"); cb.FmRxEvServiceAvailable(true); break; case 10: Log.d(TAG, "Got STEREO_EVENT"); cb.FmRxEvStereoStatus (true); break; case 11: Log.d(TAG, "Got MONO_EVENT"); cb.FmRxEvStereoStatus (false); break; case 12: Log.d(TAG, "Got RDS_AVAL_EVENT"); cb.FmRxEvRdsLockStatus (true); break; case 13: Log.d(TAG, "Got RDS_NOT_AVAL_EVENT"); cb.FmRxEvRdsLockStatus (false); break; case 14:Log.d(TAG, "Got NEW_SRCH_LIST"); state = FmReceiver.getSearchState(); switch(state) { case FmTransceiver.subSrchLevel_SrchListInProg: Log.v(TAG, "FmRxEventListener: Current state is AUTO_PRESET_INPROGRESS"); FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete); Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn"); cb.FmRxEvSearchListComplete (); break; case FmTransceiver.subSrchLevel_SrchAbort: Log.v(TAG, "Current state is SRCH_ABORTED"); Log.v(TAG, "Aborting on-going SearchList command..."); FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete); Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn"); cb.FmRxEvSearchCancelled(); break; } break; case 15:Log.d(TAG, "Got NEW_AF_LIST"); cb.FmRxEvRdsAfInfo(); break; case 18: Log.d(TAG, "Got RADIO_DISABLED"); if (FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMTurning_Off) { /*Set the state as FMOff */ FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off); Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff"); FmTransceiver.release("/dev/radio0"); cb.FmRxEvDisableReceiver(); Thread.currentThread().interrupt(); } else { Log.d(TAG, "Unexpected RADIO_DISABLED recvd"); cb.FmRxEvRadioReset(); } break; case 19:FmTransceiver.setRDSGrpMask(0); break; case 20: Log.d(TAG, "got RT plus event"); cb.FmRxEvRTPlus(); break; case 21: Log.d(TAG, "got eRT event"); cb.FmRxEvERTInfo(); break; default: Log.d(TAG, "Unknown event"); break; } }//end of for } catch ( Exception ex ) { Log.d( TAG, "RunningThread InterruptedException"); ex.printStackTrace(); Thread.currentThread().interrupt(); } } } }; mThread.start(); }Switch case取1的時候就FMReceiverJNI類中獲取頻率,調FmRxEvRadioTuneStatus接收讀取頻率
freq= FmReceiverJNI.getFreqNative(fd);
cb.FmRxEvRadioTuneStatus(freq);
將頻率保存起來
FmSharedPreferences.setTunedFrequency(frequency);
mPrefs.Save();
清除狀態信息 clearStationInfo();
調用改變界面狀態 mCallbacks.onTuneStatusChanged();
可用存儲,設置可用模擬器 enableStereo(FmSharedPreferences.getAudioOutputMode());
public void FmRxEvRadioTuneStatus(int frequency) { Log.d(LOGTAG, "FmRxEvRadioTuneStatus: Tuned Frequency: " +frequency); try { FmSharedPreferences.setTunedFrequency(frequency); mPrefs.Save(); //Log.d(LOGTAG, "Call mCallbacks.onTuneStatusChanged"); /* Since the Tuned Status changed, clear out the RDSData cached */ if(mReceiver != null) { clearStationInfo(); } if(mCallbacks != null) { mCallbacks.onTuneStatusChanged(); } /* Update the frequency in the StatusBar's Notification */ startNotification(); enableStereo(FmSharedPreferences.getAudioOutputMode()); } catch (RemoteException e) { e.printStackTrace(); } }
最後調到底層
FmReceiverJNI.setMonoStereoNative (fd, 1)
/* force mono/stereo mode */ public int stereoControl(int fd, boolean stereo) { if (stereo){ return FmReceiverJNI.setMonoStereoNative (fd, 1); } else { return FmReceiverJNI.setMonoStereoNative (fd, 0); } }
public void onTuneStatusChanged() { Log.d(LOGTAG, "mServiceCallbacks.onTuneStatusChanged: "); if (mIsScaning) { Log.d(LOGTAG, "isScanning...................."); SharedPreferences sp = getSharedPreferences(SCAN_STATION_PREFS_NAME, 0); SharedPreferences.Editor editor = sp.edit(); int station_number = sp.getInt(NUM_OF_STATIONS, 0); station_number++; editor.putInt(NUM_OF_STATIONS, station_number); editor.putString(STATION_NAME + station_number, station_number + ""); editor.putInt(STATION_FREQUENCY + station_number, FmSharedPreferences.getTunedFrequency()); editor.commit(); } cleanupTimeoutHandler(); mHandler.post(mUpdateStationInfo); mHandler.post(mOnStereo); }
Runnable mUpdateStationInfo = new Runnable() { public void run() { cleanupTimeoutHandler(); PresetStation station = new PresetStation("", FmSharedPreferences.getTunedFrequency()); if (station != null) { mTunedStation.Copy(station); } updateSearchProgress(); resetFMStationInfoUI(); } };
updateStationInfoToUI();
private void updateStationInfoToUI() { double frequency = mTunedStation.getFrequency() / 1000.0; mTuneStationFrequencyTV.setText("" + frequency + "MHz"); if ((mPicker != null) && mUpdatePickerValue) { mPicker.setValue(((mTunedStation.getFrequency() - mPrefs.getLowerLimit()) / mPrefs.getFrequencyStepSize())); } mStationCallSignTV.setText(mTunedStation.getPIString()); mProgramTypeTV.setText(mTunedStation.getPtyString()); mRadioTextTV.setText(""); mERadioTextTV.setText(""); mRadioTextScroller.mOriginalString = ""; mRadioTextScroller.mStringlength = 0; mRadioTextScroller.mIteration = 0; mERadioTextScroller.mOriginalString = ""; mERadioTextScroller.mStringlength = 0; mERadioTextScroller.mIteration = 0; mProgramServiceTV.setText(""); mStereoTV.setText(""); setupPresetLayout(); }FM啟動和關閉搜索都是通過JNI調到底層實現,代碼路徑是:vendor\qcom\opensource\fm\jni
android_hardware_fm.cpp
/* * JNI registration. */ static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "acquireFdNative", "(Ljava/lang/String;)I", (void*)android_hardware_fmradio_FmReceiverJNI_acquireFdNative}, { "closeFdNative", "(I)I", (void*)android_hardware_fmradio_FmReceiverJNI_closeFdNative}, { "getFreqNative", "(I)I", (void*)android_hardware_fmradio_FmReceiverJNI_getFreqNative}, { "setFreqNative", "(II)I", (void*)android_hardware_fmradio_FmReceiverJNI_setFreqNative}, { "getControlNative", "(II)I", (void*)android_hardware_fmradio_FmReceiverJNI_getControlNative}, { "setControlNative", "(III)I", (void*)android_hardware_fmradio_FmReceiverJNI_setControlNative}, { "startSearchNative", "(II)I", (void*)android_hardware_fmradio_FmReceiverJNI_startSearchNative}, { "cancelSearchNative", "(I)I", (void*)android_hardware_fmradio_FmReceiverJNI_cancelSearchNative}, { "getRSSINative", "(I)I", (void*)android_hardware_fmradio_FmReceiverJNI_getRSSINative}, { "setBandNative", "(III)I", (void*)android_hardware_fmradio_FmReceiverJNI_setBandNative}, { "getLowerBandNative", "(I)I", (void*)android_hardware_fmradio_FmReceiverJNI_getLowerBandNative}, { "getUpperBandNative", "(I)I", (void*)android_hardware_fmradio_FmReceiverJNI_getUpperBandNative}, { "getBufferNative", "(I[BI)I", (void*)android_hardware_fmradio_FmReceiverJNI_getBufferNative}, { "setMonoStereoNative", "(II)I", (void*)android_hardware_fmradio_FmReceiverJNI_setMonoStereoNative}, { "getRawRdsNative", "(I[BI)I", (void*)android_hardware_fmradio_FmReceiverJNI_getRawRdsNative}, { "setNotchFilterNative", "(IIZ)I", (void*)android_hardware_fmradio_FmReceiverJNI_setNotchFilterNative}, { "startRTNative", "(ILjava/lang/String;I)I", (void*)android_hardware_fmradio_FmReceiverJNI_startRTNative}, { "stopRTNative", "(I)I", (void*)android_hardware_fmradio_FmReceiverJNI_stopRTNative}, { "startPSNative", "(ILjava/lang/String;I)I", (void*)android_hardware_fmradio_FmReceiverJNI_startPSNative}, { "stopPSNative", "(I)I", (void*)android_hardware_fmradio_FmReceiverJNI_stopPSNative}, { "setPTYNative", "(II)I", (void*)android_hardware_fmradio_FmReceiverJNI_setPTYNative}, { "setPINative", "(II)I", (void*)android_hardware_fmradio_FmReceiverJNI_setPINative}, { "setPSRepeatCountNative", "(II)I", (void*)android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative}, { "setTxPowerLevelNative", "(II)I", (void*)android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative}, { "setAnalogModeNative", "(Z)I", (void*)android_hardware_fmradio_FmReceiverJNI_setAnalogModeNative}, { "SetCalibrationNative", "(I)I", (void*)android_hardware_fmradio_FmReceiverJNI_SetCalibrationNative}, { "configureSpurTable", "(I)I", (void*)android_hardware_fmradio_FmReceiverJNI_configureSpurTable}, };上面寫明了從jni的調用關系。具體的函數實現,請到Android_hardware_fm.cpp中去查看。我就不一一寫出來了。以上就是FM搜索頻率與取消搜索頻率的操作與實現。搜索到頻率後就可以聽FM了。
你的小米手機准備好迎接MIUI8的到來了嗎?今天小編搶先帶來小米MIUI 8系統更新升級教程,想要升級miui8系統的米粉們快來看看吧!MIUI8升級須知:
Activity是Android系統的4個應用程序組件之一。通過傳統方法顯示的Activity都是充滿整個屏幕,也就是全屏的Activity。事實上,Activity不僅
前面文章介紹了Android利用麥克風采集並顯示模擬信號的實現方法,這種采集手段適用於無IO控制、單純讀取信號的情況。如果傳感器本身需要包含控制電路(例如采集血氧信號需要
盡管Android向下兼容不好,但是一個程序還是可以在多個平台上跑的。向下兼容不好,接口改變,新的平台上不能用舊的API,舊的平台更不可能用新的API,不等於一個平台需要