release-request-f4ecf242-5d1c-45e0-8c7c-ede48d1a9e82-for-git_oc-release-4111650 snap-temp-L02200000075283731

Change-Id: I1cfe6096c7b6909852019cc70e2ab8dc90c4ea23
diff --git a/PMC/src/com/android/pmc/A2dpReceiver.java b/PMC/src/com/android/pmc/A2dpReceiver.java
index 7c10157..7cb4ece 100644
--- a/PMC/src/com/android/pmc/A2dpReceiver.java
+++ b/PMC/src/com/android/pmc/A2dpReceiver.java
@@ -35,6 +35,7 @@
 import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.Set;
 
 /**
  * Bluetooth A2DP Receiver functions for codec power testing.
@@ -43,31 +44,21 @@
     public static final String TAG = "A2DPPOWER";
     public static final String A2DP_INTENT = "com.android.pmc.A2DP";
     public static final String A2DP_ALARM = "com.android.pmc.A2DP.Alarm";
-    public static final String A2DP_ACTION = "com.android.pmc.A2DP.Action";
-    public static final String CURRENT_ALARM = "com.android.pmc.A2DP.CurrentAlarm";
-    public static final int ALARM_MESSAGE = 1;
     public static final int THOUSAND = 1000;
     public static final int WAIT_SECONDS = 10;
+    public static final int ALARM_MESSAGE = 1;
 
-    public static final int START_PLAY = 1;
-    public static final int PAUSE_PLAY = 2;
-    public static final int STOP_PLAY = 3;
     public static final float NORMAL_VOLUME = 0.3f;
     public static final float ZERO_VOLUME = 0.0f;
 
     private final Context mContext;
     private final AlarmManager mAlarmManager;
+    private final BluetoothAdapter mBluetoothAdapter;
 
-    private int mPlayTime;
-    private int mIdleTime;
-    private int mNumAlarms;
     private MediaPlayer mPlayer;
-    private BluetoothAdapter mBluetoothAdapter;
     private BluetoothA2dp mBluetoothA2dp;
-    // For a baseline case when music is not play but BT is enabled.
-    private boolean mNotPlay = false;
-    // For a baseline case when BT is off but music is playing with speaker is muted
-    private boolean mMute = false;
+
+    private PMCStatusLogger mPMCStatusLogger;
 
     /**
      * BroadcastReceiver() to get status after calling setCodecConfigPreference()
@@ -114,6 +105,7 @@
         // Prepare for setting alarm service
         mContext = context;
         mAlarmManager = alarmManager;
+
         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
         if (mBluetoothAdapter == null) {
             Log.e(TAG, "BluetoothAdapter is Null");
@@ -131,13 +123,48 @@
         // Setup BroadcastReceiver for ACTION_CODEC_CONFIG_CHANGED
         IntentFilter filter = new IntentFilter();
         if (mBluetoothAdapter != null) {
-            mBluetoothAdapter.getProfileProxy(context,
+            mBluetoothAdapter.getProfileProxy(mContext,
                                     mBluetoothA2dpServiceListener,
                                     BluetoothProfile.A2DP);
+            Log.d(TAG, "After getProfileProxy()");
         }
         filter = new IntentFilter();
         filter.addAction(BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED);
-        context.registerReceiver(mBluetoothA2dpReceiver, filter);
+        mContext.registerReceiver(mBluetoothA2dpReceiver, filter);
+
+        Log.d(TAG, "A2dpReceiver()");
+    }
+
+    /**
+     * initialize() to setup Bluetooth adapters and check if Bluetooth device is connected
+     *              it is called when PMC command is received to start streaming
+     */
+    private boolean initialize() {
+        Log.d(TAG, "Start initialize()");
+
+        mPMCStatusLogger = new PMCStatusLogger(TAG + ".log", TAG);
+
+        // Check if any Bluetooth devices are connected
+        ArrayList<BluetoothDevice> results = new ArrayList<BluetoothDevice>();
+        Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();
+        if (bondedDevices == null) {
+            Log.e(TAG, "Bonded devices list is null");
+            return false;
+        }
+        for (BluetoothDevice bd : bondedDevices) {
+            if (bd.isConnected()) {
+                results.add(bd);
+            }
+        }
+
+        if (results.isEmpty()) {
+            Log.e(TAG, "No device is connected");
+            return false;
+        }
+
+        Log.d(TAG, "Finish initialize()");
+
+        return true;
     }
 
     /**
@@ -151,8 +178,11 @@
         if (!intent.getAction().equals(A2DP_INTENT)) return;
         boolean alarm = intent.hasExtra(A2DP_ALARM);
         if (alarm) {
-            Log.d(TAG, "Received Alarm broadcast message");
-            handleAlarm(intent);
+            Log.v(TAG, "Alarm Message to Stop playing");
+            mPMCStatusLogger.logStatus("SUCCEED");
+            mPlayer.stop();
+            // Release the Media Player
+            mPlayer.release();
         } else {
             Log.d(TAG, "Received PMC command message");
             processParameters(intent);
@@ -173,14 +203,12 @@
         // Other code specific values are not used now
         long codecSpecific1 = 0, codecSpecific2 = 0, codecSpecific3 = 0,
                 codecSpecific4 = 0;
-        int startTime = 0, playTime = 0, idleTime = 0, repetitions = 1;
+        int playTime = 0;
         String musicUrl;
         String tmpStr;
-        // Reset these values for each test cases
-        // For a baseline case when music is not play but BT is enabled.
-        mNotPlay = false;
-        // For a baseline case when BT is off but music is playing with speaker is muted
-        mMute = false;
+
+        // For a baseline case when Blueooth is off but music is playing with speaker is muted
+        boolean bt_off_mute = false;
 
         Bundle extras = intent.getExtras();
 
@@ -188,68 +216,19 @@
             Log.e(TAG, "No parameters specified");
             return;
         }
-
-        if (!extras.containsKey("CodecType")) {
-            Log.e(TAG, "No Codec Type specified");
+        // Always initialize()
+        if (!initialize()) {
+            mPMCStatusLogger.logStatus("initialize() Failed");
             return;
         }
-        tmpStr = extras.getString("CodecType");
-        Log.d(TAG, "Codec Type= " + tmpStr);
-        codecType = Integer.valueOf(tmpStr);
-
-        if (!extras.containsKey("SampleRate")) {
-            Log.e(TAG, "No Sample Rate specified");
+        // Check if it is baseline Bluetooth is on but not stream
+        if (extras.containsKey("BT_ON_NotPlay")) {
+            Log.v(TAG, "NotPlay is specified for baseline case that only Bluetooth is on");
+            // Do nothing further
+            mPMCStatusLogger.logStatus("READY");
+            mPMCStatusLogger.logStatus("SUCCEED");
             return;
         }
-        tmpStr = extras.getString("SampleRate");
-        Log.d(TAG, "Sample Rate = " + tmpStr);
-        sampleRate = Integer.valueOf(tmpStr);
-
-        if (!extras.containsKey("BitsPerSample")) {
-            Log.e(TAG, "No BitsPerSample specified");
-            return;
-        }
-        tmpStr = extras.getString("BitsPerSample");
-        Log.d(TAG, "BitsPerSample = " + tmpStr);
-        bitsPerSample = Integer.valueOf(tmpStr);
-
-        if (extras.containsKey("ChannelMode")) {
-            tmpStr = extras.getString("ChannelMode");
-            Log.d(TAG, "ChannelMode = " + tmpStr);
-            channelMode = Integer.valueOf(tmpStr);
-        }
-
-        if (extras.containsKey("LdacPlaybackQuality")) {
-            tmpStr = extras.getString("LdacPlaybackQuality");
-            Log.d(TAG, "LdacPlaybackQuality = " + tmpStr);
-            codecSpecific1 = Integer.valueOf(tmpStr);
-        }
-
-        if (extras.containsKey("CodecSpecific2")) {
-            tmpStr = extras.getString("CodecSpecific2");
-            Log.d(TAG, "CodecSpecific2 = " + tmpStr);
-            codecSpecific1 = Integer.valueOf(tmpStr);
-        }
-
-        if (extras.containsKey("CodecSpecific3")) {
-            tmpStr = extras.getString("CodecSpecific3");
-            Log.d(TAG, "CodecSpecific3 = " + tmpStr);
-            codecSpecific1 = Integer.valueOf(tmpStr);
-        }
-
-        if (extras.containsKey("CodecSpecific4")) {
-            tmpStr = extras.getString("CodecSpecific4");
-            Log.d(TAG, "CodecSpecific4 = " + tmpStr);
-            codecSpecific1 = Integer.valueOf(tmpStr);
-        }
-
-        if (!extras.containsKey("StartTime")) {
-            Log.e(TAG, "No Start Time specified");
-            return;
-        }
-        tmpStr = extras.getString("StartTime");
-        Log.d(TAG, "Start Time = " + tmpStr);
-        startTime = Integer.valueOf(tmpStr);
 
         if (!extras.containsKey("PlayTime")) {
             Log.e(TAG, "No Play Time specified");
@@ -259,18 +238,6 @@
         Log.d(TAG, "Play Time = " + tmpStr);
         playTime = Integer.valueOf(tmpStr);
 
-        if (extras.containsKey("IdleTime")) {
-            tmpStr = extras.getString("IdleTime");
-            Log.d(TAG, "Idle Time = " + tmpStr);
-            idleTime = Integer.valueOf(tmpStr);
-        }
-
-        if (extras.containsKey("Repetitions")) {
-            tmpStr = extras.getString("Repetitions");
-            Log.d(TAG, "Repetitions = " + tmpStr);
-            repetitions = Integer.valueOf(tmpStr);
-        }
-
         if (!extras.containsKey("MusicURL")) {
             Log.e(TAG, "No Music URL specified");
             return;
@@ -278,187 +245,104 @@
         musicUrl = extras.getString("MusicURL");
         Log.d(TAG, "Music URL = " + musicUrl);
 
-        if (extras.containsKey("NotPlay")) {
-            Log.v(TAG, "NotPlay is specified for baseline case of only BT on");
-            mNotPlay = true;
-        }
-
-        if (extras.containsKey("Mute")) {
-            Log.v(TAG, "Mute is specified for BT off baseline case");
-            mMute = true;
-        }
-
-        if (playTime == 0 || startTime == 0 || musicUrl.isEmpty() || musicUrl == null
-                || codecType == BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID
-                || sampleRate == BluetoothCodecConfig.SAMPLE_RATE_NONE
-                || bitsPerSample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
+        // playTime and musicUrl are necessary
+        if (playTime == 0 || musicUrl.isEmpty() || musicUrl == null) {
             Log.d(TAG, "Invalid paramters");
             return;
         }
+        // Check if it is the baseline that Bluetooth is off but streaming with speakers muted
+        if (extras.containsKey("BT_OFF_Mute")) {
+            Log.v(TAG, "Mute is specified for Bluetooth off baseline case");
+            bt_off_mute = true;
+        } else {
 
-        if (prepare(codecType, sampleRate, bitsPerSample, channelMode, codecSpecific1,
-                    codecSpecific2, codecSpecific3, codecSpecific4,
-                    playTime, idleTime, repetitions, musicUrl)) {
-            startAlarm(startTime, null);
-        }
-    }
-
-    /**
-     * Method to start or stop playing music when Alarm is triggered
-     *
-     * @param intent - system will provide an intent to this function
-     */
-    private void handleAlarm(Intent intent) {
-
-        int action = intent.getIntExtra(A2DP_ACTION, 0);
-        Log.d(TAG, "handleAlarm() Action: " + action);
-        if (action == -1) {
-            Log.e(TAG, "Received Alarm with no Action");
-            return;
-        }
-        if (mPlayer == null) {
-            Log.e(TAG, "Media Player is null");
-            return;
-        }
-
-        if (mNotPlay) {
-            notPlayCase(intent, action);
-            return;
-        }
-
-        if (action == START_PLAY) {
-            Log.v(TAG, "Before Start Play");
-            mPlayer.start();
-            mPlayer.setLooping(true);
-            if (!mPlayer.isPlaying()) {
-                Log.e(TAG, "Media Player is not playing");
+            if (!extras.containsKey("CodecType")) {
+                Log.e(TAG, "No Codec Type specified");
+                return;
             }
-            startAlarm(mPlayTime, intent);
-        } else if (action == PAUSE_PLAY) {
-            Log.v(TAG, "Before Pause play");
-            mPlayer.pause();
-            startAlarm(mIdleTime, intent);
-        } else if (action == STOP_PLAY) {
-            Log.v(TAG, "Before Stop play");
-            mPlayer.stop();
-            // Release the Media Player
-            mPlayer.release();
+            tmpStr = extras.getString("CodecType");
+            Log.d(TAG, "Codec Type= " + tmpStr);
+            codecType = Integer.valueOf(tmpStr);
 
+            if (!extras.containsKey("SampleRate")) {
+                Log.e(TAG, "No Sample Rate specified");
+                return;
+            }
+            tmpStr = extras.getString("SampleRate");
+            Log.d(TAG, "Sample Rate = " + tmpStr);
+            sampleRate = Integer.valueOf(tmpStr);
+
+            if (!extras.containsKey("BitsPerSample")) {
+                Log.e(TAG, "No BitsPerSample specified");
+                return;
+            }
+            tmpStr = extras.getString("BitsPerSample");
+            Log.d(TAG, "BitsPerSample = " + tmpStr);
+            bitsPerSample = Integer.valueOf(tmpStr);
+
+            if (extras.containsKey("ChannelMode")) {
+                tmpStr = extras.getString("ChannelMode");
+                Log.d(TAG, "ChannelMode = " + tmpStr);
+                channelMode = Integer.valueOf(tmpStr);
+            }
+
+            if (extras.containsKey("LdacPlaybackQuality")) {
+                tmpStr = extras.getString("LdacPlaybackQuality");
+                Log.d(TAG, "LdacPlaybackQuality = " + tmpStr);
+                codecSpecific1 = Integer.valueOf(tmpStr);
+            }
+
+            if (extras.containsKey("CodecSpecific2")) {
+                tmpStr = extras.getString("CodecSpecific2");
+                Log.d(TAG, "CodecSpecific2 = " + tmpStr);
+                codecSpecific1 = Integer.valueOf(tmpStr);
+            }
+
+            if (extras.containsKey("CodecSpecific3")) {
+                tmpStr = extras.getString("CodecSpecific3");
+                Log.d(TAG, "CodecSpecific3 = " + tmpStr);
+                codecSpecific1 = Integer.valueOf(tmpStr);
+            }
+
+            if (extras.containsKey("CodecSpecific4")) {
+                tmpStr = extras.getString("CodecSpecific4");
+                Log.d(TAG, "CodecSpecific4 = " + tmpStr);
+                codecSpecific1 = Integer.valueOf(tmpStr);
+            }
+
+            if (codecType == BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID
+                    || sampleRate == BluetoothCodecConfig.SAMPLE_RATE_NONE
+                    || bitsPerSample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
+                Log.d(TAG, "Invalid paramters");
+                return;
+            }
+        }
+
+        if (playMusic(musicUrl, bt_off_mute)) {
+            // Set the requested Codecs on the device for normal codec cases
+            if (!bt_off_mute) {
+                if (!setCodecValue(codecType, sampleRate, bitsPerSample, channelMode,
+                        codecSpecific1, codecSpecific2, codecSpecific3, codecSpecific4)) {
+                    mPMCStatusLogger.logStatus("setCodecValue() Failed");
+                }
+            }
+            mPMCStatusLogger.logStatus("READY");
+            startAlarm(playTime);
         } else {
-            Log.e(TAG, "Unknown Action");
+            mPMCStatusLogger.logStatus("playMusic() Failed");
         }
     }
 
-    /**
-     * Method for baseline case "Not Play" when Alarm is triggered
-     *
-     * @param intent - system will provide an intent to this function
-     */
-    private void notPlayCase(Intent intent, int action) {
-
-        if (action == START_PLAY) {
-            Log.v(TAG, "NotPlay case for PlAY action");
-            startAlarm(mPlayTime, intent);
-        } else if (action == PAUSE_PLAY) {
-            Log.v(TAG, "NotPlay case for PAUSE");
-            startAlarm(mIdleTime, intent);
-        } else if (action == STOP_PLAY) {
-            Log.v(TAG, "NotPlay case for Stop play");
-            // Release the Media Player
-            mPlayer.release();
-        } else {
-            Log.e(TAG, "Unknown Action");
-        }
-    }
 
     /**
-     * Method to verify if the codec config values are changed
+     * Function to setup MediaPlayer and play music
      *
-     * @param codecType - Codec Type
-     * @param sampleRate - Sample Rate
-     * @param bitsPerSample - Bit Per Sample
-     * @param codecSpecific1 - LDAC playback quality
-     */
-    private boolean verifyCodeConfig(int codecType, int sampleRate, int bitsPerSample,
-                                     int channelMode, long codecSpecific1) {
-        BluetoothCodecConfig codecConfig = null;
-        codecConfig = getCodecValue(false);
-        if (codecConfig == null) return false;
-
-        if (codecType == BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC) {
-            if (codecConfig.getCodecType() == codecType
-                    && codecConfig.getSampleRate() == sampleRate
-                    && codecConfig.getBitsPerSample() == bitsPerSample
-                    && codecConfig.getChannelMode() == channelMode
-                    && codecConfig.getCodecSpecific1() == codecSpecific1) return true;
-        } else {
-            if (codecConfig.getCodecType() == codecType
-                    && codecConfig.getSampleRate() == sampleRate
-                    && codecConfig.getBitsPerSample() == bitsPerSample
-                    && codecConfig.getChannelMode() == channelMode) return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Function to setup MediaPlayer
-     *
-     * @param codecType - Codec Type
-     * @param sampleRate - Sample Rate
-     * @param bitsPerSample - Bit Per Sample
-     * @param codecSpecific1 - LDAC playback quality
-     * @param codecSpecific2 - codecSpecific2
-     * @param codecSpecific3 - codecSpecific3
-     * @param codecSpecific4 - codecSpecific4
-     * @param playTime - Music playing duration
-     * @param idleTime - Pause time for music
-     * @param repetitions - number of cycles of play/pause
      * @param musicURL - Music URL
+     * @param bt_off_mute - true is to mute speakers
      *
      */
-    private boolean prepare(int codecType, int sampleRate, int bitsPerSample, int channelMode,
-                             long codecSpecific1, long codecSpecific2, long codecSpecific3,
-                             long codecSpecific4,
-                             int playTime, int idleTime, int repetitions, String musicURL) {
-        ArrayList<BluetoothDevice> results = new ArrayList<BluetoothDevice>();
-        // When mMute is specific Bluetooth will be disabled by Python script
-        if (!mMute) {
-            for (BluetoothDevice bd : mBluetoothAdapter.getBondedDevices()) {
-                if (bd.isConnected()) {
-                    results.add(bd);
-                }
-            }
+    private boolean playMusic(String musicURL, boolean btOffMute) {
 
-            if (results.isEmpty()) {
-                Log.e(TAG, "No device is connected");
-                return false;
-            }
-
-            // Set the requested Codecs on the device
-            setCodecValue(codecType, sampleRate, bitsPerSample, channelMode, codecSpecific1,
-                    codecSpecific2, codecSpecific3, codecSpecific4);
-            // Wait here to see if the codec is changed to new value
-            for (int i = 0; i < WAIT_SECONDS; i++) {
-                if (verifyCodeConfig(codecType, sampleRate,
-                        bitsPerSample, channelMode, codecSpecific1))  {
-                    break;
-                }
-                try {
-                    Thread.sleep(THOUSAND);
-                } catch (InterruptedException e) {
-                    Log.d(TAG, "Sleep is interrupted");
-                }
-            }
-            if (!verifyCodeConfig(codecType, sampleRate,
-                    bitsPerSample, channelMode, codecSpecific1)) {
-                Log.e(TAG, "Codec config is NOT set correctly");
-                return false;
-            }
-        }
-        mPlayTime = playTime;
-        mIdleTime = idleTime;
-        mNumAlarms = repetitions * 2;
         mPlayer = MediaPlayer.create(mContext, Uri.parse(musicURL));
         if (mPlayer == null) {
             Log.e(TAG, "Failed to create Media Player");
@@ -466,14 +350,22 @@
         }
         Log.d(TAG, "Media Player created: " + musicURL);
 
-        if (mMute) {
-            Log.v(TAG, "Mute Speakers for BT off baseline case");
+        if (btOffMute) {
+            Log.v(TAG, "Mute Speakers for Bluetooth off baseline case");
             mPlayer.setVolume(ZERO_VOLUME, ZERO_VOLUME);
         } else {
             Log.d(TAG, "Set Normal Volume for speakers");
             mPlayer.setVolume(NORMAL_VOLUME, NORMAL_VOLUME);
         }
 
+        // Play Music now and setup looping
+        mPlayer.start();
+        mPlayer.setLooping(true);
+        if (!mPlayer.isPlaying()) {
+            Log.e(TAG, "Media Player is not playing");
+            return false;
+        }
+
         return true;
     }
 
@@ -481,38 +373,11 @@
      * Function to be called to start alarm
      *
      * @param alarmStartTime - time when the music needs to be started or stopped
-     * @param intent - intent to content alarm number and current action
      */
-    public void startAlarm(int alarmStartTime, Intent intent) {
-        int currentAlarm = 0;
-        int nextAction = START_PLAY;
-        int currentAction = 0;
-
-        if (intent != null) {
-            if (currentAlarm >= mNumAlarms) {
-                Log.d(TAG, "All alarms are done");
-                return;
-            }
-            // Get alarm number inside the intent
-            currentAlarm = intent.getIntExtra(CURRENT_ALARM, 0);
-            currentAction =  intent.getIntExtra(A2DP_ACTION, 0);
-            if (currentAlarm == mNumAlarms - 1) {
-                // last alarm
-                nextAction = STOP_PLAY;
-            } else if (currentAction == START_PLAY) {
-                nextAction = PAUSE_PLAY;
-            } else {
-                nextAction = START_PLAY;
-            }
-        }
-
-        Log.d(TAG, "Current Alarm: " + currentAlarm + " Action: " + currentAction
-                + " trigger time: " + alarmStartTime);
+    private void startAlarm(int alarmStartTime) {
 
         Intent alarmIntent = new Intent(A2DP_INTENT);
         alarmIntent.putExtra(A2DP_ALARM, ALARM_MESSAGE);
-        alarmIntent.putExtra(A2DP_ACTION, nextAction);
-        alarmIntent.putExtra(CURRENT_ALARM, ++currentAlarm);
 
         long triggerTime = SystemClock.elapsedRealtime()
                                + alarmStartTime * THOUSAND;
@@ -531,8 +396,6 @@
         BluetoothCodecConfig codecConfig = null;
         BluetoothCodecConfig[] codecsLocalCapabilities = null;
         BluetoothCodecConfig[] codecsSelectableCapabilities = null;
-        // In the mute case BT is off there will be not Codec Info available
-        if (mMute) return null;
 
         if (mBluetoothA2dp != null) {
             codecStatus = mBluetoothA2dp.getCodecStatus();
@@ -570,26 +433,87 @@
      * @param codecSpecific3 - codecSpecific3
      * @param codecSpecific4 - codecSpecific4
      */
-    private void setCodecValue(int codecType, int sampleRate, int bitsPerSample,
+    private boolean setCodecValue(int codecType, int sampleRate, int bitsPerSample,
                 int channelMode, long codecSpecific1, long codecSpecific2,
                 long codecSpecific3, long codecSpecific4) {
         Log.d(TAG, "SetCodecValue: Codec Type: " + codecType + " sampleRate: " + sampleRate
                 + " bitsPerSample: " + bitsPerSample + " Channel Mode: " + channelMode
                 + " LDAC quality: " + codecSpecific1);
 
-        // In the mute case BT is off there will be not Codec Info available
-        if (mMute) return;
-
         BluetoothCodecConfig codecConfig =
                 new BluetoothCodecConfig(codecType, BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST,
                 sampleRate, bitsPerSample, channelMode,
                 codecSpecific1, codecSpecific2, codecSpecific3, codecSpecific4);
 
+        // Wait here to see if mBluetoothA2dp is set
+        for (int i = 0; i < WAIT_SECONDS; i++) {
+            Log.d(TAG, "Wait for BluetoothA2dp");
+            if (mBluetoothA2dp != null) {
+                break;
+            }
+
+            try {
+                Thread.sleep(THOUSAND);
+            } catch (InterruptedException e) {
+                Log.d(TAG, "Sleep is interrupted");
+            }
+        }
+
         if (mBluetoothA2dp != null) {
             Log.d(TAG, "setCodecConfigPreference()");
             mBluetoothA2dp.setCodecConfigPreference(codecConfig);
         } else {
             Log.e(TAG, "mBluetoothA2dp is null. Codec is not set");
+            return false;
         }
+        // Wait here to see if the codec is changed to new value
+        for (int i = 0; i < WAIT_SECONDS; i++) {
+            if (verifyCodeConfig(codecType, sampleRate,
+                    bitsPerSample, channelMode, codecSpecific1))  {
+                break;
+            }
+            try {
+                Thread.sleep(THOUSAND);
+            } catch (InterruptedException e) {
+                Log.d(TAG, "Sleep is interrupted");
+            }
+        }
+        if (!verifyCodeConfig(codecType, sampleRate,
+                bitsPerSample, channelMode, codecSpecific1)) {
+            Log.e(TAG, "Codec config is NOT set correctly");
+            return false;
+        }
+        return true;
     }
+
+    /**
+     * Method to verify if the codec config values are changed
+     *
+     * @param codecType - Codec Type
+     * @param sampleRate - Sample Rate
+     * @param bitsPerSample - Bit Per Sample
+     * @param codecSpecific1 - LDAC playback quality
+     */
+    private boolean verifyCodeConfig(int codecType, int sampleRate, int bitsPerSample,
+                                     int channelMode, long codecSpecific1) {
+        BluetoothCodecConfig codecConfig = null;
+        codecConfig = getCodecValue(false);
+        if (codecConfig == null) return false;
+
+        if (codecType == BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC) {
+            if (codecConfig.getCodecType() == codecType
+                    && codecConfig.getSampleRate() == sampleRate
+                    && codecConfig.getBitsPerSample() == bitsPerSample
+                    && codecConfig.getChannelMode() == channelMode
+                    && codecConfig.getCodecSpecific1() == codecSpecific1) return true;
+        } else {
+            if (codecConfig.getCodecType() == codecType
+                    && codecConfig.getSampleRate() == sampleRate
+                    && codecConfig.getBitsPerSample() == bitsPerSample
+                    && codecConfig.getChannelMode() == channelMode) return true;
+        }
+
+        return false;
+    }
+
 }
diff --git a/PMC/src/com/android/pmc/BleScanReceiver.java b/PMC/src/com/android/pmc/BleScanReceiver.java
index bd090a2..56532dd 100644
--- a/PMC/src/com/android/pmc/BleScanReceiver.java
+++ b/PMC/src/com/android/pmc/BleScanReceiver.java
@@ -50,6 +50,10 @@
     private BluetoothLeScanner mBleScanner;
     private ScanSettings mScanSettings;
     private List<ScanFilter> mScanFilterList;
+    // Use PMCStatusLogger to send status and start & end times back to Python client
+    private PMCStatusLogger mPMCStatusLogger;
+    // Test start time is set when receiving the broadcast message from Python client
+    private long mStartTestTime;
 
     private ScanCallback mScanCallback = new ScanCallback() {
         @Override
@@ -74,12 +78,16 @@
         private int mScanTime;
         private int mNoScanTime;
         private int mNumAlarms;
+        private int mFirstScanTime;
+        private long mScanStartTime;
+        private long mScanEndTime;
 
         /**
          * Constructor
          *
          */
         public BleScanListener() {
+            Log.d(TAG, "Start BleScanListener()");
             BluetoothAdapter bleAdaptor = BluetoothAdapter.getDefaultAdapter();
 
             if (bleAdaptor == null) {
@@ -98,6 +106,7 @@
 
             mBleScanner = bleAdaptor.getBluetoothLeScanner();
             mScanFilterList = new ArrayList<ScanFilter>();
+            Log.d(TAG, "End BleScanListener()");
         }
 
         /**
@@ -117,14 +126,15 @@
             mScanTime = scanTime;
             mNoScanTime = noScanTime;
             mNumAlarms = numAlarms;
+            mFirstScanTime = startTime;
+
             mScanSettings = new ScanSettings.Builder().setScanMode(
                                             scanMode).build();
 
             Intent alarmIntent = new Intent(BleScanListener.BLESCAN);
             alarmIntent.putExtra("com.android.pmc.BLESCAN.Action", START_SCAN);
             alarmIntent.putExtra("com.android.pmc.BLESCAN.CurrentAlarm", INIT_ALARM_NO);
-            long triggerTime = SystemClock.elapsedRealtime()
-                               + startTime * 1000;
+            long triggerTime = SystemClock.elapsedRealtime() + startTime * 1000;
             mAlarmManager.setExactAndAllowWhileIdle(
                           AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime,
                           PendingIntent.getBroadcast(mContext, 0,
@@ -149,6 +159,7 @@
                 return;
             }
             if (currentAlarm >= mNumAlarms) {
+                mPMCStatusLogger.flash();  // To flash out timestamps into log file
                 Log.d(TAG, "All alarms are done");
                 return;
             }
@@ -183,13 +194,22 @@
             }
             if (action == START_SCAN) {
                 Log.v(TAG, "Before Start Scan");
+                mScanStartTime = System.currentTimeMillis();
                 mBleScanner.startScan(mScanFilterList, mScanSettings,
                                  mScanCallback);
                 repeatAlarm(intent, mScanTime, STOP_SCAN);
             } else if (action == STOP_SCAN) {
                 Log.v(TAG, "Before Stop scan");
+                mScanEndTime = System.currentTimeMillis();
+                mPMCStatusLogger.logAlarmTimes(mScanStartTime / 1000.0, mScanEndTime / 1000.0);
                 mBleScanner.stopScan(mScanCallback);
-                repeatAlarm(intent, mNoScanTime, START_SCAN);
+                if ((mScanEndTime - mStartTestTime)
+                        < ((mScanTime + mNoScanTime) * mNumAlarms / 2 + mFirstScanTime) * 1000) {
+                    repeatAlarm(intent, mNoScanTime, START_SCAN);
+                } else {
+                    mPMCStatusLogger.flash();  // To flash out timestamps into log file
+                    Log.d(TAG, "Time is up to end");
+                }
             } else {
                 Log.e(TAG, "Unknown Action");
             }
@@ -228,6 +248,9 @@
             int repetitions = 1;
             String str;
 
+            mStartTestTime = System.currentTimeMillis();
+            mPMCStatusLogger = new PMCStatusLogger(TAG + ".log", TAG);
+
             if (extras == null) {
                 Log.e(TAG, "No parameters specified");
                 return;
@@ -277,6 +300,12 @@
             }
             mAlarmScanListener.firstAlarm(scanMode, startTime,
                                        scanTime, noScanTime, repetitions * 2);
+            if (mBleScanner != null && mScanFilterList != null && mScanSettings != null
+                                 && mScanCallback != null) {
+                mPMCStatusLogger.logStatus("READY");
+            } else {
+                Log.e(TAG, "BLE scanner is not ready to start test");
+            }
         }
     }
 }
diff --git a/PMC/src/com/android/pmc/GattClientListener.java b/PMC/src/com/android/pmc/GattClientListener.java
index 428149c..a99f41c 100644
--- a/PMC/src/com/android/pmc/GattClientListener.java
+++ b/PMC/src/com/android/pmc/GattClientListener.java
@@ -72,6 +72,7 @@
      * @param alarmManager - system will provide a AlarmManager to this function
      */
     public GattClientListener(Context context, AlarmManager alarmManager) {
+        Log.d(TAG, "Start GattClientListener()");
         mContext = context;
         mAlarmManager = alarmManager;
         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -95,6 +96,7 @@
         mBluetoothGatt = null;
         mMacAddress = null;
         mDevice = null;
+        Log.d(TAG, "End GattClientListener");
     }
 
     /**
diff --git a/PMC/src/com/android/pmc/GattPMCReceiver.java b/PMC/src/com/android/pmc/GattPMCReceiver.java
index 5044a9a..4a29dbb 100644
--- a/PMC/src/com/android/pmc/GattPMCReceiver.java
+++ b/PMC/src/com/android/pmc/GattPMCReceiver.java
@@ -40,6 +40,8 @@
      * @param alarmManager - PMC will provide alarmManager
      */
     public GattPMCReceiver(Context context, AlarmManager alarmManager) {
+        Log.d(TAG, "Start GattPMCReceiver()");
+
         // Prepare for setting alarm service
         mGattClientListener = new GattClientListener(context, alarmManager);
         mGattServer = new GattServer(context);
@@ -47,6 +49,7 @@
         // RegisterAlarmReceiver for GattListener
         context.registerReceiver(mGattClientListener,
                 new IntentFilter(GattClientListener.GATTCLIENT_ALARM));
+        Log.d(TAG, "Start GattPMCReceiver()");
     }
 
     /**
diff --git a/PMC/src/com/android/pmc/GattServer.java b/PMC/src/com/android/pmc/GattServer.java
index 9e88364..c84861d 100644
--- a/PMC/src/com/android/pmc/GattServer.java
+++ b/PMC/src/com/android/pmc/GattServer.java
@@ -59,6 +59,7 @@
      * @param context - System will provide a context
      */
     public GattServer(Context context) {
+        Log.d(TAG, "Start GattServer()");
         mContext = context;
         // Check if Bluetooth is enabled
         BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -102,7 +103,7 @@
 
         // Create BLE Advertiser object
         mBleAdvertiser = new MyBleAdvertiser(bluetoothAdapter);
-        Log.d(TAG, "Construstor finished");
+        Log.d(TAG, "End GattServer()");
     }
 
     /**
diff --git a/PMC/src/com/android/pmc/PMCStatusLogger.java b/PMC/src/com/android/pmc/PMCStatusLogger.java
new file mode 100644
index 0000000..500780e
--- /dev/null
+++ b/PMC/src/com/android/pmc/PMCStatusLogger.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.pmc;
+
+import android.util.Log;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+
+/**
+ * Logging class to log status so PMC can communicate the status back to client
+ */
+public class PMCStatusLogger {
+    private File mFile;
+    public static String TAG;
+    public static String LOG_DIR = "/mnt/sdcard/Download";
+    public static JSONObject mJObject;
+    public static JSONArray mJArray;
+
+    /**
+     * Construtor - check if the file exist. If it is delete and create a new.
+     *
+     * @param message - message to be logged
+     */
+    public PMCStatusLogger(String fileName, String tag) {
+        TAG = tag;
+
+        try {
+            mFile = new File(LOG_DIR + "/" + fileName);
+            if (mFile.exists()) mFile.delete();
+            mFile.createNewFile();
+        } catch (IOException e) {
+            Log.e(TAG, "Exception creating log file: " + fileName + " " + e);
+        }
+        mJObject = new JSONObject();
+        mJArray = new JSONArray();
+    }
+
+    /**
+     * Function to log status message into log file
+     *
+     * @param message - message to be logged
+     */
+    public void logStatus(String message) {
+        try {
+            FileWriter fos = new FileWriter(mFile);
+            BufferedWriter bw = new BufferedWriter(fos);
+            bw.write(message);
+            bw.newLine();
+            bw.close();
+        } catch (IOException e) {
+            Log.e(TAG, "Exception writing log: " + message + " " + e);
+        }
+    }
+
+    /**
+     * Function to add alarm times into JSONArray object
+     *
+     * @param startTime - Start time for the cycle
+     * @param endTime - End time for the cycle
+     */
+    public void logAlarmTimes(double startTime, double endTime) {
+        JSONObject obj = new JSONObject();
+        try {
+            obj.put("StartTime", startTime);
+            obj.put("EndTime", endTime);
+            mJArray.put(obj);
+        } catch (JSONException e) {
+            Log.e(TAG, "Exception to put Alarm Times into JSONArray: " + e);
+        }
+    }
+
+    /**
+     * Function to save Json object into log file
+     *
+     */
+    public void flash() {
+        try {
+            mJObject.put("AlarmTimes", mJArray);
+
+            FileWriter fos = new FileWriter(mFile);
+            BufferedWriter bw = new BufferedWriter(fos);
+            Log.v(TAG, "JSON: " + mJObject.toString());
+            bw.write(mJObject.toString());
+            bw.newLine();
+            bw.close();
+        } catch (JSONException e) {
+            Log.e(TAG, "Exception to put JSONArray into main JSON object: " + e);
+        } catch (IOException e) {
+            Log.e(TAG, "Exception writing JSON to log file: " + e);
+        }
+    }
+
+}
+