Android FM模塊學習之二 FM搜索頻率流程

上一篇大概分析了一下FM啓動流程,若不瞭解Fm啓動流程的,能夠去打開前面的連接先了解FM啓動流程,接下來咱們簡單分析一下FM的搜索頻率流程。java

在瞭解源碼以前,咱們先看一下流程圖:android

    其實從圖中能夠看到,實現搜索頻率的功能是在底層CPP文件,java層只操做和更新一些界面(GUI),Java調用JNI實現功能。Java app基本核心,經過方法回調實現a類和b類方法,b類調a類方法信息交互相互控制融爲一體。App實現一些JNI接口最終實現核心功能是cpp文件,最後經過Service類(耗時操做)調用New一個線程循環不斷的獲取cpp裏的信息,去更新UI界面活動狀態。app

   搜索流程簡單分析:點擊搜索按鈕,經過互調方法,最後調到FMReceiverJNI類中的方法實現功能。經過FMRxEventListner類不斷獲取cpp變頻的頻率,每獲取一次頻率(直到頻率搜索完成中止調用)就回調FMRadioService內部FmRxEvCallbacksAdaptor的方法在回調到FMRadio類中方法,將頻率存入FmSharedPreferences類xml文檔中,發送Handler更新UI,即刻度盤,對話框,左右箭頭中間顯示的頻率一致跳動。ide

   接下來詳細代碼分析:函數

    FMRadio中的菜單搜索功能,onOptionsItemSelected(MenuItem item)監聽中走initiateSearch(mScanPtyIndex);方法。post


調用FMRadioService的scan()方法(mService.scan(pty))進行掃描頻率ui


updateSearchProgress()里加了同步方法對象鎖this

調用了private Dialog createProgressDialog(int id)對話框進行搜索信息線程

標準耳機FmSharedPreferences.isRBDSStd()xml

    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
       *
       *    <p>
       *    This method sets the FM power state.
       *
       *    <p>
       */
       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);
          }
       }


初始化菜單  invalidateOptionsMenu();

調用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);
         }
     
       }


 經過mCallbacks.onTuneStatusChanged();調用到FMRadio.java的內部存根類IFMRadioServiceCallbacks.stub類的public void onTuneStatusChanged()方法進行存入fm頻率,數據最後調用FMRadio的resetFMStationInfoUI()刷新UI

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


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

     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了。  

相關文章
相關標籤/搜索