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