当前位置:   article > 正文

收音机(FM2)增加自己主动唤醒功能

com.caf.fmradio
高通原有代码里面就有收音机的睡眠功能。就是你能够进入收音机中设置睡眠时间类似“天天动听”等应用,到时间了就自己主动的退出该应用。
客户看到有这个功能就想要有一个自己主动唤醒的功能咯。客户总是希望相同的价格你能给我做到很多其它的功能更划算咯。
1、改动文件:
/FMRadio/src/com/caf/fmradio/FMRadio.java
/FMRadio/src/com/caf/fmradio/FMMediaButtonIntentReceiver.java
/FMRadio/AndroidManifest.xml
/FMRadio/res/values/arrays.xml
/FMRadio/res/values/strings.xml

2、FMRadio.java文件的改动相对来说多些。


用//20150326 added by  lisineng for wakeup FM做了标注

  1. </pre><pre name="code" class="java">
  2. package com.caf.fmradio;
  3. import android.app.Activity;
  4. import android.app.AlertDialog;
  5. import android.app.Dialog;
  6. //20150326 added by lisineng for wakeup FM
  7. import android.app.AlarmManager;
  8. import android.app.PendingIntent;
  9. //added end
  10. import android.app.ProgressDialog;
  11. import android.bluetooth.BluetoothA2dp;
  12. import android.bluetooth.BluetoothDevice;
  13. import android.content.ComponentName;
  14. import android.content.Context;
  15. import android.content.DialogInterface;
  16. import android.content.DialogInterface.OnKeyListener;
  17. import android.content.Intent;
  18. import android.content.IntentFilter;
  19. import android.content.BroadcastReceiver;
  20. import android.media.AudioSystem;
  21. import android.media.AudioManager;
  22. import android.media.MediaRecorder;
  23. import android.os.Bundle;
  24. import android.os.Environment;
  25. import android.os.Handler;
  26. import android.os.IBinder;
  27. import android.os.Message;
  28. import android.os.RemoteException;
  29. import android.os.SystemClock;
  30. import android.os.SystemProperties;
  31. import android.util.DisplayMetrics;
  32. import android.util.Log;
  33. import android.view.LayoutInflater;
  34. import android.view.Menu;
  35. import android.view.MenuItem;
  36. import android.view.View;
  37. import android.view.Window;
  38. import android.view.KeyEvent;
  39. import android.view.animation.Animation;
  40. import android.view.animation.AnimationUtils;
  41. import android.widget.ArrayAdapter;
  42. import android.widget.Button;
  43. import android.widget.EditText;
  44. import android.widget.ImageButton;
  45. import android.widget.ImageView;
  46. import android.widget.ListView;
  47. import android.widget.TextView;
  48. import android.widget.Toast;
  49. import android.text.TextUtils;
  50. import java.util.*;
  51. import java.io.File;
  52. import java.io.IOException;
  53. import java.lang.ref.WeakReference;
  54. import java.util.Formatter;
  55. import java.util.HashMap;
  56. import java.util.List;
  57. import java.util.ListIterator;
  58. import java.util.Locale;
  59. import java.util.ArrayList;
  60. import com.caf.utils.FrequencyPicker;
  61. import com.caf.utils.FrequencyPickerDialog;
  62. import android.content.ServiceConnection;
  63. import android.media.MediaRecorder;
  64. import qcom.fmradio.FmConfig;
  65. import android.os.ServiceManager;
  66. import com.caf.fmradio.HorizontalNumberPicker.OnScrollFinishListener;
  67. import com.caf.fmradio.HorizontalNumberPicker.OnValueChangeListener;
  68. import com.caf.fmradio.HorizontalNumberPicker.Scale;
  69. import android.content.SharedPreferences;
  70. import android.graphics.Color;
  71. public class FMRadio extends Activity
  72. {
  73. public static final String LOGTAG = "FMRadio";
  74. public static final boolean RECORDING_ENABLE = true;
  75. MediaRecorder mRecorder = null;
  76. /* menu Identifiers */
  77. private static final int MENU_SCAN_START = Menu.FIRST + 2;
  78. private static final int MENU_SCAN_STOP = Menu.FIRST + 3;
  79. private static final int MENU_RECORD_START = Menu.FIRST + 4;
  80. private static final int MENU_RECORD_STOP = Menu.FIRST + 5;
  81. private static final int MENU_SLEEP = Menu.FIRST + 6;
  82. private static final int MENU_SLEEP_CANCEL = Menu.FIRST + 7;
  83. private static final int MENU_SETTINGS = Menu.FIRST + 8;
  84. private static final int MENU_SPEAKER = Menu.FIRST + 9;
  85. private static final int MENU_TAGS = Menu.FIRST + 10;
  86. private static final int MENU_STAT_TEST = Menu.FIRST + 11;
  87. private static final int MENU_STATION_LIST = Menu.FIRST + 12;
  88. //20150326 added by lisineng for wakeup FM
  89. private static final int MENU_WAKEUP = Menu.FIRST + 13;
  90. private static final int MENU_WAKEUP_CANCEL = Menu.FIRST + 14;
  91. public final String ALARM_FM = "android.intent.action_WAKE_UP";
  92. boolean hasWakeup = false;
  93. //added end
  94. /* Dialog Identifiers */
  95. private static final int DIALOG_SEARCH = 1;
  96. private static final int DIALOG_SLEEP = 2;
  97. private static final int DIALOG_SELECT_PRESET_LIST = 3;
  98. private static final int DIALOG_PRESETS_LIST = 4;
  99. private static final int DIALOG_PRESET_LIST_RENAME = 5;
  100. private static final int DIALOG_PRESET_LIST_DELETE = 6;
  101. private static final int DIALOG_PRESET_LIST_AUTO_SET = 7;
  102. private static final int DIALOG_PICK_FREQUENCY = 8;
  103. private static final int DIALOG_PROGRESS_PROGRESS = 9;
  104. private static final int DIALOG_PRESET_OPTIONS = 10;
  105. private static final int DIALOG_PRESET_RENAME = 11;
  106. private static final int DIALOG_CMD_TIMEOUT = 12;
  107. private static final int DIALOG_CMD_FAILED = 13;
  108. private static final int DIALOG_CMD_FAILED_HDMI_ON = 14;
  109. private static final int DIALOG_CMD_FAILED_CALL_ON = 15;
  110. private static final int DIALOG_TAGS = 16;
  111. private static final int DIALOG_WAKEUP = 17; //20150326 added by lisineng for wakeup FM
  112. /* Activity Return ResultIdentifiers */
  113. private static final int ACTIVITY_RESULT_SETTINGS = 1;
  114. /* Activity Return ResultIdentifiers */
  115. private static final int MAX_PRESETS_PER_PAGE = 7;
  116. /* Station's Audio is Stereo */
  117. private static final int FMRADIO_UI_STATION_AUDIO_STEREO = 1;
  118. /* Station's Audio is Mono */
  119. private static final int FMRADIO_UI_STATION_AUDIO_MONO = 2;
  120. /* The duration during which the "Sleep: xx:xx" string will be toggling
  121. */
  122. private static final int SLEEP_TOGGLE_SECONDS = 60;
  123. /* The number of Preset Stations to create.
  124. * The hardware supports a maximum of 12.
  125. */
  126. private static final int NUM_AUTO_PRESETS_SEARCH= 12;
  127. /*
  128. * Command time out: For asynchonous operations, if no response
  129. * is received with int this duration, a timeout msg will be displayed.
  130. */
  131. private static final int CMD_TIMEOUT_DELAY_MS = 5000;
  132. private static final int MSG_CMD_TIMEOUT = 101;
  133. private static final int CMD_NONE = 0;
  134. private static final int CMD_TUNE = 1;
  135. private static final int CMD_FMON = 2;
  136. private static final int CMD_FMOFF = 3;
  137. private static final int CMD_FMCONFIGURE = 4;
  138. private static final int CMD_MUTE = 5;
  139. private static final int CMD_SEEK = 6;
  140. private static final int CMD_SCAN = 7;
  141. private static final int CMD_SEEKPI = 8;
  142. private static final int CMD_SEARCHLIST = 9;
  143. private static final int CMD_CANCELSEARCH = 10;
  144. private static final int CMD_SET_POWER_MODE = 11;
  145. private static final int CMD_SET_AUDIO_MODE = 12;
  146. private static final int CMD_SET_AUTOAF = 13;
  147. private static final int CMD_GET_INTERNALANTENNA_MODE = 14;
  148. private static final int PRESETS_OPTIONS_TUNE = 0;
  149. private static final int PRESETS_OPTIONS_REPLACE = 1;
  150. private static final int PRESETS_OPTIONS_RENAME = 2;
  151. private static final int PRESETS_OPTIONS_DELETE = 3;
  152. private static final int PRESETS_OPTIONS_SEARCHPI = 4;
  153. public static final String SCAN_STATION_PREFS_NAME = "scan_station_list";
  154. public static final String NUM_OF_STATIONS= "number_of_stations";
  155. public static final String STATION_NAME = "name_of_station";
  156. public static final String STATION_FREQUENCY = "frequency_of_station";
  157. private IFMRadioService mService = null;
  158. private FmSharedPreferences mPrefs;
  159. /* Button Resources */
  160. private ImageView mOnOffButton;
  161. private ImageView mMuteButton;
  162. private ImageView mSpeakerButton;
  163. /* Button to navigate Preset pages */
  164. private ImageButton mPresetPageButton;
  165. /* 6 Preset Buttons */
  166. private Button[] mPresetButtons = {null, null, null, null, null, null, null};
  167. private Button mPresetListButton;
  168. // private ImageButton mSearchButton;
  169. private ImageView mForwardButton;
  170. private ImageView mBackButton;
  171. /* Top row in the station info layout */
  172. private ImageView mRSSI;
  173. private TextView mProgramServiceTV;
  174. private TextView mStereoTV;
  175. /* Middle row in the station info layout */
  176. private TextView mTuneStationFrequencyTV;
  177. private TextView mStationCallSignTV;
  178. private TextView mProgramTypeTV;
  179. /* Bottom row in the station info layout */
  180. private TextView mRadioTextTV;
  181. private TextView mERadioTextTV;
  182. /* Sleep and Recording Messages */
  183. private TextView mSleepMsgTV;
  184. private TextView mRecordingMsgTV;
  185. private double mOutputFreq;
  186. private int mPresetPageNumber = 0;
  187. private int mStereo = -1;
  188. // default audio device - speaker
  189. private static int mAudioRoute = FMRadioService.RADIO_AUDIO_DEVICE_WIRED_HEADSET;
  190. private static boolean mFMStats = false;
  191. /* Current Status Indicators */
  192. private static boolean mRecording = false;
  193. private static boolean mIsScaning = false;
  194. private static boolean mIsSeeking = false;
  195. private static boolean mIsSearching = false;
  196. private static int mScanPty = 0;
  197. private static int mScanPtyIndex = 0;
  198. private Animation mAnimation = null;
  199. private ScrollerText mRadioTextScroller = null;
  200. private ScrollerText mERadioTextScroller = null;
  201. private PresetStation mTunedStation = new PresetStation("", 102100);
  202. private PresetStation mPresetButtonStation = null;
  203. /* Radio Vars */
  204. private Handler mHandler = new Handler();
  205. /* Search Progress Dialog */
  206. private ProgressDialog mProgressDialog = null;
  207. /* Asynchronous command active */
  208. private static int mCommandActive = 0;
  209. /* Command that failed (Sycnhronous or Asynchronous) */
  210. private static int mCommandFailed = 0;
  211. private HorizontalNumberPicker mPicker;
  212. private int mFrequency;
  213. /** Index of arrays.xml key word "search_category_rbds_entries or search_category_rds_entries resources*/
  214. private int mItemsIndex = -1;
  215. private static int mDisplayWidth;
  216. private static final int TEXTSIZE_PARAMETER_FOR_NUMBER_PICKER = 20;
  217. private static final int FREQUENCY_STEP_SMALL = 50;
  218. private static final int FREQUENCY_STEP_MEDIUM = 100;
  219. private static final int FREQUENCY_STEP_LARGE = 200;
  220. public static boolean mUpdatePickerValue = false;
  221. private LoadedDataAndState SavedDataAndState = null;
  222. private static String mBTsoc = "invalid";
  223. /** fm stats property string */
  224. public static final String FM_STATS_PROP = "persist.fm.stats";
  225. private BroadcastReceiver mFmSettingReceiver = null;
  226. /** Called when the activity is first created. */
  227. @Override
  228. public void onCreate(Bundle savedInstanceState) {
  229. super.onCreate(savedInstanceState);
  230. setVolumeControlStream(AudioManager.STREAM_MUSIC);
  231. mPrefs = new FmSharedPreferences(this);
  232. mCommandActive = CMD_NONE;
  233. mCommandFailed = CMD_NONE;
  234. Log.d(LOGTAG, "onCreate - Height : "+ getWindowManager().getDefaultDisplay().getHeight()
  235. + " - Width : "+ getWindowManager().getDefaultDisplay().getWidth());
  236. mDisplayWidth = getWindowManager().getDefaultDisplay().getWidth();
  237. DisplayMetrics outMetrics = new DisplayMetrics();
  238. getWindowManager().getDefaultDisplay().getMetrics(outMetrics );
  239. setContentView(R.layout.fmradio);
  240. SavedDataAndState = (LoadedDataAndState)getLastNonConfigurationInstance();
  241. mPicker = (HorizontalNumberPicker)findViewById(R.id.fm_picker);
  242. if (mPicker != null) {
  243. mPicker.setTextSize(mDisplayWidth / TEXTSIZE_PARAMETER_FOR_NUMBER_PICKER);
  244. mPicker.setDensity(outMetrics.densityDpi);
  245. mPicker.setOnValueChangedListener(new OnValueChangeListener(){
  246. @Override
  247. public void onValueChange(HorizontalNumberPicker picker,
  248. int oldVal, int newVal) {
  249. // TODO Auto-generated method stub
  250. valueToFrequency(newVal);
  251. mHandler.post(mRadioChangeFrequency);
  252. }
  253. });
  254. }
  255. mAnimation = AnimationUtils.loadAnimation(this,
  256. R.anim.preset_select);
  257. mMuteButton = (ImageView)findViewById(R.id.btn_silent);
  258. if (mMuteButton != null) {
  259. mMuteButton.setOnClickListener(mMuteModeClickListener);
  260. }
  261. mSpeakerButton = (ImageView)findViewById(R.id.btn_speaker_earphone);
  262. if (mSpeakerButton != null) {
  263. mSpeakerButton.setOnClickListener(mSpeakerClickListener);
  264. }
  265. mOnOffButton = (ImageView)findViewById(R.id.btn_onoff);
  266. if (mOnOffButton != null) {
  267. mOnOffButton.setOnClickListener(mTurnOnOffClickListener);
  268. }
  269. mForwardButton = (ImageView)findViewById(R.id.btn_forward);
  270. if (mForwardButton != null) {
  271. mForwardButton.setOnClickListener(mForwardClickListener);
  272. mForwardButton.setOnLongClickListener(mForwardLongClickListener);
  273. }
  274. mBackButton = (ImageView)findViewById(R.id.btn_back);
  275. if (mBackButton != null) {
  276. mBackButton.setOnClickListener(mBackClickListener);
  277. mBackButton.setOnLongClickListener(mBackLongClickListener);
  278. }
  279. /* 6 Preset Buttons */
  280. mPresetButtons[0] = (Button)findViewById(R.id.presets_button_1);
  281. mPresetButtons[1] = (Button)findViewById(R.id.presets_button_2);
  282. mPresetButtons[2] = (Button)findViewById(R.id.presets_button_3);
  283. mPresetButtons[3] = (Button)findViewById(R.id.presets_button_4);
  284. mPresetButtons[4] = (Button)findViewById(R.id.presets_button_5);
  285. mPresetButtons[5] = (Button)findViewById(R.id.presets_button_6);
  286. mPresetButtons[6] = (Button)findViewById(R.id.presets_button_7);
  287. for (int nButton = 0; nButton < MAX_PRESETS_PER_PAGE; nButton++) {
  288. if (mPresetButtons[nButton] != null) {
  289. mPresetButtons[nButton]
  290. .setOnClickListener(mPresetButtonClickListener);
  291. mPresetButtons[nButton]
  292. .setOnLongClickListener(mPresetButtonOnLongClickListener);
  293. }
  294. }
  295. mTuneStationFrequencyTV = (TextView)findViewById(R.id.prog_frequency_tv);
  296. if (mTuneStationFrequencyTV != null) {
  297. mTuneStationFrequencyTV.setOnLongClickListener(mFrequencyViewClickListener);
  298. }
  299. mProgramServiceTV = (TextView)findViewById(R.id.prog_service_tv);
  300. mStereoTV = (TextView)findViewById(R.id.stereo_text_tv);
  301. mStationCallSignTV = (TextView)findViewById(R.id.call_sign_tv);
  302. mProgramTypeTV = (TextView)findViewById(R.id.pty_tv);
  303. mRadioTextTV = (TextView)findViewById(R.id.radio_text_tv);
  304. mERadioTextTV = (TextView)findViewById(R.id.eradio_text_tv);
  305. mSleepMsgTV = (TextView)findViewById(R.id.sleep_msg_tv);
  306. mRecordingMsgTV = (TextView)findViewById(R.id.record_msg_tv);
  307. if (mRecordingMsgTV != null) {
  308. mRecordingMsgTV.setOnClickListener(mRecordButtonListener);
  309. }
  310. /* Disable displaying RSSI */
  311. mRSSI = (ImageView)findViewById(R.id.signal_level);
  312. if (mRSSI != null) {
  313. mRSSI.setVisibility(View.INVISIBLE);
  314. }
  315. if ((mRadioTextScroller == null) && (mRadioTextTV != null)) {
  316. mRadioTextScroller = new ScrollerText(mRadioTextTV);
  317. }
  318. if ((mERadioTextScroller == null) && (mERadioTextTV != null)) {
  319. mERadioTextScroller = new ScrollerText(mERadioTextTV);
  320. }
  321. mBTsoc = SystemProperties.get("qcom.bluetooth.soc");
  322. //20150326 added by lisineng for wakeup FM
  323. if(!getIntent().getBooleanExtra("fromBroadcast", false)){
  324. hasWakeup = getSharedPreferences("fmradio_prefs",MODE_PRIVATE).getBoolean("hasWakeup", false);
  325. }
  326. //added end
  327. }
  328. protected void setDisplayvalue(){
  329. int max = mPrefs.getUpperLimit();
  330. int min = mPrefs.getLowerLimit();
  331. int step = mPrefs.getFrequencyStepSize();
  332. switch(step) {
  333. case FREQUENCY_STEP_SMALL:
  334. mPicker.setScale(Scale.SCALE_SMALL);
  335. break;
  336. case FREQUENCY_STEP_MEDIUM:
  337. mPicker.setScale(Scale.SCALE_MEDIUM);
  338. break;
  339. case FREQUENCY_STEP_LARGE:
  340. mPicker.setScale(Scale.SCALE_LARGE);
  341. }
  342. int channels = (int)((max - min) / step);
  343. String [] displayValues = new String[channels + 1];
  344. for(int i = 0; i < displayValues.length; i++) {
  345. displayValues[i] = String.valueOf((min + i * step) / 1000.0f);
  346. }
  347. mPicker.setDisplayedValues(displayValues, true);
  348. try {
  349. mPicker.setWrapSelectorWheel(true);
  350. } catch (IllegalStateException e) {
  351. e.printStackTrace();
  352. }
  353. mPicker.invalidate();
  354. }
  355. protected int valueToFrequency(int value) {
  356. mFrequency = mPrefs.getLowerLimit() + value *
  357. mPrefs.getFrequencyStepSize();
  358. return mFrequency;
  359. }
  360. @Override
  361. public void onRestart() {
  362. Log.d(LOGTAG, "FMRadio: onRestart");
  363. try {
  364. if (null != mService) {
  365. mService.requestFocus();
  366. }
  367. } catch (Exception e) {
  368. e.printStackTrace();
  369. }
  370. super.onRestart();
  371. }
  372. @Override
  373. public void onStop() {
  374. Log.d(LOGTAG, "FMRadio: onStop");
  375. if(isRecording()) {
  376. try {
  377. if (null != mRecordUpdateHandlerThread) {
  378. mRecordUpdateHandlerThread.interrupt();
  379. }
  380. }catch (NullPointerException e) {
  381. e.printStackTrace();
  382. }
  383. }
  384. super.onStop();
  385. }
  386. @Override
  387. public void onStart() {
  388. super.onStart();
  389. Log.d(LOGTAG, "FMRadio: onStart");
  390. if ((mService == null ) && (false == bindToService(this, osc))) {
  391. Log.d(LOGTAG, "onStart: Failed to Start Service");
  392. } else {
  393. Log.d(LOGTAG, "onStart: Start Service completed successfully");
  394. }
  395. registerFMSettingListner();
  396. mPrefs.Load();
  397. if (mPicker != null) {
  398. setDisplayvalue();
  399. }
  400. PresetStation station = new PresetStation("",
  401. FmSharedPreferences.getTunedFrequency());
  402. if (station != null) {
  403. mTunedStation.Copy(station);
  404. }
  405. }
  406. //20150326 added by lisineng for wakeup FM
  407. @Override
  408. protected void onNewIntent(Intent intent) {
  409. super.onNewIntent(intent);
  410. if(intent.getBooleanExtra("fromBroadcast", false)){
  411. hasWakeup = false;
  412. AudioManager localAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
  413. boolean hasHeadset = localAudioManager.isWiredHeadsetOn(); //had headset
  414. if(hasHeadset){
  415. if (!isFmOn()) {
  416. Log.i(LOGTAG, "lsn enableRadio");
  417. mDisableRadioHandler.removeCallbacks(mDisableRadioTask);
  418. mEnableRadioHandler.removeCallbacks(mEnableRadioTask);
  419. mEnableRadioHandler.postDelayed(mEnableRadioTask, 0);
  420. }
  421. }
  422. }
  423. cleanupTimeoutHandler();
  424. }
  425. //added end
  426. @Override
  427. protected void onPause() {
  428. Log.d(LOGTAG, "FMRadio: onPause");
  429. super.onPause();
  430. if (isSleepTimerActive()) {
  431. Log.d(LOGTAG, "FMRadio: Sleep Timer active");
  432. mSleepUpdateHandlerThread.interrupt();
  433. }
  434. mRadioTextScroller.stopScroll();
  435. mERadioTextScroller.stopScroll();
  436. FmSharedPreferences.setTunedFrequency(mTunedStation.getFrequency());
  437. mPrefs.Save();
  438. }
  439. @Override
  440. public void onResume() {
  441. super.onResume();
  442. try {
  443. if(mService != null) {
  444. mService.registerCallbacks(mServiceCallbacks);
  445. }
  446. }catch (RemoteException e) {
  447. e.printStackTrace();
  448. }
  449. if(isSleepTimerActive()) {
  450. Log.d(LOGTAG, "isSleepTimerActive is true");
  451. try {
  452. if(null != mService) {
  453. mService.cancelDelayedStop(FMRadioService.STOP_SERVICE);
  454. }
  455. if(null != mSleepUpdateHandlerThread) {
  456. mSleepUpdateHandlerThread.interrupt();
  457. }
  458. }catch (Exception e) {
  459. e.printStackTrace();
  460. }
  461. initiateSleepThread();
  462. }
  463. if(isRecording()) {
  464. Log.d(LOGTAG,"isRecordTimerActive is true");
  465. try {
  466. if (null != mService) {
  467. mService.cancelDelayedStop(FMRadioService.STOP_RECORD);
  468. }
  469. }catch (Exception e) {
  470. e.printStackTrace();
  471. }
  472. if(isRecording()) {
  473. initiateRecordThread();
  474. }
  475. }
  476. Log.d(LOGTAG, "FMRadio: onResume");
  477. mStereo = FmSharedPreferences.getLastAudioMode();
  478. mHandler.post(mUpdateProgramService);
  479. mHandler.post(mUpdateRadioText);
  480. mHandler.post(mOnStereo);
  481. mUpdatePickerValue = true;
  482. updateStationInfoToUI();
  483. enableRadioOnOffUI();
  484. }
  485. private static class LoadedDataAndState {
  486. public LoadedDataAndState(){};
  487. public boolean onOrOff;
  488. }
  489. @Override
  490. public Object onRetainNonConfigurationInstance() {
  491. LoadedDataAndState data = new LoadedDataAndState();
  492. if (mService != null) {
  493. try {
  494. data.onOrOff = mService.isFmOn();
  495. }catch(RemoteException e) {
  496. data.onOrOff = false;
  497. e.printStackTrace();
  498. }
  499. }else {
  500. data.onOrOff = false;
  501. }
  502. return data;
  503. }
  504. @Override
  505. public void onDestroy() {
  506. super.onDestroy();
  507. Log.d(LOGTAG, "FMRadio: onDestroy");
  508. mHandler.removeCallbacksAndMessages(null);
  509. cleanupTimeoutHandler();
  510. if(mProgressDialog != null) {
  511. mProgressDialog.dismiss();
  512. }
  513. if(mSearchProgressHandler != null) {
  514. mSearchProgressHandler.removeCallbacksAndMessages(null);
  515. }
  516. removeDialog(DIALOG_PRESET_OPTIONS);
  517. unRegisterReceiver(mFmSettingReceiver);
  518. if (mService != null) {
  519. try {
  520. if(!mService.isFmOn()) {
  521. endSleepTimer();
  522. }
  523. }catch (RemoteException e) {
  524. e.printStackTrace();
  525. }
  526. }
  527. getSharedPreferences("fmradio_prefs", MODE_PRIVATE).edit().putBoolean("hasWakeup", hasWakeup).commit();//20150326 added by lisineng for wakeup FM
  528. unbindFromService(this);
  529. mService = null;
  530. Log.d(LOGTAG, "onDestroy: unbindFromService completed");
  531. }
  532. @Override
  533. public boolean onCreateOptionsMenu(Menu menu) {
  534. super.onCreateOptionsMenu(menu);
  535. MenuItem item;
  536. boolean radioOn = isFmOn();
  537. boolean recording = isRecording();
  538. boolean mSpeakerPhoneOn = isSpeakerEnabled();
  539. boolean sleepActive = isSleepTimerActive();
  540. boolean searchActive = isScanActive() || isSeekActive();
  541. item = menu.add(0, MENU_SCAN_START, 0, R.string.menu_scan_start).
  542. setIcon(R.drawable.ic_btn_search);
  543. if (item != null) {
  544. item.setVisible((!searchActive) && radioOn);
  545. }
  546. item = menu.add(0, MENU_SCAN_STOP, 0, R.string.menu_scan_stop).
  547. setIcon(R.drawable.ic_btn_search);
  548. if (item != null) {
  549. item.setVisible(searchActive && radioOn);
  550. }
  551. if (RECORDING_ENABLE) {
  552. item = menu.add(0, MENU_RECORD_START, 0, R.string.menu_record_start)
  553. .setIcon(R.drawable.ic_menu_record);
  554. if (item != null) {
  555. item.setVisible(true);
  556. item.setEnabled((!recording) && radioOn);
  557. }
  558. item = menu.add(0, MENU_RECORD_STOP, 0, R.string.menu_record_stop)
  559. .setIcon(R.drawable.ic_menu_record);
  560. if (item != null) {
  561. item.setVisible(true);
  562. item.setEnabled(recording && radioOn);
  563. }
  564. }
  565. /* Settings can be active */
  566. item = menu.add(0, MENU_SETTINGS, 0, R.string.menu_settings).
  567. setIcon(android.R.drawable.ic_menu_preferences);
  568. item = menu.add(0, MENU_SLEEP, 0, R.string.menu_sleep).
  569. setTitle(R.string.menu_sleep);
  570. if (item != null) {
  571. item.setVisible((!sleepActive) && radioOn);
  572. }
  573. item = menu.add(0, MENU_SLEEP_CANCEL, 0, R.string.menu_sleep_cancel).
  574. setTitle(R.string.menu_sleep_cancel);
  575. if (item != null) {
  576. item.setVisible(sleepActive && radioOn);
  577. }
  578. //20150326 added by lisineng for wakeup FM
  579. item = menu.add(0,MENU_WAKEUP,0,R.string.menu_wakeup).setTitle(R.string.menu_wakeup);
  580. if(item != null){
  581. item.setVisible(!hasWakeup);
  582. }
  583. item = menu.add(0,MENU_WAKEUP_CANCEL,0,R.string.menu_wakeup_cancel).setTitle(R.string.menu_wakeup_cancel);
  584. Log.i(LOGTAG, "lsn hasWakeup = "+hasWakeup);
  585. if(item != null ){
  586. item.setVisible(hasWakeup);
  587. }
  588. //added end
  589. mFMStats = SystemProperties.getBoolean(FM_STATS_PROP, false);
  590. if(mFMStats) {
  591. item = menu.add(0, MENU_STAT_TEST, 0,R.string.menu_stats).
  592. setIcon(android.R.drawable.ic_menu_info_details);
  593. }
  594. menu.add(0, MENU_STATION_LIST, 0, R.string.menu_all_channels);
  595. item = menu.add(0, MENU_TAGS, 0, R.string.menu_display_tags);
  596. return true;
  597. }
  598. @Override
  599. public boolean onPrepareOptionsMenu(Menu menu) {
  600. super.onPrepareOptionsMenu(menu);
  601. MenuItem item;
  602. boolean radioOn = isFmOn();
  603. boolean recording = isRecording();
  604. boolean mSpeakerPhoneOn = isSpeakerEnabled();
  605. boolean searchActive = isScanActive() || isSeekActive();
  606. item = menu.findItem(MENU_SCAN_START);
  607. if (item != null) {
  608. item.setVisible((!searchActive) && radioOn);
  609. }
  610. item = menu.findItem(MENU_SCAN_STOP);
  611. if (item != null) {
  612. item.setVisible(searchActive && radioOn);
  613. }
  614. if (RECORDING_ENABLE) {
  615. item = menu.findItem(MENU_RECORD_START);
  616. if (item != null) {
  617. item.setVisible(true);
  618. item.setEnabled((!recording) && radioOn && (!isAnalogModeEnabled()));
  619. }
  620. item = menu.findItem(MENU_RECORD_STOP);
  621. if (item != null) {
  622. item.setVisible(true);
  623. item.setEnabled(recording && radioOn && (!isAnalogModeEnabled()));
  624. }
  625. }
  626. boolean sleepActive = isSleepTimerActive();
  627. item = menu.findItem(MENU_SLEEP);
  628. if (item != null) {
  629. item.setVisible((!sleepActive) && radioOn);
  630. }
  631. item = menu.findItem(MENU_SLEEP_CANCEL);
  632. if (item != null) {
  633. item.setVisible(sleepActive && radioOn);
  634. }
  635. //20150326 added by lisineng for wakeup FM
  636. item = menu.findItem(MENU_WAKEUP);
  637. if(item != null){
  638. item.setVisible(!hasWakeup);
  639. }
  640. item = menu.findItem(MENU_WAKEUP_CANCEL);
  641. if(item != null){
  642. item.setVisible(hasWakeup);
  643. }
  644. //added end
  645. return true;
  646. }
  647. @Override
  648. public boolean onOptionsItemSelected(MenuItem item) {
  649. switch (item.getItemId()) {
  650. case MENU_SETTINGS:
  651. Intent launchPreferencesIntent = new Intent().setClass(this,
  652. Settings.class);
  653. launchPreferencesIntent.putExtra(Settings.RX_MODE,true);
  654. startActivityForResult(launchPreferencesIntent,
  655. ACTIVITY_RESULT_SETTINGS);
  656. return true;
  657. case MENU_STAT_TEST:
  658. Intent launchFMStatIntent = new Intent().setClass(this,
  659. FMStats.class);
  660. startActivity(launchFMStatIntent);
  661. return true;
  662. case MENU_SCAN_START:
  663. //20150604 modified by lisineng for deleted the useless stations
  664. // if (mBTsoc.equals("rome")) {
  665. clearStationList();
  666. initiateSearch(0); // 0 - All stations
  667. // } else {
  668. // showDialog(DIALOG_SEARCH);
  669. // }
  670. //modifed end
  671. return true;
  672. case MENU_SCAN_STOP:
  673. cancelSearch();
  674. return true;
  675. case MENU_RECORD_START:
  676. startRecording();
  677. return true;
  678. case MENU_RECORD_STOP:
  679. stopRecording();
  680. return true;
  681. case MENU_SLEEP:
  682. showDialog(DIALOG_SLEEP);
  683. return true;
  684. case MENU_SLEEP_CANCEL:
  685. DebugToasts("Sleep Cancelled", Toast.LENGTH_SHORT);
  686. endSleepTimer();
  687. return true;
  688. case MENU_STATION_LIST:
  689. Intent stationListIntent = new Intent().setClass(this,
  690. StationListActivity.class);
  691. startActivity(stationListIntent);
  692. return true;
  693. case MENU_TAGS:
  694. Intent launchFMTagsIntent = new Intent().setClass(this,
  695. FmTags.class);
  696. startActivity(launchFMTagsIntent);
  697. return true;
  698. //20150326 added by lisineng for wakeup FM
  699. case MENU_WAKEUP:
  700. showDialog(DIALOG_WAKEUP);
  701. return true;
  702. case MENU_WAKEUP_CANCEL:
  703. cancelWakeup();
  704. return true;
  705. //added end
  706. default:
  707. break;
  708. }
  709. return super.onOptionsItemSelected(item);
  710. }
  711. private void enableSpeaker() {
  712. //This method with toggle Speaker phone based on existing state .
  713. boolean bSpeakerPhoneOn = isSpeakerEnabled();
  714. if(mService != null) {
  715. try {
  716. if (bSpeakerPhoneOn) { // as Speaker is already on turn it off.
  717. mService.enableSpeaker(false);
  718. Log.d(LOGTAG, "Speaker phone is turned off");
  719. mSpeakerButton.setImageResource(R.drawable.btn_earphone);
  720. }else { // as Speaker is off turn it on.
  721. mService.enableSpeaker(true);
  722. Log.d(LOGTAG, "Speaker phone is turned on");
  723. mSpeakerButton.setImageResource(R.drawable.btn_speaker);
  724. }
  725. invalidateOptionsMenu();
  726. }catch (RemoteException e) {
  727. e.printStackTrace();
  728. }
  729. }
  730. }
  731. private static final int RECORDTIMER_EXPIRED = 0x1003;
  732. private static final int RECORDTIMER_UPDATE = 0x1004;
  733. private void updateExpiredRecordTime() {
  734. int vis = View.VISIBLE;
  735. if(isRecording())
  736. {
  737. long timeNow = ((SystemClock.elapsedRealtime()));
  738. long seconds = (timeNow - getRecordingStartTime()) / 1000;
  739. String Msg = makeTimeString(seconds);
  740. mRecordingMsgTV.setText(Msg);
  741. mRecordingMsgTV.setVisibility(vis);
  742. }
  743. }
  744. /* Recorder Thread processing */
  745. private Runnable doRecordProcessing = new Runnable() {
  746. public void run() {
  747. while (isRecording() &&
  748. (!Thread.currentThread().isInterrupted()))
  749. {
  750. try
  751. {
  752. Thread.sleep(500);
  753. Message statusUpdate = new Message();
  754. statusUpdate.what = RECORDTIMER_UPDATE;
  755. mUIUpdateHandlerHandler.sendMessage(statusUpdate);
  756. } catch (InterruptedException e)
  757. {
  758. break;
  759. }
  760. if(!isRecording()) {
  761. Message finished = new Message();
  762. finished.what = RECORDTIMER_EXPIRED;
  763. mUIUpdateHandlerHandler.sendMessage(finished);
  764. }
  765. }
  766. }
  767. };
  768. private Thread mRecordUpdateHandlerThread = null;
  769. private long getRecordingStartTime() {
  770. if(mService == null)
  771. return 0;
  772. try {
  773. return mService.getRecordingStartTime();
  774. }catch(RemoteException e) {
  775. return 0;
  776. }
  777. }
  778. private void initiateRecordDurationTimer(long mins ) {
  779. Log.d(LOGTAG, "Stop Recording in mins : " + mins);
  780. initiateRecordThread();
  781. }
  782. private void initiateRecordThread() {
  783. if (mRecordUpdateHandlerThread == null) {
  784. mRecordUpdateHandlerThread = new Thread(null, doRecordProcessing,
  785. "RecordUpdateThread");
  786. }
  787. /* Launch the dummy thread to simulate the transfer progress */
  788. Log.d(LOGTAG, "Thread State: " + mRecordUpdateHandlerThread.getState());
  789. if (mRecordUpdateHandlerThread.getState() == Thread.State.TERMINATED) {
  790. mRecordUpdateHandlerThread = new Thread(null, doRecordProcessing,
  791. "RecordUpdateThread");
  792. }
  793. /* If the thread state is "new" then the thread has not yet started */
  794. if (mRecordUpdateHandlerThread.getState() == Thread.State.NEW) {
  795. mRecordUpdateHandlerThread.start();
  796. }
  797. }
  798. private void audioRoute (int audioDevice) {
  799. boolean bStatus;
  800. if (mService != null) {
  801. try {
  802. bStatus = mService.routeAudio(audioDevice);
  803. }catch (RemoteException e) {
  804. e.printStackTrace();
  805. }
  806. }
  807. }
  808. @Override
  809. protected Dialog onCreateDialog(int id) {
  810. AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(this);
  811. dlgBuilder.setOnKeyListener(new OnKeyListener() {
  812. public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
  813. Log.d(LOGTAG, "OnKeyListener event received"+keyCode);
  814. switch (keyCode) {
  815. case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
  816. case 126: //KeyEvent.KEYCODE_MEDIA_PLAY:
  817. case 127: //KeyEvent.KEYCODE_MEDIA_PAUSE:
  818. case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
  819. case KeyEvent.KEYCODE_MEDIA_NEXT:
  820. case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
  821. case KeyEvent.KEYCODE_MEDIA_REWIND:
  822. case KeyEvent.KEYCODE_MEDIA_STOP:
  823. return true;
  824. }
  825. return false;
  826. }
  827. });
  828. switch (id) {
  829. case DIALOG_SEARCH: {
  830. return createSearchDlg(id, dlgBuilder);
  831. }
  832. case DIALOG_SLEEP: {
  833. return createSleepDlg(id, dlgBuilder);
  834. }
  835. case DIALOG_PROGRESS_PROGRESS: {
  836. return createProgressDialog(id);
  837. }
  838. case DIALOG_PRESET_OPTIONS: {
  839. return createPresetOptionsDlg(id, dlgBuilder);
  840. }
  841. case DIALOG_PRESET_RENAME: {
  842. return createPresetRenameDlg(id, dlgBuilder);
  843. }
  844. case DIALOG_CMD_TIMEOUT:{
  845. return createCmdTimeoutDlg(id, dlgBuilder);
  846. }
  847. case DIALOG_CMD_FAILED:{
  848. return createCmdFailedDlg(id, dlgBuilder);
  849. }
  850. case DIALOG_CMD_FAILED_HDMI_ON:{
  851. return createCmdFailedDlgHdmiOn(id);
  852. }
  853. case DIALOG_CMD_FAILED_CALL_ON:{
  854. return createCmdFailedDlgCallOn(id);
  855. }
  856. case DIALOG_PICK_FREQUENCY: {
  857. FmConfig fmConfig = FmSharedPreferences.getFMConfiguration();
  858. return new FrequencyPickerDialog(this, fmConfig, mTunedStation.getFrequency(), mFrequencyChangeListener);
  859. }
  860. //20150326 added by lisineng for wakeup FM
  861. case DIALOG_WAKEUP: {
  862. return createWakeupDlg(id, dlgBuilder);
  863. }
  864. //added end
  865. default:
  866. break;
  867. }
  868. return null;
  869. }
  870. @Override
  871. protected void onPrepareDialog(int id, Dialog dialog) {
  872. super.onPrepareDialog(id, dialog);
  873. int curListIndex = FmSharedPreferences.getCurrentListIndex();
  874. PresetList curList = FmSharedPreferences.getStationList(curListIndex);
  875. switch (id) {
  876. case DIALOG_PRESET_RENAME: {
  877. EditText et = (EditText) dialog.findViewById(R.id.list_edit);
  878. if ((et != null) && (mPresetButtonStation != null)) {
  879. et.setText(mPresetButtonStation.getName());
  880. }
  881. break;
  882. }
  883. case DIALOG_PRESET_OPTIONS: {
  884. AlertDialog alertDlg = ((AlertDialog) dialog);
  885. if ((alertDlg != null) && (mPresetButtonStation != null)) {
  886. alertDlg.setTitle(mPresetButtonStation.getName());
  887. }
  888. break;
  889. }
  890. case DIALOG_PICK_FREQUENCY:
  891. {
  892. if (dialog != null && mTunedStation != null)
  893. {
  894. FmConfig fmConfig = FmSharedPreferences.getFMConfiguration();
  895. ((FrequencyPickerDialog) dialog).updateSteps(fmConfig.getChSpacing());
  896. ((FrequencyPickerDialog) dialog).updateMinFreq(fmConfig.getLowerLimit());
  897. ((FrequencyPickerDialog) dialog).updateMaxFreq(fmConfig.getUpperLimit());
  898. ((FrequencyPickerDialog) dialog).UpdateFrequency(mTunedStation.getFrequency());
  899. }
  900. break;
  901. }
  902. default:
  903. break;
  904. }
  905. }
  906. @Override
  907. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  908. super.onActivityResult(requestCode, resultCode, data);
  909. Log.d(LOGTAG, "onActivityResult : requestCode -> " + requestCode);
  910. Log.d(LOGTAG, "onActivityResult : resultCode -> " + resultCode);
  911. if (requestCode == ACTIVITY_RESULT_SETTINGS) {
  912. if (resultCode == RESULT_OK) {
  913. if (data != null) {
  914. String action = data.getAction();
  915. if (action != null) {
  916. if (action.equals(Settings.RESTORE_FACTORY_DEFAULT_ACTION)) {
  917. RestoreDefaults();
  918. enableRadioOnOffUI();
  919. tuneRadio(FmSharedPreferences.DEFAULT_NO_FREQUENCY);
  920. FmSharedPreferences.addStation("", FmSharedPreferences.DEFAULT_NO_FREQUENCY, 0);
  921. }
  922. }
  923. }
  924. } //if ACTIVITY_RESULT_SETTINGS
  925. }//if (resultCode == RESULT_OK)
  926. }
  927. /**
  928. * @return true if a wired headset is connected.
  929. */
  930. boolean isWiredHeadsetAvailable() {
  931. boolean bAvailable = false;
  932. if(mService != null) {
  933. try {
  934. bAvailable = mService.isWiredHeadsetAvailable();
  935. }catch (RemoteException e) {
  936. e.printStackTrace();
  937. }
  938. }
  939. Log.e(LOGTAG, "isWiredHeadsetAvailable: " + bAvailable);
  940. return bAvailable;
  941. }
  942. /**
  943. * @return true if a internal antenna is available.
  944. *
  945. */
  946. boolean isAntennaAvailable() {
  947. boolean bAvailable = false;
  948. if(mService != null) {
  949. try {
  950. bAvailable = mService.isAntennaAvailable();
  951. }catch (RemoteException e) {
  952. e.printStackTrace();
  953. }
  954. }
  955. return bAvailable;
  956. }
  957. boolean isCallActive(){
  958. boolean bCallActive = false;
  959. if(mService != null) {
  960. try {
  961. bCallActive = mService.isCallActive();
  962. }catch (RemoteException e) {
  963. e.printStackTrace();
  964. }
  965. }
  966. return bCallActive;
  967. }
  968. private Dialog createSearchDlg(int id, AlertDialog.Builder dlgBuilder) {
  969. String[] items;
  970. dlgBuilder.setIcon(R.drawable.ic_btn_search);
  971. dlgBuilder.setTitle(getString(R.string.search_dialog_title));
  972. /* Pick RBDS or RDS */
  973. if(FmSharedPreferences.isRBDSStd()) {
  974. items = getResources().getStringArray(R.array.search_category_rbds_entries);
  975. }else { // if(FmSharedPreferences.isRDSStd())
  976. items = getResources().getStringArray(R.array.search_category_rds_entries);
  977. }
  978. dlgBuilder.setItems(items, new DialogInterface.OnClickListener() {
  979. public void onClick(DialogInterface dialog, int item) {
  980. String[] items;
  981. String[] values;
  982. mItemsIndex = item ;
  983. /* Pick RBDS or RDS */
  984. if(FmSharedPreferences.isRBDSStd()) {
  985. items = getResources().
  986. getStringArray(R.array.search_category_rbds_entries);
  987. values = getResources().
  988. getStringArray(R.array.search_category_rbds_values);
  989. }else { // if(FmSharedPreferences.isRDSStd())
  990. items = getResources().
  991. getStringArray(R.array.search_category_rds_entries);
  992. values = getResources().
  993. getStringArray(R.array.search_category_rds_values);
  994. }
  995. if ((items != null) && (values != null) && (item >= 0)) {
  996. if ((item >= 0) && (item <= items.length)
  997. && (item <= items.length)) {
  998. DebugToasts("Search Stations for : " + items[item]
  999. + " (" + values[item] + ")",
  1000. Toast.LENGTH_SHORT);
  1001. int pty = Integer.parseInt(values[item]);
  1002. clearStationList();
  1003. mScanPtyIndex = item;
  1004. initiateSearch(pty);
  1005. }
  1006. }
  1007. removeDialog(DIALOG_SEARCH);
  1008. }
  1009. });
  1010. return dlgBuilder.create();
  1011. }
  1012. private Dialog createPresetOptionsDlg(int id, AlertDialog.Builder dlgBuilder) {
  1013. if(mPresetButtonStation != null) {
  1014. dlgBuilder.setTitle(mPresetButtonStation.getName());
  1015. ArrayList<String> arrayList = new ArrayList<String>();
  1016. //PRESETS_OPTIONS_TUNE=0
  1017. arrayList.add(getResources().getString(R.string.preset_tune));
  1018. //PRESETS_OPTIONS_REPLACE=1
  1019. arrayList.add(getResources().getString(R.string.preset_replace));
  1020. //PRESETS_OPTIONS_RENAME=2
  1021. arrayList.add(getResources().getString(R.string.preset_rename));
  1022. //PRESETS_OPTIONS_DELETE=3
  1023. arrayList.add(getResources().getString(R.string.preset_delete));
  1024. String piString = mPresetButtonStation.getPIString();
  1025. if (!TextUtils.isEmpty(piString)) {
  1026. //PRESETS_OPTIONS_SEARCHPI=4
  1027. arrayList.add(getResources().getString(R.string.preset_search, piString));
  1028. }
  1029. dlgBuilder.setCancelable(true);
  1030. dlgBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {
  1031. public void onCancel(DialogInterface dialog) {
  1032. mPresetButtonStation = null;
  1033. removeDialog(DIALOG_PRESET_OPTIONS);
  1034. }
  1035. });
  1036. String[] items = new String [arrayList.size ()];
  1037. arrayList.toArray(items);
  1038. dlgBuilder.setItems(items, new DialogInterface.OnClickListener() {
  1039. public void onClick(DialogInterface dialog, int item) {
  1040. if(mPresetButtonStation != null) {
  1041. switch(item) {
  1042. case PRESETS_OPTIONS_TUNE: {
  1043. // Tune to the station
  1044. tuneRadio(mPresetButtonStation.getFrequency());
  1045. mPresetButtonStation = null;
  1046. break;
  1047. }
  1048. case PRESETS_OPTIONS_REPLACE: {
  1049. // Replace preset Station with currently tuned station
  1050. if(!stationExists(mTunedStation)) {
  1051. Log.d(LOGTAG, "station - " + mPresetButtonStation.getName() + " ("
  1052. + mPresetButtonStation.getFrequency() + ")");
  1053. mPresetButtonStation.Copy(mTunedStation);
  1054. mPresetButtonStation = null;
  1055. setupPresetLayout();
  1056. mPrefs.Save();
  1057. }
  1058. break;
  1059. }
  1060. case PRESETS_OPTIONS_RENAME: {
  1061. // Rename
  1062. showDialog(DIALOG_PRESET_RENAME);
  1063. break;
  1064. }
  1065. case PRESETS_OPTIONS_DELETE: {
  1066. // Delete
  1067. int curListIndex = FmSharedPreferences.getCurrentListIndex();
  1068. FmSharedPreferences.removeStation(curListIndex, mPresetButtonStation);
  1069. if (mPresetButtonStation.getFrequency() == mTunedStation.getFrequency()) {
  1070. // Restore current tuned station's name as its frequency
  1071. mTunedStation.setName("");
  1072. }
  1073. mPresetButtonStation = null;
  1074. setupPresetLayout();
  1075. mPrefs.Save();
  1076. break;
  1077. }
  1078. case PRESETS_OPTIONS_SEARCHPI: {
  1079. // SearchPI
  1080. String piString = mPresetButtonStation.getPIString();
  1081. int pi = mPresetButtonStation.getPI();
  1082. if ((!TextUtils.isEmpty(piString)) && (pi > 0)) {
  1083. initiatePISearch(pi);
  1084. }
  1085. mPresetButtonStation = null;
  1086. break;
  1087. }
  1088. default: {
  1089. // Should not happen
  1090. mPresetButtonStation = null;
  1091. break;
  1092. }
  1093. }//switch item
  1094. }//if(mPresetButtonStation != null)
  1095. removeDialog (DIALOG_PRESET_OPTIONS);
  1096. }//onClick
  1097. });
  1098. return dlgBuilder.create();
  1099. }
  1100. return null;
  1101. }
  1102. private Dialog createSleepDlg(int id, AlertDialog.Builder dlgBuilder) {
  1103. dlgBuilder.setTitle(R.string.dialog_sleep_title);
  1104. String[] items = getResources().getStringArray(R.array.sleep_duration_values);
  1105. dlgBuilder.setItems(items, new DialogInterface.OnClickListener() {
  1106. public void onClick(DialogInterface dialog, int item) {
  1107. String[] items = getResources().getStringArray(R.array.sleep_duration_values);
  1108. Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
  1109. if ((item >= 0) && (item <= items.length)) {
  1110. long seconds = (long) (900 * (item + 1));
  1111. initiateSleepTimer(seconds);
  1112. }
  1113. removeDialog (DIALOG_SLEEP);
  1114. }
  1115. });
  1116. return dlgBuilder.create();
  1117. }
  1118. //20150326 added by lisineng for wakeup FM
  1119. private Dialog createWakeupDlg(int id, AlertDialog.Builder dlgBuilder) {
  1120. dlgBuilder.setTitle(R.string.dialog_wakeup_title);
  1121. String[] items = getResources().getStringArray(R.array.wakeup_duration_values);
  1122. dlgBuilder.setItems(items, new DialogInterface.OnClickListener() {
  1123. public void onClick(DialogInterface dialog, int item) {
  1124. hasWakeup = true;
  1125. String[] items = getResources().getStringArray(R.array.wakeup_duration_values);
  1126. Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
  1127. if ((item >= 0) && (item <= items.length)) {
  1128. long seconds = (long) (900 * (item + 1));
  1129. Log.i(LOGTAG, "lsn seconds = "+seconds);
  1130. AlarmManager am = (AlarmManager)FMRadio.this.getSystemService(Context.ALARM_SERVICE);
  1131. Intent intent = new Intent(ALARM_FM);
  1132. PendingIntent pi = PendingIntent.getBroadcast(FMRadio.this, 0, intent, 0);
  1133. am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+seconds*1000, pi);
  1134. }
  1135. removeDialog (DIALOG_WAKEUP);
  1136. }
  1137. });
  1138. return dlgBuilder.create();
  1139. }
  1140. private void cancelWakeup(){
  1141. hasWakeup = false;
  1142. AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
  1143. Intent intent = new Intent(ALARM_FM);
  1144. PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, 0);
  1145. if (sender != null){
  1146. Log.i(LOGTAG," lsn cancel alarm");
  1147. am.cancel(sender);
  1148. Toast toast = Toast.makeText(this, R.string.menu_wakeup_cancel, Toast.LENGTH_SHORT);
  1149. toast.show();
  1150. }else{
  1151. Log.i(LOGTAG,"lsn sender == null");
  1152. }
  1153. }
  1154. //added end
  1155. private Dialog createProgressDialog(int id) {
  1156. String msgStr = "";
  1157. String titleStr = "";
  1158. String []items;
  1159. double frequency = mTunedStation.getFrequency() / 1000.0;
  1160. boolean bSearchActive = false;
  1161. if (isSeekActive()) {
  1162. msgStr = getString(R.string.msg_seeking);
  1163. bSearchActive = true;
  1164. }else if (isScanActive()) {
  1165. if(FmSharedPreferences.isRBDSStd()) {
  1166. items = getResources().
  1167. getStringArray(R.array.search_category_rbds_entries);
  1168. }else { // if(FmSharedPreferences.isRDSStd())
  1169. items = getResources().
  1170. getStringArray(R.array.search_category_rds_entries);
  1171. }
  1172. String ptyStr = "";
  1173. if (items.length > mScanPtyIndex)
  1174. ptyStr = items[mScanPtyIndex];
  1175. if (!TextUtils.isEmpty(ptyStr)) {
  1176. msgStr = getString(R.string.msg_scanning_pty, ptyStr);
  1177. }else {
  1178. Log.d(LOGTAG, "pty is null\n");
  1179. msgStr = getString(R.string.msg_scanning);
  1180. }
  1181. titleStr = getString(R.string.msg_search_title, ("" + frequency));
  1182. bSearchActive=true;
  1183. }else if (isSearchActive()) {
  1184. msgStr = getString(R.string.msg_searching);
  1185. titleStr = getString(R.string.msg_searching_title);
  1186. bSearchActive = true;
  1187. }
  1188. if (bSearchActive) {
  1189. mProgressDialog = new ProgressDialog(FMRadio.this);
  1190. if (mProgressDialog != null) {
  1191. mProgressDialog.setTitle(titleStr);
  1192. mProgressDialog.setMessage(msgStr);
  1193. mProgressDialog.setIcon(R.drawable.ic_launcher_fmradio);
  1194. mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
  1195. mProgressDialog.setCanceledOnTouchOutside(false);
  1196. mProgressDialog.setButton(DialogInterface.BUTTON_POSITIVE,
  1197. getText(R.string.button_text_stop),
  1198. new DialogInterface.OnClickListener() {
  1199. public void onClick(DialogInterface dialog, int whichButton) {
  1200. cancelSearch();
  1201. }
  1202. });
  1203. mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
  1204. public void onCancel(DialogInterface dialog) {
  1205. cancelSearch();
  1206. }
  1207. });
  1208. mProgressDialog.setOnKeyListener(new OnKeyListener() {
  1209. public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
  1210. Log.d(LOGTAG, "OnKeyListener event received in ProgressDialog" + keyCode);
  1211. switch (keyCode) {
  1212. case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
  1213. case 126: //KeyEvent.KEYCODE_MEDIA_PLAY:
  1214. case 127: //KeyEvent.KEYCODE_MEDIA_PAUSE:
  1215. case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
  1216. case KeyEvent.KEYCODE_MEDIA_NEXT:
  1217. case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
  1218. case KeyEvent.KEYCODE_MEDIA_REWIND:
  1219. case KeyEvent.KEYCODE_MEDIA_STOP:
  1220. return true;
  1221. }
  1222. return false;
  1223. }
  1224. });
  1225. }
  1226. Message msg = new Message();
  1227. msg.what = TIMEOUT_PROGRESS_DLG;
  1228. mSearchProgressHandler.sendMessageDelayed(msg, SHOWBUSY_TIMEOUT);
  1229. }
  1230. return mProgressDialog;
  1231. }
  1232. private void updateSelectPresetListDlg(ListView lv) {
  1233. if (lv != null) {
  1234. List<PresetList> presetLists = FmSharedPreferences.getPresetLists();
  1235. ListIterator<PresetList> presetIter;
  1236. presetIter = presetLists.listIterator();
  1237. int numLists = presetLists.size();
  1238. int curIndex = FmSharedPreferences.getCurrentListIndex();
  1239. ArrayAdapter<String> typeAdapter = new ArrayAdapter<String>
  1240. (this, android.R.layout.
  1241. simple_list_item_single_choice);
  1242. for (int stationIter = 0; stationIter < numLists; stationIter++) {
  1243. PresetList temp = presetIter.next();
  1244. if (temp != null) {
  1245. typeAdapter.add(getString(R.string.presetlist_select_name,
  1246. temp.getName()));
  1247. }
  1248. }
  1249. typeAdapter.add(getString(R.string.presetlist_add_new));
  1250. lv.setAdapter(typeAdapter);
  1251. lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
  1252. lv.clearChoices();
  1253. if (curIndex >= numLists) {
  1254. curIndex = 0;
  1255. }
  1256. if (lv.getCount() >= curIndex) {
  1257. lv.setItemChecked(curIndex, true);
  1258. lv.setSelection(curIndex);
  1259. }else {
  1260. lv.setItemChecked(0, true);
  1261. lv.setSelection(0);
  1262. }
  1263. }
  1264. }
  1265. private Dialog createPresetRenameDlg(int id, AlertDialog.Builder dlgBuilder) {
  1266. if(mPresetButtonStation == null) {
  1267. return null;
  1268. }
  1269. LayoutInflater factory = LayoutInflater.from(this);
  1270. final View textEntryView = factory.inflate(
  1271. R.layout.alert_dialog_text_entry, null);
  1272. dlgBuilder.setTitle(R.string.dialog_presetlist_rename_title);
  1273. dlgBuilder.setView(textEntryView);
  1274. dlgBuilder.setPositiveButton(R.string.alert_dialog_ok,
  1275. new DialogInterface.OnClickListener() {
  1276. public void onClick(DialogInterface dialog, int whichButton) {
  1277. //int curList = FmSharedPreferences.getCurrentListIndex();
  1278. EditText mTV = (EditText) textEntryView
  1279. .findViewById(R.id.list_edit);
  1280. CharSequence newName = null;
  1281. if (mTV != null) {
  1282. newName = mTV.getEditableText();
  1283. }
  1284. String nName = String.valueOf(newName);
  1285. mPresetButtonStation.setName(nName);
  1286. mPresetButtonStation=null;
  1287. setupPresetLayout();
  1288. mPrefs.Save();
  1289. removeDialog(DIALOG_PRESET_RENAME);
  1290. }
  1291. });
  1292. dlgBuilder.setNegativeButton(R.string.alert_dialog_cancel,
  1293. new DialogInterface.OnClickListener() {
  1294. public void onClick(DialogInterface dialog, int whichButton) {
  1295. removeDialog(DIALOG_PRESET_RENAME);
  1296. }
  1297. });
  1298. return(dlgBuilder.create());
  1299. }
  1300. private Dialog createCmdTimeoutDlg(int id, AlertDialog.Builder dlgBuilder) {
  1301. if(mCommandActive > 0) {
  1302. dlgBuilder.setIcon(R.drawable.alert_dialog_icon)
  1303. .setTitle(R.string.fm_command_timeout_title);
  1304. dlgBuilder.setMessage(R.string.fm_tune_timeout_msg);
  1305. dlgBuilder.setPositiveButton(R.string.alert_dialog_ok,
  1306. new DialogInterface.OnClickListener() {
  1307. public void onClick(DialogInterface dialog,
  1308. int whichButton) {
  1309. cleanupTimeoutHandler();
  1310. removeDialog(DIALOG_CMD_TIMEOUT);
  1311. }
  1312. });
  1313. return(dlgBuilder.create());
  1314. }else {
  1315. return(null);
  1316. }
  1317. }
  1318. private Dialog createCmdFailedDlg(int id, AlertDialog.Builder dlgBuilder) {
  1319. dlgBuilder.setIcon(R.drawable.alert_dialog_icon)
  1320. .setTitle(R.string.fm_command_failed_title);
  1321. dlgBuilder.setMessage(R.string.fm_cmd_failed_msg);
  1322. dlgBuilder.setPositiveButton(R.string.alert_dialog_ok,
  1323. new DialogInterface.OnClickListener() {
  1324. public void onClick(DialogInterface dialog,
  1325. int whichButton) {
  1326. removeDialog(DIALOG_CMD_TIMEOUT);
  1327. mCommandFailed = CMD_NONE;
  1328. }
  1329. });
  1330. return(dlgBuilder.create());
  1331. }
  1332. private Dialog createCmdFailedDlgHdmiOn(int id) {
  1333. AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(this);
  1334. dlgBuilder.setIcon(R.drawable.alert_dialog_icon)
  1335. .setTitle(R.string.fm_command_failed_title);
  1336. dlgBuilder.setMessage(R.string.fm_cmd_failed_msg_hdmi);
  1337. dlgBuilder.setPositiveButton(R.string.alert_dialog_ok,
  1338. new DialogInterface.OnClickListener() {
  1339. public void onClick(DialogInterface dialog,
  1340. int whichButton) {
  1341. removeDialog(DIALOG_CMD_TIMEOUT);
  1342. mCommandFailed = CMD_NONE;
  1343. }
  1344. });
  1345. return(dlgBuilder.create());
  1346. }
  1347. private Dialog createCmdFailedDlgCallOn(int id) {
  1348. AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(this);
  1349. dlgBuilder.setIcon(R.drawable.alert_dialog_icon)
  1350. .setTitle(R.string.fm_command_failed_title);
  1351. dlgBuilder.setMessage(R.string.fm_cmd_failed_call_on);
  1352. dlgBuilder.setPositiveButton(R.string.alert_dialog_ok,
  1353. new DialogInterface.OnClickListener() {
  1354. public void onClick(DialogInterface dialog,
  1355. int whichButton) {
  1356. removeDialog(DIALOG_CMD_TIMEOUT);
  1357. mCommandFailed = CMD_NONE;
  1358. finish();
  1359. }
  1360. });
  1361. return(dlgBuilder.create());
  1362. }
  1363. private void RestoreDefaults() {
  1364. FmSharedPreferences.SetDefaults();
  1365. mPrefs.Save();
  1366. }
  1367. private View.OnLongClickListener mFrequencyViewClickListener =
  1368. new View.OnLongClickListener() {
  1369. public boolean onLongClick(View v) {
  1370. showDialog(DIALOG_PICK_FREQUENCY);
  1371. return true;
  1372. }
  1373. };
  1374. private View.OnClickListener mForwardClickListener =
  1375. new View.OnClickListener() {
  1376. public void onClick(View v) {
  1377. int frequency = FmSharedPreferences.getNextTuneFrequency();
  1378. Log.d(LOGTAG, "Tune Up: to " + frequency);
  1379. tuneRadio(frequency);
  1380. }
  1381. };
  1382. private View.OnClickListener mBackClickListener =
  1383. new View.OnClickListener() {
  1384. public void onClick(View v) {
  1385. int frequency = FmSharedPreferences.getPrevTuneFrequency();
  1386. Log.d(LOGTAG, "Tune Down: to " + frequency);
  1387. tuneRadio(frequency);
  1388. }
  1389. };
  1390. private View.OnLongClickListener mForwardLongClickListener =
  1391. new View.OnLongClickListener() {
  1392. public boolean onLongClick(View view) {
  1393. SeekNextStation();
  1394. return true;
  1395. }
  1396. };
  1397. private View.OnLongClickListener mBackLongClickListener =
  1398. new View.OnLongClickListener() {
  1399. public boolean onLongClick(View view) {
  1400. SeekPreviousStation();
  1401. return true;
  1402. }
  1403. };
  1404. private View.OnClickListener mPresetListClickListener =
  1405. new View.OnClickListener() {
  1406. public void onClick(View v) {
  1407. showDialog(DIALOG_SELECT_PRESET_LIST);
  1408. }
  1409. };
  1410. private View.OnLongClickListener mPresetListButtonOnLongClickListener =
  1411. new View.OnLongClickListener() {
  1412. public boolean onLongClick(View view) {
  1413. showDialog(DIALOG_PRESETS_LIST);
  1414. return true;
  1415. }
  1416. };
  1417. private View.OnClickListener mPresetsPageClickListener =
  1418. new View.OnClickListener() {
  1419. public void onClick(View v) {
  1420. mPresetPageNumber++;
  1421. setupPresetLayout();
  1422. }
  1423. };
  1424. private View.OnClickListener mPresetButtonClickListener =
  1425. new View.OnClickListener() {
  1426. public void onClick(View view) {
  1427. PresetStation station = (PresetStation)view.getTag();
  1428. if (station != null) {
  1429. Log.d(LOGTAG, "station - " + station.getName() + " ("
  1430. + station.getFrequency() + ")");
  1431. tuneRadio(station.getFrequency());
  1432. view.startAnimation(mAnimation);
  1433. }
  1434. }
  1435. };
  1436. private View.OnLongClickListener mPresetButtonOnLongClickListener =
  1437. new View.OnLongClickListener() {
  1438. public boolean onLongClick(View view) {
  1439. PresetStation station = (PresetStation)view.getTag();
  1440. mPresetButtonStation = station;
  1441. if (station != null) {
  1442. showDialog(DIALOG_PRESET_OPTIONS);
  1443. }else {
  1444. addToPresets();
  1445. view.startAnimation(mAnimation);
  1446. }
  1447. return true;
  1448. }
  1449. };
  1450. FrequencyPickerDialog.OnFrequencySetListener mFrequencyChangeListener
  1451. = new FrequencyPickerDialog.OnFrequencySetListener() {
  1452. public void onFrequencySet(FrequencyPicker view, int frequency) {
  1453. Log.d(LOGTAG, "mFrequencyChangeListener: onFrequencyChanged to: " +
  1454. frequency);
  1455. tuneRadio(frequency);
  1456. }
  1457. };
  1458. private View.OnClickListener mSpeakerClickListener =
  1459. new View.OnClickListener() {
  1460. @Override
  1461. public void onClick(View v) {
  1462. // TODO Auto-generated method stub
  1463. mSpeakerButton.setClickable(false);
  1464. mSpeakerButton.setOnClickListener(null);
  1465. mHandler.removeCallbacks(mEnableRadioTask);
  1466. mHandler.postDelayed(mEnableSpeakerTask, 0);
  1467. }
  1468. };
  1469. private Runnable mEnableSpeakerTask = new Runnable() {
  1470. public void run() {
  1471. enableSpeaker();
  1472. mSpeakerButton.setClickable(true);
  1473. mSpeakerButton.setOnClickListener(mSpeakerClickListener);
  1474. }
  1475. };
  1476. private View.OnClickListener mMuteModeClickListener =
  1477. new View.OnClickListener() {
  1478. public void onClick(View v) {
  1479. boolean bStatus = false;
  1480. if (mService != null) {
  1481. try {
  1482. if (true == isMuted()) {
  1483. bStatus = mService.unMute();
  1484. }else {
  1485. bStatus = mService.mute();
  1486. }
  1487. if (bStatus) {
  1488. setMuteModeButtonImage(true);
  1489. v.startAnimation(mAnimation);
  1490. }else {
  1491. mCommandFailed = CMD_MUTE;
  1492. if(isCallActive()) {
  1493. showDialog(DIALOG_CMD_FAILED_CALL_ON);
  1494. }else {
  1495. showDialog(DIALOG_CMD_FAILED);
  1496. }
  1497. }
  1498. }catch (RemoteException e) {
  1499. e.printStackTrace();
  1500. }
  1501. }
  1502. }
  1503. };
  1504. private View.OnClickListener mRecordButtonListener =
  1505. new View.OnClickListener() {
  1506. public void onClick(View v) {
  1507. if (isRecording()) {
  1508. stopRecording();
  1509. }else if(!isAnalogModeEnabled()) {
  1510. startRecording();
  1511. }
  1512. invalidateOptionsMenu();
  1513. }
  1514. };
  1515. private Handler mEnableRadioHandler = new Handler();
  1516. private Handler mDisableRadioHandler = new Handler();
  1517. private Runnable mEnableRadioTask = new Runnable() {
  1518. public void run() {
  1519. enableRadio();
  1520. mOnOffButton.setEnabled(true);
  1521. mOnOffButton.setClickable(true);
  1522. mOnOffButton.setOnClickListener(mTurnOnOffClickListener);
  1523. }
  1524. };
  1525. private Runnable mDisableRadioTask = new Runnable() {
  1526. public void run() {
  1527. disableRadio();
  1528. mOnOffButton.setEnabled(true);
  1529. mOnOffButton.setClickable(true);
  1530. mOnOffButton.setOnClickListener(mTurnOnOffClickListener);
  1531. }
  1532. };
  1533. private View.OnClickListener mTurnOnOffClickListener =
  1534. new View.OnClickListener() {
  1535. public void onClick(View v) {
  1536. mOnOffButton.setEnabled(false);
  1537. mOnOffButton.setClickable(false);
  1538. mOnOffButton.setOnClickListener(null);
  1539. if (isFmOn()) {
  1540. mEnableRadioHandler.removeCallbacks(mEnableRadioTask);
  1541. mDisableRadioHandler.removeCallbacks(mDisableRadioTask);
  1542. mDisableRadioHandler.postDelayed(mDisableRadioTask, 0);
  1543. }else {
  1544. mDisableRadioHandler.removeCallbacks(mDisableRadioTask);
  1545. mEnableRadioHandler.removeCallbacks(mEnableRadioTask);
  1546. mEnableRadioHandler.postDelayed(mEnableRadioTask, 0);
  1547. }
  1548. cleanupTimeoutHandler();
  1549. }
  1550. };
  1551. private void setTurnOnOffButtonImage() {
  1552. if (isFmOn() == true) {
  1553. mOnOffButton.setEnabled(true);
  1554. }else {
  1555. mOnOffButton.setEnabled(false);
  1556. }
  1557. }
  1558. private void setMuteModeButtonImage(boolean notify) {
  1559. String fmMutedString;
  1560. if (isMuted() == true) {
  1561. mMuteButton.setImageResource(R.drawable.ic_silent_mode);
  1562. fmMutedString = "FM Radio Muted";
  1563. }else {
  1564. /* Find a icon for Stations */
  1565. mMuteButton.setImageResource(R.drawable.ic_silent_mode_off);
  1566. fmMutedString = "FM Radio Playing";
  1567. }
  1568. if (notify) {
  1569. //Toast.makeText(this, fmMutedString, Toast.LENGTH_SHORT).show();
  1570. Log.d(LOGTAG, fmMutedString);
  1571. }
  1572. }
  1573. private void enableRadio() {
  1574. mIsScaning = false;
  1575. mIsSeeking = false;
  1576. mIsSearching = false;
  1577. boolean bStatus = false;
  1578. if (mService != null) {
  1579. try {
  1580. if(mService.isSSRInProgress()) {
  1581. Log.e(LOGTAG, "SSR In Progress, looping");
  1582. while(mService.isSSRInProgress()) {
  1583. try
  1584. {
  1585. Thread.sleep(500);
  1586. } catch (InterruptedException e)
  1587. {
  1588. break;
  1589. }
  1590. }
  1591. Log.e(LOGTAG, "SSR done, continuing");
  1592. }
  1593. if((false == mService.isFmOn()) && isAntennaAvailable()) {
  1594. bStatus = mService.fmOn();
  1595. if(bStatus) {
  1596. tuneRadio(FmSharedPreferences.getTunedFrequency());
  1597. enableRadioOnOffUI();
  1598. }else {
  1599. Log.e(LOGTAG, "mService.fmOn failed");
  1600. mCommandFailed = CMD_FMON;
  1601. if(isCallActive()) {
  1602. enableRadioOnOffUI();
  1603. showDialog(DIALOG_CMD_FAILED_CALL_ON);
  1604. }else {
  1605. showDialog(DIALOG_CMD_FAILED);
  1606. }
  1607. }
  1608. }else {
  1609. enableRadioOnOffUI();
  1610. }
  1611. }catch (RemoteException e) {
  1612. e.printStackTrace();
  1613. }
  1614. }
  1615. }
  1616. private void disableRadio() {
  1617. boolean bStatus = false;
  1618. boolean bSpeakerPhoneOn = isSpeakerEnabled();
  1619. cancelSearch();
  1620. endSleepTimer();
  1621. if(mRecording) {
  1622. //Stop if there is an ongoing Record
  1623. stopRecording();
  1624. }
  1625. if(mService != null) {
  1626. try {
  1627. if(bSpeakerPhoneOn) {
  1628. mService.enableSpeaker(false);
  1629. }
  1630. bStatus = mService.fmOff();
  1631. enableRadioOnOffUI();
  1632. if (bStatus == false) {
  1633. mCommandFailed = CMD_FMOFF;
  1634. Log.e(LOGTAG, " mService.fmOff failed");
  1635. }
  1636. }catch (RemoteException e) {
  1637. e.printStackTrace();
  1638. }
  1639. }
  1640. }
  1641. private void resetRadio() {
  1642. boolean bSpeakerPhoneOn = isSpeakerEnabled();
  1643. resetSearch();
  1644. endSleepTimer();
  1645. if (mRecording) {
  1646. //Stop if there is an ongoing Record
  1647. stopRecording();
  1648. }
  1649. if (mService != null) {
  1650. try {
  1651. mService.fmRadioReset();
  1652. enableRadioOnOffUI(false);
  1653. Log.e(LOGTAG, "Done with reset, restarting FM");
  1654. /* Start Turn ON sequence again */
  1655. mOnOffButton.setEnabled(false);
  1656. mOnOffButton.setClickable(false);
  1657. mOnOffButton.setOnClickListener(null);
  1658. mDisableRadioHandler.removeCallbacks(mDisableRadioTask);
  1659. mEnableRadioHandler.removeCallbacks(mEnableRadioTask);
  1660. mEnableRadioHandler.postDelayed(mEnableRadioTask, 0);
  1661. cleanupTimeoutHandler();
  1662. Log.e(LOGTAG, "Done with restart");
  1663. }catch (RemoteException e) {
  1664. e.printStackTrace();
  1665. }
  1666. }
  1667. }
  1668. public void clearStationList() {
  1669. SharedPreferences sp = getSharedPreferences(SCAN_STATION_PREFS_NAME, 0);
  1670. SharedPreferences.Editor editor = sp.edit();
  1671. editor.clear();
  1672. editor.commit();
  1673. }
  1674. public boolean fmConfigure() {
  1675. boolean bStatus = true;
  1676. if(mService != null) {
  1677. try {
  1678. bStatus = mService.fmReconfigure();
  1679. if (bStatus == false) {
  1680. mCommandFailed = CMD_FMCONFIGURE;
  1681. Log.e(LOGTAG, "mService.fmReconfigure failed");
  1682. }else {
  1683. }
  1684. }catch (RemoteException e) {
  1685. e.printStackTrace();
  1686. }
  1687. }
  1688. return bStatus;
  1689. }
  1690. public void fmAutoAFSwitch() {
  1691. boolean bStatus = false;
  1692. if (mService != null) {
  1693. try {
  1694. bStatus = mService.enableAutoAF(FmSharedPreferences.getAutoAFSwitch());
  1695. if (bStatus == false) {
  1696. mCommandFailed = CMD_SET_AUTOAF;
  1697. Log.e(LOGTAG, " mService.enableAutoAF failed");
  1698. }
  1699. }catch (RemoteException e) {
  1700. e.printStackTrace();
  1701. }
  1702. }
  1703. }
  1704. public void fmAudioOutputMode() {
  1705. boolean bStatus = false;
  1706. if (mService != null) {
  1707. try {
  1708. bStatus = mService.enableStereo(FmSharedPreferences.getAudioOutputMode());
  1709. if (bStatus == false) {
  1710. mCommandFailed = CMD_SET_AUDIO_MODE;
  1711. Log.e(LOGTAG, "mService.enableStereo failed");
  1712. }
  1713. }catch (RemoteException e) {
  1714. e.printStackTrace();
  1715. }
  1716. }
  1717. }
  1718. private void startRecording() {
  1719. if(mService != null) {
  1720. try {
  1721. mService.startRecording();
  1722. } catch (RemoteException e) {
  1723. e.printStackTrace();
  1724. }
  1725. }
  1726. }
  1727. private void setRecordingStopImage() {
  1728. if(null != mRecordingMsgTV) {
  1729. mRecordingMsgTV.setCompoundDrawablesWithIntrinsicBounds
  1730. (R.drawable.recorder_stop, 0, 0, 0);
  1731. }
  1732. }
  1733. private void setRecordingStartImage() {
  1734. if(null != mRecordingMsgTV) {
  1735. mRecordingMsgTV.setCompoundDrawablesWithIntrinsicBounds
  1736. (R.drawable.recorder_start, 0, 0, 0);
  1737. }
  1738. }
  1739. private void startRecordingTimer() {
  1740. mRecording = true;
  1741. int durationInMins = FmSharedPreferences.getRecordDuration();
  1742. Log.e(LOGTAG, " Fected duration:" + durationInMins );
  1743. initiateRecordDurationTimer( durationInMins );
  1744. setRecordingStopImage();
  1745. invalidateOptionsMenu();
  1746. }
  1747. private void stopRecording() {
  1748. mRecording = false;
  1749. DebugToasts("Stopped Recording", Toast.LENGTH_SHORT);
  1750. if(null != mRecordUpdateHandlerThread) {
  1751. mRecordUpdateHandlerThread.interrupt();
  1752. }
  1753. if(null != mRecordingMsgTV) {
  1754. mRecordingMsgTV.setText("");
  1755. setRecordingStartImage();
  1756. }
  1757. if (mService != null) {
  1758. try {
  1759. mService.stopRecording();
  1760. }catch (RemoteException e) {
  1761. e.printStackTrace();
  1762. }
  1763. }
  1764. invalidateOptionsMenu();
  1765. }
  1766. private boolean isRecording() {
  1767. mRecording = false;
  1768. if (mService != null) {
  1769. try {
  1770. mRecording = mService.isFmRecordingOn();
  1771. }catch (RemoteException e) {
  1772. e.printStackTrace();
  1773. }
  1774. }
  1775. return(mRecording);
  1776. }
  1777. private boolean isSpeakerEnabled() {
  1778. boolean speakerEnabled = false;
  1779. if (mService != null) {
  1780. try {
  1781. speakerEnabled = mService.isSpeakerEnabled();
  1782. }catch (RemoteException e) {
  1783. e.printStackTrace();
  1784. }
  1785. }
  1786. return(speakerEnabled);
  1787. }
  1788. private boolean stationExists(PresetStation station ){
  1789. boolean exists = FmSharedPreferences.sameStationExists(station);
  1790. if(exists){
  1791. Toast t = Toast.makeText(this, getString(R.string.station_exists), Toast.LENGTH_SHORT);
  1792. t.show();
  1793. }
  1794. return exists;
  1795. }
  1796. private void addToPresets() {
  1797. int currentList = FmSharedPreferences.getCurrentListIndex();
  1798. PresetStation selectedStation = getCurrentTunedStation();
  1799. if(!stationExists(selectedStation)) {
  1800. FmSharedPreferences.addStation(selectedStation.getName(), selectedStation
  1801. .getFrequency(), currentList);
  1802. setupPresetLayout();
  1803. }
  1804. }
  1805. private void enableRadioOnOffUI() {
  1806. boolean bEnable = isFmOn();
  1807. /* Disable if no antenna/headset is available */
  1808. if (!isAntennaAvailable()) {
  1809. bEnable = false;
  1810. }
  1811. enableRadioOnOffUI(bEnable);
  1812. }
  1813. private void enableRadioOnOffUI(boolean bEnable) {
  1814. if (mMuteButton != null) {
  1815. mMuteButton.setEnabled(bEnable);
  1816. setMuteModeButtonImage(false);
  1817. }
  1818. if (bEnable) {
  1819. if (mRadioTextScroller != null) {
  1820. mRadioTextScroller.startScroll();
  1821. }
  1822. if (mERadioTextScroller != null) {
  1823. mERadioTextScroller.startScroll();
  1824. }
  1825. if (mTuneStationFrequencyTV != null) {
  1826. mTuneStationFrequencyTV.setOnLongClickListener(mFrequencyViewClickListener);
  1827. }
  1828. invalidateOptionsMenu();
  1829. if ((mRecordingMsgTV != null) && !isRecording()) {
  1830. mRecordingMsgTV.setText("");
  1831. }
  1832. if(isRecording()) {
  1833. setRecordingStopImage();
  1834. }else {
  1835. setRecordingStartImage();
  1836. }
  1837. for (int nButton = 0; nButton < MAX_PRESETS_PER_PAGE; nButton++) {
  1838. if (mPresetButtons[nButton] != null) {
  1839. mPresetButtons[nButton].setTextColor(Color.WHITE);
  1840. }
  1841. }
  1842. }else {
  1843. if (mRadioTextScroller != null) {
  1844. mRadioTextScroller.stopScroll();
  1845. }
  1846. if (mERadioTextScroller != null) {
  1847. mERadioTextScroller.stopScroll();
  1848. }
  1849. for (int nButton = 0; nButton < MAX_PRESETS_PER_PAGE; nButton++) {
  1850. if (mPresetButtons[nButton] != null) {
  1851. mPresetButtons[nButton].setTextColor(Color.BLACK);
  1852. }
  1853. }
  1854. }
  1855. if (mForwardButton != null) {
  1856. mForwardButton.setVisibility(((bEnable == true) ? View.VISIBLE
  1857. : View.INVISIBLE));
  1858. }
  1859. if (mBackButton != null) {
  1860. mBackButton.setVisibility(((bEnable == true) ? View.VISIBLE
  1861. : View.INVISIBLE));
  1862. }
  1863. if (mTuneStationFrequencyTV != null) {
  1864. mTuneStationFrequencyTV.setVisibility(((bEnable == true) ? View.VISIBLE
  1865. : View.INVISIBLE));
  1866. }
  1867. if (mPicker != null) {
  1868. mPicker.setVisibility(
  1869. bEnable ?

View.VISIBLE : View.INVISIBLE ); } if (mStationCallSignTV != null) { mStationCallSignTV.setVisibility(((bEnable == true) ? View.VISIBLE : View.INVISIBLE)); } if (mProgramTypeTV != null) { mProgramTypeTV.setVisibility(((bEnable == true) ?

View.VISIBLE : View.INVISIBLE)); } if (mSleepMsgTV != null) { mSleepMsgTV.setVisibility(((bEnable && isSleepTimerActive()) ? View.VISIBLE : View.INVISIBLE)); } if (mRecordingMsgTV != null) { mRecordingMsgTV.setVisibility(((bEnable == true) ? View.VISIBLE : View.INVISIBLE)); } if (mRadioTextTV != null) { mRadioTextTV.setVisibility(((bEnable == true) ? View.VISIBLE : View.INVISIBLE)); } if(mERadioTextTV != null) { mERadioTextTV.setVisibility(((bEnable == true) ?

View.VISIBLE : View.INVISIBLE)); } if (mProgramServiceTV != null) { mProgramServiceTV.setVisibility(((bEnable == true) ? View.VISIBLE : View.INVISIBLE)); } if (!isAntennaAvailable()) { if (mRadioTextTV != null) { mRadioTextTV.setVisibility(View.VISIBLE); mRadioTextTV.setText(getString(R.string.msg_noantenna)); mRadioTextScroller.mOriginalString = getString(R.string.msg_noantenna); } if (mOnOffButton != null) { mOnOffButton.setEnabled(false); } }else if (isCallActive()) { if (mRadioTextTV != null) { mRadioTextTV.setText(""); mRadioTextScroller.mOriginalString = ""; } if (mERadioTextTV != null) { mERadioTextTV.setText(""); mERadioTextScroller.mOriginalString = ""; } if (mOnOffButton != null) { mOnOffButton.setEnabled(false); } }else { if (mRadioTextTV != null) { mRadioTextTV.setText(""); mRadioTextScroller.mOriginalString = ""; } if (mERadioTextTV != null) { mERadioTextTV.setText(""); mERadioTextScroller.mOriginalString = ""; } if (mOnOffButton != null) { mOnOffButton.setEnabled(true); } } if (mStereoTV != null) { mStereoTV.setVisibility(((bEnable == true) ? View.VISIBLE : View.INVISIBLE)); } for (int nButton = 0; nButton < MAX_PRESETS_PER_PAGE; nButton++) { if (mPresetButtons[nButton] != null) { mPresetButtons[nButton].setEnabled(bEnable); } } if (mPresetListButton != null) { mPresetListButton.setEnabled(bEnable); } if (mPresetPageButton != null) { mPresetPageButton.setEnabled(bEnable && (FmSharedPreferences.getListStationCount() >= MAX_PRESETS_PER_PAGE)); } if(mSpeakerButton != null) { mSpeakerButton.setEnabled(bEnable); if (bEnable) { if(isSpeakerEnabled()) { mSpeakerButton.setImageResource(R.drawable.btn_speaker); }else { mSpeakerButton.setImageResource(R.drawable.btn_earphone); } }else{ mSpeakerButton.setImageResource(R.drawable.btn_earphone); } } } private void resetSearchProgress() { Message msg = new Message(); msg.what = END_PROGRESS_DLG; mSearchProgressHandler.sendMessage(msg); } 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); } } private void setupPresetLayout() { int numStations = FmSharedPreferences.getListStationCount(); int addedStations = 0; /* * Validate mPresetPageNumber (Preset Page Number) */ if (mPresetPageNumber > ((numStations) / MAX_PRESETS_PER_PAGE)) { mPresetPageNumber = 0; } /* * For every station, save the station as a tag and update the display * on the preset Button. */ for (int buttonIndex = 0; (buttonIndex < MAX_PRESETS_PER_PAGE); buttonIndex++) { if (mPresetButtons[buttonIndex] != null) { mPresetButtons[buttonIndex].setHeight(-1); int stationIdex = (mPresetPageNumber * MAX_PRESETS_PER_PAGE) + buttonIndex; PresetStation station = FmSharedPreferences.getStationInList(stationIdex); String display = ""; if (station != null) { display = station.getName(); if (display.length() > 6) display = display.substring(0,6)+"..."; mPresetButtons[buttonIndex].setEllipsize(TextUtils.TruncateAt.END); mPresetButtons[buttonIndex].setText(display); mPresetButtons[buttonIndex].setTag(station); addedStations++; }else { mPresetButtons[buttonIndex].setText(R.string.add_station); mPresetButtons[buttonIndex].setTag(station); } } } } 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(); } private boolean isFmOn() { boolean bOn = false; if(mService != null) { try { bOn = mService.isFmOn(); }catch (RemoteException e) { e.printStackTrace(); } } return(bOn); } private boolean isAnalogModeEnabled() { boolean aEnabled = false; if (mService != null) { try { aEnabled = mService.isAnalogModeEnabled(); }catch (RemoteException e) { e.printStackTrace(); } } return (aEnabled); } private boolean isMuted() { boolean bMuted = false; if (mService != null) { try { bMuted = mService.isMuted(); }catch (RemoteException e) { e.printStackTrace(); } } return(bMuted); } private boolean isScanActive() { return(mIsScaning); } private boolean isSeekActive() { return(mIsSeeking); } private boolean isSearchActive() { return(mIsSearching); } public PresetStation getCurrentTunedStation() { return mTunedStation; } private void SeekPreviousStation() { Log.d(LOGTAG, "SeekPreviousStation"); if (mService != null) { try { if(!isSeekActive()) { mIsSeeking = mService.seek(false); if (mIsSeeking == false) { mCommandFailed = CMD_SEEK; Log.e(LOGTAG, "mService.seek failed"); showDialog(DIALOG_CMD_FAILED); } } }catch (RemoteException e) { e.printStackTrace(); } } updateSearchProgress(); } private void SeekNextStation() { Log.d(LOGTAG, "SeekNextStation"); if(mService != null) { try { if(!isSeekActive()) { mIsSeeking = mService.seek(true); if (mIsSeeking == false) { mCommandFailed = CMD_SEEK; Log.e(LOGTAG, "mService.seek failed"); showDialog(DIALOG_CMD_FAILED); } } }catch (RemoteException e) { e.printStackTrace(); } } updateSearchProgress(); } /** Scan related */ private void initiateSearch(int pty) { synchronized (this) { mIsScaning = true; if(mService != null) { try { mIsScaning = mService.scan(pty); if (mIsScaning == false) { mCommandFailed = CMD_SCAN; Log.e(LOGTAG, "mService.scan failed"); showDialog(DIALOG_CMD_FAILED); }else { mScanPty = pty; } }catch (RemoteException e) { e.printStackTrace(); } updateSearchProgress(); } } } /** SEEK Station with the matching PI */ private void initiatePISearch(int pi) { Log.d(LOGTAG, "initiatePISearch"); if(mService != null) { try { if(!isSeekActive()) { mIsSeeking = mService.seekPI(pi); if (mIsSeeking == false) { mCommandFailed = CMD_SEEKPI; Log.e(LOGTAG, "mService.seekPI failed"); showDialog(DIALOG_CMD_FAILED); } } }catch (RemoteException e) { e.printStackTrace(); } } updateSearchProgress(); } private void resetSearch() { mIsScaning = false; mIsSeeking = false; mIsSearching = false; resetSearchProgress(); } private void cancelSearch() { synchronized (this) { if (mService != null) { try { if ((mIsScaning == true) || (mIsSeeking == true) || (mIsSearching == true)) { mService.cancelSearch(); mIsScaning = false; mIsSeeking = false; mIsSearching=false; } }catch (RemoteException e) { e.printStackTrace(); } } } updateSearchProgress(); invalidateOptionsMenu(); } /** get Strongest Stations */ private void initiateSearchList() { synchronized (this) { mIsSearching = false; if (mService != null) { try { mIsSearching = mService.searchStrongStationList(NUM_AUTO_PRESETS_SEARCH); if (mIsSearching == false) { mCommandFailed = CMD_SEARCHLIST; Log.e(LOGTAG, "mService.searchStrongStationList failed"); showDialog(DIALOG_CMD_FAILED); } }catch (RemoteException e) { e.printStackTrace(); } updateSearchProgress(); } } } private static final int UPDATE_PROGRESS_DLG = 1; private static final int END_PROGRESS_DLG = 2; private static final int TIMEOUT_PROGRESS_DLG = 3; private static final int SHOWBUSY_TIMEOUT = 300000; 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(); } } }; /** Sleep Handling: After the timer expires, the app needs to shut down */ private static final int SLEEPTIMER_EXPIRED = 0x1001; private static final int SLEEPTIMER_UPDATE = 0x1002; private Thread mSleepUpdateHandlerThread = null; /* * Phone time when the App has to be shut down, calculated based on what the * user configured */ private static long mSleepAtPhoneTime = 0; private void initiateSleepTimer(long seconds) { mSleepAtPhoneTime = (SystemClock.elapsedRealtime()) + (seconds * 1000); Log.d(LOGTAG, "Sleep in seconds: " + seconds); initiateSleepThread(); } private void initiateSleepThread() { if (mSleepUpdateHandlerThread == null) { mSleepUpdateHandlerThread = new Thread(null, doSleepProcessing, "SleepUpdateThread"); } /* Launch he dummy thread to simulate the transfer progress */ Log.d(LOGTAG, "Thread State: " + mSleepUpdateHandlerThread.getState()); if (mSleepUpdateHandlerThread.getState() == Thread.State.TERMINATED) { mSleepUpdateHandlerThread = new Thread(null, doSleepProcessing, "SleepUpdateThread"); } /* If the thread state is "new" then the thread has not yet started */ if(mSleepUpdateHandlerThread.getState() != Thread.State.TERMINATED && isFmOn()) { try { if((mService != null) && !mService.isSleepTimerActive()) { long timeNow = ((SystemClock.elapsedRealtime())); if(timeNow < mSleepAtPhoneTime) { mService.delayedStop((mSleepAtPhoneTime - timeNow), FMRadioService.STOP_SERVICE); } } mSleepUpdateHandlerThread.start(); }catch(Exception e) { e.printStackTrace(); } } } private void endSleepTimer() { mSleepAtPhoneTime = 0; try { if(mService != null) { mService.cancelDelayedStop(FMRadioService.STOP_SERVICE); } }catch(RemoteException e) { e.printStackTrace(); } if(null != mSleepUpdateHandlerThread) { mSleepUpdateHandlerThread.interrupt(); } if(null != mSleepMsgTV) { mSleepMsgTV.setVisibility(View.INVISIBLE); } } private boolean hasSleepTimerExpired() { boolean expired = true; if (isSleepTimerActive()) { long timeNow = ((SystemClock.elapsedRealtime())); if (timeNow < mSleepAtPhoneTime) { expired = false; } } return expired; } private boolean isSleepTimerActive() { boolean active = false; try { if((mService != null) && (mService.isSleepTimerActive()) && (mSleepAtPhoneTime > 0)) { active = true; Log.d(LOGTAG, "Sleeptimer is active"); }else { } }catch(RemoteException e) { e.printStackTrace(); } return active; } private void updateExpiredSleepTime() { int vis = View.INVISIBLE; if (isSleepTimerActive()) { long timeNow = ((SystemClock.elapsedRealtime())); if (mSleepAtPhoneTime >= timeNow) { long seconds = (mSleepAtPhoneTime - timeNow) / 1000; String sleepMsg = makeTimeString(seconds); mSleepMsgTV.setText(sleepMsg); if (seconds < SLEEP_TOGGLE_SECONDS) { int nowVis = mSleepMsgTV.getVisibility(); vis = (nowVis == View.INVISIBLE) ?

View.VISIBLE : View.INVISIBLE; }else { vis = View.VISIBLE; } }else { /* Clean up timer */ mSleepAtPhoneTime = 0; } } mSleepMsgTV.setVisibility(vis); } private Handler mUIUpdateHandlerHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case SLEEPTIMER_EXPIRED: { mSleepAtPhoneTime = 0; DebugToasts("Turning Off FM Radio", Toast.LENGTH_SHORT); disableRadio(); return; } case SLEEPTIMER_UPDATE: { updateExpiredSleepTime(); break; } case RECORDTIMER_EXPIRED: { Log.d(LOGTAG, "mUIUpdateHandlerHandler - RECORDTIMER_EXPIRED"); //Clear the Recorder text mRecordingMsgTV.setText(""); if (mRecording != false) { DebugToasts("Stop Recording", Toast.LENGTH_SHORT); stopRecording(); } return; } case RECORDTIMER_UPDATE: { Log.d(LOGTAG, "mUIUpdateHandlerHandler - RECORDTIMER_UPDATE"); updateExpiredRecordTime(); break; } default: break; } super.handleMessage(msg); } }; /* Thread processing */ private Runnable doSleepProcessing = new Runnable() { public void run() { boolean sleepTimerExpired = hasSleepTimerExpired(); while ((sleepTimerExpired == false) && (!Thread.currentThread().isInterrupted())) { try { Thread.sleep(500); Message statusUpdate = new Message(); statusUpdate.what = SLEEPTIMER_UPDATE; Log.d(LOGTAG, "SLEEP TIMER UPDATE"); mUIUpdateHandlerHandler.sendMessage(statusUpdate); sleepTimerExpired = hasSleepTimerExpired(); }catch (Exception ex) { Log.d( LOGTAG, "RunningThread InterruptedException"); break; } } if(true == sleepTimerExpired) { Message finished = new Message(); finished.what = SLEEPTIMER_EXPIRED; mUIUpdateHandlerHandler.sendMessage(finished); } } }; private static StringBuilder sFormatBuilder = new StringBuilder(); private static Formatter sFormatter = new Formatter(sFormatBuilder, Locale .getDefault()); private static final Object[] sTimeArgs = new Object[5]; private String makeTimeString(long secs) { String durationformat = getString(R.string.durationformat); /* * Provide multiple arguments so the format can be changed easily by * modifying the xml. */ sFormatBuilder.setLength(0); final Object[] timeArgs = sTimeArgs; timeArgs[0] = secs / 3600; timeArgs[1] = secs / 60; timeArgs[2] = (secs / 60) % 60; timeArgs[3] = secs; timeArgs[4] = secs % 60; return sFormatter.format(durationformat, timeArgs).toString(); } private void tuneRadio(int frequency){ /* Issue the tune command only if tuneCommand is already not active */ if((mService != null) && (mCommandActive != CMD_TUNE) && isFmOn()) { boolean bStatus = false; try { bStatus = mService.tune(frequency); if (bStatus) { postTimeoutHandler(CMD_TUNE); }else { if (isFmOn()) { mCommandFailed = CMD_TUNE; Log.e(LOGTAG, "mService.tune failed"); showDialog(DIALOG_CMD_FAILED); } } mTunedStation.setName(""); mTunedStation.setPI(0); mTunedStation.setPty(0); updateStationInfoToUI(); }catch (RemoteException e) { e.printStackTrace(); } }else { Log.e(LOGTAG, "Delayed Tune handler stopped"); } } /* Start a Command timeout */ private synchronized void postTimeoutHandler(int cmd){ mCommandActive = cmd; mCommandTimeoutHandler.sendEmptyMessageDelayed(MSG_CMD_TIMEOUT, CMD_TIMEOUT_DELAY_MS); } /* Stop the Command timeout */ private synchronized void cleanupTimeoutHandler(){ mCommandActive = CMD_NONE; mCommandTimeoutHandler.removeMessages(MSG_CMD_TIMEOUT); } /* Command timeout Handler Routine to handle the Command timeouts for FM operations that return asynchronous event callbacks */ private Handler mCommandTimeoutHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_CMD_TIMEOUT: { if (mCommandActive > 0) { Log.d(LOGTAG, "mCommandTimeoutHandler: Cmd failed: " + mCommandActive); mCommandTimeoutHandler.removeMessages(MSG_CMD_TIMEOUT); showDialog(DIALOG_CMD_TIMEOUT); return; } break; }//case MSG_CMD_TIMEOUT }//switch }//handleMessage }; @Override public boolean onKeyDown(int keyCode, KeyEvent event) { Log.d(LOGTAG, "KEY event received" + 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 super.onKeyDown(keyCode, event); } private void resetFMStationInfoUI() { mTunedStation.setFrequency(FmSharedPreferences.getTunedFrequency()); mTunedStation.setName(""); mTunedStation.setPI(0); mTunedStation.setRDSSupported(false); mTunedStation.setPty(0); mRadioTextTV.setText(""); mERadioTextTV.setText(""); mRadioTextScroller.mOriginalString = ""; mProgramServiceTV.setText(""); mRadioTextScroller.stopScroll(); mERadioTextScroller.mOriginalString = ""; mERadioTextScroller.stopScroll(); mUpdatePickerValue = true; updateStationInfoToUI(); } Runnable mRadioEnabled = new Runnable() { public void run() { /* Update UI to FM On State */ enableRadioOnOffUI(true); /* Tune to the last tuned frequency */ mUpdatePickerValue = true; tuneRadio(FmSharedPreferences.getTunedFrequency()); } }; Runnable mRadioDisabled = new Runnable() { public void run() { /* Update UI to FM Off State */ cleanupTimeoutHandler(); endSleepTimer(); stopRecording(); cancelSearch(); enableRadioOnOffUI(false); } }; Runnable mRadioReset = new Runnable() { public void run() { /* Update UI to FM Reset (Off) State */ resetRadio(); } }; Runnable mUpdateStationInfo = new Runnable() { public void run() { cleanupTimeoutHandler(); PresetStation station = new PresetStation("", FmSharedPreferences.getTunedFrequency()); if (station != null) { mTunedStation.Copy(station); } updateSearchProgress(); resetFMStationInfoUI(); } }; Runnable mSearchComplete = new Runnable() { public void run() { Log.d(LOGTAG, "mSearchComplete: "); mScanPty=0; mScanPtyIndex = 0; mIsScaning = false; mIsSeeking = false; mIsSearching = false; updateSearchProgress(); resetFMStationInfoUI(); invalidateOptionsMenu(); } }; Runnable mOnMute = new Runnable() { public void run() { setMuteModeButtonImage(true); } }; Runnable mOnStereo = new Runnable() { public void run() { if (FMRADIO_UI_STATION_AUDIO_STEREO == mStereo) { if ((Locale.getDefault().toString().equals("zh_HK"))) mStereoTV.setText("立體聲"); else mStereoTV.setText(R.string.audio_type_stereo); } else if (FMRADIO_UI_STATION_AUDIO_MONO == mStereo) { if ((Locale.getDefault().toString().equals("zh_HK"))) mStereoTV.setText("單聲道"); else mStereoTV.setText(R.string.audio_type_mono); }else { mStereoTV.setText(""); } FmSharedPreferences.setLastAudioMode(mStereo); } }; Runnable mUpdateRadioText = new Runnable() { public void run() { String str = ""; if ((mService != null) && isFmOn()) { try { /* Get Radio Text and update the display */ str = mService.getRadioText(); /* Update only if all the characters are printable */ if (TextUtils.isPrintableAsciiOnly(str)) { Log.d(LOGTAG, "mUpdateRadioText: Updatable string: [" + str + "]"); mRadioTextTV.setText(str); mRadioTextScroller.mOriginalString = str; }else if(TextUtils.isEmpty(str)) { /* Rest the string to empty*/ mRadioTextTV.setText(""); mRadioTextScroller.mOriginalString = ""; }else { //Log.d(LOGTAG, "mUpdateRadioText: Leaving old string " + mRadioTextTV.getText()); } /* Get PTY and PI and update the display */ int tempInt = mService.getProgramType(); /* Save PTY */ mTunedStation.setPty(tempInt); mProgramTypeTV.setText(PresetStation.parsePTY(tempInt)); tempInt = mService.getProgramID(); mStationCallSignTV.setText(PresetStation.parsePI(tempInt)); if (tempInt != 0) { mTunedStation.setPI(tempInt); } /* For non-Empty, non-Printable string, just leave the existing old string */ mRadioTextScroller.startScroll(); }catch (RemoteException e) { e.printStackTrace(); } } } }; Runnable mRadioChangeFrequency = new Runnable(){ public void run() { mUpdatePickerValue = false; tuneRadio(mFrequency); } }; Runnable mUpdateExtenRadioText = new Runnable() { public void run() { String str = ""; if ((mService != null) && isFmOn()) { try { /* Get Extended Radio Text and update the display */ str = mService.getExtenRadioText(); if (TextUtils.isEmpty(str)) { mERadioTextTV.setText(""); mERadioTextScroller.mOriginalString = ""; }else { mERadioTextTV.setText(str); mERadioTextScroller.mOriginalString = str; } mERadioTextScroller.startScroll(); }catch (RemoteException e) { e.printStackTrace(); } } } }; /* Create runnable for posting */ Runnable mUpdateProgramService = new Runnable() { public void run() { String str = ""; if (mService != null) { try { /* Get the Station PS and update the display */ str = mService.getProgramService(); /* Update only if all the characters are printable */ //if(isStringPrintable(str)) if (TextUtils.isPrintableAsciiOnly(str)) { Log.d(LOGTAG, "mUpdateProgramService: Updatable string: [" + str + "]"); mProgramServiceTV.setText(str); }else if (TextUtils.isEmpty(str)) { /* Rest the string to empty*/ mProgramServiceTV.setText(""); }else { /* For non-Empty, non-Printable string, just leave the existing old string */ } /* Get PTY and PI and update the display */ int tempInt = mService.getProgramType(); /* Save PTY */ mTunedStation.setPty(tempInt); mProgramTypeTV.setText(PresetStation.parsePTY(tempInt)); tempInt =mService.getProgramID(); /* Save the program ID */ if (tempInt != 0) { mTunedStation.setPI(tempInt); } mStationCallSignTV.setText(PresetStation.parsePI(tempInt)); }catch (RemoteException e) { e.printStackTrace(); } } } }; private void DebugToasts(String str, int duration) { //Toast.makeText(this, str, duration).show(); Log.d(LOGTAG, "Debug:" + str); } /** * This Handler will scroll the text view. * On startScroll, the scrolling starts after SCROLLER_START_DELAY_MS * The Text View is scrolled left one character after every * SCROLLER_UPDATE_DELAY_MS * When the entire text is scrolled, the scrolling will restart * after SCROLLER_RESTART_DELAY_MS */ private final class ScrollerText extends Handler { private static final byte SCROLLER_STOPPED = 0x51; private static final byte SCROLLER_STARTING = 0x52; private static final byte SCROLLER_RUNNING = 0x53; private static final int SCROLLER_MSG_START = 0xF1; private static final int SCROLLER_MSG_TICK = 0xF2; private static final int SCROLLER_MSG_RESTART = 0xF3; private static final int SCROLLER_START_DELAY_MS = 1000; private static final int SCROLLER_RESTART_DELAY_MS = 3000; private static final int SCROLLER_UPDATE_DELAY_MS = 200; private final WeakReference<TextView> mView; private byte mStatus = SCROLLER_STOPPED; String mOriginalString; int mStringlength = 0; int mIteration = 0; ScrollerText(TextView v) { mView = new WeakReference<TextView>(v); } /** * Scrolling Message Handler */ @Override public void handleMessage(Message msg) { switch (msg.what) { case SCROLLER_MSG_START: mStatus = SCROLLER_RUNNING; updateText(); break; case SCROLLER_MSG_TICK: updateText(); break; case SCROLLER_MSG_RESTART: if (mStatus == SCROLLER_RUNNING) { startScroll(); } break; } } /** * Moves the text left by one character and posts a * delayed message for next update after SCROLLER_UPDATE_DELAY_MS. * If the entire string is scrolled, then it displays the entire string * and waits for SCROLLER_RESTART_DELAY_MS for scrolling restart */ void updateText() { if (mStatus != SCROLLER_RUNNING) { return; } removeMessages(SCROLLER_MSG_TICK); TextView textView = mView.get(); if (textView != null) { mStringlength = mOriginalString.length(); String szStr2 = ""; if (mStringlength > 0) { mIteration++; if (mIteration >= mStringlength) { mIteration = 0; sendEmptyMessageDelayed(SCROLLER_MSG_RESTART, SCROLLER_RESTART_DELAY_MS); }else { sendEmptyMessageDelayed(SCROLLER_MSG_TICK, SCROLLER_UPDATE_DELAY_MS); } if ((mOriginalString !=null) && (mOriginalString.length() >= mIteration)) szStr2 = mOriginalString.substring(mIteration); } textView.setText(szStr2); } } /** * Stops the scrolling * The textView will be set to the original string. */ void stopScroll() { mStatus = SCROLLER_STOPPED; removeMessages(SCROLLER_MSG_TICK); removeMessages(SCROLLER_MSG_RESTART); removeMessages(SCROLLER_MSG_START); resetScroll(); } /** * Resets the scroll to display the original string. */ private void resetScroll() { mIteration = 0; TextView textView = mView.get(); if (textView != null) { textView.setText(mOriginalString); } } /** Starts the Scrolling of the TextView after a * delay of SCROLLER_START_DELAY_MS * Starts only if Length > 0 */ void startScroll() { TextView textView = mView.get(); if (textView != null) { mOriginalString = textView.getText().toString(); mStringlength = mOriginalString.length(); if (mStringlength > 0) { mStatus = SCROLLER_STARTING; sendEmptyMessageDelayed(SCROLLER_MSG_START, SCROLLER_START_DELAY_MS); } } } } public IFMRadioService sService = null; private HashMap<Context, ServiceBinder> sConnectionMap = new HashMap<Context, ServiceBinder>(); public boolean bindToService(Context context) { Log.e(LOGTAG, "bindToService: Context"); return bindToService(context, null); } public boolean bindToService(Context context, ServiceConnection callback) { Log.e(LOGTAG, "bindToService: Context with serviceconnection callback"); context.startService(new Intent(context, FMRadioService.class)); ServiceBinder sb = new ServiceBinder(callback); sConnectionMap.put(context, sb); return context.bindService((new Intent()).setClass(context, FMRadioService.class), sb, 0); } public void unbindFromService(Context context) { ServiceBinder sb = (ServiceBinder) sConnectionMap.remove(context); Log.e(LOGTAG, "unbindFromService: Context"); if (sb == null) { Log.e(LOGTAG, "Trying to unbind for unknown Context"); return; } context.unbindService(sb); if (sConnectionMap.isEmpty()) { // presumably there is nobody interested in the service at this point, // so don't hang on to the ServiceConnection sService = null; } } private class ServiceBinder implements ServiceConnection { ServiceConnection mCallback; ServiceBinder(ServiceConnection callback) { mCallback = callback; } public void onServiceConnected(ComponentName className, android.os.IBinder service) { sService = IFMRadioService.Stub.asInterface(service); if (mCallback != null) { Log.e(LOGTAG, "onServiceConnected: mCallback"); mCallback.onServiceConnected(className, service); } } public void onServiceDisconnected(ComponentName className) { if (mCallback != null) { mCallback.onServiceDisconnected(className); } sService = null; mService = null; } } private ServiceConnection osc = new ServiceConnection() { public void onServiceConnected(ComponentName classname, IBinder obj) { mService = IFMRadioService.Stub.asInterface(obj); Log.e(LOGTAG, "ServiceConnection: onServiceConnected: "); if (mService != null) { try { mService.registerCallbacks(mServiceCallbacks); if (SavedDataAndState == null) { enableRadio(); }else if (isFmOn()) { enableRadioOnOffUI(true); }else { enableRadioOnOffUI(false); } }catch (RemoteException e) { e.printStackTrace(); } if (isRecording()) { initiateRecordThread(); } if(isSleepTimerActive()) { initiateSleepThread(); } return; }else { Log.e(LOGTAG, "IFMRadioService onServiceConnected failed"); } if (getIntent().getData() == null) { Intent intent = new Intent(Intent.ACTION_MAIN); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setClass(FMRadio.this, FMRadio.class); startActivity(intent); } finish(); } public void onServiceDisconnected(ComponentName classname) { Log.d(LOGTAG, "Service got disconnected"); unbindFromService(FMRadio.this); mService = null; sService = null; } }; private IFMRadioServiceCallbacks.Stub mServiceCallbacks = new IFMRadioServiceCallbacks.Stub() { public void onEnabled() { Log.d(LOGTAG, "mServiceCallbacks.onEnabled :"); mHandler.post(mRadioEnabled); } public void onDisabled() { Log.d(LOGTAG, "mServiceCallbacks.onDisabled :"); mHandler.post(mRadioDisabled); } public void onRadioReset() { Log.d(LOGTAG, "mServiceCallbacks.onRadioReset :"); mHandler.post(mRadioReset); } 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); } public void onProgramServiceChanged() { Log.d(LOGTAG, "mServiceCallbacks.onProgramServiceChanged :"); mHandler.post(mUpdateProgramService); } public void onRadioTextChanged() { Log.d(LOGTAG, "mServiceCallbacks.onRadioTextChanged :"); mHandler.post(mUpdateRadioText); } public void onExtenRadioTextChanged() { mHandler.post(mUpdateExtenRadioText); } public void onAlternateFrequencyChanged() { Log.d(LOGTAG, "mServiceCallbacks.onAlternateFrequencyChanged :"); } public void onSignalStrengthChanged() { Log.d(LOGTAG, "mServiceCallbacks.onSignalStrengthChanged :"); } public void onSearchComplete() { Log.d(LOGTAG, "mServiceCallbacks.onSearchComplete :"); mScanPty = 0; mScanPtyIndex = 0; mIsScaning = false; mIsSeeking = false; mIsSearching = false; mHandler.post(mSearchComplete); } public void onSearchListComplete() { Log.d(LOGTAG, "mServiceCallbacks.onSearchListComplete :"); } public void onMute(boolean bMuted) { Log.d(LOGTAG, "mServiceCallbacks.onMute :" + bMuted); mHandler.post(mOnMute); } public void onAudioUpdate(boolean bStereo) { if((bStereo) && (FmSharedPreferences.getAudioOutputMode())) { mStereo = FMRADIO_UI_STATION_AUDIO_STEREO; }else { mStereo = FMRADIO_UI_STATION_AUDIO_MONO; } Log.d(LOGTAG, "mServiceCallbacks.onAudioUpdate :" + mStereo); mHandler.post(mOnStereo); } public void onStationRDSSupported(boolean bRDSSupported) { Log.d(LOGTAG, "mServiceCallbacks.onStationRDSSupported :" + bRDSSupported); /* * Depending on the signal strength etc, RDS Lock Sync/Supported may toggle, * Since if a station Supports RDS, it will not change its support intermittently * just save the status and ignore any "unsupported" state. */ if (bRDSSupported) { mTunedStation.setRDSSupported(true); } } public void onRecordingStopped() { Log.d(LOGTAG, "mServiceCallbacks.onRecordingStopped:"); stopRecording(); } public void onRecordingStarted() { Log.d(LOGTAG, "mServiceCallbacks.onRecordingStarted:"); startRecordingTimer(); } }; private void registerFMSettingListner() { if (mFmSettingReceiver == null) { mFmSettingReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d(LOGTAG, "Received intent " + intent); String action = intent.getAction(); Log.d(LOGTAG, " action = " + action); if (action.equals(Settings.ACTION_FM_SETTING)) { int state = intent.getIntExtra("state", 0); Log.d(LOGTAG, "ACTION_FM_SETTING Intent received" + state); switch(state) { case Settings.FM_BAND_CHANGED: fmConfigure(); break; case Settings.FM_CHAN_SPACING_CHANGED: fmConfigure(); break; case Settings.FM_AF_OPTION_CHANGED: fmAutoAFSwitch(); break; case Settings.FM_AUDIO_MODE_CHANGED: fmAudioOutputMode(); break; } } } }; IntentFilter iFilter = new IntentFilter(); iFilter.addAction(Settings.ACTION_FM_SETTING); registerReceiver(mFmSettingReceiver, iFilter); } } private void unRegisterReceiver(BroadcastReceiver myReceiver) { if(myReceiver != null) { unregisterReceiver(myReceiver); myReceiver = null; } } }


3、FMMediaButtonIntentReceiver.java文件就是对接收到的定时广播做出响应

  1. package com.caf.fmradio;
  2. import android.content.Intent;
  3. import android.content.IntentFilter;
  4. import android.app.IntentService;
  5. import android.content.BroadcastReceiver;
  6. import android.content.pm.PackageManager;
  7. import android.content.Context;
  8. import android.content.ComponentName;
  9. import android.media.AudioManager;
  10. import android.util.Log;
  11. import android.view.KeyEvent;
  12. import android.os.Bundle;
  13. import java.lang.Object;
  14. public class FMMediaButtonIntentReceiver extends BroadcastReceiver {
  15. private static final String TAG = "FMMediaButtonIntentReceiver";
  16. public static final String FM_MEDIA_BUTTON = "com.caf.fmradio.action.MEDIA_BUTTON";
  17. public static final String AUDIO_BECOMING_NOISY = "com.caf.fmradio.action.AUDIO_BECOMING_NOISY";
  18. public static final String ALARM_FM = "android.intent.action_WAKE_UP";//20150326 added by lisineng for wakeup FM
  19. public void onReceive(Context context, Intent intent) {
  20. String action = intent.getAction();
  21. //20150326 added by lisineng for wakeup FM
  22. if (action.equals(ALARM_FM)) {
  23. Log.i(TAG, "lsn mReceive action = android.media.action_WAKE_UP");
  24. Intent intent_Alarm = new Intent();
  25. intent_Alarm.putExtra("fromBroadcast", true);
  26. intent_Alarm.setClass(context, FMRadio.class);
  27. intent_Alarm.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  28. context.startActivity(intent_Alarm);
  29. }
  30. //added end
  31. if ((action != null) && action.equals(AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
  32. Log.d(TAG, "ACTION_AUDIO_BECOMING_NOISY intent received for ACTION_HEADSET_PLUG");
  33. Intent i = new Intent(AUDIO_BECOMING_NOISY);
  34. context.sendBroadcast(i);
  35. } else if ((action != null) && action.equals("android.intent.action.MEDIA_BUTTON")) {
  36. KeyEvent event = (KeyEvent)
  37. intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
  38. if (event == null) {
  39. return;
  40. }
  41. int keycode = event.getKeyCode();
  42. int key_action = event.getAction();
  43. if (((KeyEvent.KEYCODE_HEADSETHOOK == keycode) &&
  44. (key_action == KeyEvent.ACTION_DOWN)) ||
  45. (KeyEvent.KEYCODE_MEDIA_PAUSE == keycode) ||
  46. (KeyEvent.KEYCODE_MEDIA_PLAY == keycode)) {
  47. Log.d(TAG, "ACTION_MEDIA_BUTTON intent received for ACTION_DOWN");
  48. Intent i = new Intent(FM_MEDIA_BUTTON);
  49. i.putExtra(Intent.EXTRA_KEY_EVENT, event);
  50. context.sendBroadcast(i);
  51. }
  52. }
  53. }
  54. }

4、对广播的注冊AndroidManifest.xml

  1. <receiver android:name="com.caf.fmradio.FMMediaButtonIntentReceiver">
  2. <intent-filter>
  3. <action android:name="android.intent.action.MEDIA_BUTTON" />
  4. <action android:name="android.media.AUDIO_BECOMING_NOISY" />
  5. <action android:name="android.intent.action_WAKE_UP" /><!-- 20150326 added by lisineng for wakeup FM -->
  6. </intent-filter>
  7. </receiver>

5、对话框数组的定义arrays.xml

  1. <!-- 20150326 added by lisineng for wakeup FM-->
  2. <string-array name="wakeup_duration_values">
  3. <item>15 minutes</item>
  4. <item>30 minutes</item>
  5. <item>45 minutes</item>
  6. <item>1 Hour</item>
  7. </string-array>
  8. <!-- added end -->
6、对话框的title和menu的字符串

  1. <!--20150326 added by lisineng for X1_Qmobile wakeup FM-->
  2. <string name="menu_wakeup">Wakeup</string>
  3. <string name="menu_wakeup_cancel">Cancel wakeup</string>
  4. <string name="dialog_wakeup_title">Select Auto-Wakeup Time</string>
  5. <!-- added end -->

收音机增加自己主动唤醒功能
1、加入两个菜单项。利用hasWakeup状态的推断。显示唤醒还是取消;
2、当启用自己主动唤醒功能时,弹出选择时间对话框给用户,并利用AlarmManager.RTC_WAKEUP
在设定的时间给系统发一个无序广播。

程序在收到这个广播之后启动FMRadio
在启动的时候推断是否有耳机。假设有则打开收音机。没有则仅仅是将FMRadio拉起。
3、要注意的地方就是对打开FM的时候要推断是自己主动唤醒的还是用户点击launcher启动的。


对于hasWakeuo状态的推断来决定menu的显示。



转载于:https://www.cnblogs.com/ljbguanli/p/6955817.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/377048
推荐阅读
相关标签
  

闽ICP备14008679号