zoukankan      html  css  js  c++  java
  • Android FM模块学习之二 FM搜索频率流程

        上一篇大概分析了一下FM启动流程,若不了解Fm启动流程的,能够去打开前面的链接先了解FM启动流程,接下来我们简单分析一下FM的搜索频率流程。

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

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

       搜索流程简单分析:点击搜索button,通过互调方法,最后调到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()

    private Dialog <strong>createProgressDialog</strong>(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()) {<span style="font-family:KaiTi_GB2312;">//标准耳机</span>
                    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
    ");
                 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) {
                          <strong>cancelSearch();</strong>
                      }
                  });
                  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<strong> scan(int pty)</strong>
       {
          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 = <strong>mReceiver.searchStations</strong>(FmReceiver.FM_RX_SRCHRDS_MODE_SCAN_PTY,
                                                           FmReceiver.FM_RX_DWELL_PERIOD_2S,
                                                           FmReceiver.FM_RX_SEARCHDIR_UP,
                                                           pty,
                                                           0);
                }
                else
                {
                   bCommandSent = <strong>mReceiver.searchStations</strong>(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 = <strong>mReceiver.searchStations</strong>(FmReceiver.FM_RX_SRCHRDS_MODE_SCAN_PTY,
                                                              FmReceiver.FM_RX_DWELL_PERIOD_2S,
                                                              FmReceiver.FM_RX_SEARCHDIR_UP,
                                                              pty,
                                                              0);
                }
                else{
                   bCommandSent =<strong> mReceiver.searchStations</strong>(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 <strong>searchStations </strong>(int mode,
                                      int dwellPeriod,
                                      int direction){
    
         <strong> int state = getFMState();</strong>//<span style="font-family:KaiTi_GB2312;font-size:18px;">获得FMState状态</span>
          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");
    
            <strong> re = mControl.searchStations(sFd, mode, dwellPeriod, direction, 0, 0);</strong>
             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 <strong>setSearchState</strong>(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 <strong>setFMPowerState(</strong>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 <strong>searchStations </strong>(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);
    
    
    
         <strong> re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCHMODE, mode);</strong>
          if (re != 0) {
              Log.e(TAG, "setting of search mode failed");
              return re;
          }
          <strong>re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SCANDWELL, dwell);</strong>
          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)
          {
            <strong> re = FmReceiverJNI.setControlNative (fd, V4L2_CID_PRIVATE_TAVARUA_SRCH_PI, pi);</strong>
             if (re != 0) {
                 Log.e(TAG, "setting of PI failed");
                 return re;
             }
          }
    
          <strong>re = FmReceiverJNI.startSearchNative (fd, dir );</strong>
          return re;
       }
    

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

    关闭搜索

    FMRadio 调用 FMRadioService 的CancelSearch()方法

    public boolean cancelSearch()

    public boolean <strong>cancelSearch()</strong>
       {
          boolean bCommandSent=false;
          if (mReceiver != null)
          {
             Log.d(LOGTAG, "cancelSearch");
             bCommandSent = <strong>mReceiver.cancelSearch();</strong>
          }
          return bCommandSent;
       }
    
    调用FRReceiver的cancelSearch()

    mReceiver.cancelSearch()

    更新搜索 FMRadio.java中

    updateSearchProgress();

    private void <strong>updateSearchProgress()</strong> {
          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){
         <strong> FmReceiverJNI.cancelSearchNative(fd);</strong>
       }
    最后发送一个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) {
                  <strong>mSearchProgressHandler.removeMessages(END_PROGRESS_DLG);
                  mSearchProgressHandler.removeMessages(UPDATE_PROGRESS_DLG);
                  mSearchProgressHandler.removeMessages(TIMEOUT_PROGRESS_DLG);
                  removeDialog(DIALOG_PROGRESS_PROGRESS);
                  mProgressDialog = null;</strong>
               }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 = <strong>FmReceiverJNI.getBufferNative (fd, buff, EVENT_LISTEN);</strong>
    
                            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");
                                    <strong>freq = FmReceiverJNI.getFreqNative(fd);</strong>
                                    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");
                                           <strong> cb.FmRxEvSearchComplete(freq);</strong>
                                            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 <strong>FmRxEvRadioTuneStatus</strong>(int frequency)
          {
             Log.d(LOGTAG, "FmRxEvRadioTuneStatus: Tuned Frequency: " +frequency);
             try
             {
                <strong>FmSharedPreferences.setTunedFrequency(frequency);
                mPrefs.Save();</strong>
                //Log.d(LOGTAG, "Call mCallbacks.onTuneStatusChanged");
                /* Since the Tuned Status changed, clear out the RDSData cached */
                if(mReceiver != null) {
                  <strong> clearStationInfo();</strong>
                }
                if(mCallbacks != null)
                {
                  <strong> mCallbacks.onTuneStatusChanged();</strong>
                }
                /* 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 <strong>onTuneStatusChanged() </strong> {
             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();
             }
             <strong>cleanupTimeoutHandler();
             mHandler.post(mUpdateStationInfo);
             mHandler.post(mOnStereo);</strong>
          }
    

    发送一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);
             }
             <strong>updateSearchProgress();
             resetFMStationInfoUI();</strong>
          }
       };

    updateStationInfoToUI()。

    private void <strong>updateStationInfoToUI()</strong> {
          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调究竟层实现,代码路径是:vendorqcomopensourcefmjni

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








  • 相关阅读:
    Problem C: 时间类的常量
    Problem B: 时间类的错误数据处理
    Problem A: 时间类的拷贝和整体读写
    Problem B: 平面上的点——Point类 (IV)
    Problem C: 平面上的点——Point类 (V)
    Problem A: 平面上的点——Point类 (III)
    中间的数(若已经排好序)
    软件工程概论团队结组
    软件工程个人作业04 子数组循环数组
    软件工程个人作业03
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5316839.html
Copyright © 2011-2022 走看看