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