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

转自:http://blog.csdn.net/tfslovexizi/article/details/41315483

上一篇大概分析了一下FM启动流程,若不了解Fm启动流程的,可以去打开前面的链接先了解FM启动流程,接下来我们简单分析一下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()

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

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

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

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

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

设置FM搜索电源状态

  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电源状态

  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

  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.   
  6.   
  7.       Log.d(TAG, "Mode is " + mode + " Dwell is " + dwell);  
  8.       Log.d(TAG, "dir is "  + dir + " PTY is " + pty);  
  9.       Log.d(TAG, "pi is " + pi + " id " +  V4L2_CID_PRIVATE_TAVARUA_SRCHMODE);  
  10.   
  11.   
  12.   
  13.      <strong> re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCHMODE, mode);</strong>  
  14.       if (re != 0) {  
  15.           Log.e(TAG, "setting of search mode failed");  
  16.           return re;  
  17.       }  
  18.       <strong>re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SCANDWELL, dwell);</strong>  
  19.       if (re != 0) {  
  20.           Log.e(TAG, "setting of scan dwell time failed");  
  21.           return re;  
  22.       }  
  23.       if (pty != 0)  
  24.       {  re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY, pty);  
  25.          if (re != 0) {  
  26.              Log.e(TAG, "setting of PTY failed");  
  27.              return re;  
  28.          }  
  29.       }  
  30.   
  31.       if (pi != 0)  
  32.       {  
  33.         <strong> re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PI, pi);</strong>  
  34.          if (re != 0) {  
  35.              Log.e(TAG, "setting of PI failed");  
  36.              return re;  
  37.          }  
  38.       }  
  39.   
  40.       <strong>re = FmReceiverJNI.startSearchNative (fd, dir );</strong>  
  41.       return re;  
  42.    }  

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

关闭搜索

FMRadio 调用 FMRadioService 的CancelSearch()方法

public boolean cancelSearch()

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

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

  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发送消息关闭对话框

  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

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

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

freq= FmReceiverJNI.getFreqNative(fd);

 cb.FmRxEvRadioTuneStatus(freq);

将频率保存起来

FmSharedPreferences.setTunedFrequency(frequency);

           mPrefs.Save();

清除状态信息 clearStationInfo();

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

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

  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)

  1. /* force mono/stereo mode */  
  2.    public int stereoControl(int fd, boolean stereo) {  
  3.   
  4.      if (stereo){  
  5.        return  FmReceiverJNI.setMonoStereoNative (fd, 1);  
  6.      }  
  7.      else {  
  8.        return  FmReceiverJNI.setMonoStereoNative (fd, 0);  
  9.      }  
  10.   
  11.    }  

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

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

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

  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调到底层实现,代码路径是:vendorqcomopensourcefmjni

android_hardware_fm.cpp 

  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.   
  59. };  

上面写明了从jni的调用关系。具体的函数实现,请到Android_hardware_fm.cpp中去查看。我就不一一写出来了。以上就是FM搜索频率与取消搜索频率的操作与实现。搜索到频率后就可以听FM了。

原文地址:https://www.cnblogs.com/mochaMM/p/5151838.html