編輯:關於Android編程
上一篇大概分析了一下FM啟動流程,若不了解Fm啟動流程的,可以去打開前面的鏈接先了解FM啟動流程,接下來我們簡單分析一下FM的搜索頻率流程。
在了解源碼之前,我們先看一下流程圖:

其實從圖中可以看到,實現搜索頻率的功能是在底層CPP文件,java層只操作和更新一些界面(GUI),Java調用JNI實現功能。Java app基本核心,通過方法回調實現a類和b類方法,b類調a類方法信息交互相互控制融為一體。App實現一些JNI接口最終實現核心功能是cpp文件,最後通過Service類(耗時操作)調用New一個線程循環不斷的獲取cpp裡的信息,去更新UI界面活動狀態。
搜索流程簡單分析<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPqO6teO798vRy/ewtMWlo6zNqLn9u6W197e9t6ijrNfuuvO197W9Rk1SZWNlaXZlckpOScDg1tC1xLe9t6jKtc/WuabE3KGjzai5/UZNUnhFdmVudExpc3RuZXLA4LK7ts+78cihY3BwseTGtbXExrXCyqOsw7+78cih0ru0zsa1wsoo1rG1vca1wsrL0cv3zeqzyc2j1rm199PDKb7Nu9i190ZNUmFkaW9TZXJ2aWNlxNqyv0ZtUnhFdkNhbGxiYWNrc0FkYXB0b3K1xLe9t6jU2rvYtfe1vUZNUmFkaW/A4NbQt723qKOsvavGtcLKtObI60ZtU2hhcmVkUHJlZmVyZW5jZXPA4HhtbM7EtbXW0KOst6LLzUhhbmRsZXK4/NDCVUmjrLy0v8y2yMXMo6y21Luwv/KjrNfz09K8/c231tC85M/Uyr61xMa1wsrSu9bCzPi2r6GjPC9wPgo8cD4gICC908/CwLTP6s+4tPrC67fWzvajujxicj4KPC9wPgo8cD4gICAgRk1SYWRpb9bQtcSyy7Wly9HL97mmxNyjrG9uT3B0aW9uc0l0ZW1TZWxlY3RlZChNZW51SXRlbSBpdGVtKbzgzP3W0NffaW5pdGlhdGVTZWFyY2gobVNjYW5QdHlJbmRleCk7t723qKGjPC9wPgo8cD48aW1nIHNyYz0="/uploadfile/Collfiles/20141121/2014112108585517.jpg" alt="\">


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

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

調用了private Dialog createProgressDialog(int id)對話框進行搜索信息
標准耳機FmSharedPreferences.isRBDSStd()
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 * ** This method sets the FM power state. * *
*/ 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);
}
}
調用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);
}
}
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);
}
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了。
miui8怎麼升級 小米MIUI 8系統更新升級教程
你的小米手機准備好迎接MIUI8的到來了嗎?今天小編搶先帶來小米MIUI 8系統更新升級教程,想要升級miui8系統的米粉們快來看看吧!MIUI8升級須知:
Android懸浮對話框(即點即關對話框)實現代碼
Activity是Android系統的4個應用程序組件之一。通過傳統方法顯示的Activity都是充滿整個屏幕,也就是全屏的Activity。事實上,Activity不僅
Android提高之藍牙傳感應用實例
前面文章介紹了Android利用麥克風采集並顯示模擬信號的實現方法,這種采集手段適用於無IO控制、單純讀取信號的情況。如果傳感器本身需要包含控制電路(例如采集血氧信號需要
Android Build.VERSION.SDK_INT兼容介紹
盡管Android向下兼容不好,但是一個程序還是可以在多個平台上跑的。向下兼容不好,接口改變,新的平台上不能用舊的API,舊的平台更不可能用新的API,不等於一個平台需要