Merge tag 'AU_LINUX_ANDROID_LA.HB.1.1.1.05.01.01.063.362' into HEAD

* commit '6c5cd5c66629b5f802fa4a2dbba72aaccd3c4635':
  FM: Handle the airplane mode change gracefully

Change-Id: If740e101942cef9add243b33b55378a2665fcf9b
diff --git a/Android.mk b/Android.mk
index 027bddf..4777981 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,13 +1,14 @@
-ifneq ($(TARGET_USES_AOSP),true)
-
-ifeq ($(BOARD_HAVE_QCOM_FM),true)
-ifneq (,$(filter $(QCOM_BOARD_PLATFORMS),$(TARGET_BOARD_PLATFORM)))
 LOCAL_PATH:= $(call my-dir)
 LOCAL_DIR_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := optional
 
+#ifneq ($(TARGET_USES_AOSP),true)
+
+#ifeq ($(BOARD_HAVE_QCOM_FM),true)
+#ifneq (,$(filter $(QCOM_BOARD_PLATFORMS),$(TARGET_BOARD_PLATFORM)))
+
 LOCAL_SRC_FILES := $(call all-java-files-under, qcom/fmradio)
 LOCAL_JNI_SHARED_LIBRARIES := libqcomfm_jni
 
@@ -18,11 +19,12 @@
 include $(LOCAL_PATH)/jni/Android.mk
 LOCAL_PATH := $(LOCAL_DIR_PATH)
 include $(LOCAL_PATH)/fmapp2/Android.mk
-LOCAL_PATH := $(LOCAL_DIR_PATH)
-include $(LOCAL_PATH)/FMRecord/Android.mk
+#LOCAL_PATH := $(LOCAL_DIR_PATH)
+#include $(LOCAL_PATH)/FMRecord/Android.mk
+#endif # is-vendor-board-platform
+#endif # BOARD_HAVE_QCOM_FM
+
+#endif # Not (TARGET_USES_AOSP)
+
 LOCAL_PATH := $(LOCAL_DIR_PATH)
 include $(LOCAL_PATH)/libfm_jni/Android.mk
-endif # is-vendor-board-platform
-endif # BOARD_HAVE_QCOM_FM
-
-endif # Not (TARGET_USES_AOSP)
diff --git a/FMRecord/res/layout/record_status_bar.xml b/FMRecord/res/layout/record_status_bar.xml
index d2e1151..9651fd0 100644
--- a/FMRecord/res/layout/record_status_bar.xml
+++ b/FMRecord/res/layout/record_status_bar.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-14, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -37,6 +37,7 @@
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="15sp"
+       android:textColor="#000000"
        android:text="@string/fm_record_progress"/>
 
 </RelativeLayout>
diff --git a/fmapp2/res/values/strings.xml b/fmapp2/res/values/strings.xml
index 55b2932..3d490d0 100644
--- a/fmapp2/res/values/strings.xml
+++ b/fmapp2/res/values/strings.xml
@@ -273,6 +273,7 @@
     <string name="band_sweep_choose">Choose Band Sweep Method</string>
     <string name="set">Set</string>
     <string name="cancel">Cancel</string>
-    <string name="user_defind_band_msg">Enter Freq from range 76.0 - 108.0 and with min 1 channel spacing</string>
+    <string name="user_defind_band_msg">Enter Freq from range 76.0 - 108.0, with min 1 channel spacing and 100KHz space between max, min freq</string>
+    <string name="save_record_file">FM Recorded file saved to "<xliff:g id="record_file">%1$s</xliff:g>"</string>
 
 </resources>
diff --git a/fmapp2/src/com/caf/fmradio/FMRadio.java b/fmapp2/src/com/caf/fmradio/FMRadio.java
index 99a71f4..12693cf 100644
--- a/fmapp2/src/com/caf/fmradio/FMRadio.java
+++ b/fmapp2/src/com/caf/fmradio/FMRadio.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2015, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -443,9 +443,6 @@
    @Override
    public void onStop() {
       Log.d(LOGTAG, "FMRadio: onStop");
-      if(isSleepTimerActive()) {
-         mSleepUpdateHandlerThread.interrupt();
-      }
       if(isRecording()) {
           try {
               if (null != mRecordUpdateHandlerThread) {
@@ -484,6 +481,10 @@
    protected void onPause() {
       Log.d(LOGTAG, "FMRadio: onPause");
       super.onPause();
+      if (isSleepTimerActive()) {
+          Log.d(LOGTAG, "FMRadio: Sleep Timer active");
+          mSleepUpdateHandlerThread.interrupt();
+      }
       mRadioTextScroller.stopScroll();
       mERadioTextScroller.stopScroll();
       FmSharedPreferences.setTunedFrequency(mTunedStation.getFrequency());
@@ -1774,9 +1775,17 @@
    private void startRecording() {
       if(mService != null) {
          try {
-              mService.startRecording();
-         } catch (RemoteException e) {
-              e.printStackTrace();
+             mRecording = mService.startRecording();
+         }catch (RemoteException e) {
+             e.printStackTrace();
+         }
+         //Initiate record timer thread here
+         if(mRecording == true) {
+             mRecordingMsgTV.setCompoundDrawablesWithIntrinsicBounds
+                                   (R.drawable.recorder_stop, 0, 0, 0);
+             int durationInMins = FmSharedPreferences.getRecordDuration();
+             Log.e(LOGTAG, "Fected duration: " + durationInMins);
+             initiateRecordDurationTimer( durationInMins );
          }
       }
    }
diff --git a/fmapp2/src/com/caf/fmradio/FMRadioService.java b/fmapp2/src/com/caf/fmradio/FMRadioService.java
index ec535c5..25ceeb2 100644
--- a/fmapp2/src/com/caf/fmradio/FMRadioService.java
+++ b/fmapp2/src/com/caf/fmradio/FMRadioService.java
@@ -48,6 +48,17 @@
 import android.media.AudioManager.OnAudioFocusChangeListener;
 import android.media.AudioSystem;
 import android.media.MediaRecorder;
+import android.media.AudioDevicePort;
+import android.media.AudioDevicePortConfig;
+import android.media.AudioFormat;
+import android.media.AudioManager.OnAudioPortUpdateListener;
+import android.media.AudioMixPort;
+import android.media.AudioPatch;
+import android.media.AudioPort;
+import android.media.AudioPortConfig;
+import android.media.AudioRecord;
+import android.media.AudioTrack;
+
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
@@ -76,7 +87,6 @@
 import android.content.ContentValues;
 import android.database.Cursor;
 import com.caf.utils.A2dpDeviceStatus;
-import android.media.AudioManager;
 import android.content.ComponentName;
 import android.os.StatFs;
 import android.os.SystemClock;
@@ -133,6 +143,7 @@
    private boolean misAnalogModeSupported = false;
    private boolean misAnalogPathEnabled = false;
    private boolean mA2dpDisconnected = false;
+   private boolean mA2dpConnected = false;
    //PhoneStateListener instances corresponding to each
 
    private FmRxRdsData mFMRxRDSData=null;
@@ -186,6 +197,20 @@
    private boolean mIsSSRInProgress = false;
    private boolean mIsSSRInProgressFromActivity = false;
    private int mKeyActionDownCount = 0;
+   private static final int AUDIO_SAMPLE_RATE = 44100;
+   private static final int AUDIO_CHANNEL_CONFIG =
+                                   AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+   private static final int AUDIO_ENCODING_FORMAT =
+                                           AudioFormat.ENCODING_PCM_16BIT;
+   private static final int FM_RECORD_BUF_SIZE =
+                      AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE,
+                                   AUDIO_CHANNEL_CONFIG, AUDIO_ENCODING_FORMAT);
+   private Thread mRecordSinkThread = null;
+   private AudioRecord mAudioRecord = null;
+   private AudioTrack mAudioTrack = null;
+   private boolean mIsRecordSink = false;
+   private static final int AUDIO_FRAMES_COUNT_TO_IGNORE = 3;
+   private Object mRecordSinkLock = new Object();
 
    public FMRadioService() {
    }
@@ -210,7 +235,7 @@
       registerSleepExpired();
       registerRecordTimeout();
       registerDelayedServiceStop();
-      registerFMRecordingStatus();
+      registerExternalStorageListener();
       registerAirplaneModeStatusChanged();
       // registering media button receiver seperately as we need to set
       // different priority for receiving media events
@@ -298,8 +323,13 @@
           unregisterReceiver(mAirplaneModeChanged);
           mAirplaneModeChanged = null;
       }
+      if( mSdcardUnmountReceiver != null ) {
+          unregisterReceiver(mSdcardUnmountReceiver);
+          mSdcardUnmountReceiver = null;
+      }
       /* Since the service is closing, disable the receiver */
-      fmOff();
+      if (isFmOn())
+          fmOff();
 
       TelephonyManager tmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
       tmgr.listen(mPhoneStateListener, 0);
@@ -311,50 +341,162 @@
       super.onDestroy();
    }
 
-   public void registerFMRecordingStatus() {
-         if (mFmRecordingStatus == null) {
-             mFmRecordingStatus = new BroadcastReceiver() {
+   private synchronized void startAudioRecordSink() {
+        mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.RADIO_TUNER,
+                                       AUDIO_SAMPLE_RATE, AUDIO_CHANNEL_CONFIG,
+                                       AUDIO_ENCODING_FORMAT, FM_RECORD_BUF_SIZE);
+        mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
+                                     AUDIO_SAMPLE_RATE, AUDIO_CHANNEL_CONFIG,
+                                     AUDIO_ENCODING_FORMAT, FM_RECORD_BUF_SIZE,
+                                     AudioTrack.MODE_STREAM);
+   }
+
+   private synchronized void startRecordSink() {
+        Log.d(LOGTAG, "startRecordSink "
+                        + AudioSystem.getForceUse(AudioSystem.FOR_MEDIA));
+
+       if (mAudioRecord != null) {
+           mAudioRecord.stop();
+       }
+       if (mAudioTrack != null) {
+           mAudioTrack.stop();
+       }
+       startAudioRecordSink();
+       createRecordSinkThread();
+
+        mIsRecordSink = true;
+        synchronized (mRecordSinkLock) {
+            mRecordSinkLock.notify();
+        }
+   }
+
+   private synchronized void stopRecordSink() {
+        Log.d(LOGTAG, "stopRecordSink");
+        mRecordSinkLock = false;
+        synchronized (mRecordSinkLock) {
+            mRecordSinkLock.notify();
+        }
+    }
+
+    private synchronized void createRecordSinkThread() {
+        if (mRecordSinkThread == null) {
+            mRecordSinkThread = new RecordSinkThread();
+            mRecordSinkThread.start();
+        }
+    }
+
+    private synchronized void exitRecordSinkThread() {
+        stopRecordSink();
+        mRecordSinkThread.interrupt();
+        mRecordSinkThread = null;
+    }
+
+    private boolean isRecordSinking() {
+        return mIsRecordSink;
+    }
+
+    class RecordSinkThread extends Thread {
+        private int mCurrentFrame = 0;
+        private boolean isAudioFrameNeedIgnore() {
+            return mCurrentFrame < AUDIO_FRAMES_COUNT_TO_IGNORE;
+        }
+
+        @Override
+        public void run() {
+            try {
+                byte[] buffer = new byte[FM_RECORD_BUF_SIZE];
+                while (!Thread.interrupted()) {
+                    if (isRecordSinking()) {
+                        // Speaker mode or BT a2dp mode will come here and keep reading and writing.
+                        // If we want FM sound output from speaker or BT a2dp, we must record data
+                        // to AudioRecrd and write data to AudioTrack.
+                        if (mAudioRecord.getRecordingState() == AudioRecord.RECORDSTATE_STOPPED) {
+                            mAudioRecord.startRecording();
+                        }
+
+                        if (mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_STOPPED) {
+                            mAudioTrack.play();
+                        }
+                        int size = mAudioRecord.read(buffer, 0, FM_RECORD_BUF_SIZE);
+                        // check whether need to ignore first 3 frames audio data from AudioRecord
+                        // to avoid pop noise.
+                        if (isAudioFrameNeedIgnore()) {
+                            mCurrentFrame += 1;
+                            continue ;
+                        }
+                        if (size <= 0) {
+                            Log.e(LOGTAG, "RecordSinkThread read data from AudioRecord "
+                                    + "error size: " + size);
+                            continue;
+                        }
+                        byte[] tmpBuf = new byte[size];
+                        System.arraycopy(buffer, 0, tmpBuf, 0, size);
+                        // Check again to avoid noises, because RecordSink may be changed
+                        // while AudioRecord is reading.
+                        if (isRecordSinking()) {
+                            mAudioTrack.write(tmpBuf, 0, tmpBuf.length);
+                        }
+                    } else {
+                        // Earphone mode will come here and wait.
+                        mCurrentFrame = 0;
+
+                        if (mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
+                            mAudioTrack.stop();
+                        }
+
+                        if (mAudioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
+                            mAudioRecord.stop();
+                        }
+
+                        synchronized (mRecordSinkLock) {
+                            mRecordSinkLock.wait();
+                        }
+                    }
+                }
+            } catch (InterruptedException e) {
+                Log.d(LOGTAG, "RecordSinkThread.run, thread is interrupted, need exit thread");
+            } finally {
+                if (mAudioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
+                    mAudioRecord.stop();
+                }
+                if (mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
+                    mAudioTrack.stop();
+                }
+            }
+        }
+    }
+
+    /**
+      * Registers an intent to listen for ACTION_MEDIA_UNMOUNTED notifications.
+      * The intent will call closeExternalStorageFiles() if the external media
+      * is going to be ejected, so applications can clean up.
+      */
+     public void registerExternalStorageListener() {
+         if (mSdcardUnmountReceiver == null) {
+             mSdcardUnmountReceiver = new BroadcastReceiver() {
                  @Override
                  public void onReceive(Context context, Intent intent) {
-                     Log.d(LOGTAG, "received intent " +intent);
                      String action = intent.getAction();
-                     if (action.equals(ACTION_FM_RECORDING_STATUS)) {
-                         Log.d(LOGTAG, "ACTION_FM_RECORDING_STATUS Intent received");
-                         int state = intent.getIntExtra("state", 0);
-                         if (state == RECORD_START) {
-                             Log.d(LOGTAG, "FM Recording started");
-                             mFmRecordingOn = true;
-                             mSampleStart = SystemClock.elapsedRealtime();
+                     if ((action.equals(Intent.ACTION_MEDIA_UNMOUNTED))
+                           || (action.equals(Intent.ACTION_MEDIA_EJECT))) {
+                         Log.d(LOGTAG, "ACTION_MEDIA_UNMOUNTED Intent received");
+                         if (mFmRecordingOn == true) {
                              try {
-                                  if ((mServiceInUse) && (mCallbacks != null) ) {
-                                      Log.d(LOGTAG, "start recording thread");
-                                      mCallbacks.onRecordingStarted();
-                                  }
-                                  startRecordServiceStatusCheck();
-                             } catch (RemoteException e) {
+                                  stopRecording();
+                             } catch (Exception e) {
                                   e.printStackTrace();
                              }
-                         } else if (state == RECORD_STOP) {
-                             Log.d(LOGTAG, "FM Recording stopped");
-                             mFmRecordingOn = false;
-                             try {
-                                  if ((mServiceInUse) && (mCallbacks != null) ) {
-                                     mCallbacks.onRecordingStopped();
-                                  }
-                             } catch (RemoteException e) {
-                                  e.printStackTrace();
-                             }
-                             mSampleStart = 0;
-                             stopRecordServiceStatusCheck();
-                        }
+                         }
                      }
                  }
              };
              IntentFilter iFilter = new IntentFilter();
-             iFilter.addAction(ACTION_FM_RECORDING_STATUS);
-             registerReceiver(mFmRecordingStatus , iFilter);
+             iFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
+             iFilter.addAction(Intent.ACTION_MEDIA_EJECT);
+             iFilter.addDataScheme("file");
+             registerReceiver(mSdcardUnmountReceiver, iFilter);
          }
-   }
+     }
 
    public void registerAirplaneModeStatusChanged() {
        if (mAirplaneModeChanged == null) {
@@ -395,6 +537,7 @@
                 @Override
                 public void onReceive(Context context, Intent intent) {
                     String action = intent.getAction();
+                    Log.d(LOGTAG, "on receive HeadsetListener" +action);
                     if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
                        Log.d(LOGTAG, "ACTION_HEADSET_PLUG Intent received");
                        // Listen for ACTION_HEADSET_PLUG broadcasts.
@@ -411,26 +554,16 @@
                     } else if(mA2dpDeviceState.isA2dpStateChange(action) ) {
                         boolean  bA2dpConnected =
                         mA2dpDeviceState.isConnected(intent);
+                        Log.d(LOGTAG, "bA2dpConnected:" +bA2dpConnected);
                         if (!bA2dpConnected) {
                             Log.d(LOGTAG, "A2DP device is dis-connected!");
                             mA2dpDisconnected = true;
+                            mA2dpConnected = false;
                         } else {
                             Log.d(LOGTAG, "A2DP device is connected!");
                             mA2dpDisconnected = false;
+                            mA2dpConnected = true;
                         }
-                        if (isAnalogModeEnabled()) {
-                            Log.d(LOGTAG, "FM Audio Path is Analog Mode: FM Over BT not allowed");
-                            return ;
-                        }
-                       //when A2dp connected/disconnected
-                       // In above two cases we need to Stop and Start FM which
-                       // will take care of audio routing
-                       if( (isFmOn()) &&
-                           (false == mStoppedOnFocusLoss)) {
-                           Log.d(LOGTAG, "stopping and starting FM\n");
-                           stopFM();
-                           startFM();
-                       }
                     } else if (action.equals("HDMI_CONNECTED")) {
                         //FM should be off when HDMI is connected.
                         fmOff();
@@ -922,13 +1055,7 @@
        mAudioManager.registerMediaButtonEventReceiver(fmRadio);
        mStoppedOnFocusLoss = false;
 
-       if (!isSpeakerEnabled() && !mA2dpDeviceSupportInHal &&  (true == mA2dpDeviceState.isDeviceAvailable()) &&
-           !isAnalogModeEnabled()
-            && (true == startA2dpPlayback())) {
-            mOverA2DP=true;
-            Log.d(LOGTAG, "Audio source set it as A2DP");
-            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_BT_A2DP);
-       } else {
+       if (!mA2dpDeviceState.isDeviceAvailable()) {
            Log.d(LOGTAG, "FMRadio: Requesting to start FM");
            //reason for resending the Speaker option is we are sending
            //ACTION_FM=1 to AudioManager, the previous state of Speaker we set
@@ -941,11 +1068,8 @@
                Log.d(LOGTAG, "Audio source set it as headset");
                AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);
            }
-           AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
-                               AudioSystem.DEVICE_STATE_AVAILABLE, "");
-
        }
-       sendRecordServiceIntent(RECORD_START);
+       startRecordSink();
        mPlaybackInProgress = true;
        mUnMuteOnFocusLoss = false;
        mSpeakerOnFocusLoss = false;
@@ -953,28 +1077,13 @@
 
    private void stopFM(){
        Log.d(LOGTAG, "In stopFM");
-       if (mOverA2DP==true){
-           mOverA2DP=false;
-           stopA2dpPlayback();
-       }else{
-           Log.d(LOGTAG, "FMRadio: Requesting to stop FM");
-           AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
-                                     AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
-       }
+       stopRecordSink();
+       exitRecordSinkThread();
        mPlaybackInProgress = false;
    }
 
    private void resetFM(){
        Log.d(LOGTAG, "resetFM");
-       if (mOverA2DP==true){
-           mOverA2DP=false;
-           resetA2dpPlayback();
-       }else{
-           Log.d(LOGTAG, "FMRadio: Requesting to stop FM");
-           AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
-                                     AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
-           sendRecordServiceIntent(RECORD_STOP);
-       }
        mPlaybackInProgress = false;
    }
 
@@ -994,178 +1103,258 @@
        return status;
    }
 
-   private Runnable recordStatusCheckThread = new Runnable() {
-       @Override
-       public void run() {
-          while(!Thread.currentThread().isInterrupted()) {
-               try {
-                     if(!getRecordServiceStatus()) {
-                        Log.d(LOGTAG, "FM Recording Service stopped");
-                        mFmRecordingOn = false;
-                        try {
-                            if ((mServiceInUse) && (mCallbacks != null) ) {
-                                Log.d(LOGTAG, "Callback for stop recording");
-                                mCallbacks.onRecordingStopped();
-                            }
-                        } catch (RemoteException e) {
-                            e.printStackTrace();
-                        }
-                        mSampleStart = 0;
-                        break;
-                     };
-                     Thread.sleep(500);
-                }catch(Exception e) {
-                     Log.d(LOGTAG, "RecordService status check thread interrupted");
-                     break;
-                }
-          }
-       }
-   };
-
-   private void startRecordServiceStatusCheck() {
-       if((mRecordServiceCheckThread == null) ||
-          (mRecordServiceCheckThread.getState() == Thread.State.TERMINATED)) {
-           mRecordServiceCheckThread = new Thread(null,
-                                           recordStatusCheckThread,
-                                           "getRecordServiceStatus");
-       }
-       if((mRecordServiceCheckThread != null) &&
-          (mRecordServiceCheckThread.getState() == Thread.State.NEW)) {
-           mRecordServiceCheckThread.start();
-       }
-   }
-
-   private void stopRecordServiceStatusCheck() {
-       if(mRecordServiceCheckThread != null) {
-          mRecordServiceCheckThread.interrupt();
-       }
-   }
-
-   public void startRecording() {
-       Log.d(LOGTAG, "In startRecording of Recorder");
-       if (!getRecordServiceStatus()) {
-           Log.d(LOGTAG, "Recording Service is not in running state");
-           sendRecordServiceIntent(RECORD_START);
-           try {
-               Thread.sleep(200);
-           } catch (Exception ex) {
-               Log.d( LOGTAG, "RunningThread InterruptedException");
-               return;
-           }
-       }
-       if ((true == mSingleRecordingInstanceSupported) &&
-                               (true == mOverA2DP )) {
-            Toast.makeText( this,
-                      "playback on BT in progress,can't record now",
-                       Toast.LENGTH_SHORT).show();
-            return;
-       }
-       sendRecordIntent(RECORD_START);
-   }
-
-   public boolean startA2dpPlayback() {
-        Log.d(LOGTAG, "In startA2dpPlayback");
-    if( (true == mSingleRecordingInstanceSupported) &&
-        (true == mFmRecordingOn )) {
-                Toast.makeText(this,
-                               "Recording already in progress,can't play on BT",
-                               Toast.LENGTH_SHORT).show();
-                return false;
-       }
-        if(mOverA2DP)
-           stopA2dpPlayback();
-        mA2dp = new MediaRecorder();
-        if (mA2dp == null) {
-           Toast.makeText(this,"A2dpPlayback failed to create an instance",
-                            Toast.LENGTH_SHORT).show();
-           return false;
-        }
-        try {
-            mA2dp.setAudioSource(MediaRecorder.AudioSource.FM_RX_A2DP);
-            mA2dp.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
-            mA2dp.setAudioEncoder(MediaRecorder.OutputFormat.DEFAULT);
-            File sampleDir = new File(getFilesDir().getAbsolutePath());
-            try {
-                mA2DPSampleFile = File
-                    .createTempFile("FMRecording", ".3gpp", sampleDir);
-            } catch (IOException e) {
-                Log.e(LOGTAG, "Not able to access Phone's internal memory");
-                Toast.makeText(this, "Not able to access Phone's internal memory",
+   public boolean startRecording() {
+      Log.d(LOGTAG, "In startRecording of Recorder");
+      if((true == mSingleRecordingInstanceSupported) &&
+         (true == mOverA2DP )) {
+                Toast.makeText( this,
+                                "playback on BT in progress,can't record now",
                                 Toast.LENGTH_SHORT).show();
                 return false;
-            }
-            mA2dp.setOutputFile(mA2DPSampleFile.getAbsolutePath());
-            mA2dp.prepare();
-            mA2dp.start();
-        } catch (Exception exception) {
-            mA2dp.reset();
-            mA2dp.release();
-            mA2dp = null;
+       }
+       stopRecording();
+
+       if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
+            Log.e(LOGTAG, "startRecording, no external storage available");
+            return false;
+       }
+
+        if (!updateAndShowStorageHint())
+            return false;
+        long maxFileSize = mStorageSpace - LOW_STORAGE_THRESHOLD;
+        mRecorder = new MediaRecorder();
+        try {
+              mRecorder.setMaxFileSize(maxFileSize);
+        } catch (RuntimeException exception) {
+
+        }
+
+        mSampleFile = null;
+        File sampleDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +"/FMRecording");
+        if(!(sampleDir.mkdirs() || sampleDir.isDirectory()))
+            return false;
+        try {
+            mSampleFile = File
+                    .createTempFile("FMRecording", ".3gpp", sampleDir);
+        } catch (IOException e) {
+            Log.e(LOGTAG, "Not able to access SD Card");
+            Toast.makeText(this, "Not able to access SD Card", Toast.LENGTH_SHORT).show();
             return false;
         }
+
+        try {
+             Log.d(LOGTAG, "AudioSource.RADIO_TUNER" +MediaRecorder.AudioSource.RADIO_TUNER);
+             mRecorder.setAudioSource(MediaRecorder.AudioSource.RADIO_TUNER);
+             mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+             mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+        } catch (RuntimeException exception) {
+             mRecorder.reset();
+             mRecorder.release();
+             mRecorder = null;
+             return false;
+        }
+        mRecorder.setOutputFile(mSampleFile.getAbsolutePath());
+        try {
+             mRecorder.prepare();
+             Log.d(LOGTAG, "start");
+             mRecorder.start();
+        } catch (IOException e) {
+             mRecorder.reset();
+             mRecorder.release();
+             mRecorder = null;
+             return false;
+        } catch (RuntimeException e) {
+             mRecorder.reset();
+             mRecorder.release();
+             mRecorder = null;
+             return false;
+        }
+        mFmRecordingOn = true;
+        Log.d(LOGTAG, "mSampleFile.getAbsolutePath() " +mSampleFile.getAbsolutePath());
+        mRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
+             public void onInfo(MediaRecorder mr, int what, int extra) {
+                 if ((what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) ||
+                     (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED)) {
+                     if (mFmRecordingOn) {
+                         Log.d(LOGTAG, "Maximum file size/duration reached, stop the recording");
+                         stopRecording();
+                     }
+                     // Show the toast.
+                     Toast.makeText(FMRadioService.this, R.string.FMRecording_reach_size_limit,
+                               Toast.LENGTH_LONG).show();
+                 }
+             }
+             // from MediaRecorder.OnErrorListener
+             public void onError(MediaRecorder mr, int what, int extra) {
+                 Log.e(LOGTAG, "MediaRecorder error. what=" + what + ". extra=" + extra);
+                 if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) {
+                     // We may have run out of space on the sdcard.
+                     if (mFmRecordingOn) {
+                         stopRecording();
+                     }
+                     updateAndShowStorageHint();
+                 }
+             }
+        });
+
+        mSampleStart = SystemClock.elapsedRealtime();
+        Log.d(LOGTAG, "mSampleStart: " +mSampleStart);
         return true;
- }
-
-   public void stopA2dpPlayback() {
-       if (mA2dp == null)
-           return;
-       if(mA2DPSampleFile != null)
-       {
-          try {
-              mA2DPSampleFile.delete();
-          } catch (Exception e) {
-              Log.e(LOGTAG, "Not able to delete file");
-          }
-       }
-       try {
-           mA2dp.stop();
-           mA2dp.reset();
-           mA2dp.release();
-           mA2dp = null;
-       } catch (Exception exception ) {
-           Log.e( LOGTAG, "Stop failed with exception"+ exception);
-       }
-       return;
-   }
-
-   private void resetA2dpPlayback() {
-       if (mA2dp == null)
-           return;
-       if(mA2DPSampleFile != null)
-       {
-          try {
-              mA2DPSampleFile.delete();
-          } catch (Exception e) {
-              Log.e(LOGTAG, "Not able to delete file");
-          }
-       }
-       try {
-           // Send Intent for IOBUSY VOTE, because MediaRecorder.stop
-           // gets Activity context which might not be always available
-           // and would thus fail to send the intent.
-           Intent ioBusyUnVoteIntent = new Intent(IOBUSY_UNVOTE);
-           // Remove vote for io_is_busy to be turned off.
-           ioBusyUnVoteIntent.putExtra("com.android.server.CpuGovernorService.voteType", 0);
-           sendBroadcast(ioBusyUnVoteIntent);
-
-           mA2dp.stop();
-
-           mA2dp.reset();
-           mA2dp.release();
-           mA2dp = null;
-       } catch (Exception exception ) {
-           Log.e( LOGTAG, "Stop failed with exception"+ exception);
-       }
-       return;
-   }
+  }
 
    public void stopRecording() {
-       if (!mFmRecordingOn)
+       Log.d(LOGTAG, "Enter stopRecord");
+       mFmRecordingOn = false;
+       if (mRecorder == null)
            return;
-       sendRecordIntent(RECORD_STOP);
+       try {
+             mRecorder.stop();
+             mRecorder.reset();
+             mRecorder.release();
+             mRecorder = null;
+       } catch(Exception e) {
+             e.printStackTrace();
+       }
+       int sampleLength = (int)((System.currentTimeMillis() - mSampleStart)/1000 );
+       if (sampleLength == 0)
+           return;
+       String state = Environment.getExternalStorageState();
+       Log.d(LOGTAG, "storage state is " + state);
+
+       if (Environment.MEDIA_MOUNTED.equals(state)) {
+          try {
+               this.addToMediaDB(mSampleFile);
+               Toast.makeText(this,getString(R.string.save_record_file,
+                              mSampleFile.getAbsolutePath( )),
+                              Toast.LENGTH_LONG).show();
+          } catch(Exception e) {
+               e.printStackTrace();
+          }
+       } else {
+           Log.e(LOGTAG, "SD card must have removed during recording. ");
+           Toast.makeText(this, "Recording aborted", Toast.LENGTH_SHORT).show();
+       }
+       try {
+           if((mServiceInUse) && (mCallbacks != null) ) {
+               mCallbacks.onRecordingStopped();
+           }
+       } catch (RemoteException e) {
+           e.printStackTrace();
+       }
        return;
    }
 
+   /*
+    * Adds file and returns content uri.
+    */
+   private Uri addToMediaDB(File file) {
+       Log.d(LOGTAG, "In addToMediaDB");
+       Resources res = getResources();
+       ContentValues cv = new ContentValues();
+       long current = System.currentTimeMillis();
+       long modDate = file.lastModified();
+       Date date = new Date(current);
+       SimpleDateFormat formatter = new SimpleDateFormat(
+               res.getString(R.string.audio_db_title_format));
+       String title = formatter.format(date);
+
+       // Lets label the recorded audio file as NON-MUSIC so that the file
+       // won't be displayed automatically, except for in the playlist.
+       cv.put(MediaStore.Audio.Media.IS_MUSIC, "1");
+
+       cv.put(MediaStore.Audio.Media.TITLE, title);
+       cv.put(MediaStore.Audio.Media.DATA, file.getAbsolutePath());
+       cv.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000));
+       cv.put(MediaStore.Audio.Media.DATE_MODIFIED, (int) (modDate / 1000));
+       cv.put(MediaStore.Audio.Media.MIME_TYPE, "AUDIO_AAC_MP4");
+       cv.put(MediaStore.Audio.Media.ARTIST,
+               res.getString(R.string.audio_db_artist_name));
+       cv.put(MediaStore.Audio.Media.ALBUM,
+               res.getString(R.string.audio_db_album_name));
+       Log.d(LOGTAG, "Inserting audio record: " + cv.toString());
+       ContentResolver resolver = getContentResolver();
+       Uri base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+       Log.d(LOGTAG, "ContentURI: " + base);
+       Uri result = resolver.insert(base, cv);
+       if (result == null) {
+           Toast.makeText(this, "Unable to save recorded audio", Toast.LENGTH_SHORT).show();
+           return null;
+       }
+       if (getPlaylistId(res) == -1) {
+           createPlaylist(res, resolver);
+       }
+       int audioId = Integer.valueOf(result.getLastPathSegment());
+       addToPlaylist(resolver, audioId, getPlaylistId(res));
+
+       // Notify those applications such as Music listening to the
+       // scanner events that a recorded audio file just created.
+       sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
+       return result;
+   }
+
+   private int getPlaylistId(Resources res) {
+       Uri uri = MediaStore.Audio.Playlists.getContentUri("external");
+       final String[] ids = new String[] { MediaStore.Audio.Playlists._ID };
+       final String where = MediaStore.Audio.Playlists.NAME + "=?";
+       final String[] args = new String[] { res.getString(R.string.audio_db_playlist_name) };
+       Cursor cursor = query(uri, ids, where, args, null);
+       if (cursor == null) {
+           Log.v(LOGTAG, "query returns null");
+       }
+       int id = -1;
+       if (cursor != null) {
+           cursor.moveToFirst();
+           if (!cursor.isAfterLast()) {
+               id = cursor.getInt(0);
+           }
+           cursor.close();
+       }
+       return id;
+   }
+
+   private Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+       try {
+           ContentResolver resolver = getContentResolver();
+           if (resolver == null) {
+               return null;
+           }
+           return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
+        } catch (UnsupportedOperationException ex) {
+           return null;
+       }
+   }
+
+   private Uri createPlaylist(Resources res, ContentResolver resolver) {
+       ContentValues cv = new ContentValues();
+       cv.put(MediaStore.Audio.Playlists.NAME, res.getString(R.string.audio_db_playlist_name));
+       Uri uri = resolver.insert(MediaStore.Audio.Playlists.getContentUri("external"), cv);
+       if (uri == null) {
+           Toast.makeText(this, "Unable to save recorded audio", Toast.LENGTH_SHORT).show();
+       }
+       return uri;
+   }
+
+   private void addToPlaylist(ContentResolver resolver, int audioId, long playlistId) {
+       String[] cols = new String[] {
+               "count(*)"
+       };
+       Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
+       Cursor cur = resolver.query(uri, cols, null, null, null);
+       final int base;
+       if (cur != null) {
+            cur.moveToFirst();
+            base = cur.getInt(0);
+            cur.close();
+       }
+       else {
+            base = 0;
+       }
+       ContentValues values = new ContentValues();
+       values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(base + audioId));
+       values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audioId);
+       resolver.insert(uri, values);
+   }
+
    private void fmActionOnCallState( int state ) {
    //if Call Status is non IDLE we need to Mute FM as well stop recording if
    //any. Similarly once call is ended FM should be unmuted.
@@ -1224,6 +1413,14 @@
                       }
                    }
               }
+          } else {
+              if (!isFmOn() && (mServiceInUse) && (mCallbacks != null)) {
+                  try {
+                      mCallbacks.onDisabled();
+                  } catch (RemoteException e) {
+                      e.printStackTrace();
+                  }
+              }
           }
        }//idle
    }
@@ -1559,9 +1756,9 @@
          return(mService.get().isMuted());
       }
 
-      public void startRecording()
+      public boolean startRecording()
       {
-         mService.get().startRecording();
+         return(mService.get().startRecording());
       }
 
       public void stopRecording()
@@ -2074,53 +2271,17 @@
        if(isCallActive())
            return ;
        mSpeakerPhoneOn = speakerOn;
-       boolean analogmode = isAnalogModeSupported();
-       if (false == speakerOn) {
-           if (analogmode) {
-                if (isFmRecordingOn())
-                    stopRecording();
-                stopFM();
-               AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);
-               if (mMuted) {
-                   setAudioPath(true);
-               } else {
-                   mute();
-                   setAudioPath(true);
-                   unMute();
-               }
-           } else {
-               AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);
-           }
-           if (analogmode)
-                startFM();
+       Log.d(LOGTAG, "speakerOn:" + speakerOn);
+       if ((false == speakerOn) && (!mA2dpConnected)) {
+            Log.d(LOGTAG, "enabling headset");
+            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);
        }
 
-
-       //Need to turn off BT path when Speaker is set on vice versa.
-       if( !mA2dpDeviceSupportInHal && !analogmode && true == mA2dpDeviceState.isDeviceAvailable()) {
-           if( ((true == mOverA2DP) && (true == speakerOn)) ||
-               ((false == mOverA2DP) && (false == speakerOn)) ) {
-              //disable A2DP playback for speaker option
-               stopFM();
-               startFM();
-           }
-       }
        if (speakerOn) {
-           if (analogmode) {
-                 stopFM();
-                 if (mMuted) {
-                     setAudioPath(false);
-                 } else {
-                     mute();
-                     setAudioPath(false);
-                     unMute();
-                 }
-           }
+           Log.d(LOGTAG, "enabling speaker");
            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_SPEAKER);
-           if (analogmode)
-                startFM();
        }
-
+       Log.d(LOGTAG, "speakerOn completed:" + speakerOn);
    }
   /*
    *  ReConfigure the FM Setup parameters
diff --git a/fmapp2/src/com/caf/fmradio/FMTransmitterService.java b/fmapp2/src/com/caf/fmradio/FMTransmitterService.java
index 980c968..021e468 100644
--- a/fmapp2/src/com/caf/fmradio/FMTransmitterService.java
+++ b/fmapp2/src/com/caf/fmradio/FMTransmitterService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, 2015, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -474,8 +474,8 @@
              }
 
              Log.e(LOGTAG, "FMTx is on: Requesting to start FM TX");
-             AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_TX,
-                                  AudioSystem.DEVICE_STATE_AVAILABLE, "");
+//             AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_TX,
+//                                  AudioSystem.DEVICE_STATE_AVAILABLE, "");
          }
 
          if(true == bStatus )
@@ -507,8 +507,8 @@
       Log.d(LOGTAG, "fmOperationsOff" );
 
       Log.e(LOGTAG, "FMTx is off: Requesting to stop FM Tx");
-      AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_TX,
-                           AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
+//      AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_TX,
+//                           AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
    }
    /*
     * Turn OFF FM: Disable the FM Host and hardware                                  .
diff --git a/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl b/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl
index 7a2062d..6140f0d 100644
--- a/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl
+++ b/fmapp2/src/com/caf/fmradio/IFMRadioService.aidl
@@ -18,7 +18,7 @@
     boolean routeAudio(int device);
     boolean unMute();
     boolean isMuted();
-    void startRecording();
+    boolean startRecording();
     void stopRecording();
     boolean tune(int frequency);
     boolean seek(boolean up);
diff --git a/fmapp2/src/com/caf/fmradio/Settings.java b/fmapp2/src/com/caf/fmradio/Settings.java
index e6adb21..de19f01 100644
--- a/fmapp2/src/com/caf/fmradio/Settings.java
+++ b/fmapp2/src/com/caf/fmradio/Settings.java
@@ -265,6 +265,7 @@
           int noOfChannels = 0;
           int channelSpacing = 0;
           int preIndex;
+          int band_width;
 
           if (key.equals(REGIONAL_BAND_KEY)) {
               int curListIndex = FmSharedPreferences.getCurrentListIndex();
@@ -339,8 +340,10 @@
                noOfChannels = 0;
                max_freq = FmSharedPreferences.getUpperLimit();
                min_freq = FmSharedPreferences.getLowerLimit();
-               noOfChannels =  (int) (max_freq - freq)/FmSharedPreferences.getFrequencyStepSize();
-               if((freq > 0) && (freq < max_freq) && (freq >= 76000) && (noOfChannels > 0)) {
+               band_width = (int) (max_freq - freq);
+               noOfChannels =  band_width/FmSharedPreferences.getFrequencyStepSize();
+               if((freq > 0) && (freq < max_freq) && (freq >= 76000)
+                  && (noOfChannels > 0) && (band_width >= 100)) {
                   FmSharedPreferences.setLowerLimit((int)freq);
                   sendSettingsChangedIntent(FM_BAND_CHANGED);
                   setBandSummary(summaryBandItems.length - 1);
@@ -365,8 +368,10 @@
                noOfChannels = 0;
                min_freq = FmSharedPreferences.getLowerLimit();
                max_freq = FmSharedPreferences.getUpperLimit();
-               noOfChannels = (int) (freq - min_freq)/FmSharedPreferences.getFrequencyStepSize();
-               if((freq > 0) && (freq > min_freq) && (freq <= 108000) && (noOfChannels > 0)) {
+               band_width = (int) (freq - min_freq);
+               noOfChannels = band_width/FmSharedPreferences.getFrequencyStepSize();
+               if((freq > 0) && (freq > min_freq) && (freq <= 108000)
+                  && (noOfChannels > 0) && (band_width >= 100)) {
                   FmSharedPreferences.setUpperLimit((int)freq);
                   sendSettingsChangedIntent(FM_BAND_CHANGED);
                   setBandSummary(summaryBandItems.length - 1);
diff --git a/jni/FmConst.h b/jni/FmConst.h
index c4cd33b..00e6f82 100644
--- a/jni/FmConst.h
+++ b/jni/FmConst.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2015, The Linux Foundation. All rights reserved.
 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -44,7 +44,7 @@
 #define STD_BUF_SIZE  256
 
 const char *const FM_PERFORMANCE_PARAMS = "/etc/fm/fm_srch_af_th.conf";
-const char *const CALIB_DATA_NAME = "/data/app/Riva_fm_cal";
+const char *const CALIB_DATA_NAME = "/data/misc/fm/Riva_fm_cal";
 
 #define V4L2_CTRL_CLASS_USER  0x00980000
 #define V4L2_CID_BASE  (V4L2_CTRL_CLASS_USER | 0x900)
diff --git a/libfm_jni/FM_Const.h b/libfm_jni/FM_Const.h
index a93fe77..b0cc684 100644
--- a/libfm_jni/FM_Const.h
+++ b/libfm_jni/FM_Const.h
@@ -121,7 +121,7 @@
 const char *const SCRIPT_START_PROP = "ctl.start";
 const char *const FM_SOC_DL_SCRIPT = "fm_dl";
 const char *const SCRIPT_STOP_PROP = "ctl.stOP";
-const char *const CALIB_DATA_NAME = "/data/app/Riva_fm_cal";
+const char *const CALIB_DATA_NAME = "/data/misc/fm/Riva_fm_cal";
 const char *const SOC_PATCH_DL_SCRPT = "fm_dl";
 const char *const FM_DEVICE_PATH = "/dev/radio0";
 const char *const FM_PERFORMANCE_PARAMS = "/etc/fm/fm_srch_af_th.conf";
diff --git a/libfm_jni/FmIoctlsInterface.cpp b/libfm_jni/FmIoctlsInterface.cpp
index bd3440b..fbe035c 100644
--- a/libfm_jni/FmIoctlsInterface.cpp
+++ b/libfm_jni/FmIoctlsInterface.cpp
@@ -119,7 +119,7 @@
     channel.type = V4L2_TUNER_RADIO;
     ret = ioctl(fd, VIDIOC_G_FREQUENCY, &channel);
 
-    if(ret != IOCTL_SUCC) {
+    if(ret < IOCTL_SUCC) {
         return FM_FAILURE;
     }else {
         freq = (channel.frequency / TUNE_MULT);
@@ -139,7 +139,7 @@
     channel.frequency = (freq * TUNE_MULT);
 
     ret = ioctl(fd, VIDIOC_S_FREQUENCY, &channel);
-    if(ret != IOCTL_SUCC) {
+    if(ret < IOCTL_SUCC) {
         return FM_FAILURE;
     }else {
         return FM_SUCCESS;
@@ -158,7 +158,7 @@
     control.id = id;
 
     ret = ioctl(fd, VIDIOC_S_CTRL, &control);
-    if(ret != IOCTL_SUCC) {
+    if(ret < IOCTL_SUCC) {
         return FM_FAILURE;
     }else {
         return FM_SUCCESS;
@@ -190,7 +190,7 @@
        v4l2_ctls.count = 1;
        v4l2_ctls.controls = &ext_ctl;
        ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &v4l2_ctls);
-       if(ret != IOCTL_SUCC) {
+       if(ret < IOCTL_SUCC) {
            return FM_FAILURE;
        }else {
            return FM_SUCCESS;
@@ -210,7 +210,7 @@
 
     control.id = id;
     ret = ioctl(fd, VIDIOC_G_CTRL, &control);
-    if(ret != IOCTL_SUCC) {
+    if(ret < IOCTL_SUCC) {
         return FM_FAILURE;
     }else {
         val = control.value;
@@ -230,7 +230,7 @@
     hw_seek.type = V4L2_TUNER_RADIO;
 
     ret = ioctl(fd, VIDIOC_S_HW_FREQ_SEEK, &hw_seek);
-    if(ret != IOCTL_SUCC) {
+    if(ret < IOCTL_SUCC) {
         return FM_FAILURE;
     }else {
         return FM_SUCCESS;
@@ -252,7 +252,7 @@
 
     ret = ioctl(fd, VIDIOC_S_TUNER, &tuner);
     ret = set_control(fd, V4L2_CID_PRV_REGION, 0);
-    if(ret != IOCTL_SUCC) {
+    if(ret < IOCTL_SUCC) {
         return FM_FAILURE;
     }else {
         return FM_SUCCESS;
@@ -270,8 +270,8 @@
     tuner.index = 0;
     tuner.signal = 0;
     ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
-    if(ret != IOCTL_SUCC) {
-        ret = FM_SUCCESS;
+    if(ret < IOCTL_SUCC) {
+        ret = FM_FAILURE;
     }else {
         rmssi = tuner.signal;
         ret = FM_SUCCESS;
@@ -289,7 +289,7 @@
 
     tuner.index = 0;
     ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
-    if(ret != IOCTL_SUCC) {
+    if(ret < IOCTL_SUCC) {
         return FM_FAILURE;
     }else {
         freq = (tuner.rangehigh / TUNE_MULT);
@@ -308,7 +308,7 @@
 
     tuner.index = 0;
     ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
-    if(ret != IOCTL_SUCC) {
+    if(ret < IOCTL_SUCC) {
         return FM_FAILURE;
     }else {
         freq = (tuner.rangelow / TUNE_MULT);
@@ -327,7 +327,7 @@
 
     tuner.index = 0;
     ret = ioctl(fd, VIDIOC_G_TUNER, &tuner);
-    if(ret != IOCTL_SUCC) {
+    if(ret < IOCTL_SUCC) {
         return FM_FAILURE;
     }else {
         tuner.audmode = mode;
@@ -357,7 +357,7 @@
         v4l2_buf.length = STD_BUF_SIZE;
         v4l2_buf.m.userptr = (ULINT)buff;
         ret = ioctl(fd, VIDIOC_DQBUF, &v4l2_buf);
-        if(ret != IOCTL_SUCC) {
+        if(ret < IOCTL_SUCC) {
             return FM_FAILURE;
         }else {
             return v4l2_buf.bytesused;
@@ -375,7 +375,7 @@
 
     ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, v4l2_ctls);
 
-    if(ret != IOCTL_SUCC) {
+    if(ret < IOCTL_SUCC) {
        return FM_FAILURE;
     }else {
        return FM_SUCCESS;
diff --git a/libfm_jni/FmRadioController.cpp b/libfm_jni/FmRadioController.cpp
index 55bcef4..613a062 100644
--- a/libfm_jni/FmRadioController.cpp
+++ b/libfm_jni/FmRadioController.cpp
@@ -159,8 +159,11 @@
     int ret = FM_SUCCESS;
     struct timespec ts;
     ConfigFmThs thsObj;
+    char value[PROPERTY_VALUE_MAX] = {'\0'};
 
     ALOGI("%s,[freq=%d]\n", __func__, freq);
+    property_get("qcom.bluetooth.soc", value, NULL);
+    ALOGD("BT soc is %s\n", value);
     if (fd_driver < 0) {
         ret = open_dev();
         if (ret != FM_SUCCESS) {
@@ -171,12 +174,14 @@
 
     if (cur_fm_state == FM_OFF) {
         ALOGE("cur_fm_state = %d\n",cur_fm_state);
-        ret = FmIoctlsInterface::start_fm_patch_dl(fd_driver);
-        if (ret != FM_SUCCESS) {
-            ALOGE("FM patch downloader failed: %d\n", ret);
-            close_dev();
-            set_fm_state(FM_OFF);
-            return FM_FAILURE;
+        if (strcmp(value, "rome") != 0) {
+            ret = FmIoctlsInterface::start_fm_patch_dl(fd_driver);
+            if (ret != FM_SUCCESS) {
+                ALOGE("FM patch downloader failed: %d\n", ret);
+                close_dev();
+                set_fm_state(FM_OFF);
+                return FM_FAILURE;
+            }
         }
         if (event_listener_thread == 0) {
             ret = pthread_create(&event_listener_thread, NULL,
@@ -1095,10 +1100,15 @@
      void
 )
 {
+     char value[PROPERTY_VALUE_MAX] = {'\0'};
+
      ALOGI("FM handle ready Event\n");
      FmIoctlsInterface::set_control(fd_driver,
              V4L2_CID_PRV_AUDIO_PATH, AUDIO_DIGITAL_PATH);
-     FmIoctlsInterface::set_calibration(fd_driver);
+     property_get("qcom.bluetooth.soc", value, NULL);
+     if (strcmp(value, "rome") != 0) {
+         FmIoctlsInterface::set_calibration(fd_driver);
+     }
      pthread_mutex_lock(&mutex_turn_on_cond);
      set_fm_state(FM_ON);
      pthread_cond_broadcast(&turn_on_cond);