blob: b162627d8a0f5dc7420c221be640691a7ffe3c7d [file] [log] [blame]
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05301/*
2 * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of The Linux Foundation nor
12 * the names of its contributors may be used to endorse or promote
13 * products derived from this software without specific prior written
14 * permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29package com.caf.fmradio;
30
31import java.io.File;
32import java.util.*;
33import java.io.IOException;
34import java.lang.ref.WeakReference;
35
36import android.app.AlarmManager;
37import android.app.Notification;
38import android.app.NotificationManager;
39import android.app.PendingIntent;
40import android.app.Service;
41import android.content.Context;
42import android.content.Intent;
43import android.content.IntentFilter;
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +053044import android.app.IntentService;
45import android.os.UserHandle;
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +053046import android.content.BroadcastReceiver;
47import android.media.AudioManager;
48import android.media.AudioManager.OnAudioFocusChangeListener;
49import android.media.AudioSystem;
50import android.media.MediaRecorder;
51import android.os.Environment;
52import android.os.Handler;
53import android.os.IBinder;
54import android.os.Message;
55import android.os.PowerManager;
56import android.os.PowerManager.WakeLock;
57import android.os.RemoteException;
58import android.telephony.PhoneStateListener;
59import android.telephony.TelephonyManager;
60import android.util.Log;
61import android.widget.RemoteViews;
62import android.widget.Toast;
63import android.view.KeyEvent;
64import android.os.SystemProperties;
65
66import qcom.fmradio.FmReceiver;
67import qcom.fmradio.FmRxEvCallbacksAdaptor;
68import qcom.fmradio.FmRxRdsData;
69import qcom.fmradio.FmConfig;
70import android.net.Uri;
71import android.content.res.Resources;
72import java.util.Date;
73import java.text.SimpleDateFormat;
74import android.provider.MediaStore;
75import android.content.ContentResolver;
76import android.content.ContentValues;
77import android.database.Cursor;
78import com.caf.utils.A2dpDeviceStatus;
79import android.media.AudioManager;
80import android.content.ComponentName;
81import android.os.StatFs;
82import android.os.SystemClock;
83
84/**
85 * Provides "background" FM Radio (that uses the hardware) capabilities,
86 * allowing the user to switch between activities without stopping playback.
87 */
88public class FMRadioService extends Service
89{
90
91 public static final int RADIO_AUDIO_DEVICE_WIRED_HEADSET = 0;
92 public static final int RADIO_AUDIO_DEVICE_SPEAKER = 1;
93
94 private static final int FMRADIOSERVICE_STATUS = 101;
95 private static final String FMRADIO_DEVICE_FD_STRING = "/dev/radio0";
96 private static final String LOGTAG = "FMService";//FMRadio.LOGTAG;
97
98 private FmReceiver mReceiver;
99 private BroadcastReceiver mHeadsetReceiver = null;
100 private BroadcastReceiver mSdcardUnmountReceiver = null;
101 private BroadcastReceiver mMusicCommandListener = null;
102 private BroadcastReceiver mSleepExpiredListener = null;
Ayaz Ahmad594e34a2013-09-12 17:04:29 +0530103 private boolean mSleepActive = false;
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530104 private BroadcastReceiver mRecordTimeoutListener = null;
105 private BroadcastReceiver mDelayedServiceStopListener = null;
106 private boolean mOverA2DP = false;
107 private BroadcastReceiver mFmMediaButtonListener;
108 private IFMRadioServiceCallbacks mCallbacks;
109 private static FmSharedPreferences mPrefs;
110 private boolean mHeadsetPlugged = false;
111 private boolean mInternalAntennaAvailable = false;
112 private WakeLock mWakeLock;
113 private int mServiceStartId = -1;
114 private boolean mServiceInUse = false;
115 private static boolean mMuted = false;
116 private static boolean mResumeAfterCall = false;
117 private static String mAudioDevice="headset";
118 MediaRecorder mRecorder = null;
119 MediaRecorder mA2dp = null;
120 private boolean mFMOn = false;
121 private boolean mFmRecordingOn = false;
122 private boolean mSpeakerPhoneOn = false;
123 private int mCallStatus = 0;
124 private BroadcastReceiver mScreenOnOffReceiver = null;
125 final Handler mHandler = new Handler();
126 private boolean misAnalogModeSupported = false;
127 private boolean misAnalogPathEnabled = false;
128 private boolean mA2dpDisconnected = false;
129 //PhoneStateListener instances corresponding to each
130
131 private FmRxRdsData mFMRxRDSData=null;
132 // interval after which we stop the service when idle
133 private static final int IDLE_DELAY = 60000;
134 private File mA2DPSampleFile = null;
135 //Track FM playback for reenter App usecases
136 private boolean mPlaybackInProgress = false;
137 private boolean mStoppedOnFocusLoss = false;
138 private File mSampleFile = null;
139 long mSampleStart = 0;
140 // Messages handled in FM Service
141 private static final int FM_STOP =1;
142 private static final int RESET_NOTCH_FILTER =2;
143 private static final int STOPSERVICE_ONSLEEP = 3;
144 private static final int STOPRECORD_ONTIMEOUT = 4;
145 private static final int FOCUSCHANGE = 5;
146 //Track notch filter settings
147 private boolean mNotchFilterSet = false;
148 public static final int STOP_SERVICE = 0;
149 public static final int STOP_RECORD = 1;
150 // A2dp Device Status will be queried through this class
151 A2dpDeviceStatus mA2dpDeviceState = null;
152 private boolean mA2dpDeviceSupportInHal = false;
153 //on shutdown not to send start Intent to AudioManager
154 private boolean mAppShutdown = false;
155 private boolean mSingleRecordingInstanceSupported = false;
156 private AudioManager mAudioManager;
157 public static final long UNAVAILABLE = -1L;
158 public static final long PREPARING = -2L;
159 public static final long UNKNOWN_SIZE = -3L;
160 public static final long LOW_STORAGE_THRESHOLD = 50000000;
161 private long mStorageSpace;
162 private static final String IOBUSY_UNVOTE = "com.android.server.CpuGovernorService.action.IOBUSY_UNVOTE";
163 private static final String SLEEP_EXPIRED_ACTION = "com.caf.fmradio.SLEEP_EXPIRED";
164 private static final String RECORD_EXPIRED_ACTION = "com.caf.fmradio.RECORD_TIMEOUT";
165 private static final String SERVICE_DELAYED_STOP_ACTION = "com.caf.fmradio.SERVICE_STOP";
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530166 public static final String ACTION_FM =
167 "codeaurora.intent.action.FM";
168 public static final String ACTION_FM_RECORDING =
169 "codeaurora.intent.action.FM_Recording";
170 public static final String ACTION_FM_RECORDING_STATUS =
171 "codeaurora.intent.action.FM.Recording.Status";
172 private BroadcastReceiver mFmRecordingStatus = null;
173 static final int RECORD_START = 1;
174 static final int RECORD_STOP = 0;
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530175
176 public FMRadioService() {
177 }
178
179 @Override
180 public void onCreate() {
181 super.onCreate();
182
183 mPrefs = new FmSharedPreferences(this);
184 mCallbacks = null;
185 TelephonyManager tmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
186 tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE |
187 PhoneStateListener.LISTEN_DATA_ACTIVITY);
188 PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
189 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
190 mWakeLock.setReferenceCounted(false);
191 misAnalogModeSupported = SystemProperties.getBoolean("ro.fm.analogpath.supported",false);
192 /* Register for Screen On/off broadcast notifications */
193 mA2dpDeviceState = new A2dpDeviceStatus(getApplicationContext());
194 registerScreenOnOffListener();
195 registerHeadsetListener();
196 registerSleepExpired();
197 registerRecordTimeout();
198 registerDelayedServiceStop();
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530199 registerFMRecordingStatus();
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530200 // registering media button receiver seperately as we need to set
201 // different priority for receiving media events
202 registerFmMediaButtonReceiver();
203 if ( false == SystemProperties.getBoolean("ro.fm.mulinst.recording.support",true)) {
204 mSingleRecordingInstanceSupported = true;
205 }
206
207 // Register for pause commands from other apps to stop FM
208 registerMusicServiceCommandReceiver();
209
210 // If the service was idle, but got killed before it stopped itself, the
211 // system will relaunch it. Make sure it gets stopped again in that case.
212 setAlarmDelayedServiceStop();
213 /* Query to check is a2dp supported in Hal */
214 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
215 String valueStr = audioManager.getParameters("isA2dpDeviceSupported");
216 mA2dpDeviceSupportInHal = valueStr.contains("=true");
217 Log.d(LOGTAG, " is A2DP device Supported In HAL"+mA2dpDeviceSupportInHal);
218 }
219
220 @Override
221 public void onDestroy() {
222 Log.d(LOGTAG, "onDestroy");
223 if (isFmOn())
224 {
225 Log.e(LOGTAG, "Service being destroyed while still playing.");
226 }
227
228 // make sure there aren't any other messages coming
229 mDelayedStopHandler.removeCallbacksAndMessages(null);
230 cancelAlarms();
231 //release the audio focus listener
232 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
233 if (isMuted()) {
234 mMuted = false;
235 audioManager.setStreamMute(AudioManager.STREAM_MUSIC,false);
236 }
237 audioManager.abandonAudioFocus(mAudioFocusListener);
238 /* Remove the Screen On/off listener */
239 if (mScreenOnOffReceiver != null) {
240 unregisterReceiver(mScreenOnOffReceiver);
241 mScreenOnOffReceiver = null;
242 }
243 /* Unregister the headset Broadcase receiver */
244 if (mHeadsetReceiver != null) {
245 unregisterReceiver(mHeadsetReceiver);
246 mHeadsetReceiver = null;
247 }
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530248 if( mMusicCommandListener != null ) {
249 unregisterReceiver(mMusicCommandListener);
250 mMusicCommandListener = null;
251 }
252 if( mFmMediaButtonListener != null ) {
253 unregisterReceiver(mFmMediaButtonListener);
254 mFmMediaButtonListener = null;
255 }
256 if (mSleepExpiredListener != null ) {
257 unregisterReceiver(mSleepExpiredListener);
258 mSleepExpiredListener = null;
259 }
260 if (mRecordTimeoutListener != null) {
261 unregisterReceiver(mRecordTimeoutListener);
262 mRecordTimeoutListener = null;
263 }
264 if (mDelayedServiceStopListener != null) {
265 unregisterReceiver(mDelayedServiceStopListener);
266 mDelayedServiceStopListener = null;
267 }
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530268 if (mFmRecordingStatus != null ) {
269 unregisterReceiver(mFmRecordingStatus);
270 mFmRecordingStatus = null;
271 }
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530272 /* Since the service is closing, disable the receiver */
273 fmOff();
274
275 TelephonyManager tmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
276 tmgr.listen(mPhoneStateListener, 0);
277
278 Log.d(LOGTAG, "onDestroy: unbindFromService completed");
279
280 //unregisterReceiver(mIntentReceiver);
281 mWakeLock.release();
282 super.onDestroy();
283 }
284
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530285 public void registerFMRecordingStatus() {
286 if (mFmRecordingStatus == null) {
287 mFmRecordingStatus = new BroadcastReceiver() {
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530288 @Override
289 public void onReceive(Context context, Intent intent) {
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530290 Log.d(LOGTAG, "received intent " +intent);
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530291 String action = intent.getAction();
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530292 if (action.equals(ACTION_FM_RECORDING_STATUS)) {
293 Log.d(LOGTAG, "ACTION_FM_RECORDING_STATUS Intent received");
294 int state = intent.getIntExtra("state", 0);
295 if (state == RECORD_START) {
296 Log.d(LOGTAG, "FM Recording started");
297 mFmRecordingOn = true;
Ayaz Ahmad613e5832013-08-01 19:57:19 +0530298 mSampleStart = SystemClock.elapsedRealtime();
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530299 try {
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530300 if ((mServiceInUse) && (mCallbacks != null) ) {
301 Log.d(LOGTAG, "start recording thread");
302 mCallbacks.onRecordingStarted();
303 }
304 } catch (RemoteException e) {
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530305 e.printStackTrace();
306 }
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530307 } else if (state == RECORD_STOP) {
308 Log.d(LOGTAG, "FM Recording stopped");
309 mFmRecordingOn = false;
310 try {
311 if ((mServiceInUse) && (mCallbacks != null) ) {
312 mCallbacks.onRecordingStopped();
313 }
314 } catch (RemoteException e) {
315 e.printStackTrace();
316 }
Ayaz Ahmad613e5832013-08-01 19:57:19 +0530317 mSampleStart = 0;
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530318 }
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530319 }
320 }
321 };
322 IntentFilter iFilter = new IntentFilter();
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530323 iFilter.addAction(ACTION_FM_RECORDING_STATUS);
324 registerReceiver(mFmRecordingStatus , iFilter);
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530325 }
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530326 }
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530327
328 /**
329 * Registers an intent to listen for ACTION_HEADSET_PLUG
330 * notifications. This intent is called to know if the headset
331 * was plugged in/out
332 */
333 public void registerHeadsetListener() {
334 if (mHeadsetReceiver == null) {
335 mHeadsetReceiver = new BroadcastReceiver() {
336 @Override
337 public void onReceive(Context context, Intent intent) {
338 String action = intent.getAction();
339 if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
340 Log.d(LOGTAG, "ACTION_HEADSET_PLUG Intent received");
341 // Listen for ACTION_HEADSET_PLUG broadcasts.
342 Log.d(LOGTAG, "mReceiver: ACTION_HEADSET_PLUG");
343 Log.d(LOGTAG, "==> intent: " + intent);
344 Log.d(LOGTAG, " state: " + intent.getIntExtra("state", 0));
345 Log.d(LOGTAG, " name: " + intent.getStringExtra("name"));
346 mHeadsetPlugged = (intent.getIntExtra("state", 0) == 1);
347 // if headset is plugged out it is required to disable
348 // in minimal duration to avoid race conditions with
349 // audio policy manager switch audio to speaker.
350 mHandler.removeCallbacks(mHeadsetPluginHandler);
351 mHandler.post(mHeadsetPluginHandler);
352 } else if(mA2dpDeviceState.isA2dpStateChange(action) ) {
353 boolean bA2dpConnected =
354 mA2dpDeviceState.isConnected(intent);
355 if (!bA2dpConnected) {
356 Log.d(LOGTAG, "A2DP device is dis-connected!");
357 mA2dpDisconnected = true;
358 } else {
359 mA2dpDisconnected = false;
360 }
361 if (isAnalogModeEnabled()) {
362 Log.d(LOGTAG, "FM Audio Path is Analog Mode: FM Over BT not allowed");
363 return ;
364 }
365 //when playback is overA2Dp and A2dp disconnected
366 //when playback is not overA2DP and A2DP Connected
367 // In above two cases we need to Stop and Start FM which
368 // will take care of audio routing
369 if( (isFmOn()) &&
370 (true == ((bA2dpConnected)^(mOverA2DP))) &&
371 (false == mStoppedOnFocusLoss) &&
372 (!isSpeakerEnabled())) {
373 stopFM();
374 startFM();
375 }
376 } else if (action.equals("HDMI_CONNECTED")) {
377 //FM should be off when HDMI is connected.
378 fmOff();
379 try
380 {
381 /* Notify the UI/Activity, only if the service is "bound"
382 by an activity and if Callbacks are registered
383 */
384 if((mServiceInUse) && (mCallbacks != null) )
385 {
386 mCallbacks.onDisabled();
387 }
388 } catch (RemoteException e)
389 {
390 e.printStackTrace();
391 }
392 } else if( action.equals(Intent.ACTION_SHUTDOWN)) {
393 mAppShutdown = true;
394 }
395
396 }
397 };
398 IntentFilter iFilter = new IntentFilter();
399 iFilter.addAction(Intent.ACTION_HEADSET_PLUG);
400 iFilter.addAction(mA2dpDeviceState.getActionSinkStateChangedString());
401 iFilter.addAction("HDMI_CONNECTED");
402 iFilter.addAction(Intent.ACTION_SHUTDOWN);
403 iFilter.addCategory(Intent.CATEGORY_DEFAULT);
404 registerReceiver(mHeadsetReceiver, iFilter);
405 }
406 }
407
408 public void registerFmMediaButtonReceiver() {
409 if (mFmMediaButtonListener == null) {
410 mFmMediaButtonListener = new BroadcastReceiver() {
411 public void onReceive(Context context, Intent intent) {
412 Log.d(LOGTAG, "FMMediaButtonIntentReceiver.FM_MEDIA_BUTTON");
413 Log.d(LOGTAG, "KeyEvent = " +intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
414 String action = intent.getAction();
415 if (action.equals(FMMediaButtonIntentReceiver.FM_MEDIA_BUTTON)) {
416 KeyEvent event = (KeyEvent)
417 intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
418 int keycode = event.getKeyCode();
419 switch (keycode) {
420 case KeyEvent.KEYCODE_HEADSETHOOK :
421 if (isFmOn()){
422 //FM should be off when Headset hook pressed.
423 fmOff();
424 if (isOrderedBroadcast()) {
425 abortBroadcast();
426 }
427 try {
428 /* Notify the UI/Activity, only if the service is "bound"
429 by an activity and if Callbacks are registered
430 */
431 if ((mServiceInUse) && (mCallbacks != null) ) {
432 mCallbacks.onDisabled();
433 }
434 } catch (RemoteException e) {
435 e.printStackTrace();
436 }
437 } else if( mServiceInUse ) {
438 fmOn();
439 if (isOrderedBroadcast()) {
440 abortBroadcast();
441 }
442 try {
443 /* Notify the UI/Activity, only if the service is "bound"
444 by an activity and if Callbacks are registered
445 */
446 if (mCallbacks != null ) {
447 mCallbacks.onEnabled();
448 }
449 } catch (RemoteException e) {
450 e.printStackTrace();
451 }
452 }
453 break;
454 case KeyEvent.KEYCODE_MEDIA_PAUSE :
455 if (isFmOn()){
456 //FM should be off when Headset hook pressed.
457 fmOff();
458 if (isOrderedBroadcast()) {
459 abortBroadcast();
460 }
461 try {
462 /* Notify the UI/Activity, only if the service is "bound"
463 by an activity and if Callbacks are registered
464 */
465 if ((mServiceInUse) && (mCallbacks != null) ) {
466 mCallbacks.onDisabled();
467 }
468 } catch (RemoteException e) {
469 e.printStackTrace();
470 }
471 }
472 break;
473 case KeyEvent.KEYCODE_MEDIA_PLAY:
Venkateshwarlu Domakondac0f384c2013-09-05 18:15:13 +0530474 if (isAntennaAvailable() && mServiceInUse) {
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530475 fmOn();
476 if (isOrderedBroadcast()) {
477 abortBroadcast();
478 }
479 try {
480 /* Notify the UI/Activity, only if the service is "bound"
481 by an activity and if Callbacks are registered
482 */
483 if (mCallbacks != null ) {
484 mCallbacks.onEnabled();
485 }
486 } catch (RemoteException e) {
487 e.printStackTrace();
488 }
489 }
490 break;
491 } // end of switch
492 } // end of FMMediaButtonIntentReceiver.FM_MEDIA_BUTTON
493 } // end of onReceive
494 };
495 IntentFilter iFilter = new IntentFilter();
496 iFilter.addAction(FMMediaButtonIntentReceiver.FM_MEDIA_BUTTON);
497 registerReceiver(mFmMediaButtonListener, iFilter);
498 }
499 }
500
501 public void registerMusicServiceCommandReceiver() {
502 if (mMusicCommandListener == null) {
503 mMusicCommandListener = new BroadcastReceiver() {
504 @Override
505 public void onReceive(Context context, Intent intent) {
506 String action = intent.getAction();
507
508 if (action.equals("com.android.music.musicservicecommand")) {
509 String cmd = intent.getStringExtra("command");
510 Log.d(LOGTAG, "Music Service command : "+cmd+ " received");
511 if (cmd != null && cmd.equals("pause")) {
512 if (mA2dpDisconnected) {
513 Log.d(LOGTAG, "not to pause,this is a2dp disconnected's pause");
514 mA2dpDisconnected = false;
515 return;
516 }
517 if(isFmOn()){
518 fmOff();
519 if (isOrderedBroadcast()) {
520 abortBroadcast();
521 }
522 try {
523 /* Notify the UI/Activity, only if the service is "bound"
524 by an activity and if Callbacks are registered
525 */
526 if((mServiceInUse) && (mCallbacks != null) ){
527 mCallbacks.onDisabled();
528 }
529 } catch (RemoteException e) {
530 e.printStackTrace();
531 }
532 }
533 }
534 }
535 }
536 };
537 IntentFilter commandFilter = new IntentFilter();
538 commandFilter.addAction("com.android.music.musicservicecommand");
539 registerReceiver(mMusicCommandListener, commandFilter);
540 }
541 }
542 public void registerSleepExpired() {
543 if (mSleepExpiredListener == null) {
544 mSleepExpiredListener = new BroadcastReceiver() {
545 @Override
546 public void onReceive(Context context, Intent intent) {
547 Log.d(LOGTAG, "registerSleepExpired");
548 mWakeLock.acquire(10 * 1000);
549 fmOff();
550 }
551 };
552 IntentFilter intentFilter = new IntentFilter(SLEEP_EXPIRED_ACTION);
553 registerReceiver(mSleepExpiredListener, intentFilter);
554 }
555 }
556 public void registerRecordTimeout() {
557 if (mRecordTimeoutListener == null) {
558 mRecordTimeoutListener = new BroadcastReceiver() {
559 @Override
560 public void onReceive(Context context, Intent intent) {
561 Log.d(LOGTAG, "registerRecordTimeout");
562 mWakeLock.acquire(5 * 1000);
563 stopRecording();
564 }
565 };
566 IntentFilter intentFilter = new IntentFilter(RECORD_EXPIRED_ACTION);
567 registerReceiver(mRecordTimeoutListener, intentFilter);
568 }
569 }
570 public void registerDelayedServiceStop() {
571 if (mDelayedServiceStopListener == null) {
572 mDelayedServiceStopListener = new BroadcastReceiver() {
573 @Override
574 public void onReceive(Context context, Intent intent) {
575 Log.d(LOGTAG, "registerDelayedServiceStop");
576 mWakeLock.acquire(5 * 1000);
577 if (isFmOn() || mServiceInUse) {
578 return;
579 }
580 stopSelf(mServiceStartId);
581 }
582 };
583 IntentFilter intentFilter = new IntentFilter(SERVICE_DELAYED_STOP_ACTION);
584 registerReceiver(mDelayedServiceStopListener, intentFilter);
585 }
586 }
587
588
589
590 final Runnable mHeadsetPluginHandler = new Runnable() {
591 public void run() {
592 /* Update the UI based on the state change of the headset/antenna*/
593 if(!isAntennaAvailable())
594 {
595 /* Disable FM and let the UI know */
596 fmOff();
597 try
598 {
599 /* Notify the UI/Activity, only if the service is "bound"
600 by an activity and if Callbacks are registered
601 */
602 if((mServiceInUse) && (mCallbacks != null) )
603 {
604 mCallbacks.onDisabled();
605 }
606 } catch (RemoteException e)
607 {
608 e.printStackTrace();
609 }
610 }
611 else
612 {
613 /* headset is plugged back in,
614 So turn on FM if:
615 - FM is not already ON.
616 - If the FM UI/Activity is in the foreground
617 (the service is "bound" by an activity
618 and if Callbacks are registered)
619 */
620 if ((!isFmOn()) && (mServiceInUse)
621 && (mCallbacks != null))
622 {
623 if( true != fmOn() ) {
624 return;
625 }
626 try
627 {
628 mCallbacks.onEnabled();
629 } catch (RemoteException e)
630 {
631 e.printStackTrace();
632 }
633 }
634 }
635 }
636 };
637
638
639 @Override
640 public IBinder onBind(Intent intent) {
641 mDelayedStopHandler.removeCallbacksAndMessages(null);
642 cancelAlarms();
643 mServiceInUse = true;
644 /* Application/UI is attached, so get out of lower power mode */
645 setLowPowerMode(false);
646 Log.d(LOGTAG, "onBind");
647 return mBinder;
648 }
649
650 @Override
651 public void onRebind(Intent intent) {
652 mDelayedStopHandler.removeCallbacksAndMessages(null);
Ayaz Ahmad594e34a2013-09-12 17:04:29 +0530653 cancelAlarmDealyedServiceStop();
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530654 mServiceInUse = true;
655 /* Application/UI is attached, so get out of lower power mode */
656 setLowPowerMode(false);
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530657 Log.d(LOGTAG, "onRebind");
658 }
659
660 @Override
661 public void onStart(Intent intent, int startId) {
662 Log.d(LOGTAG, "onStart");
663 mServiceStartId = startId;
664 // make sure the service will shut down on its own if it was
665 // just started but not bound to and nothing is playing
666 mDelayedStopHandler.removeCallbacksAndMessages(null);
Ayaz Ahmad594e34a2013-09-12 17:04:29 +0530667 cancelAlarmDealyedServiceStop();
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530668 setAlarmDelayedServiceStop();
669 }
670
671 @Override
672 public boolean onUnbind(Intent intent) {
673 mServiceInUse = false;
674 Log.d(LOGTAG, "onUnbind");
675
676 /* Application/UI is not attached, so go into lower power mode */
677 unregisterCallbacks();
678 setLowPowerMode(true);
679 if (isFmOn())
680 {
681 // something is currently playing, or will be playing once
682 // an in-progress call ends, so don't stop the service now.
683 return true;
684 }
685 gotoIdleState();
686 return true;
687 }
688
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530689 private void sendRecordIntent(int action) {
690 Intent intent = new Intent(ACTION_FM_RECORDING);
691 intent.putExtra("state", action);
Ayaz Ahmad613e5832013-08-01 19:57:19 +0530692 if(action == RECORD_START) {
693 int mRecordDuration = -1;
694 if(FmSharedPreferences.getRecordDuration() !=
695 FmSharedPreferences.RECORD_DUR_INDEX_3_VAL) {
696 mRecordDuration = (FmSharedPreferences.getRecordDuration() * 60 * 1000);
697 }
698 intent.putExtra("record_duration", mRecordDuration);
699 }
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530700 Log.d(LOGTAG, "Sending Recording intent for = " +action);
701 getApplicationContext().sendBroadcast(intent);
702 }
703
704 private void sendRecordServiceIntent(int action) {
705 Intent intent = new Intent(ACTION_FM);
706 intent.putExtra("state", action);
707 Log.d(LOGTAG, "Sending Recording intent for = " +action);
708 getApplicationContext().sendBroadcast(intent);
709 }
710
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530711 private void startFM(){
712 Log.d(LOGTAG, "In startFM");
713 if(true == mAppShutdown) { // not to send intent to AudioManager in Shutdown
714 return;
715 }
716 if (isCallActive()) { // when Call is active never let audio playback
717 mResumeAfterCall = true;
718 return;
719 }
720 mResumeAfterCall = false;
721 if ( true == mPlaybackInProgress ) // no need to resend event
722 return;
723 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
724 audioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
725 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
726 Log.d(LOGTAG,"FM registering for registerMediaButtonEventReceiver");
727 mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
728 ComponentName fmRadio = new ComponentName(this.getPackageName(),
729 FMMediaButtonIntentReceiver.class.getName());
730 mAudioManager.registerMediaButtonEventReceiver(fmRadio);
731 mStoppedOnFocusLoss = false;
732
733 if (!mA2dpDeviceSupportInHal && (true == mA2dpDeviceState.isDeviceAvailable()) &&
734 (!isSpeakerEnabled()) && !isAnalogModeEnabled()
735 && (true == startA2dpPlayback())) {
736 mOverA2DP=true;
737 } else {
738 Log.d(LOGTAG, "FMRadio: Requesting to start FM");
739 //reason for resending the Speaker option is we are sending
740 //ACTION_FM=1 to AudioManager, the previous state of Speaker we set
741 //need not be retained by the Audio Manager.
Ayaz Ahmad5dfffc02013-09-04 19:07:05 +0530742 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
743 AudioSystem.DEVICE_STATE_AVAILABLE, "");
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530744 if (isSpeakerEnabled()) {
Venkateshwarlu Domakonda7e348af2013-08-05 18:11:01 +0530745 mSpeakerPhoneOn = true;
746 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_SPEAKER);
747 } else {
748 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530749 }
Ayaz Ahmad5dfffc02013-09-04 19:07:05 +0530750
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530751 sendRecordServiceIntent(RECORD_START);
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530752 }
753 mPlaybackInProgress = true;
754 }
755
756 private void stopFM(){
757 Log.d(LOGTAG, "In stopFM");
758 if (mOverA2DP==true){
759 mOverA2DP=false;
760 stopA2dpPlayback();
761 }else{
762 Log.d(LOGTAG, "FMRadio: Requesting to stop FM");
763 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
764 AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
765 }
766 mPlaybackInProgress = false;
767 }
768
769 private void resetFM(){
770 Log.d(LOGTAG, "resetFM");
771 if (mOverA2DP==true){
772 mOverA2DP=false;
773 resetA2dpPlayback();
774 }else{
775 Log.d(LOGTAG, "FMRadio: Requesting to stop FM");
776 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
777 AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530778 sendRecordServiceIntent(RECORD_STOP);
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530779 }
780 mPlaybackInProgress = false;
781 }
782
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530783 public void startRecording() {
784
785 Log.d(LOGTAG, "In startRecording of Recorder");
786 if ((true == mSingleRecordingInstanceSupported) &&
787 (true == mOverA2DP )) {
788 Toast.makeText( this,
789 "playback on BT in progress,can't record now",
790 Toast.LENGTH_SHORT).show();
791 return;
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530792 }
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530793 sendRecordIntent(RECORD_START);
794 }
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530795
796 public boolean startA2dpPlayback() {
797 Log.d(LOGTAG, "In startA2dpPlayback");
798 if( (true == mSingleRecordingInstanceSupported) &&
799 (true == mFmRecordingOn )) {
800 Toast.makeText(this,
801 "Recording already in progress,can't play on BT",
802 Toast.LENGTH_SHORT).show();
803 return false;
804 }
805 if(mOverA2DP)
806 stopA2dpPlayback();
807 mA2dp = new MediaRecorder();
808 if (mA2dp == null) {
809 Toast.makeText(this,"A2dpPlayback failed to create an instance",
810 Toast.LENGTH_SHORT).show();
811 return false;
812 }
813 try {
814 mA2dp.setAudioSource(MediaRecorder.AudioSource.FM_RX_A2DP);
815 mA2dp.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
816 mA2dp.setAudioEncoder(MediaRecorder.OutputFormat.DEFAULT);
817 File sampleDir = new File(getFilesDir().getAbsolutePath());
818 try {
819 mA2DPSampleFile = File
820 .createTempFile("FMRecording", ".3gpp", sampleDir);
821 } catch (IOException e) {
822 Log.e(LOGTAG, "Not able to access Phone's internal memory");
823 Toast.makeText(this, "Not able to access Phone's internal memory",
824 Toast.LENGTH_SHORT).show();
825 return false;
826 }
827 mA2dp.setOutputFile(mA2DPSampleFile.getAbsolutePath());
828 mA2dp.prepare();
829 mA2dp.start();
830 } catch (Exception exception) {
831 mA2dp.reset();
832 mA2dp.release();
833 mA2dp = null;
834 return false;
835 }
836 return true;
837 }
838
839 public void stopA2dpPlayback() {
840 if (mA2dp == null)
841 return;
842 if(mA2DPSampleFile != null)
843 {
844 try {
845 mA2DPSampleFile.delete();
846 } catch (Exception e) {
847 Log.e(LOGTAG, "Not able to delete file");
848 }
849 }
850 try {
851 mA2dp.stop();
852 mA2dp.reset();
853 mA2dp.release();
854 mA2dp = null;
855 } catch (Exception exception ) {
856 Log.e( LOGTAG, "Stop failed with exception"+ exception);
857 }
858 return;
859 }
860
861 private void resetA2dpPlayback() {
862 if (mA2dp == null)
863 return;
864 if(mA2DPSampleFile != null)
865 {
866 try {
867 mA2DPSampleFile.delete();
868 } catch (Exception e) {
869 Log.e(LOGTAG, "Not able to delete file");
870 }
871 }
872 try {
873 // Send Intent for IOBUSY VOTE, because MediaRecorder.stop
874 // gets Activity context which might not be always available
875 // and would thus fail to send the intent.
876 Intent ioBusyUnVoteIntent = new Intent(IOBUSY_UNVOTE);
877 // Remove vote for io_is_busy to be turned off.
878 ioBusyUnVoteIntent.putExtra("com.android.server.CpuGovernorService.voteType", 0);
879 sendBroadcast(ioBusyUnVoteIntent);
880
881 mA2dp.stop();
882
883 mA2dp.reset();
884 mA2dp.release();
885 mA2dp = null;
886 } catch (Exception exception ) {
887 Log.e( LOGTAG, "Stop failed with exception"+ exception);
888 }
889 return;
890 }
891
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530892 public void stopRecording() {
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530893 if (!mFmRecordingOn)
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530894 return;
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +0530895 sendRecordIntent(RECORD_STOP);
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530896 return;
897 }
898
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530899 private void fmActionOnCallState( int state ) {
900 //if Call Status is non IDLE we need to Mute FM as well stop recording if
901 //any. Similarly once call is ended FM should be unmuted.
902 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
903 mCallStatus = state;
904
905 if((TelephonyManager.CALL_STATE_OFFHOOK == state)||
906 (TelephonyManager.CALL_STATE_RINGING == state)) {
907 if (state == TelephonyManager.CALL_STATE_RINGING) {
908 int ringvolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);
909 if (ringvolume == 0) {
910 return;
911 }
912 }
913 boolean bTempSpeaker = mSpeakerPhoneOn; //need to restore SpeakerPhone
914 boolean bTempMute = mMuted;// need to restore Mute status
915 int bTempCall = mCallStatus;//need to restore call status
Ayaz Ahmadb7cd23b2013-08-01 11:49:05 +0530916 if (isFmOn() && fmOff()) {
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +0530917 if((mServiceInUse) && (mCallbacks != null)) {
918 try {
919 mCallbacks.onDisabled();
920 } catch (RemoteException e) {
921 e.printStackTrace();
922 }
923 }
924 mResumeAfterCall = true;
925 mSpeakerPhoneOn = bTempSpeaker;
926 mCallStatus = bTempCall;
927 mMuted = bTempMute;
928 } else if (!mResumeAfterCall) {
929 mResumeAfterCall = false;
930 mSpeakerPhoneOn = bTempSpeaker;
931 mCallStatus = bTempCall;
932 mMuted = bTempMute;
933 }
934 }
935 else if (state == TelephonyManager.CALL_STATE_IDLE) {
936 // start playing again
937 if (mResumeAfterCall)
938 {
939 // resume playback only if FM Radio was playing
940 // when the call was answered
941 if (isAntennaAvailable() && (!isFmOn()) && mServiceInUse)
942 {
943 Log.d(LOGTAG, "Resuming after call:");
944 if(true != fmOn()) {
945 return;
946 }
947 mResumeAfterCall = false;
948 if(mCallbacks != null) {
949 try {
950 mCallbacks.onEnabled();
951 } catch (RemoteException e) {
952 e.printStackTrace();
953 }
954 }
955 }
956 }
957 }//idle
958 }
959
960 /* Handle Phone Call + FM Concurrency */
961 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
962 @Override
963 public void onCallStateChanged(int state, String incomingNumber) {
964 Log.d(LOGTAG, "onCallStateChanged: State - " + state );
965 Log.d(LOGTAG, "onCallStateChanged: incomingNumber - " + incomingNumber );
966 fmActionOnCallState(state );
967 }
968
969 @Override
970 public void onDataActivity (int direction) {
971 Log.d(LOGTAG, "onDataActivity - " + direction );
972 if (direction == TelephonyManager.DATA_ACTIVITY_NONE ||
973 direction == TelephonyManager.DATA_ACTIVITY_DORMANT) {
974 if (mReceiver != null) {
975 Message msg = mDelayedStopHandler.obtainMessage(RESET_NOTCH_FILTER);
976 mDelayedStopHandler.sendMessageDelayed(msg, 10000);
977 }
978 } else {
979 if (mReceiver != null) {
980 if( true == mNotchFilterSet )
981 {
982 mDelayedStopHandler.removeMessages(RESET_NOTCH_FILTER);
983 }
984 else
985 {
986 mReceiver.setNotchFilter(true);
987 mNotchFilterSet = true;
988 }
989 }
990 }
991 }
992 };
993
Ayaz Ahmadd405c1d2013-07-31 13:41:16 +0530994 private Handler mSpeakerDisableHandler = new Handler();
995
996 private Runnable mSpeakerDisableTask = new Runnable() {
997 public void run() {
998 Log.v(LOGTAG, "Disabling Speaker");
999 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);
1000 }
1001 };
1002
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05301003 private Handler mDelayedStopHandler = new Handler() {
1004 @Override
1005 public void handleMessage(Message msg) {
1006 switch (msg.what) {
1007 case FM_STOP:
1008 // Check again to make sure nothing is playing right now
1009 if (isFmOn() || mServiceInUse)
1010 {
1011 return;
1012 }
1013 Log.d(LOGTAG, "mDelayedStopHandler: stopSelf");
1014 stopSelf(mServiceStartId);
1015 break;
1016 case RESET_NOTCH_FILTER:
1017 if (mReceiver != null) {
1018 mReceiver.setNotchFilter(false);
1019 mNotchFilterSet = false;
1020 }
1021 break;
1022 case STOPSERVICE_ONSLEEP:
1023 fmOff();
1024 break;
1025 case STOPRECORD_ONTIMEOUT:
1026 stopRecording();
1027 break;
1028 case FOCUSCHANGE:
1029 if( false == isFmOn() ) {
1030 Log.v(LOGTAG, "FM is not running, not handling change");
1031 return;
1032 }
1033 switch (msg.arg1) {
1034 case AudioManager.AUDIOFOCUS_LOSS:
1035 Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS");
1036 //intentional fall through.
1037 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
1038 Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS_TRANSIENT");
Ayaz Ahmadd405c1d2013-07-31 13:41:16 +05301039 if (true == isFmRecordingOn())
1040 stopRecording();
1041 if (mSpeakerPhoneOn) {
1042 mSpeakerDisableHandler.removeCallbacks(mSpeakerDisableTask);
1043 mSpeakerDisableHandler.postDelayed(mSpeakerDisableTask, 0);
1044 }
1045 if (true == mPlaybackInProgress) {
Venkateshwarlu Domakonda7447ba72013-09-05 17:01:30 +05301046 fmOff();
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05301047 }
1048 mStoppedOnFocusLoss = true;
1049 break;
1050 case AudioManager.AUDIOFOCUS_GAIN:
1051 Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_GAIN");
1052 if(false == mPlaybackInProgress)
1053 startFM();
1054 mStoppedOnFocusLoss = false;
1055 break;
1056 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
1057 default:
1058 Log.e(LOGTAG, "Unknown audio focus change code"+msg.arg1);
1059 }
1060 break;
1061 }
1062 }
1063 };
1064
1065
1066 /**
1067 * Registers an intent to listen for
1068 * ACTION_SCREEN_ON/ACTION_SCREEN_OFF notifications. This intent
1069 * is called to know iwhen the screen is turned on/off.
1070 */
1071 public void registerScreenOnOffListener() {
1072 if (mScreenOnOffReceiver == null) {
1073 mScreenOnOffReceiver = new BroadcastReceiver() {
1074 @Override
1075 public void onReceive(Context context, Intent intent) {
1076 String action = intent.getAction();
1077 if (action.equals(Intent.ACTION_SCREEN_ON)) {
1078 Log.d(LOGTAG, "ACTION_SCREEN_ON Intent received");
1079 //Screen turned on, set FM module into normal power mode
1080 mHandler.post(mScreenOnHandler);
1081 }
1082 else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1083 Log.d(LOGTAG, "ACTION_SCREEN_OFF Intent received");
1084 //Screen turned on, set FM module into low power mode
1085 mHandler.post(mScreenOffHandler);
1086 }
1087 }
1088 };
1089 IntentFilter iFilter = new IntentFilter();
1090 iFilter.addAction(Intent.ACTION_SCREEN_ON);
1091 iFilter.addAction(Intent.ACTION_SCREEN_OFF);
1092 registerReceiver(mScreenOnOffReceiver, iFilter);
1093 }
1094 }
1095
1096 /* Handle all the Screen On actions:
1097 Set FM Power mode to Normal
1098 */
1099 final Runnable mScreenOnHandler = new Runnable() {
1100 public void run() {
1101 setLowPowerMode(false);
1102 }
1103 };
1104 /* Handle all the Screen Off actions:
1105 Set FM Power mode to Low Power
1106 This will reduce all the interrupts coming up from the SoC, saving power
1107 */
1108 final Runnable mScreenOffHandler = new Runnable() {
1109 public void run() {
1110 setLowPowerMode(true);
1111 }
1112 };
1113
1114 /* Show the FM Notification */
1115 public void startNotification() {
1116 RemoteViews views = new RemoteViews(getPackageName(), R.layout.statusbar);
1117 views.setImageViewResource(R.id.icon, R.drawable.stat_notify_fm);
1118 if (isFmOn())
1119 {
1120 views.setTextViewText(R.id.frequency, getTunedFrequencyString());
1121 } else
1122 {
1123 views.setTextViewText(R.id.frequency, "");
1124 }
1125
1126 Notification status = new Notification();
1127 status.contentView = views;
1128 status.flags |= Notification.FLAG_ONGOING_EVENT;
1129 status.icon = R.drawable.stat_notify_fm;
1130 status.contentIntent = PendingIntent.getActivity(this, 0,
1131 new Intent("com.caf.fmradio.FMRADIO_ACTIVITY"), 0);
1132 startForeground(FMRADIOSERVICE_STATUS, status);
1133 //NotificationManager nm = (NotificationManager)
1134 // getSystemService(Context.NOTIFICATION_SERVICE);
1135 //nm.notify(FMRADIOSERVICE_STATUS, status);
1136 //setForeground(true);
1137 mFMOn = true;
1138 }
1139
1140 private void stop() {
1141 Log.d(LOGTAG,"in stop");
1142 if (!mServiceInUse) {
1143 Log.d(LOGTAG,"calling unregisterMediaButtonEventReceiver in stop");
1144 mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1145 ComponentName fmRadio = new ComponentName(this.getPackageName(),
1146 FMMediaButtonIntentReceiver.class.getName());
1147 mAudioManager.unregisterMediaButtonEventReceiver(fmRadio);
1148 }
1149 gotoIdleState();
1150 mFMOn = false;
1151 }
1152
1153 private void gotoIdleState() {
1154 mDelayedStopHandler.removeCallbacksAndMessages(null);
1155 cancelAlarms();
1156 setAlarmDelayedServiceStop();
1157 stopForeground(true);
1158 }
1159
1160 /** Read's the internal Antenna available state from the FM
1161 * Device.
1162 */
1163 public void readInternalAntennaAvailable()
1164 {
1165 mInternalAntennaAvailable = false;
1166 if (mReceiver != null)
1167 {
1168 mInternalAntennaAvailable = mReceiver.getInternalAntenna();
1169 Log.d(LOGTAG, "getInternalAntenna: " + mInternalAntennaAvailable);
1170 }
1171 }
1172
1173 /*
1174 * By making this a static class with a WeakReference to the Service, we
1175 * ensure that the Service can be GCd even when the system process still
1176 * has a remote reference to the stub.
1177 */
1178 static class ServiceStub extends IFMRadioService.Stub
1179 {
1180 WeakReference<FMRadioService> mService;
1181
1182 ServiceStub(FMRadioService service)
1183 {
1184 mService = new WeakReference<FMRadioService>(service);
1185 }
1186
1187 public boolean fmOn() throws RemoteException
1188 {
1189 return(mService.get().fmOn());
1190 }
1191
1192 public boolean fmOff() throws RemoteException
1193 {
1194 return(mService.get().fmOff());
1195 }
1196
1197 public boolean fmRadioReset() throws RemoteException
1198 {
1199 return true;
1200 }
1201
1202 public boolean isFmOn()
1203 {
1204 return(mService.get().isFmOn());
1205 }
1206
1207 public boolean isAnalogModeEnabled()
1208 {
1209 return(mService.get().isAnalogModeEnabled());
1210 }
1211
1212 public boolean isFmRecordingOn()
1213 {
1214 return(mService.get().isFmRecordingOn());
1215 }
1216
1217 public boolean isSpeakerEnabled()
1218 {
1219 return(mService.get().isSpeakerEnabled());
1220 }
1221
1222 public boolean fmReconfigure()
1223 {
1224 return(mService.get().fmReconfigure());
1225 }
1226
1227 public void registerCallbacks(IFMRadioServiceCallbacks cb) throws RemoteException
1228 {
1229 mService.get().registerCallbacks(cb);
1230 }
1231
1232 public void unregisterCallbacks() throws RemoteException
1233 {
1234 mService.get().unregisterCallbacks();
1235 }
1236
1237 public boolean routeAudio(int device)
1238 {
1239 return(mService.get().routeAudio(device));
1240 }
1241
1242 public boolean mute()
1243 {
1244 return(mService.get().mute());
1245 }
1246
1247 public boolean unMute()
1248 {
1249 return(mService.get().unMute());
1250 }
1251
1252 public boolean isMuted()
1253 {
1254 return(mService.get().isMuted());
1255 }
1256
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +05301257 public void startRecording()
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05301258 {
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +05301259 mService.get().startRecording();
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05301260 }
1261
1262 public void stopRecording()
1263 {
1264 mService.get().stopRecording();
1265 }
1266
1267 public boolean tune(int frequency)
1268 {
1269 return(mService.get().tune(frequency));
1270 }
1271
1272 public boolean seek(boolean up)
1273 {
1274 return(mService.get().seek(up));
1275 }
1276
1277 public void enableSpeaker(boolean speakerOn)
1278 {
1279 mService.get().enableSpeaker(speakerOn);
1280 }
1281
1282 public boolean scan(int pty)
1283 {
1284 return(mService.get().scan(pty));
1285 }
1286
1287 public boolean seekPI(int piCode)
1288 {
1289 return(mService.get().seekPI(piCode));
1290 }
1291 public boolean searchStrongStationList(int numStations)
1292 {
1293 return(mService.get().searchStrongStationList(numStations));
1294 }
1295
1296 public boolean cancelSearch()
1297 {
1298 return(mService.get().cancelSearch());
1299 }
1300
1301 public String getProgramService()
1302 {
1303 return(mService.get().getProgramService());
1304 }
1305 public String getRadioText()
1306 {
1307 return(mService.get().getRadioText());
1308 }
1309 public String getExtenRadioText()
1310 {
1311 return(mService.get().getExtenRadioText());
1312 }
1313 public int getProgramType()
1314 {
1315 return(mService.get().getProgramType());
1316 }
1317 public int getProgramID()
1318 {
1319 return(mService.get().getProgramID());
1320 }
1321 public int[] getSearchList()
1322 {
1323 return(mService.get().getSearchList());
1324 }
1325
1326 public boolean setLowPowerMode(boolean enable)
1327 {
1328 return(mService.get().setLowPowerMode(enable));
1329 }
1330
1331 public int getPowerMode()
1332 {
1333 return(mService.get().getPowerMode());
1334 }
1335 public boolean enableAutoAF(boolean bEnable)
1336 {
1337 return(mService.get().enableAutoAF(bEnable));
1338 }
1339 public boolean enableStereo(boolean bEnable)
1340 {
1341 return(mService.get().enableStereo(bEnable));
1342 }
1343 public boolean isAntennaAvailable()
1344 {
1345 return(mService.get().isAntennaAvailable());
1346 }
1347 public boolean isWiredHeadsetAvailable()
1348 {
1349 return(mService.get().isWiredHeadsetAvailable());
1350 }
1351 public boolean isCallActive()
1352 {
1353 return(mService.get().isCallActive());
1354 }
1355 public int getRssi()
1356 {
1357 return (mService.get().getRssi());
1358 }
1359 public int getIoC()
1360 {
1361 return (mService.get().getIoC());
1362 }
1363 public int getMpxDcc()
1364 {
1365 return (mService.get().getMpxDcc());
1366 }
1367 public int getIntDet()
1368 {
1369 return (mService.get().getIntDet());
1370 }
1371 public void setHiLoInj(int inj)
1372 {
1373 mService.get().setHiLoInj(inj);
1374 }
1375 public void delayedStop(long duration, int nType)
1376 {
1377 mService.get().delayedStop(duration, nType);
1378 }
1379 public void cancelDelayedStop(int nType)
1380 {
1381 mService.get().cancelDelayedStop(nType);
1382 }
1383 public void requestFocus()
1384 {
1385 mService.get().requestFocus();
1386 }
1387 public int getSINR()
1388 {
1389 return (mService.get().getSINR());
1390 }
1391 public boolean setSinrSamplesCnt(int samplesCnt)
1392 {
1393 return (mService.get().setSinrSamplesCnt(samplesCnt));
1394 }
1395 public boolean setSinrTh(int sinr)
1396 {
1397 return (mService.get().setSinrTh(sinr));
1398 }
1399 public boolean setIntfDetLowTh(int intfLowTh)
1400 {
1401 return (mService.get().setIntfDetLowTh(intfLowTh));
1402 }
1403 public boolean setIntfDetHighTh(int intfHighTh)
1404 {
1405 return (mService.get().setIntfDetHighTh(intfHighTh));
1406 }
Ayaz Ahmada32e3772013-07-31 12:24:29 +05301407 public int getSearchAlgoType()
1408 {
1409 return (mService.get().getSearchAlgoType());
1410 }
1411 public boolean setSearchAlgoType(int searchType)
1412 {
1413 return (mService.get().setSearchAlgoType(searchType));
1414 }
1415 public int getSinrFirstStage()
1416 {
1417 return (mService.get().getSinrFirstStage());
1418 }
1419 public boolean setSinrFirstStage(int sinr)
1420 {
1421 return (mService.get().setSinrFirstStage(sinr));
1422 }
1423 public int getRmssiFirstStage()
1424 {
1425 return (mService.get().getRmssiFirstStage());
1426 }
1427 public boolean setRmssiFirstStage(int rmssi)
1428 {
1429 return (mService.get().setRmssiFirstStage(rmssi));
1430 }
1431 public int getCFOMeanTh()
1432 {
1433 return (mService.get().getCFOMeanTh());
1434 }
1435 public boolean setCFOMeanTh(int th)
1436 {
1437 return (mService.get().setCFOMeanTh(th));
1438 }
1439 public int getSinrSamplesCnt()
1440 {
1441 return (mService.get().getSinrSamplesCnt());
1442 }
1443 public int getSinrTh()
1444 {
1445 return (mService.get().getSinrTh());
1446 }
1447 public int getAfJmpRmssiTh()
1448 {
1449 return (mService.get().getAfJmpRmssiTh());
1450 }
1451 public boolean setAfJmpRmssiTh(int afJmpRmssiTh)
1452 {
1453 return (mService.get().setAfJmpRmssiTh(afJmpRmssiTh));
1454 }
1455 public int getGoodChRmssiTh()
1456 {
1457 return (mService.get().getGoodChRmssiTh());
1458 }
1459 public boolean setGoodChRmssiTh(int gdChRmssiTh)
1460 {
1461 return (mService.get().setGoodChRmssiTh(gdChRmssiTh));
1462 }
1463 public int getAfJmpRmssiSamplesCnt()
1464 {
1465 return (mService.get().getAfJmpRmssiSamplesCnt());
1466 }
1467 public boolean setAfJmpRmssiSamplesCnt(int afJmpRmssiSmplsCnt)
1468 {
1469 return (mService.get().setAfJmpRmssiSamplesCnt(afJmpRmssiSmplsCnt));
1470 }
Ayaz Ahmad61bedff2013-07-31 13:04:19 +05301471 public boolean setRxRepeatCount(int count)
1472 {
1473 return (mService.get().setRxRepeatCount(count));
1474 }
Ayaz Ahmad613e5832013-08-01 19:57:19 +05301475 public long getRecordingStartTime()
1476 {
1477 return (mService.get().getRecordingStartTime());
1478 }
Ayaz Ahmad594e34a2013-09-12 17:04:29 +05301479 public boolean isSleepTimerActive()
1480 {
1481 return (mService.get().isSleepTimerActive());
1482 }
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05301483 }
1484 private final IBinder mBinder = new ServiceStub(this);
1485
1486 private boolean setAudioPath(boolean analogMode) {
1487
1488 if (mReceiver == null) {
1489 return false;
1490 }
1491 if (isAnalogModeEnabled() == analogMode) {
1492 Log.d(LOGTAG,"Analog Path already is set to "+analogMode);
1493 return false;
1494 }
1495 if (!isAnalogModeSupported()) {
1496 Log.d(LOGTAG,"Analog Path is not supported ");
1497 return false;
1498 }
1499 if (SystemProperties.getBoolean("hw.fm.digitalpath",false)) {
1500 return false;
1501 }
1502
1503 boolean state = mReceiver.setAnalogMode(analogMode);
1504 if (false == state) {
1505 Log.d(LOGTAG, "Error in toggling analog/digital path " + analogMode);
1506 return false;
1507 }
1508 misAnalogPathEnabled = analogMode;
1509 return true;
1510 }
1511 /*
1512 * Turn ON FM: Powers up FM hardware, and initializes the FM module
1513 * .
1514 * @return true if fm Enable api was invoked successfully, false if the api failed.
1515 */
1516 private boolean fmOn() {
1517 boolean bStatus=false;
1518 mWakeLock.acquire(10*1000);
1519 if ( TelephonyManager.CALL_STATE_IDLE != getCallState() ) {
1520 return bStatus;
1521 }
1522
1523 if(mReceiver == null)
1524 {
1525 try {
1526 mReceiver = new FmReceiver(FMRADIO_DEVICE_FD_STRING, fmCallbacks);
1527 }
1528 catch (InstantiationException e)
1529 {
1530 throw new RuntimeException("FmReceiver service not available!");
1531 }
1532 }
1533
1534 if (mReceiver != null)
1535 {
1536 if (isFmOn())
1537 {
1538 /* FM Is already on,*/
1539 bStatus = true;
1540 Log.d(LOGTAG, "mReceiver.already enabled");
1541 }
1542 else
1543 {
1544 // This sets up the FM radio device
1545 FmConfig config = FmSharedPreferences.getFMConfiguration();
1546 Log.d(LOGTAG, "fmOn: RadioBand :"+ config.getRadioBand());
1547 Log.d(LOGTAG, "fmOn: Emphasis :"+ config.getEmphasis());
1548 Log.d(LOGTAG, "fmOn: ChSpacing :"+ config.getChSpacing());
1549 Log.d(LOGTAG, "fmOn: RdsStd :"+ config.getRdsStd());
1550 Log.d(LOGTAG, "fmOn: LowerLimit :"+ config.getLowerLimit());
1551 Log.d(LOGTAG, "fmOn: UpperLimit :"+ config.getUpperLimit());
1552 bStatus = mReceiver.enable(FmSharedPreferences.getFMConfiguration());
1553 if (isSpeakerEnabled()) {
1554 setAudioPath(false);
1555 } else {
1556 setAudioPath(true);
1557 }
1558 Log.d(LOGTAG, "mReceiver.enable done, Status :" + bStatus);
1559 }
1560
1561 if (bStatus == true)
1562 {
1563 /* Put the hardware into normal mode */
1564 bStatus = setLowPowerMode(false);
1565 Log.d(LOGTAG, "setLowPowerMode done, Status :" + bStatus);
1566
1567
1568 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1569 if( (audioManager != null) &&(false == mPlaybackInProgress) )
1570 {
1571 Log.d(LOGTAG, "mAudioManager.setFmRadioOn = true \n" );
1572 //audioManager.setParameters("FMRadioOn="+mAudioDevice);
1573 int state = getCallState();
1574 if ( TelephonyManager.CALL_STATE_IDLE != getCallState() )
1575 {
1576 fmActionOnCallState(state);
1577 } else {
1578 startFM(); // enable FM Audio only when Call is IDLE
1579 }
1580 Log.d(LOGTAG, "mAudioManager.setFmRadioOn done \n" );
1581 }
1582 if (mReceiver != null) {
1583 bStatus = mReceiver.registerRdsGroupProcessing(FmReceiver.FM_RX_RDS_GRP_RT_EBL|
1584 FmReceiver.FM_RX_RDS_GRP_PS_EBL|
1585 FmReceiver.FM_RX_RDS_GRP_AF_EBL|
1586 FmReceiver.FM_RX_RDS_GRP_PS_SIMPLE_EBL);
1587 Log.d(LOGTAG, "registerRdsGroupProcessing done, Status :" + bStatus);
1588 }
1589 bStatus = enableAutoAF(FmSharedPreferences.getAutoAFSwitch());
1590 Log.d(LOGTAG, "enableAutoAF done, Status :" + bStatus);
1591
1592 /* There is no internal Antenna*/
1593 bStatus = mReceiver.setInternalAntenna(false);
1594 Log.d(LOGTAG, "setInternalAntenna done, Status :" + bStatus);
1595
1596 /* Read back to verify the internal Antenna mode*/
1597 readInternalAntennaAvailable();
1598
1599 startNotification();
1600 bStatus = true;
1601 }
1602 else
1603 {
1604 mReceiver = null; // as enable failed no need to disable
1605 // failure of enable can be because handle
1606 // already open which gets effected if
1607 // we disable
1608 stop();
1609 }
1610 }
1611 return(bStatus);
1612 }
1613
1614 /*
1615 * Turn OFF FM Operations: This disables all the current FM operations .
1616 */
1617 private void fmOperationsOff() {
1618 if ( mSpeakerPhoneOn)
1619 {
1620 mSpeakerPhoneOn = false;
1621 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);
1622 }
1623 if (isFmRecordingOn())
1624 {
1625 stopRecording();
1626 }
1627 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1628 if(audioManager != null)
1629 {
1630 Log.d(LOGTAG, "audioManager.setFmRadioOn = false \n" );
1631 unMute();
1632 stopFM();
1633 //audioManager.setParameters("FMRadioOn=false");
1634 Log.d(LOGTAG, "audioManager.setFmRadioOn false done \n" );
1635 }
1636
Venkateshwarlu Domakondab11a44e2013-09-02 16:20:55 +05301637 sendRecordServiceIntent(RECORD_STOP);
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05301638 if (isAnalogModeEnabled()) {
1639 SystemProperties.set("hw.fm.isAnalog","false");
1640 misAnalogPathEnabled = false;
1641 }
1642 }
1643
1644 /*
1645 * Reset (OFF) FM Operations: This resets all the current FM operations .
1646 */
1647 private void fmOperationsReset() {
1648 if ( mSpeakerPhoneOn)
1649 {
1650 mSpeakerPhoneOn = false;
1651 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);
1652 }
1653
1654 if (isFmRecordingOn())
1655 {
Venkateshwarlu Domakondafa22ae12013-07-27 12:25:16 +05301656 stopRecording();
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05301657 }
1658
1659 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1660 if(audioManager != null)
1661 {
1662 Log.d(LOGTAG, "audioManager.setFmRadioOn = false \n" );
1663 unMute();
1664 resetFM();
1665 //audioManager.setParameters("FMRadioOn=false");
1666 Log.d(LOGTAG, "audioManager.setFmRadioOn false done \n" );
1667 }
1668
1669 if (isAnalogModeEnabled()) {
1670 SystemProperties.set("hw.fm.isAnalog","false");
1671 misAnalogPathEnabled = false;
1672 }
1673 }
1674
1675 /*
1676 * Turn OFF FM: Disable the FM Host and hardware .
1677 * .
1678 * @return true if fm Disable api was invoked successfully, false if the api failed.
1679 */
1680 private boolean fmOff() {
1681 boolean bStatus=false;
1682
1683 fmOperationsOff();
1684
1685 // This will disable the FM radio device
1686 if (mReceiver != null)
1687 {
1688 bStatus = mReceiver.disable();
1689 mReceiver = null;
1690 }
1691 stop();
1692 return(bStatus);
1693 }
1694
1695 /*
1696 * Turn OFF FM: Disable the FM Host when hardware resets asynchronously .
1697 * .
1698 * @return true if fm Reset api was invoked successfully, false if the api failed .
1699 */
1700 private boolean fmRadioReset() {
1701 boolean bStatus=false;
1702
1703 Log.v(LOGTAG, "fmRadioReset");
1704
1705 fmOperationsReset();
1706
1707 // This will reset the FM radio receiver
1708 if (mReceiver != null)
1709 {
1710 bStatus = mReceiver.reset();
1711 mReceiver = null;
1712 }
1713 stop();
1714 return(bStatus);
1715 }
1716
1717 /* Returns whether FM hardware is ON.
1718 *
1719 * @return true if FM was tuned, searching. (at the end of
1720 * the search FM goes back to tuned).
1721 *
1722 */
1723 public boolean isFmOn() {
1724 return mFMOn;
1725 }
1726
1727 /* Returns true if Analog Path is enabled */
1728 public boolean isAnalogModeEnabled() {
1729 return misAnalogPathEnabled;
1730 }
1731
1732 public boolean isAnalogModeSupported() {
1733 return misAnalogModeSupported;
1734 }
1735
1736 public boolean isFmRecordingOn() {
1737 return mFmRecordingOn;
1738 }
1739
1740 public boolean isSpeakerEnabled() {
1741 return mSpeakerPhoneOn;
1742 }
1743 public boolean isExternalStorageAvailable() {
1744 boolean mStorageAvail = false;
1745 String state = Environment.getExternalStorageState();
1746
1747 if(Environment.MEDIA_MOUNTED.equals(state)){
1748 Log.d(LOGTAG, "device available");
1749 mStorageAvail = true;
1750 }
1751 return mStorageAvail;
1752 }
1753 public void enableSpeaker(boolean speakerOn) {
1754 if(isCallActive())
1755 return ;
1756 mSpeakerPhoneOn = speakerOn;
1757 boolean analogmode = isAnalogModeSupported();
1758 if (false == speakerOn) {
1759 if (analogmode) {
1760 if (isFmRecordingOn())
1761 stopRecording();
1762 stopFM();
1763 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);
1764 if (mMuted) {
1765 setAudioPath(true);
1766 } else {
1767 mute();
1768 setAudioPath(true);
1769 unMute();
1770 }
1771 } else {
1772 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);
1773 }
1774 if (analogmode)
1775 startFM();
1776 }
1777
1778
1779 //Need to turn off BT path when Speaker is set on vice versa.
1780 if( !mA2dpDeviceSupportInHal && !analogmode && true == mA2dpDeviceState.isDeviceAvailable()) {
1781 if( ((true == mOverA2DP) && (true == speakerOn)) ||
1782 ((false == mOverA2DP) && (false == speakerOn)) ) {
1783 //disable A2DP playback for speaker option
1784 stopFM();
1785 startFM();
1786 }
1787 }
1788 if (speakerOn) {
1789 if (analogmode) {
1790 stopFM();
1791 if (mMuted) {
1792 setAudioPath(false);
1793 } else {
1794 mute();
1795 setAudioPath(false);
1796 unMute();
1797 }
1798 }
1799 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_SPEAKER);
1800 if (analogmode)
1801 startFM();
1802 }
1803
1804 }
1805 /*
1806 * ReConfigure the FM Setup parameters
1807 * - Band
1808 * - Channel Spacing (50/100/200 KHz)
1809 * - Emphasis (50/75)
1810 * - Frequency limits
1811 * - RDS/RBDS standard
1812 *
1813 * @return true if configure api was invoked successfully, false if the api failed.
1814 */
1815 public boolean fmReconfigure() {
1816 boolean bStatus=false;
1817 Log.d(LOGTAG, "fmReconfigure");
1818 if (mReceiver != null)
1819 {
1820 // This sets up the FM radio device
1821 FmConfig config = FmSharedPreferences.getFMConfiguration();
1822 Log.d(LOGTAG, "RadioBand :"+ config.getRadioBand());
1823 Log.d(LOGTAG, "Emphasis :"+ config.getEmphasis());
1824 Log.d(LOGTAG, "ChSpacing :"+ config.getChSpacing());
1825 Log.d(LOGTAG, "RdsStd :"+ config.getRdsStd());
1826 Log.d(LOGTAG, "LowerLimit :"+ config.getLowerLimit());
1827 Log.d(LOGTAG, "UpperLimit :"+ config.getUpperLimit());
1828 bStatus = mReceiver.configure(config);
1829 }
1830 return(bStatus);
1831 }
1832
1833 /*
1834 * Register UI/Activity Callbacks
1835 */
1836 public void registerCallbacks(IFMRadioServiceCallbacks cb)
1837 {
1838 mCallbacks = cb;
1839 }
1840
1841 /*
1842 * unRegister UI/Activity Callbacks
1843 */
1844 public void unregisterCallbacks()
1845 {
1846 mCallbacks=null;
1847 }
1848
1849 /*
1850 * Route Audio to headset or speaker phone
1851 * @return true if routeAudio call succeeded, false if the route call failed.
1852 */
1853 public boolean routeAudio(int audioDevice) {
1854 boolean bStatus=false;
1855 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1856
1857 //Log.d(LOGTAG, "routeAudio: " + audioDevice);
1858
1859 switch (audioDevice) {
1860
1861 case RADIO_AUDIO_DEVICE_WIRED_HEADSET:
1862 mAudioDevice = "headset";
1863 break;
1864
1865 case RADIO_AUDIO_DEVICE_SPEAKER:
1866 mAudioDevice = "speaker";
1867 break;
1868
1869 default:
1870 mAudioDevice = "headset";
1871 break;
1872 }
1873
1874 if (mReceiver != null)
1875 {
1876 //audioManager.setParameters("FMRadioOn=false");
1877 //Log.d(LOGTAG, "mAudioManager.setFmRadioOn =" + mAudioDevice );
1878 //audioManager.setParameters("FMRadioOn="+mAudioDevice);
1879 //Log.d(LOGTAG, "mAudioManager.setFmRadioOn done \n");
1880 }
1881
1882 return bStatus;
1883 }
1884
1885 /*
1886 * Mute FM Hardware (SoC)
1887 * @return true if set mute mode api was invoked successfully, false if the api failed.
1888 */
1889 public boolean mute() {
1890 boolean bCommandSent=true;
1891 if(isMuted())
1892 return bCommandSent;
1893 if(isCallActive())
1894 return false;
1895 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1896 Log.d(LOGTAG, "mute:");
1897 if (audioManager != null)
1898 {
1899 mMuted = true;
1900 audioManager.setStreamMute(AudioManager.STREAM_MUSIC,true);
1901 }
1902 return bCommandSent;
1903 }
1904
1905 /*
1906 * UnMute FM Hardware (SoC)
1907 * @return true if set mute mode api was invoked successfully, false if the api failed.
1908 */
1909 public boolean unMute() {
1910 boolean bCommandSent=true;
1911 if(!isMuted())
1912 return bCommandSent;
1913 if(isCallActive())
1914 return false;
1915 Log.d(LOGTAG, "unMute:");
1916 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1917 if (audioManager != null)
1918 {
1919 mMuted = false;
1920 audioManager.setStreamMute(AudioManager.STREAM_MUSIC,false);
1921 if (mResumeAfterCall)
1922 {
1923 //We are unmuting FM in a voice call. Need to enable FM audio routing.
1924 startFM();
1925 }
1926 }
1927 return bCommandSent;
1928 }
1929
1930 /* Returns whether FM Hardware(Soc) Audio is Muted.
1931 *
1932 * @return true if FM Audio is muted, false if not muted.
1933 *
1934 */
1935 public boolean isMuted() {
1936 return mMuted;
1937 }
1938
1939 /* Tunes to the specified frequency
1940 *
1941 * @return true if Tune command was invoked successfully, false if not muted.
1942 * Note: Callback FmRxEvRadioTuneStatus will be called when the tune
1943 * is complete
1944 */
1945 public boolean tune(int frequency) {
1946 boolean bCommandSent=false;
1947 double doubleFrequency = frequency/1000.00;
1948
1949 Log.d(LOGTAG, "tuneRadio: " + doubleFrequency);
1950 if (mReceiver != null)
1951 {
1952 mReceiver.setStation(frequency);
1953 bCommandSent = true;
1954 }
1955 return bCommandSent;
1956 }
1957
1958 /* Seeks (Search for strong station) to the station in the direction specified
1959 * relative to the tuned station.
1960 * boolean up: true - Search in the forward direction.
1961 * false - Search in the backward direction.
1962 * @return true if Seek command was invoked successfully, false if not muted.
1963 * Note: 1. Callback FmRxEvSearchComplete will be called when the Search
1964 * is complete
1965 * 2. Callback FmRxEvRadioTuneStatus will also be called when tuned to a station
1966 * at the end of the Search or if the seach was cancelled.
1967 */
1968 public boolean seek(boolean up)
1969 {
1970 boolean bCommandSent=false;
1971 if (mReceiver != null)
1972 {
1973 if (up == true)
1974 {
1975 Log.d(LOGTAG, "seek: Up");
1976 mReceiver.searchStations(FmReceiver.FM_RX_SRCH_MODE_SEEK,
1977 FmReceiver.FM_RX_DWELL_PERIOD_1S,
1978 FmReceiver.FM_RX_SEARCHDIR_UP);
1979 }
1980 else
1981 {
1982 Log.d(LOGTAG, "seek: Down");
1983 mReceiver.searchStations(FmReceiver.FM_RX_SRCH_MODE_SEEK,
1984 FmReceiver.FM_RX_DWELL_PERIOD_1S,
1985 FmReceiver.FM_RX_SEARCHDIR_DOWN);
1986 }
1987 bCommandSent = true;
1988 }
1989 return bCommandSent;
1990 }
1991
1992 /* Scan (Search for station with a "preview" of "n" seconds)
1993 * FM Stations. It always scans in the forward direction relative to the
1994 * current tuned station.
1995 * int pty: 0 or a reserved PTY value- Perform a "strong" station search of all stations.
1996 * Valid/Known PTY - perform RDS Scan for that pty.
1997 *
1998 * @return true if Scan command was invoked successfully, false if not muted.
1999 * Note: 1. Callback FmRxEvRadioTuneStatus will be called when tuned to various stations
2000 * during the Scan.
2001 * 2. Callback FmRxEvSearchComplete will be called when the Search
2002 * is complete
2003 * 3. Callback FmRxEvRadioTuneStatus will also be called when tuned to a station
2004 * at the end of the Search or if the seach was cancelled.
2005 *
2006 */
2007 public boolean scan(int pty)
2008 {
2009 boolean bCommandSent=false;
2010 if (mReceiver != null)
2011 {
2012 Log.d(LOGTAG, "scan: PTY: " + pty);
2013 if(FmSharedPreferences.isRBDSStd())
2014 {
2015 /* RBDS : Validate PTY value?? */
2016 if( ((pty > 0) && (pty <= 23)) || ((pty >= 29) && (pty <= 31)) )
2017 {
2018 bCommandSent = mReceiver.searchStations(FmReceiver.FM_RX_SRCHRDS_MODE_SCAN_PTY,
2019 FmReceiver.FM_RX_DWELL_PERIOD_2S,
2020 FmReceiver.FM_RX_SEARCHDIR_UP,
2021 pty,
2022 0);
2023 }
2024 else
2025 {
2026 bCommandSent = mReceiver.searchStations(FmReceiver.FM_RX_SRCH_MODE_SCAN,
2027 FmReceiver.FM_RX_DWELL_PERIOD_2S,
2028 FmReceiver.FM_RX_SEARCHDIR_UP);
2029 }
2030 }
2031 else
2032 {
2033 /* RDS : Validate PTY value?? */
2034 if( (pty > 0) && (pty <= 31) )
2035 {
2036 bCommandSent = mReceiver.searchStations(FmReceiver.FM_RX_SRCHRDS_MODE_SCAN_PTY,
2037 FmReceiver.FM_RX_DWELL_PERIOD_2S,
2038 FmReceiver.FM_RX_SEARCHDIR_UP,
2039 pty,
2040 0);
2041 }
2042 else
2043 {
2044 bCommandSent = mReceiver.searchStations(FmReceiver.FM_RX_SRCH_MODE_SCAN,
2045 FmReceiver.FM_RX_DWELL_PERIOD_2S,
2046 FmReceiver.FM_RX_SEARCHDIR_UP);
2047 }
2048 }
2049 }
2050 return bCommandSent;
2051 }
2052
2053 /* Search for the 'numStations' number of strong FM Stations.
2054 *
2055 * It searches in the forward direction relative to the current tuned station.
2056 * int numStations: maximum number of stations to search.
2057 *
2058 * @return true if Search command was invoked successfully, false if not muted.
2059 * Note: 1. Callback FmRxEvSearchListComplete will be called when the Search
2060 * is complete
2061 * 2. Callback FmRxEvRadioTuneStatus will also be called when tuned to
2062 * the previously tuned station.
2063 */
2064 public boolean searchStrongStationList(int numStations)
2065 {
2066 boolean bCommandSent=false;
2067 if (mReceiver != null)
2068 {
2069 Log.d(LOGTAG, "searchStrongStationList: numStations: " + numStations);
2070 bCommandSent = mReceiver.searchStationList(FmReceiver.FM_RX_SRCHLIST_MODE_STRONG,
2071 FmReceiver.FM_RX_SEARCHDIR_UP,
2072 numStations,
2073 0);
2074 }
2075 return bCommandSent;
2076 }
2077
2078 /* Search for the FM Station that matches the RDS PI (Program Identifier) code.
2079 * It always scans in the forward direction relative to the current tuned station.
2080 * int piCode: PI Code of the station to search.
2081 *
2082 * @return true if Search command was invoked successfully, false if not muted.
2083 * Note: 1. Callback FmRxEvSearchComplete will be called when the Search
2084 * is complete
2085 * 2. Callback FmRxEvRadioTuneStatus will also be called when tuned to a station
2086 * at the end of the Search or if the seach was cancelled.
2087 */
2088 public boolean seekPI(int piCode)
2089 {
2090 boolean bCommandSent=false;
2091 if (mReceiver != null)
2092 {
2093 Log.d(LOGTAG, "seekPI: piCode: " + piCode);
2094 bCommandSent = mReceiver.searchStations(FmReceiver.FM_RX_SRCHRDS_MODE_SEEK_PI,
2095 FmReceiver.FM_RX_DWELL_PERIOD_1S,
2096 FmReceiver.FM_RX_SEARCHDIR_UP,
2097 0,
2098 piCode
2099 );
2100 }
2101 return bCommandSent;
2102 }
2103
2104
2105 /* Cancel any ongoing Search (Seek/Scan/SearchStationList).
2106 *
2107 * @return true if Search command was invoked successfully, false if not muted.
2108 * Note: 1. Callback FmRxEvSearchComplete will be called when the Search
2109 * is complete/cancelled.
2110 * 2. Callback FmRxEvRadioTuneStatus will also be called when tuned to a station
2111 * at the end of the Search or if the seach was cancelled.
2112 */
2113 public boolean cancelSearch()
2114 {
2115 boolean bCommandSent=false;
2116 if (mReceiver != null)
2117 {
2118 Log.d(LOGTAG, "cancelSearch");
2119 bCommandSent = mReceiver.cancelSearch();
2120 }
2121 return bCommandSent;
2122 }
2123
2124 /* Retrieves the RDS Program Service (PS) String.
2125 *
2126 * @return String - RDS PS String.
2127 * Note: 1. This is a synchronous call that should typically called when
2128 * Callback FmRxEvRdsPsInfo is invoked.
2129 * 2. Since PS contains multiple fields, this Service reads all the fields and "caches"
2130 * the values and provides this helper routine for the Activity to get only the information it needs.
2131 * 3. The "cached" data fields are always "cleared" when the tune status changes.
2132 */
2133 public String getProgramService() {
2134 String str = "";
2135 if (mFMRxRDSData != null)
2136 {
2137 str = mFMRxRDSData.getPrgmServices();
2138 if(str == null)
2139 {
2140 str= "";
2141 }
2142 }
2143 Log.d(LOGTAG, "Program Service: [" + str + "]");
2144 return str;
2145 }
2146
2147 /* Retrieves the RDS Radio Text (RT) String.
2148 *
2149 * @return String - RDS RT String.
2150 * Note: 1. This is a synchronous call that should typically called when
2151 * Callback FmRxEvRdsRtInfo is invoked.
2152 * 2. Since RT contains multiple fields, this Service reads all the fields and "caches"
2153 * the values and provides this helper routine for the Activity to get only the information it needs.
2154 * 3. The "cached" data fields are always "cleared" when the tune status changes.
2155 */
2156 public String getRadioText() {
2157 String str = "";
2158 if (mFMRxRDSData != null)
2159 {
2160 str = mFMRxRDSData.getRadioText();
2161 if(str == null)
2162 {
2163 str= "";
2164 }
2165 }
2166 Log.d(LOGTAG, "Radio Text: [" + str + "]");
2167 return str;
2168 }
2169
2170 public String getExtenRadioText() {
2171 String str = "";
2172 if (mFMRxRDSData != null)
2173 {
2174 str = mFMRxRDSData.getERadioText();
2175 if(str == null)
2176 {
2177 str= "";
2178 }
2179 }
2180 Log.d(LOGTAG, "eRadio Text:[" + str +"]");
2181 return str;
2182 }
2183 /* Retrieves the RDS Program Type (PTY) code.
2184 *
2185 * @return int - RDS PTY code.
2186 * Note: 1. This is a synchronous call that should typically called when
2187 * Callback FmRxEvRdsRtInfo and or FmRxEvRdsPsInfo is invoked.
2188 * 2. Since RT/PS contains multiple fields, this Service reads all the fields and "caches"
2189 * the values and provides this helper routine for the Activity to get only the information it needs.
2190 * 3. The "cached" data fields are always "cleared" when the tune status changes.
2191 */
2192 public int getProgramType() {
2193 int pty = -1;
2194 if (mFMRxRDSData != null)
2195 {
2196 pty = mFMRxRDSData.getPrgmType();
2197 }
2198 Log.d(LOGTAG, "PTY: [" + pty + "]");
2199 return pty;
2200 }
2201
2202 /* Retrieves the RDS Program Identifier (PI).
2203 *
2204 * @return int - RDS PI code.
2205 * Note: 1. This is a synchronous call that should typically called when
2206 * Callback FmRxEvRdsRtInfo and or FmRxEvRdsPsInfo is invoked.
2207 * 2. Since RT/PS contains multiple fields, this Service reads all the fields and "caches"
2208 * the values and provides this helper routine for the Activity to get only the information it needs.
2209 * 3. The "cached" data fields are always "cleared" when the tune status changes.
2210 */
2211 public int getProgramID() {
2212 int pi = -1;
2213 if (mFMRxRDSData != null)
2214 {
2215 pi = mFMRxRDSData.getPrgmId();
2216 }
2217 Log.d(LOGTAG, "PI: [" + pi + "]");
2218 return pi;
2219 }
2220
2221
2222 /* Retrieves the station list from the SearchStationlist.
2223 *
2224 * @return Array of integers that represents the station frequencies.
2225 * Note: 1. This is a synchronous call that should typically called when
2226 * Callback onSearchListComplete.
2227 */
2228 public int[] getSearchList()
2229 {
2230 int[] frequencyList = null;
2231 if (mReceiver != null)
2232 {
2233 Log.d(LOGTAG, "getSearchList: ");
2234 frequencyList = mReceiver.getStationList();
2235 }
2236 return frequencyList;
2237 }
2238
2239 /* Set the FM Power Mode on the FM hardware SoC.
2240 * Typically used when UI/Activity is in the background, so the Host is interrupted less often.
2241 *
2242 * boolean bLowPower: true: Enable Low Power mode on FM hardware.
2243 * false: Disable Low Power mode on FM hardware. (Put into normal power mode)
2244 * @return true if set power mode api was invoked successfully, false if the api failed.
2245 */
2246 public boolean setLowPowerMode(boolean bLowPower)
2247 {
2248 boolean bCommandSent=false;
2249 if (mReceiver != null)
2250 {
2251 Log.d(LOGTAG, "setLowPowerMode: " + bLowPower);
2252 if(bLowPower)
2253 {
2254 bCommandSent = mReceiver.setPowerMode(FmReceiver.FM_RX_LOW_POWER_MODE);
2255 }
2256 else
2257 {
2258 bCommandSent = mReceiver.setPowerMode(FmReceiver.FM_RX_NORMAL_POWER_MODE);
2259 }
2260 }
2261 return bCommandSent;
2262 }
2263
2264 /* Get the FM Power Mode on the FM hardware SoC.
2265 *
2266 * @return the device power mode.
2267 */
2268 public int getPowerMode()
2269 {
2270 int powerMode=FmReceiver.FM_RX_NORMAL_POWER_MODE;
2271 if (mReceiver != null)
2272 {
2273 powerMode = mReceiver.getPowerMode();
2274 Log.d(LOGTAG, "getLowPowerMode: " + powerMode);
2275 }
2276 return powerMode;
2277 }
2278
2279 /* Set the FM module to auto switch to an Alternate Frequency for the
2280 * station if one the signal strength of that frequency is stronger than the
2281 * current tuned frequency.
2282 *
2283 * boolean bEnable: true: Auto switch to stronger alternate frequency.
2284 * false: Do not switch to alternate frequency.
2285 *
2286 * @return true if set Auto AF mode api was invoked successfully, false if the api failed.
2287 * Note: Callback FmRxEvRadioTuneStatus will be called when tune
2288 * is complete to a different frequency.
2289 */
2290 public boolean enableAutoAF(boolean bEnable)
2291 {
2292 boolean bCommandSent=false;
2293 if (mReceiver != null)
2294 {
2295 Log.d(LOGTAG, "enableAutoAF: " + bEnable);
2296 bCommandSent = mReceiver.enableAFjump(bEnable);
2297 }
2298 return bCommandSent;
2299 }
2300
2301 /* Set the FM module to Stereo Mode or always force it to Mono Mode.
2302 * Note: The stereo mode will be available only when the station is broadcasting
2303 * in Stereo mode.
2304 *
2305 * boolean bEnable: true: Enable Stereo Mode.
2306 * false: Always stay in Mono Mode.
2307 *
2308 * @return true if set Stereo mode api was invoked successfully, false if the api failed.
2309 */
2310 public boolean enableStereo(boolean bEnable)
2311 {
2312 boolean bCommandSent=false;
2313 if (mReceiver != null)
2314 {
2315 Log.d(LOGTAG, "enableStereo: " + bEnable);
2316 bCommandSent = mReceiver.setStereoMode(bEnable);
2317 }
2318 return bCommandSent;
2319 }
2320
2321 /** Determines if an internal Antenna is available.
2322 * Returns the cached value initialized on FMOn.
2323 *
2324 * @return true if internal antenna is available or wired
2325 * headset is plugged in, false if internal antenna is
2326 * not available and wired headset is not plugged in.
2327 */
2328 public boolean isAntennaAvailable()
2329 {
2330 boolean bAvailable = false;
2331 if ((mInternalAntennaAvailable) || (mHeadsetPlugged) )
2332 {
2333 bAvailable = true;
2334 }
2335 return bAvailable;
2336 }
2337
2338 public static long getAvailableSpace() {
2339 String state = Environment.getExternalStorageState();
2340 Log.d(LOGTAG, "External storage state=" + state);
2341 if (Environment.MEDIA_CHECKING.equals(state)) {
2342 return PREPARING;
2343 }
2344 if (!Environment.MEDIA_MOUNTED.equals(state)) {
2345 return UNAVAILABLE;
2346 }
2347
2348 try {
2349 File sampleDir = Environment.getExternalStorageDirectory();
2350 StatFs stat = new StatFs(sampleDir.getAbsolutePath());
2351 return stat.getAvailableBlocks() * (long) stat.getBlockSize();
2352 } catch (Exception e) {
2353 Log.i(LOGTAG, "Fail to access external storage", e);
2354 }
2355 return UNKNOWN_SIZE;
2356 }
2357
2358 private boolean updateAndShowStorageHint() {
2359 mStorageSpace = getAvailableSpace();
2360 return showStorageHint();
2361 }
2362
2363 private boolean showStorageHint() {
2364 String errorMessage = null;
2365 if (mStorageSpace == UNAVAILABLE) {
2366 errorMessage = getString(R.string.no_storage);
2367 } else if (mStorageSpace == PREPARING) {
2368 errorMessage = getString(R.string.preparing_sd);
2369 } else if (mStorageSpace == UNKNOWN_SIZE) {
2370 errorMessage = getString(R.string.access_sd_fail);
2371 } else if (mStorageSpace < LOW_STORAGE_THRESHOLD) {
2372 errorMessage = getString(R.string.spaceIsLow_content);
2373 }
2374
2375 if (errorMessage != null) {
2376 Toast.makeText(this, errorMessage,
2377 Toast.LENGTH_LONG).show();
2378 return false;
2379 }
2380 return true;
2381 }
2382
2383 /** Determines if a Wired headset is plugged in. Returns the
2384 * cached value initialized on broadcast receiver
2385 * initialization.
2386 *
2387 * @return true if wired headset is plugged in, false if wired
2388 * headset is not plugged in.
2389 */
2390 public boolean isWiredHeadsetAvailable()
2391 {
2392 return (mHeadsetPlugged);
2393 }
2394 public boolean isCallActive()
2395 {
2396 //Non-zero: Call state is RINGING or OFFHOOK on the available subscriptions
2397 //zero: Call state is IDLE on all the available subscriptions
2398 if(0 != getCallState()) return true;
2399 return false;
2400 }
2401 public int getCallState()
2402 {
2403 return mCallStatus;
2404 }
2405
2406 public void clearStationInfo() {
2407 if(mFMRxRDSData != null) {
2408 mFMRxRDSData.setRadioText("");
2409 mFMRxRDSData.setPrgmId(0);
2410 mFMRxRDSData.setPrgmType(0);
2411 mFMRxRDSData.setPrgmServices("");
2412 mFMRxRDSData.setERadioText("");
2413 mFMRxRDSData.setTagValue("", 1);
2414 mFMRxRDSData.setTagValue("", 2);
2415 mFMRxRDSData.setTagCode((byte)0, 1);
2416 mFMRxRDSData.setTagCode((byte)0, 2);
2417 Log.d(LOGTAG, "clear tags data");
2418 FmSharedPreferences.clearTags();
2419 }
2420 }
2421
2422 /* Receiver callbacks back from the FM Stack */
2423 FmRxEvCallbacksAdaptor fmCallbacks = new FmRxEvCallbacksAdaptor()
2424 {
2425 public void FmRxEvEnableReceiver() {
2426 Log.d(LOGTAG, "FmRxEvEnableReceiver");
2427 mReceiver.setRawRdsGrpMask();
2428 }
2429 public void FmRxEvDisableReceiver()
2430 {
2431 Log.d(LOGTAG, "FmRxEvDisableReceiver");
2432 mFMOn = false;
2433 FmSharedPreferences.clearTags();
2434 }
2435 public void FmRxEvRadioReset()
2436 {
2437 Log.d(LOGTAG, "FmRxEvRadioReset");
2438 if(isFmOn()) {
2439 // Received radio reset event while FM is ON
2440 Log.d(LOGTAG, "FM Radio reset");
2441 fmRadioReset();
2442 try
2443 {
2444 /* Notify the UI/Activity, only if the service is "bound"
2445 by an activity and if Callbacks are registered
2446 */
2447 if((mServiceInUse) && (mCallbacks != null) )
2448 {
2449 mCallbacks.onRadioReset();
2450 }
2451 }
2452 catch (RemoteException e)
2453 {
2454 e.printStackTrace();
2455 }
2456 }
2457 }
2458 public void FmRxEvConfigReceiver()
2459 {
2460 Log.d(LOGTAG, "FmRxEvConfigReceiver");
2461 }
2462 public void FmRxEvMuteModeSet()
2463 {
2464 Log.d(LOGTAG, "FmRxEvMuteModeSet");
2465 }
2466 public void FmRxEvStereoModeSet()
2467 {
2468 Log.d(LOGTAG, "FmRxEvStereoModeSet");
2469 }
2470 public void FmRxEvRadioStationSet()
2471 {
2472 Log.d(LOGTAG, "FmRxEvRadioStationSet");
2473 }
2474 public void FmRxEvPowerModeSet()
2475 {
2476 Log.d(LOGTAG, "FmRxEvPowerModeSet");
2477 }
2478 public void FmRxEvSetSignalThreshold()
2479 {
2480 Log.d(LOGTAG, "FmRxEvSetSignalThreshold");
2481 }
2482
2483 public void FmRxEvRadioTuneStatus(int frequency)
2484 {
2485 Log.d(LOGTAG, "FmRxEvRadioTuneStatus: Tuned Frequency: " +frequency);
2486 try
2487 {
2488 FmSharedPreferences.setTunedFrequency(frequency);
2489 mPrefs.Save();
2490 //Log.d(LOGTAG, "Call mCallbacks.onTuneStatusChanged");
2491 /* Since the Tuned Status changed, clear out the RDSData cached */
2492 if(mReceiver != null) {
2493 clearStationInfo();
2494 }
2495 if(mCallbacks != null)
2496 {
2497 mCallbacks.onTuneStatusChanged();
2498 }
2499 /* Update the frequency in the StatusBar's Notification */
2500 startNotification();
Ayaz Ahmadd97a0bb2013-09-02 12:17:33 +05302501 enableStereo(FmSharedPreferences.getAudioOutputMode());
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05302502 }
2503 catch (RemoteException e)
2504 {
2505 e.printStackTrace();
2506 }
2507 }
2508
2509 public void FmRxEvStationParameters()
2510 {
2511 Log.d(LOGTAG, "FmRxEvStationParameters");
2512 }
2513
2514 public void FmRxEvRdsLockStatus(boolean bRDSSupported)
2515 {
2516 Log.d(LOGTAG, "FmRxEvRdsLockStatus: " + bRDSSupported);
2517 try
2518 {
2519 if(mCallbacks != null)
2520 {
2521 mCallbacks.onStationRDSSupported(bRDSSupported);
2522 }
2523 }
2524 catch (RemoteException e)
2525 {
2526 e.printStackTrace();
2527 }
2528 }
2529
2530 public void FmRxEvStereoStatus(boolean stereo)
2531 {
2532 Log.d(LOGTAG, "FmRxEvStereoStatus: " + stereo);
2533 try
2534 {
2535 if(mCallbacks != null)
2536 {
2537 mCallbacks.onAudioUpdate(stereo);
2538 }
2539 }
2540 catch (RemoteException e)
2541 {
2542 e.printStackTrace();
2543 }
2544 }
2545 public void FmRxEvServiceAvailable(boolean signal)
2546 {
2547 Log.d(LOGTAG, "FmRxEvServiceAvailable");
2548 if(signal) {
2549 Log.d(LOGTAG, "FmRxEvServiceAvailable: Tuned frequency is above signal threshold level");
2550 }
2551 else {
2552 Log.d(LOGTAG, "FmRxEvServiceAvailable: Tuned frequency is below signal threshold level");
2553 }
2554 }
2555 public void FmRxEvGetSignalThreshold()
2556 {
2557 Log.d(LOGTAG, "FmRxEvGetSignalThreshold");
2558 }
2559 public void FmRxEvSearchInProgress()
2560 {
2561 Log.d(LOGTAG, "FmRxEvSearchInProgress");
2562 }
2563 public void FmRxEvSearchRdsInProgress()
2564 {
2565 Log.d(LOGTAG, "FmRxEvSearchRdsInProgress");
2566 }
2567 public void FmRxEvSearchListInProgress()
2568 {
2569 Log.d(LOGTAG, "FmRxEvSearchListInProgress");
2570 }
2571 public void FmRxEvSearchComplete(int frequency)
2572 {
2573 Log.d(LOGTAG, "FmRxEvSearchComplete: Tuned Frequency: " +frequency);
2574 try
2575 {
2576 FmSharedPreferences.setTunedFrequency(frequency);
2577 //Log.d(LOGTAG, "Call mCallbacks.onSearchComplete");
2578 /* Since the Tuned Status changed, clear out the RDSData cached */
2579 if(mReceiver != null) {
2580 clearStationInfo();
2581 }
2582 if(mCallbacks != null)
2583 {
2584 mCallbacks.onSearchComplete();
2585 }
2586 /* Update the frequency in the StatusBar's Notification */
2587 startNotification();
2588 }
2589 catch (RemoteException e)
2590 {
2591 e.printStackTrace();
2592 }
2593 }
2594
2595 public void FmRxEvSearchRdsComplete()
2596 {
2597 Log.d(LOGTAG, "FmRxEvSearchRdsComplete");
2598 }
2599
2600 public void FmRxEvSearchListComplete()
2601 {
2602 Log.d(LOGTAG, "FmRxEvSearchListComplete");
2603 try
2604 {
2605 if(mCallbacks != null)
2606 {
2607 mCallbacks.onSearchListComplete();
2608 }
2609 } catch (RemoteException e)
2610 {
2611 e.printStackTrace();
2612 }
2613 }
2614
2615 public void FmRxEvSearchCancelled()
2616 {
2617 Log.d(LOGTAG, "FmRxEvSearchCancelled: Cancelled the on-going search operation.");
2618 }
2619 public void FmRxEvRdsGroupData()
2620 {
2621 Log.d(LOGTAG, "FmRxEvRdsGroupData");
2622 }
2623
2624 public void FmRxEvRdsPsInfo() {
2625 Log.d(LOGTAG, "FmRxEvRdsPsInfo: ");
2626 try
2627 {
2628 if(mReceiver != null)
2629 {
2630 mFMRxRDSData = mReceiver.getPSInfo();
2631 if(mFMRxRDSData != null)
2632 {
2633 Log.d(LOGTAG, "PI: [" + mFMRxRDSData.getPrgmId() + "]");
2634 Log.d(LOGTAG, "PTY: [" + mFMRxRDSData.getPrgmType() + "]");
2635 Log.d(LOGTAG, "PS: [" + mFMRxRDSData.getPrgmServices() + "]");
2636 }
2637 if(mCallbacks != null)
2638 {
2639 mCallbacks.onProgramServiceChanged();
2640 }
2641 }
2642 } catch (RemoteException e)
2643 {
2644 e.printStackTrace();
2645 }
2646 }
2647
2648 public void FmRxEvRdsRtInfo() {
2649 Log.d(LOGTAG, "FmRxEvRdsRtInfo");
2650 try
2651 {
2652 //Log.d(LOGTAG, "Call mCallbacks.onRadioTextChanged");
2653 if(mReceiver != null)
2654 {
2655 mFMRxRDSData = mReceiver.getRTInfo();
2656 if(mFMRxRDSData != null)
2657 {
2658 Log.d(LOGTAG, "PI: [" + mFMRxRDSData.getPrgmId() + "]");
2659 Log.d(LOGTAG, "PTY: [" + mFMRxRDSData.getPrgmType() + "]");
2660 Log.d(LOGTAG, "RT: [" + mFMRxRDSData.getRadioText() + "]");
2661 }
2662 if(mCallbacks != null)
2663 {
2664 mCallbacks.onRadioTextChanged();
2665 }
2666 }
2667 } catch (RemoteException e)
2668 {
2669 e.printStackTrace();
2670 }
2671
2672 }
2673
2674 public void FmRxEvRdsAfInfo()
2675 {
2676 Log.d(LOGTAG, "FmRxEvRdsAfInfo");
2677 mReceiver.getAFInfo();
2678 }
2679 public void FmRxEvRTPlus()
2680 {
2681 int tag_nums;
2682 Log.d(LOGTAG, "FmRxEvRTPlusInfo");
2683 if (mReceiver != null) {
2684 mFMRxRDSData = mReceiver.getRTPlusInfo();
2685 tag_nums = mFMRxRDSData.getTagNums();
2686 if (tag_nums >= 1) {
2687 Log.d(LOGTAG, "tag1 is: " + mFMRxRDSData.getTagCode(1) + "value: "
2688 + mFMRxRDSData.getTagValue(1));
2689 FmSharedPreferences.addTags(mFMRxRDSData.getTagCode(1), mFMRxRDSData.getTagValue(1));
2690 }
2691 if(tag_nums == 2) {
2692 Log.d(LOGTAG, "tag2 is: " + mFMRxRDSData.getTagCode(2) + "value: "
2693 + mFMRxRDSData.getTagValue(2));
2694 FmSharedPreferences.addTags(mFMRxRDSData.getTagCode(2), mFMRxRDSData.getTagValue(2));
2695 }
2696 }
2697 }
2698 public void FmRxEvERTInfo()
2699 {
2700 Log.d(LOGTAG, "FmRxEvERTInfo");
2701 try {
2702 if (mReceiver != null) {
2703 mFMRxRDSData = mReceiver.getERTInfo();
2704 if(mCallbacks != null)
2705 mCallbacks.onExtenRadioTextChanged();
2706 }
2707 } catch (RemoteException e) {
2708 e.printStackTrace();
2709 }
2710 }
2711 public void FmRxEvRdsPiMatchAvailable()
2712 {
2713 Log.d(LOGTAG, "FmRxEvRdsPiMatchAvailable");
2714 }
2715 public void FmRxEvRdsGroupOptionsSet()
2716 {
2717 Log.d(LOGTAG, "FmRxEvRdsGroupOptionsSet");
2718 }
2719 public void FmRxEvRdsProcRegDone()
2720 {
2721 Log.d(LOGTAG, "FmRxEvRdsProcRegDone");
2722 }
2723 public void FmRxEvRdsPiMatchRegDone()
2724 {
2725 Log.d(LOGTAG, "FmRxEvRdsPiMatchRegDone");
2726 }
2727 };
2728
2729
2730 /*
2731 * Read the Tuned Frequency from the FM module.
2732 */
2733 private String getTunedFrequencyString() {
2734
2735 double frequency = FmSharedPreferences.getTunedFrequency() / 1000.0;
2736 String frequencyString = getString(R.string.stat_notif_frequency, (""+frequency));
2737 return frequencyString;
2738 }
2739 public int getRssi() {
2740 if (mReceiver != null)
2741 return mReceiver.getRssi();
2742 else
2743 return Integer.MAX_VALUE;
2744 }
2745 public int getIoC() {
2746 if (mReceiver != null)
2747 return mReceiver.getIoverc();
2748 else
2749 return Integer.MAX_VALUE;
2750 }
2751 public int getIntDet() {
2752 if (mReceiver != null)
2753 return mReceiver.getIntDet();
2754 else
2755 return Integer.MAX_VALUE;
2756 }
2757 public int getMpxDcc() {
2758 if (mReceiver != null)
2759 return mReceiver.getMpxDcc();
2760 else
2761 return Integer.MAX_VALUE;
2762 }
2763 public void setHiLoInj(int inj) {
2764 if (mReceiver != null)
2765 mReceiver.setHiLoInj(inj);
2766 }
2767 public int getSINR() {
2768 if (mReceiver != null)
2769 return mReceiver.getSINR();
2770 else
2771 return Integer.MAX_VALUE;
2772 }
2773 public boolean setSinrSamplesCnt(int samplesCnt) {
2774 if(mReceiver != null)
2775 return mReceiver.setSINRsamples(samplesCnt);
2776 else
2777 return false;
2778 }
2779 public boolean setSinrTh(int sinr) {
2780 if(mReceiver != null)
2781 return mReceiver.setSINRThreshold(sinr);
2782 else
2783 return false;
2784 }
2785 public boolean setIntfDetLowTh(int intfLowTh) {
2786 if(mReceiver != null)
2787 return mReceiver.setOnChannelThreshold(intfLowTh);
2788 else
2789 return false;
2790 }
2791 public boolean setIntfDetHighTh(int intfHighTh) {
2792 if(mReceiver != null)
2793 return mReceiver.setOffChannelThreshold(intfHighTh);
2794 else
2795 return false;
2796 }
Ayaz Ahmada32e3772013-07-31 12:24:29 +05302797 public int getSearchAlgoType() {
2798 if(mReceiver != null)
2799 return mReceiver.getSearchAlgoType();
2800 else
2801 return -1;
2802 }
2803 public boolean setSearchAlgoType(int searchType) {
2804 if(mReceiver != null)
2805 return mReceiver.setSearchAlgoType(searchType);
2806 else
2807 return false;
2808 }
2809 public int getSinrFirstStage() {
2810 if(mReceiver != null)
2811 return mReceiver.getSinrFirstStage();
2812 else
2813 return Integer.MAX_VALUE;
2814 }
2815 public boolean setSinrFirstStage(int sinr) {
2816 if(mReceiver != null)
2817 return mReceiver.setSinrFirstStage(sinr);
2818 else
2819 return false;
2820 }
2821 public int getRmssiFirstStage() {
2822 if(mReceiver != null)
2823 return mReceiver.getRmssiFirstStage();
2824 else
2825 return Integer.MAX_VALUE;
2826 }
2827 public boolean setRmssiFirstStage(int rmssi) {
2828 if(mReceiver != null)
2829 return mReceiver.setRmssiFirstStage(rmssi);
2830 else
2831 return false;
2832 }
2833 public int getCFOMeanTh() {
2834 if(mReceiver != null)
2835 return mReceiver.getCFOMeanTh();
2836 else
2837 return Integer.MAX_VALUE;
2838 }
2839 public boolean setCFOMeanTh(int th) {
2840 if(mReceiver != null)
2841 return mReceiver.setCFOMeanTh(th);
2842 else
2843 return false;
2844 }
2845 public int getSinrSamplesCnt() {
2846 if(mReceiver != null)
2847 return mReceiver.getSINRsamples();
2848 else
2849 return Integer.MAX_VALUE;
2850 }
2851 public int getSinrTh() {
2852 if(mReceiver != null)
2853 return mReceiver.getSINRThreshold();
2854 else
2855 return Integer.MAX_VALUE;
2856 }
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05302857
Ayaz Ahmada32e3772013-07-31 12:24:29 +05302858 boolean setAfJmpRmssiTh(int afJmpRmssiTh) {
2859 if(mReceiver != null)
2860 return mReceiver.setAFJumpRmssiTh(afJmpRmssiTh);
2861 else
2862 return false;
2863 }
2864 boolean setGoodChRmssiTh(int gdChRmssiTh) {
2865 if(mReceiver != null)
2866 return mReceiver.setGdChRmssiTh(gdChRmssiTh);
2867 else
2868 return false;
2869 }
2870 boolean setAfJmpRmssiSamplesCnt(int afJmpRmssiSmplsCnt) {
2871 if(mReceiver != null)
2872 return mReceiver.setAFJumpRmssiSamples(afJmpRmssiSmplsCnt);
2873 else
2874 return false;
2875 }
2876 int getAfJmpRmssiTh() {
2877 if(mReceiver != null)
2878 return mReceiver.getAFJumpRmssiTh();
2879 else
2880 return Integer.MIN_VALUE;
2881 }
2882 int getGoodChRmssiTh() {
2883 if(mReceiver != null)
2884 return mReceiver.getGdChRmssiTh();
2885 else
2886 return Integer.MAX_VALUE;
2887 }
2888 int getAfJmpRmssiSamplesCnt() {
2889 if(mReceiver != null)
2890 return mReceiver.getAFJumpRmssiSamples();
2891 else
2892 return Integer.MIN_VALUE;
2893 }
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05302894 private void setAlarmSleepExpired (long duration) {
2895 Intent i = new Intent(SLEEP_EXPIRED_ACTION);
2896 AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
2897 PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
2898 Log.d(LOGTAG, "delayedStop called" + SystemClock.elapsedRealtime() + duration);
2899 am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + duration, pi);
Ayaz Ahmad594e34a2013-09-12 17:04:29 +05302900 mSleepActive = true;
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05302901 }
2902 private void cancelAlarmSleepExpired() {
2903 Intent i = new Intent(SLEEP_EXPIRED_ACTION);
2904 AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
2905 PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
2906 am.cancel(pi);
Ayaz Ahmad594e34a2013-09-12 17:04:29 +05302907 mSleepActive = false;
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05302908 }
2909 private void setAlarmRecordTimeout(long duration) {
2910 Intent i = new Intent(RECORD_EXPIRED_ACTION);
2911 AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
2912 PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
2913 Log.d(LOGTAG, "delayedStop called" + SystemClock.elapsedRealtime() + duration);
2914 am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + duration, pi);
2915 }
2916 private void cancelAlarmRecordTimeout() {
2917 Intent i = new Intent(RECORD_EXPIRED_ACTION);
2918 AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
2919 PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
2920 am.cancel(pi);
2921 }
2922 private void setAlarmDelayedServiceStop() {
2923 Intent i = new Intent(SERVICE_DELAYED_STOP_ACTION);
2924 AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
2925 PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
2926 am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + IDLE_DELAY, pi);
2927 }
2928 private void cancelAlarmDealyedServiceStop() {
2929 Intent i = new Intent(SERVICE_DELAYED_STOP_ACTION);
2930 AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
2931 PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
2932 am.cancel(pi);
2933 }
2934 private void cancelAlarms() {
2935 cancelAlarmSleepExpired();
2936 cancelAlarmRecordTimeout();
2937 cancelAlarmDealyedServiceStop();
2938 }
Ayaz Ahmad61bedff2013-07-31 13:04:19 +05302939 public boolean setRxRepeatCount(int count) {
2940 if(mReceiver != null)
2941 return mReceiver.setPSRxRepeatCount(count);
2942 else
2943 return false;
2944 }
2945
Ayaz Ahmad613e5832013-08-01 19:57:19 +05302946 public long getRecordingStartTime() {
2947 return mSampleStart;
2948 }
Ayaz Ahmad594e34a2013-09-12 17:04:29 +05302949
2950 public boolean isSleepTimerActive() {
2951 return mSleepActive;
2952 }
Venkateshwarlu Domakonda56262fb2013-07-24 19:56:59 +05302953 //handling the sleep and record stop when FM App not in focus
2954 private void delayedStop(long duration, int nType) {
2955 int whatId = (nType == STOP_SERVICE) ? STOPSERVICE_ONSLEEP: STOPRECORD_ONTIMEOUT;
2956 if (nType == STOP_SERVICE)
2957 setAlarmSleepExpired(duration);
2958 else
2959 setAlarmRecordTimeout(duration);
2960 }
2961 private void cancelDelayedStop(int nType) {
2962 int whatId = (nType == STOP_SERVICE) ? STOPSERVICE_ONSLEEP: STOPRECORD_ONTIMEOUT;
2963 if (nType == STOP_SERVICE)
2964 cancelAlarmSleepExpired();
2965 else
2966 cancelAlarmRecordTimeout();
2967 }
2968 private void requestFocus() {
2969 if( (false == mPlaybackInProgress) &&
2970 (true == mStoppedOnFocusLoss) ) {
2971 // adding code for audio focus gain.
2972 AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
2973 audioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
2974 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
2975 startFM();
2976 mStoppedOnFocusLoss = false;
2977 }
2978 }
2979 private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() {
2980 public void onAudioFocusChange(int focusChange) {
2981 mDelayedStopHandler.obtainMessage(FOCUSCHANGE, focusChange, 0).sendToTarget();
2982 }
2983 };
2984}