您的位置:首页 > 移动开发 > Android开发

android FM搜索频率流程

2016-02-19 13:21 288 查看
简单分析一下FM的搜索频率流程。

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



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

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

接下来详细代码分析:

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







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



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



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

标准耳机FmSharedPreferences.isRBDSStd()

[java] view
plain copy

print?





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\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) {

<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()方法进行扫描

[java] view
plain copy

print?





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

[java] view
plain copy

print?





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

[java] view
plain copy

print?





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

[java] view
plain copy

print?





/*==============================================================

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

[java] view
plain copy

print?





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

[java] view
plain copy

print?





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

[java] view
plain copy

print?





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

[java] view
plain copy

print?





/* cancel search in progress */

public void cancelSearch (int fd){

<strong> FmReceiverJNI.cancelSearchNative(fd);</strong>

}

最后发送一个mSearchProgressHandler

msg.what = END_PROGRESS_DLG;

mSearchProgressHandler.sendMessage(msg)

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

[java] view
plain copy

print?





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

[java] view
plain copy

print?





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

[java] view
plain copy

print?





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)

[java] view
plain copy

print?





/* 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

[java] view
plain copy

print?





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

[java] view
plain copy

print?





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

[java] view
plain copy

print?





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调到底层实现,代码路径是:vendor\qcom\opensource\fm\jni

android_hardware_fm.cpp

[java] view
plain copy

print?





/*

* 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中去查看
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: