简单分析一下FM的搜索频率流程。

在了解源码之前,我们先看一下流程图:

其实从图中可以看到,实现搜索频率的功能是在底层CPP文件,java层只操作和更新一些界面(GUI),Java调用JNI实现功能。Java app基本核心,通过方法回调实现a类和b类方法,b类调a类方法信息交互相互控制融为一体。App实现一些JNI接口最终实现核心功能是cpp文件,最后通过Service类(耗时操作)调用New一个线程循环不断的获取cpp里的信息,去更新UI界面活动状态。

搜索流程简单分析:点击搜索按钮,通过互调方法,最后调到FMReceiverJNI类中的方法实现功能。通过FMRxEventListner类不断获取cpp变频的频率,每获取一次频率(直到频率搜索完成停止调用)就回调FMRadioService内部FmRxEvCallbacksAdaptor的方法在回调到FMRadio类中方法,将频率存入FmSharedPreferences类xml文档中,发送Handler更新UI,即刻度盘,对话框,左右箭头中间显示的频率一致跳动。

接下来详细代码分析:

FMRadio中的菜单搜索功能,onOptionsItemSelected(MenuItem item)监听中走initiateSearch(mScanPtyIndex);方法。

调用FMRadioService的scan()方法(mService.scan(pty))进行扫描频率

updateSearchProgress()里加了同步方法对象锁

调用了private Dialog createProgressDialog(int id)对话框进行搜索信息

标准耳机FmSharedPreferences.isRBDSStd()

[java] view plain copy  print?
  1. private Dialog <strong>createProgressDialog</strong>(int id) {
  2. String msgStr = "";
  3. String titleStr = "";
  4. String []items;
  5. double frequency = mTunedStation.getFrequency() / 1000.0;
  6. boolean bSearchActive = false;
  7. if (isSeekActive()) {
  8. msgStr = getString(R.string.msg_seeking);
  9. bSearchActive = true;
  10. }else if (isScanActive()) {
  11. if(FmSharedPreferences.isRBDSStd()) {<span style="font-family:KaiTi_GB2312;">//标准耳机</span>
  12. items = getResources().
  13. getStringArray(R.array.search_category_rbds_entries);
  14. }else { // if(FmSharedPreferences.isRDSStd())
  15. items = getResources().
  16. getStringArray(R.array.search_category_rds_entries);
  17. }String ptyStr = "";
  18. if (items.length > mScanPtyIndex)
  19. ptyStr = items[mScanPtyIndex];
  20. if (!TextUtils.isEmpty(ptyStr)) {
  21. msgStr = getString(R.string.msg_scanning_pty, ptyStr);
  22. }else {
  23. Log.d(LOGTAG, "pty is null\n");
  24. msgStr = getString(R.string.msg_scanning);
  25. }
  26. titleStr = getString(R.string.msg_search_title, ("" + frequency));
  27. bSearchActive=true;
  28. }else if (isSearchActive()) {
  29. msgStr = getString(R.string.msg_searching);
  30. titleStr = getString(R.string.msg_searching_title);
  31. bSearchActive = true;
  32. }
  33. if (bSearchActive) {mProgressDialog = new ProgressDialog(FMRadio.this);
  34. if (mProgressDialog != null) {
  35. mProgressDialog.setTitle(titleStr);
  36. mProgressDialog.setMessage(msgStr);
  37. mProgressDialog.setIcon(R.drawable.ic_launcher_fmradio);
  38. mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
  39. mProgressDialog.setCanceledOnTouchOutside(false);
  40. mProgressDialog.setButton(DialogInterface.BUTTON_POSITIVE,
  41. getText(R.string.button_text_stop),
  42. new DialogInterface.OnClickListener() {
  43. public void onClick(DialogInterface dialog, int whichButton) {
  44. <strong>cancelSearch();</strong>
  45. }
  46. });
  47. mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) {
  48. cancelSearch();
  49. }
  50. });
  51. mProgressDialog.setOnKeyListener(new OnKeyListener() {
  52. public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
  53. Log.d(LOGTAG, "OnKeyListener event received in ProgressDialog" + keyCode);
  54. switch (keyCode) {
  55. case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
  56. case 126: //KeyEvent.KEYCODE_MEDIA_PLAY:
  57. case 127: //KeyEvent.KEYCODE_MEDIA_PAUSE:
  58. case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
  59. case KeyEvent.KEYCODE_MEDIA_NEXT:
  60. case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
  61. case KeyEvent.KEYCODE_MEDIA_REWIND:
  62. case KeyEvent.KEYCODE_MEDIA_STOP:
  63. return true;
  64. } return false;
  65. }
  66. });
  67. }
  68. Message msg = new Message();
  69. msg.what = TIMEOUT_PROGRESS_DLG;
  70. mSearchProgressHandler.sendMessageDelayed(msg, SHOWBUSY_TIMEOUT);
  71. }
  72. return mProgressDialog;
  73. }

调用FMRadioService类中的Scan()方法扫描

调用 FMReceiver的searchStations()方法进行扫描

[java] view plain copy  print?
  1. public boolean<strong> scan(int pty)</strong>
  2. {
  3. boolean bCommandSent=false;
  4. if (mReceiver != null)
  5. {
  6. Log.d(LOGTAG, "scan:  PTY: " + pty);
  7. if(FmSharedPreferences.isRBDSStd())
  8. {
  9. /* RBDS : Validate PTY value?? */
  10. if( ((pty  > 0) && (pty  <= 23)) || ((pty  >= 29) && (pty  <= 31)) )
  11. {bCommandSent = <strong>mReceiver.searchStations</strong>(FmReceiver.FM_RX_SRCHRDS_MODE_SCAN_PTY,
  12. FmReceiver.FM_RX_DWELL_PERIOD_2S,
  13. FmReceiver.FM_RX_SEARCHDIR_UP,
  14. pty,
  15. 0);
  16. }
  17. else
  18. {
  19. bCommandSent = <strong>mReceiver.searchStations</strong>(FmReceiver.FM_RX_SRCH_MODE_SCAN,
  20. FmReceiver.FM_RX_DWELL_PERIOD_2S,
  21. FmReceiver.FM_RX_SEARCHDIR_UP);
  22. }}
  23. else
  24. {
  25. /* RDS : Validate PTY value?? */
  26. if( (pty  > 0) && (pty  <= 31) )
  27. {
  28. bCommandSent = <strong>mReceiver.searchStations</strong>(FmReceiver.FM_RX_SRCHRDS_MODE_SCAN_PTY,
  29. FmReceiver.FM_RX_DWELL_PERIOD_2S,
  30. FmReceiver.FM_RX_SEARCHDIR_UP,
  31. pty,
  32. 0);
  33. }
  34. else{
  35. bCommandSent =<strong> mReceiver.searchStations</strong>(FmReceiver.FM_RX_SRCH_MODE_SCAN,
  36. FmReceiver.FM_RX_DWELL_PERIOD_2S,
  37. FmReceiver.FM_RX_SEARCHDIR_UP);
  38. }
  39. }
  40. }
  41. return bCommandSent;
  42. }

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);

[java] view plain copy  print?
  1. public boolean <strong>searchStations </strong>(int mode,
  2. int dwellPeriod,
  3. int direction){
  4. <strong> int state = getFMState();</strong>//<span style="font-family:KaiTi_GB2312;font-size:18px;">获得FMState状态</span>
  5. boolean bStatus = true;
  6. int re;
  7. /* Check current state of FM device */
  8. if (state == FMState_Turned_Off || state == FMState_Srch_InProg) {
  9. Log.d(TAG, "searchStations: Device currently busy in executing another command.");
  10. return false;
  11. }
  12. Log.d (TAG, "Basic search...");
  13. /* Validate the arguments */
  14. if ( (mode != FM_RX_SRCH_MODE_SEEK) &&
  15. (mode != FM_RX_SRCH_MODE_SCAN))
  16. {
  17. Log.d (TAG, "Invalid search mode: " + mode );
  18. bStatus = false;
  19. }
  20. if ( (dwellPeriod < FM_RX_DWELL_PERIOD_0S ) ||
  21. (dwellPeriod > FM_RX_DWELL_PERIOD_7S))
  22. {
  23. Log.d (TAG, "Invalid dwelling time: " + dwellPeriod);
  24. bStatus = false;
  25. }
  26. if ( (direction != FM_RX_SEARCHDIR_DOWN) &&
  27. (direction != FM_RX_SEARCHDIR_UP))
  28. {
  29. Log.d (TAG, "Invalid search direction: " + direction);
  30. bStatus = false;
  31. }
  32. if (bStatus)
  33. {
  34. Log.d (TAG, "searchStations: mode " + mode + "direction:  " + direction);
  35. if (mode == FM_RX_SRCH_MODE_SEEK)
  36. setSearchState(subSrchLevel_SeekInPrg);
  37. else if (mode == FM_RX_SRCH_MODE_SCAN)
  38. setSearchState(subSrchLevel_ScanInProg);
  39. Log.v(TAG, "searchStations: CURRENT-STATE : FMRxOn ---> NEW-STATE : SearchInProg");
  40. <strong> re = mControl.searchStations(sFd, mode, dwellPeriod, direction, 0, 0);</strong>
  41. if (re != 0) {
  42. Log.e(TAG, "search station failed");
  43. if (getFMState() == FMState_Srch_InProg)
  44. setSearchState(subSrchLevel_SrchComplete);
  45. return false;
  46. }         state = getFMState();
  47. if (state == FMState_Turned_Off) {
  48. Log.d(TAG, "searchStations: CURRENT-STATE : FMState_Off (unexpected)");
  49. return false;
  50. }
  51. }
  52. return bStatus;
  53. }

设置FM搜索电源状态

[java] view plain copy  print?
  1. static void <strong>setSearchState</strong>(int state)
  2. {
  3. mSearchState = state;
  4. switch(mSearchState) {
  5. case subSrchLevel_SeekInPrg:
  6. case subSrchLevel_ScanInProg:
  7. case subSrchLevel_SrchListInProg:
  8. setFMPowerState(FMState_Srch_InProg);
  9. break;
  10. case subSrchLevel_SrchComplete:
  11. /* Update the state of the FM device */
  12. mSearchState = subSrchLevel_NoSearch;
  13. setFMPowerState(FMState_Rx_Turned_On);
  14. break;
  15. case subSrchLevel_SrchAbort:
  16. break;
  17. default:
  18. mSearchState = subSrchLevel_NoSearch;
  19. break;
  20. }
  21. }

setFMPowerState(FMState_Rx_Turned_On); 是调用FmTransceiver类发射器类,FM电源状态

[java] view plain copy  print?
  1. /*==============================================================
  2. FUNCTION:  setFMPowerState
  3. ==============================================================*/
  4. /**
  5. *    Sets the FM power state
  6. *
  7. *    <p>
  8. *    This method sets the FM power state.
  9. *
  10. *    <p>
  11. */
  12. static void <strong>setFMPowerState(</strong>int state)
  13. {
  14. FMState = state;
  15. }

调用FMRxControls.java类的

/ * 配置各种搜索参数,开始搜索* /

public int searchStations (int fd, int mode,int dwell, int dir, int pty, int pi)

设置一些参数

FmReceiverJNI.setControlNative();

设置的搜索模式

设置扫描居住的时间

设置的企业

设置PI

[java] view plain copy  print?
  1. /* configure various search parameters and start search */
  2. public int <strong>searchStations </strong>(int fd, int mode, int dwell,
  3. int dir, int pty, int pi){
  4. int re = 0;
  5. Log.d(TAG, "Mode is " + mode + " Dwell is " + dwell);
  6. Log.d(TAG, "dir is "  + dir + " PTY is " + pty);
  7. Log.d(TAG, "pi is " + pi + " id " +  V4L2_CID_PRIVATE_TAVARUA_SRCHMODE);
  8. <strong> re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCHMODE, mode);</strong>
  9. if (re != 0) {
  10. Log.e(TAG, "setting of search mode failed");
  11. return re;
  12. }
  13. <strong>re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SCANDWELL, dwell);</strong>
  14. if (re != 0) {
  15. Log.e(TAG, "setting of scan dwell time failed");
  16. return re;
  17. }
  18. if (pty != 0)
  19. {  re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY, pty);
  20. if (re != 0) {
  21. Log.e(TAG, "setting of PTY failed");
  22. return re;
  23. }
  24. }
  25. if (pi != 0)
  26. {
  27. <strong> re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PI, pi);</strong>
  28. if (re != 0) {
  29. Log.e(TAG, "setting of PI failed");
  30. return re;
  31. }
  32. }
  33. <strong>re = FmReceiverJNI.startSearchNative (fd, dir );</strong>
  34. return re;
  35. }

启动搜索 FmReceiverJNI.startSearchNative (fd, dir );

关闭搜索

FMRadio 调用 FMRadioService 的CancelSearch()方法

public boolean cancelSearch()

[java] view plain copy  print?
  1. public boolean <strong>cancelSearch()</strong>
  2. {
  3. boolean bCommandSent=false;
  4. if (mReceiver != null)
  5. {
  6. Log.d(LOGTAG, "cancelSearch");
  7. bCommandSent = <strong>mReceiver.cancelSearch();</strong>
  8. }
  9. return bCommandSent;
  10. }

调用FRReceiver的cancelSearch()

mReceiver.cancelSearch()

更新搜索 FMRadio.java中

updateSearchProgress();

[java] view plain copy  print?
  1. private void <strong>updateSearchProgress()</strong> {
  2. boolean searchActive = isScanActive() || isSeekActive() || isSearchActive();
  3. if (searchActive) {
  4. synchronized (this) {
  5. if(mProgressDialog == null) {
  6. showDialog(DIALOG_PROGRESS_PROGRESS);
  7. }else {
  8. Message msg = new Message();
  9. msg.what = UPDATE_PROGRESS_DLG;
  10. mSearchProgressHandler.sendMessage(msg);
  11. }
  12. }
  13. }else {
  14. Message msg = new Message();
  15. msg.what = END_PROGRESS_DLG;
  16. mSearchProgressHandler.sendMessage(msg);
  17. }
  18. }

初始化菜单  invalidateOptionsMenu();

调用FMRxControls类的public void cancelSearch (int fd)方法

最后调用FMReceiver类的cancelSearchNative()

[java] view plain copy  print?
  1. /* cancel search in progress */
  2. public void cancelSearch (int fd){
  3. <strong> FmReceiverJNI.cancelSearchNative(fd);</strong>
  4. }

最后发送一个mSearchProgressHandler

msg.what = END_PROGRESS_DLG;

mSearchProgressHandler.sendMessage(msg)

删除handler发送消息关闭对话框

[java] view plain copy  print?
  1. private Handler mSearchProgressHandler = new Handler() {
  2. public void handleMessage(Message msg) {
  3. if (msg.what == UPDATE_PROGRESS_DLG) {
  4. if(mProgressDialog != null) {
  5. double frequency = mTunedStation.getFrequency() / 1000.0;
  6. String titleStr = getString(R.string.msg_search_title, ("" + frequency));
  7. mProgressDialog.setTitle(titleStr);
  8. }
  9. }else if (msg.what == END_PROGRESS_DLG) {
  10. <strong>mSearchProgressHandler.removeMessages(END_PROGRESS_DLG);
  11. mSearchProgressHandler.removeMessages(UPDATE_PROGRESS_DLG);
  12. mSearchProgressHandler.removeMessages(TIMEOUT_PROGRESS_DLG);
  13. removeDialog(DIALOG_PROGRESS_PROGRESS);
  14. mProgressDialog = null;</strong>
  15. }else if (msg.what == TIMEOUT_PROGRESS_DLG) {
  16. cancelSearch();
  17. }
  18. }
  19. };

在搜索中更新FMRadioUI界面的监听类FmRxEventListner.java

[java] view plain copy  print?
  1. public void startListner (final int fd, final FmRxEvCallbacks cb) {
  2. /* start a thread and listen for messages */
  3. mThread = new Thread(){
  4. public void run(){
  5. byte [] buff = new byte[STD_BUF_SIZE];
  6. Log.d(TAG, "Starting listener " + fd);
  7. while ((!Thread.currentThread().isInterrupted())) {
  8. try {
  9. int index = 0;
  10. int state = 0;
  11. Arrays.fill(buff, (byte)0x00);
  12. int freq = 0;
  13. int eventCount = <strong>FmReceiverJNI.getBufferNative (fd, buff, EVENT_LISTEN);</strong>
  14. if (eventCount >= 0)
  15. Log.d(TAG, "Received event. Count: " + eventCount);
  16. for (  index = 0; index < eventCount; index++ ) {
  17. Log.d(TAG, "Received <" +buff[index]+ ">" );
  18. switch(buff[index]){
  19. case 0:Log.d(TAG, "Got READY_EVENT");
  20. if(FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMRx_Starting) {
  21. /*Set the state as FMRxOn */
  22. FmTransceiver.setFMPowerState(FmTransceiver.FMState_Rx_Turned_On);
  23. Log.v(TAG, "RxEvtList: CURRENT-STATE : FMRxStarting ---> NEW-STATE : FMRxOn");
  24. cb.FmRxEvEnableReceiver();
  25. }
  26. else if (FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMTurning_Off) {
  27. /*Set the state as FMOff */
  28. FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off);
  29. Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff");
  30. FmTransceiver.release("/dev/radio0");
  31. cb.FmRxEvDisableReceiver();
  32. Thread.currentThread().interrupt();
  33. }
  34. break;case 1:
  35. Log.d(TAG, "Got TUNE_EVENT");
  36. <strong>freq = FmReceiverJNI.getFreqNative(fd);</strong>
  37. state = FmReceiver.getSearchState();
  38. switch(state) {
  39. case FmTransceiver.subSrchLevel_SeekInPrg :
  40. Log.v(TAG, "Current state is " + state);
  41. FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
  42. Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
  43. <strong> cb.FmRxEvSearchComplete(freq);</strong>
  44. break;
  45. default:
  46. if (freq > 0)
  47. cb.FmRxEvRadioTuneStatus(freq);
  48. else
  49. Log.e(TAG, "get frequency command failed");
  50. break;
  51. }
  52. break;
  53. case 2:Log.d(TAG, "Got SEEK_COMPLETE_EVENT");
  54. state = FmReceiver.getSearchState();
  55. switch(state) {
  56. case FmTransceiver.subSrchLevel_ScanInProg:
  57. Log.v(TAG, "Current state is " + state);
  58. FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
  59. Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
  60. cb.FmRxEvSearchComplete(FmReceiverJNI.getFreqNative(fd));
  61. break;
  62. case FmTransceiver.subSrchLevel_SrchAbort:
  63. Log.v(TAG, "Current state is SRCH_ABORTED");
  64. Log.v(TAG, "Aborting on-going search command...");
  65. FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
  66. Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
  67. cb.FmRxEvSearchComplete(FmReceiverJNI.getFreqNative(fd));
  68. break;
  69. }
  70. break;
  71. case 3:Log.d(TAG, "Got SCAN_NEXT_EVENT");
  72. cb.FmRxEvSearchInProgress();
  73. break;
  74. case 4:
  75. Log.d(TAG, "Got RAW_RDS_EVENT");
  76. cb.FmRxEvRdsGroupData();
  77. break;
  78. case 5:
  79. Log.d(TAG, "Got RT_EVENT");
  80. cb.FmRxEvRdsRtInfo();
  81. break;
  82. case 6:
  83. Log.d(TAG, "Got PS_EVENT");
  84. cb.FmRxEvRdsPsInfo();
  85. break;
  86. case 7:
  87. Log.d(TAG, "Got ERROR_EVENT");
  88. break;
  89. case 8:
  90. Log.d(TAG, "Got BELOW_TH_EVENT");
  91. cb.FmRxEvServiceAvailable (false);
  92. break;
  93. case 9:Log.d(TAG, "Got ABOVE_TH_EVENT");
  94. cb.FmRxEvServiceAvailable(true);
  95. break;
  96. case 10:
  97. Log.d(TAG, "Got STEREO_EVENT");
  98. cb.FmRxEvStereoStatus (true);
  99. break;
  100. case 11:
  101. Log.d(TAG, "Got MONO_EVENT");
  102. cb.FmRxEvStereoStatus (false);
  103. break;
  104. case 12:
  105. Log.d(TAG, "Got RDS_AVAL_EVENT");
  106. cb.FmRxEvRdsLockStatus (true);
  107. break;
  108. case 13:
  109. Log.d(TAG, "Got RDS_NOT_AVAL_EVENT");
  110. cb.FmRxEvRdsLockStatus (false);
  111. break;
  112. case 14:Log.d(TAG, "Got NEW_SRCH_LIST");
  113. state = FmReceiver.getSearchState();
  114. switch(state) {
  115. case FmTransceiver.subSrchLevel_SrchListInProg:
  116. Log.v(TAG, "FmRxEventListener: Current state is AUTO_PRESET_INPROGRESS");
  117. FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
  118. Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
  119. cb.FmRxEvSearchListComplete ();
  120. break;
  121. case FmTransceiver.subSrchLevel_SrchAbort:
  122. Log.v(TAG, "Current state is SRCH_ABORTED");
  123. Log.v(TAG, "Aborting on-going SearchList command...");
  124. FmReceiver.setSearchState(FmTransceiver.subSrchLevel_SrchComplete);
  125. Log.v(TAG, "RxEvtList: CURRENT-STATE : Search ---> NEW-STATE : FMRxOn");
  126. cb.FmRxEvSearchCancelled();
  127. break;
  128. }
  129. break;
  130. case 15:Log.d(TAG, "Got NEW_AF_LIST");
  131. cb.FmRxEvRdsAfInfo();
  132. break;
  133. case 18:
  134. Log.d(TAG, "Got RADIO_DISABLED");
  135. if (FmTransceiver.getFMPowerState() == FmTransceiver.subPwrLevel_FMTurning_Off) {
  136. /*Set the state as FMOff */
  137. FmTransceiver.setFMPowerState(FmTransceiver.FMState_Turned_Off);
  138. Log.v(TAG, "RxEvtList: CURRENT-STATE : FMTurningOff ---> NEW-STATE : FMOff");
  139. FmTransceiver.release("/dev/radio0");
  140. cb.FmRxEvDisableReceiver();
  141. Thread.currentThread().interrupt();
  142. } else {
  143. Log.d(TAG, "Unexpected RADIO_DISABLED recvd");
  144. cb.FmRxEvRadioReset();
  145. }
  146. break;
  147. case 19:FmTransceiver.setRDSGrpMask(0);
  148. break;
  149. case 20:
  150. Log.d(TAG, "got RT plus event");
  151. cb.FmRxEvRTPlus();
  152. break;
  153. case 21:
  154. Log.d(TAG, "got eRT event");
  155. cb.FmRxEvERTInfo();
  156. break;
  157. default:
  158. Log.d(TAG, "Unknown event");
  159. break;
  160. }
  161. }//end of for
  162. } catch ( Exception ex ) {
  163. Log.d( TAG,  "RunningThread InterruptedException");
  164. ex.printStackTrace();
  165. Thread.currentThread().interrupt();
  166. }
  167. }
  168. }
  169. };
  170. mThread.start();
  171. }

Switch case取1的时候就FMReceiverJNI类中获取频率,调FmRxEvRadioTuneStatus接收读取频率

freq= FmReceiverJNI.getFreqNative(fd);

cb.FmRxEvRadioTuneStatus(freq);

将频率保存起来

FmSharedPreferences.setTunedFrequency(frequency);

mPrefs.Save();

清除状态信息 clearStationInfo();

调用改变界面状态 mCallbacks.onTuneStatusChanged();

可用存储,设置可用模拟器 enableStereo(FmSharedPreferences.getAudioOutputMode());

[java] view plain copy  print?
  1. public void <strong>FmRxEvRadioTuneStatus</strong>(int frequency)
  2. {
  3. Log.d(LOGTAG, "FmRxEvRadioTuneStatus: Tuned Frequency: " +frequency);
  4. try
  5. {
  6. <strong>FmSharedPreferences.setTunedFrequency(frequency);
  7. mPrefs.Save();</strong>
  8. //Log.d(LOGTAG, "Call mCallbacks.onTuneStatusChanged");
  9. /* Since the Tuned Status changed, clear out the RDSData cached */
  10. if(mReceiver != null) {
  11. <strong> clearStationInfo();</strong>
  12. }
  13. if(mCallbacks != null)
  14. {
  15. <strong> mCallbacks.onTuneStatusChanged();</strong>
  16. }
  17. /* Update the frequency in the StatusBar's Notification */
  18. startNotification();
  19. enableStereo(FmSharedPreferences.getAudioOutputMode());
  20. }
  21. catch (RemoteException e)
  22. {
  23. e.printStackTrace();
  24. }
  25. }

最后调到底层

FmReceiverJNI.setMonoStereoNative (fd, 1)

[java] view plain copy  print?
  1. /* force mono/stereo mode */
  2. public int stereoControl(int fd, boolean stereo) {
  3. if (stereo){
  4. return  FmReceiverJNI.setMonoStereoNative (fd, 1);
  5. }
  6. else {
  7. return  FmReceiverJNI.setMonoStereoNative (fd, 0);
  8. }
  9. }

通过mCallbacks.onTuneStatusChanged();调用到FMRadio.java的内部存根类IFMRadioServiceCallbacks.stub类的public void onTuneStatusChanged()方法进行存入fm频率,数据最后调用FMRadio的resetFMStationInfoUI()刷新UI

[java] view plain copy  print?
  1. public void <strong>onTuneStatusChanged() </strong> {
  2. Log.d(LOGTAG, "mServiceCallbacks.onTuneStatusChanged: ");
  3. if (mIsScaning) {
  4. Log.d(LOGTAG, "isScanning....................");
  5. SharedPreferences sp = getSharedPreferences(SCAN_STATION_PREFS_NAME, 0);
  6. SharedPreferences.Editor editor = sp.edit();
  7. int station_number = sp.getInt(NUM_OF_STATIONS, 0);
  8. station_number++;
  9. editor.putInt(NUM_OF_STATIONS, station_number);
  10. editor.putString(STATION_NAME + station_number, station_number + "");
  11. editor.putInt(STATION_FREQUENCY + station_number,
  12. FmSharedPreferences.getTunedFrequency());
  13. editor.commit();
  14. }
  15. <strong>cleanupTimeoutHandler();
  16. mHandler.post(mUpdateStationInfo);
  17. mHandler.post(mOnStereo);</strong>
  18. }

发送一handler跟新UI,调用此回调方法Runnable mUpdateStationInfo = new Runnable()

[java] view plain copy  print?
  1. Runnable mUpdateStationInfo = new Runnable() {
  2. public void run() {
  3. cleanupTimeoutHandler();
  4. PresetStation station = new PresetStation("", FmSharedPreferences.getTunedFrequency());
  5. if (station != null) {
  6. mTunedStation.Copy(station);
  7. }
  8. <strong>updateSearchProgress();
  9. resetFMStationInfoUI();</strong>
  10. }
  11. };

updateStationInfoToUI();

[java] view plain copy  print?
  1. private void <strong>updateStationInfoToUI()</strong> {
  2. double frequency = mTunedStation.getFrequency() / 1000.0;
  3. mTuneStationFrequencyTV.setText("" + frequency + "MHz");
  4. if ((mPicker != null) && mUpdatePickerValue) {
  5. mPicker.setValue(((mTunedStation.getFrequency() - mPrefs.getLowerLimit())
  6. / mPrefs.getFrequencyStepSize()));
  7. }
  8. mStationCallSignTV.setText(mTunedStation.getPIString());
  9. mProgramTypeTV.setText(mTunedStation.getPtyString());
  10. mRadioTextTV.setText("");
  11. mERadioTextTV.setText("");
  12. mRadioTextScroller.mOriginalString = "";
  13. mRadioTextScroller.mStringlength = 0;
  14. mRadioTextScroller.mIteration = 0;
  15. mERadioTextScroller.mOriginalString = "";
  16. mERadioTextScroller.mStringlength = 0;
  17. mERadioTextScroller.mIteration = 0;
  18. mProgramServiceTV.setText("");
  19. mStereoTV.setText("");
  20. setupPresetLayout();
  21. }

FM启动和关闭搜索都是通过JNI调到底层实现,代码路径是:vendor\qcom\opensource\fm\jni

android_hardware_fm.cpp

[java] view plain copy  print?
  1. /*
  2. * JNI registration.
  3. */
  4. static JNINativeMethod gMethods[] = {
  5. /* name, signature, funcPtr */
  6. { "acquireFdNative", "(Ljava/lang/String;)I",
  7. (void*)android_hardware_fmradio_FmReceiverJNI_acquireFdNative},
  8. { "closeFdNative", "(I)I",
  9. (void*)android_hardware_fmradio_FmReceiverJNI_closeFdNative},
  10. { "getFreqNative", "(I)I",
  11. (void*)android_hardware_fmradio_FmReceiverJNI_getFreqNative},
  12. { "setFreqNative", "(II)I",
  13. (void*)android_hardware_fmradio_FmReceiverJNI_setFreqNative},
  14. { "getControlNative", "(II)I",
  15. (void*)android_hardware_fmradio_FmReceiverJNI_getControlNative},
  16. { "setControlNative", "(III)I",
  17. (void*)android_hardware_fmradio_FmReceiverJNI_setControlNative},
  18. { "startSearchNative", "(II)I",
  19. (void*)android_hardware_fmradio_FmReceiverJNI_startSearchNative},
  20. { "cancelSearchNative", "(I)I",
  21. (void*)android_hardware_fmradio_FmReceiverJNI_cancelSearchNative}, { "getRSSINative", "(I)I",
  22. (void*)android_hardware_fmradio_FmReceiverJNI_getRSSINative},
  23. { "setBandNative", "(III)I",
  24. (void*)android_hardware_fmradio_FmReceiverJNI_setBandNative},
  25. { "getLowerBandNative", "(I)I",
  26. (void*)android_hardware_fmradio_FmReceiverJNI_getLowerBandNative},
  27. { "getUpperBandNative", "(I)I",
  28. (void*)android_hardware_fmradio_FmReceiverJNI_getUpperBandNative},
  29. { "getBufferNative", "(I[BI)I",
  30. (void*)android_hardware_fmradio_FmReceiverJNI_getBufferNative},
  31. { "setMonoStereoNative", "(II)I",
  32. (void*)android_hardware_fmradio_FmReceiverJNI_setMonoStereoNative},
  33. { "getRawRdsNative", "(I[BI)I",
  34. (void*)android_hardware_fmradio_FmReceiverJNI_getRawRdsNative},
  35. { "setNotchFilterNative", "(IIZ)I",
  36. (void*)android_hardware_fmradio_FmReceiverJNI_setNotchFilterNative},
  37. { "startRTNative", "(ILjava/lang/String;I)I",
  38. (void*)android_hardware_fmradio_FmReceiverJNI_startRTNative},
  39. { "stopRTNative", "(I)I",
  40. (void*)android_hardware_fmradio_FmReceiverJNI_stopRTNative},
  41. { "startPSNative", "(ILjava/lang/String;I)I",
  42. (void*)android_hardware_fmradio_FmReceiverJNI_startPSNative},  { "stopPSNative", "(I)I",
  43. (void*)android_hardware_fmradio_FmReceiverJNI_stopPSNative},
  44. { "setPTYNative", "(II)I",
  45. (void*)android_hardware_fmradio_FmReceiverJNI_setPTYNative},
  46. { "setPINative", "(II)I",
  47. (void*)android_hardware_fmradio_FmReceiverJNI_setPINative},
  48. { "setPSRepeatCountNative", "(II)I",
  49. (void*)android_hardware_fmradio_FmReceiverJNI_setPSRepeatCountNative},
  50. { "setTxPowerLevelNative", "(II)I",
  51. (void*)android_hardware_fmradio_FmReceiverJNI_setTxPowerLevelNative},
  52. { "setAnalogModeNative", "(Z)I",
  53. (void*)android_hardware_fmradio_FmReceiverJNI_setAnalogModeNative},
  54. { "SetCalibrationNative", "(I)I",
  55. (void*)android_hardware_fmradio_FmReceiverJNI_SetCalibrationNative},
  56. { "configureSpurTable", "(I)I",
  57. (void*)android_hardware_fmradio_FmReceiverJNI_configureSpurTable},
  58. };

上面写明了从jni的调用关系。具体的函数实现,请到Android_hardware_fm.cpp中去查看

android FM搜索频率流程相关推荐

  1. Android FM模块学习之二 FM搜索频率流程

    上一篇大概分析了一下FM启动流程,若不了解Fm启动流程的,可以去打开前面的链接先了解FM启动流程,接下来我们简单分析一下FM的搜索频率流程. 在了解源码之前,我们先看一下流程图: 其实从图中可以看到, ...

  2. Android FM模块学习之一 FM启动流程

    转自:http://blog.csdn.net/tfslovexizi/article/details/41283743 最近在学习FM模块,FM是一个值得学习的模块,可以从上层看到底层.上层就是FM ...

  3. android fm模块学习,AndroidFM模块学习之5关闭FM流程

    AndroidFM模块学习之五关闭FM流程 前一阵子简单描述了一些关于FM开启.录音和搜索的流程,浅析了一下各个类的源码,接下来就是关闭FM了,FM模块的学习就告一段落了,希望这阵子的整理能对大家在F ...

  4. Android FM 外部短天线支持(ez fm)

    Android FM 外部播放功能(EZ FM),使用外部短天线搜台,默认FM是不支持外部功放播放功能的,因为硬件上需要FM天线低噪放大器的支持. 硬件原理 原理图: 默认使用耳机当做天线. 如果硬件 ...

  5. 搜索推荐系统根据用户搜索频率(热搜)排序

    之前写的三叉树,有点儿简单,并不能满足实际项目的需要.先简单分析一下solr中搜索推荐系统的核心算法. wiki中有关于solr的搜索推荐的详细描述,但是核心算法需要自己查看源代码.关于wiki上的解 ...

  6. Android之wifi工作流程

    Android Wifi的工作流程 一.WIFI工作相关部分 Wifi 网卡状态 1.    WIFI_STATE_DISABLED:WIFI网卡不可用 2.    WIFI_STATE_DISABL ...

  7. Android系统 lk启动流程简析

    本篇文章是对初步学习Android系统lk启动流程的一个大致简介.方便掌握lk启动流程的大致框架,具体细节后续再进行更新 1. 前言 需要了解的文件类型: 1)编译LK的链接文件(.ld) 2)汇编文 ...

  8. android T9 搜索联系人分析与实现(支持多音字)

    最近在android项目开发过程中需要实现类似电话拨号功能,这里涉及到T9键盘搜索联系人,于是研究了一番,将思路和心得记录于此,方便自己与他人. 相信大家对T9输入法并不陌生,这里并不涉及到T9输入法 ...

  9. android 通话的log分析,Android Telephony 接电话流程分析

    写在前面的话 本文主要分析Android 接电话的流程,研究的代码是Android 4.4的,现在我们只关注framework层,以CDMA为例,GSM同理. 如果图片看不清的话,可以右键选择在新标签 ...

最新文章

  1. matlab 表格控件,[转载]matlab读取excel数据并显示在excel(activex控件)中
  2. 1038. Recover the Smallest Number (30)
  3. c++清空一个txt文本_Linux下常用文本处理命令大全
  4. Triangle Counting【数学】
  5. JSON和JSONP的差别,以及用法
  6. 2018年计算机二级知识点,2018年计算机二级考试公共基础知识点:栈及其基本运算...
  7. altium designer快捷键大全
  8. 一文了解预训练语言模型!
  9. 计算机无法播放所有视频文件,在电脑中打开flv视频文件显示空白无法播放怎么办...
  10. Customer-exit总结
  11. java中的分号是什么作用,分号的作用是什么
  12. 在Ubuntu20.04上安装ros
  13. 如何使用MATLAB coder将MATLAB代码转换成C/C++语言(详细图文教程)
  14. FinalShell下载安装教程
  15. 拥有70多个名字的南京,改城市名就像改微信名一样
  16. c++ primer kindle_kindle全系列使用墨水屏版微信读书解决方法,你的无限卡有用了...
  17. php输出所有错误信息
  18. 714. [C++]买卖股票的最佳时机含手续费
  19. P1-2017级第一次算法上机 F SkyLee的艾露猫
  20. 如何用有道云笔记写含数学公式的专业文章

热门文章

  1. 计算机有游戏吗,这些容量最大的游戏,你的电脑上都有吗?
  2. Speedup:专为项目下Library project过多所设计的加速插件
  3. Multicoin Capital与Genesis互动积极
  4. 深入浅出TDD测试驱动
  5. 联合循环——18(开式水和闭式水系统)
  6. 智慧工厂人员定位系统
  7. 企业在什么情况下需要ERP系统?
  8. c语言 压缩txt文件的函数,c语言 文本文件压缩
  9. 光学镜片之焦度计测量算法
  10. 【愚公系列】华为云云数据库MySQL的体验流程|【华为云至简致远】