Merge "Bluetooth: Handle exception in SAP/DUN during BT ON/OFF"
diff --git a/Android.mk b/Android.mk
index e13554e..57028d7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -5,7 +5,8 @@
 src_dirs:= src/org/codeaurora/bluetooth/ftp \
            src/org/codeaurora/bluetooth/sap \
            src/org/codeaurora/bluetooth/dun \
-           src/org/codeaurora/bluetooth/pxpservice
+           src/org/codeaurora/bluetooth/pxpservice \
+           src/org/codeaurora/bluetooth/a4wp
 
 ifeq ($(BOARD_HAS_QCA_BT_AR3002),true)
 src_dirs += src/org/codeaurora/bluetooth/btcservice
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a97108a..de41143 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -184,6 +184,18 @@
                 <action android:name="org.codeaurora.bluetooth.pxpservice.PxpMonitorService" />
             </intent-filter>
         </service>
-
+        <service
+            android:process="@string/process"
+            android:exported="true"
+            android:name = ".a4wp.A4wpService">
+        </service>
+        <receiver
+            android:process="@string/process"
+            android:exported="true"
+            android:name=".a4wp.BTEventHandler">
+            <intent-filter>
+                <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
+            </intent-filter>
+        </receiver>
     </application>
 </manifest>
diff --git a/src/org/codeaurora/bluetooth/a4wp/A4wpService.java b/src/org/codeaurora/bluetooth/a4wp/A4wpService.java
new file mode 100644
index 0000000..c746cc0
--- /dev/null
+++ b/src/org/codeaurora/bluetooth/a4wp/A4wpService.java
@@ -0,0 +1,713 @@
+/*
+ * Copyright (c) 2013, 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:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.codeaurora.bluetooth.a4wp;
+
+import java.util.UUID;
+
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.QBluetoothAdapter;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallback;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothGattServer;
+import android.bluetooth.BluetoothGattServerCallback;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.app.Service;
+import android.net.Credentials;
+import java.io.OutputStream;
+import android.util.Log;
+import android.os.IBinder;
+import android.content.Intent;
+import android.os.Process;
+import java.nio.ByteBuffer;
+import android.wipower.WipowerManager;
+import android.wipower.WipowerManagerCallback;
+import android.wipower.WipowerManager.WipowerState;
+import android.wipower.WipowerManager.WipowerAlert;
+import android.wipower.WipowerManager.PowerLevel;
+import android.wipower.WipowerDynamicParam;
+
+/**
+ * Class which executes A4WP service
+ */
+public class A4wpService extends Service
+{
+    private static final String LOGTAG = "A4wpService";
+    private static OutputStream mOutputStream = null;
+    private BluetoothAdapter mBluetoothAdapter = null;
+    private BluetoothGattServer mBluetoothGattServer = null;
+    private BluetoothDevice mDevice = null;
+    private static final UUID A4WP_SERVICE_UUID = UUID.fromString("6455e670-a146-11e2-9e96-0800200cfffe");
+    //PRU writes
+    private static final UUID A4WP_PRU_CTRL_UUID = UUID.fromString("6455e670-a146-11e2-9e96-0800200c9a67");
+    private static final UUID A4WP_PTU_STATIC_UUID = UUID.fromString("6455e670-a146-11e2-9e96-0800200c9a68");
+    //PRU reads
+    private static final UUID A4WP_PRU_ALERT_UUID = UUID.fromString("6455e670-a146-11e2-9e96-0800200c9a69");
+    private static final UUID A4WP_PRU_STATIC_UUID = UUID.fromString("6455e670-a146-11e2-9e96-0800200c9a70");
+    private static final UUID A4WP_PRU_DYNAMIC_UUID = UUID.fromString("6455e670-a146-11e2-9e96-0800200c9a71");
+
+    private static final UUID A4WP_PRU_ALERT_DESC_UUID = UUID.fromString("6455e670-a146-11e2-9e96-0800200c9a69");
+    //CHECK: Using the Alert UUID for now
+
+    private static final Object mLock = new Object();
+    private int mState = BluetoothProfile.STATE_DISCONNECTED;
+
+    public final static int DEFAULT_ID = 0xFFFF;
+    public final static short DEFAULT_CATEGORY = 3;
+    public final static int DEFAULT_CAPABILITIES = 0x0000;
+    public final static int DEFAULT_HW_VERSION = 0x0700;
+    public final static int DEFAULT_FW_VERSION = 0x05;
+    public final static int DEFAULT_MAX_POWER_DESIRED = 3650;
+    public final static int DEFAULT_VRECT_MIN = 9000;
+    public final static int DEFAULT_VRECT_MAX = 18000;
+    public final static int DEFAULT_VRECT_SET = 11000;
+    public final static int DEFAULT_DELTA_R1 = 1;
+    public final static int DEFAULT_RRX_INT = 0;
+    public final static int DEFAULT_RECT_IMP_TRANSFORM = 0;
+    public final static int DEFAULT_RECT_EFF = 0;
+    private static final int MSB_MASK = 0xFF00;
+    private static final int LSB_MASK= 0x00FF;
+
+    private class PruStaticParam {
+        private byte mOptvalidity;
+        private short mId;
+        private byte mCategory;
+        private byte mCapabilities;
+        private byte mHwRev;
+        private byte mFwRev;
+        private byte mMaxPowerDesired;
+        private short mVrectMinStatic;
+        private short mVrectMaxStatic;
+        private short mVrectSet;
+        private short mDeltaR1;
+        private short mRrxInval;
+        private byte mRectifierImpedXform;
+        private byte mRectifierEffeciency;
+
+        public PruStaticParam() {
+            mOptvalidity = 0;
+            mId = (short)DEFAULT_ID;
+            mCategory = DEFAULT_CATEGORY;
+            mCapabilities = DEFAULT_CAPABILITIES;
+            mHwRev = (DEFAULT_HW_VERSION>>8)&0xFF;
+            mFwRev = DEFAULT_FW_VERSION;
+            mMaxPowerDesired = DEFAULT_MAX_POWER_DESIRED/100;
+            mVrectMinStatic = DEFAULT_VRECT_MIN;
+            mVrectMaxStatic = DEFAULT_VRECT_MAX;
+            mVrectSet = DEFAULT_VRECT_SET;
+            mDeltaR1 = DEFAULT_DELTA_R1;
+            mRrxInval = DEFAULT_RRX_INT;
+            mRectifierImpedXform = DEFAULT_RECT_IMP_TRANSFORM;
+            mRectifierEffeciency = DEFAULT_RECT_EFF;
+            Log.v(LOGTAG, "PruStaticParam initialized");
+        }
+
+        public byte[] getValue() {
+            byte[] res = new byte[20];
+            res[0] = mOptvalidity;
+            res[1] = (byte)(LSB_MASK & mId);
+            res[2] = (byte)(MSB_MASK & mId);
+            res[3] = mCategory;
+            res[4] = mCapabilities;
+            res[5] = mHwRev;
+            res[6] = mFwRev;
+            res[7] = mMaxPowerDesired;
+            res[8] =  (byte)(LSB_MASK & mVrectMinStatic);
+            res[9] = (byte)(MSB_MASK & mVrectMinStatic);
+            res[10] =  (byte)(LSB_MASK & mVrectMinStatic);
+            res[11] = (byte)(MSB_MASK & mVrectMinStatic);
+            res[12] =  (byte)(LSB_MASK & mVrectSet);
+            res[13] = (byte)(MSB_MASK & mVrectSet);
+            res[14] =  (byte)(LSB_MASK & mDeltaR1);
+            res[15] = (byte)(MSB_MASK & mDeltaR1);
+            res[16] =  (byte)(LSB_MASK & mRrxInval);
+            res[17] = (byte)(MSB_MASK & mRrxInval);
+            res[18] =  mRectifierImpedXform;
+            res[19] = mRectifierEffeciency;
+
+            return res;
+        }
+        /* This is used to set the charging values */
+        public void setValue(byte[] value) {
+            mOptvalidity = value[0];
+            mId = value[1];
+            mId |= (short)(8<<value[2]);
+            mCategory = value[3] ;
+            mCapabilities = value[4];
+            mHwRev = value[5];
+            mFwRev = value[6];
+            mMaxPowerDesired = value[7];
+            mVrectMinStatic = value[8];
+            mVrectMinStatic |= (short)(8<<value[9]);
+            mVrectMinStatic = value[10];
+            mVrectMinStatic |= (short)(8<<value[11]);
+            mVrectSet = value[12];
+            mVrectSet |= (short)(8<<value[13]);
+            mDeltaR1 = value[14];
+            mDeltaR1 |= (short)(8<<value[15]);
+            mRrxInval = value[16];
+            mRrxInval |= (short)(8<<value[17]);
+            mRectifierImpedXform = value[18];
+            mRectifierEffeciency = value[19];
+
+            return;
+        }
+
+    }
+
+    private class PruAlert {
+       private byte mAlert;
+
+       public PruAlert(byte value) {
+           mAlert = value;
+       }
+
+       public void setValue(byte value) {
+           mAlert = value;
+       }
+
+       public byte[] getValue() {
+           byte[] res = new byte[1];
+           res[0] = mAlert;
+           return res;
+       }
+    }
+
+    private class PtuStaticParam {
+        private byte mOptValidity;
+        private byte mPower;
+        private byte mMaxSrcImpedence;
+        private byte mMaxLoadResistance;
+        private short mId;
+        private byte mClass;
+        private byte mHwRev;
+        private byte mFwRev;
+        private byte mProtocolRev;
+        private byte mMaxDevicesSupported;
+        private int mReserved1;
+        private short mReserved2;
+
+        public PtuStaticParam(byte[] value) {
+            mOptValidity = value[0];
+            mPower = value[1];
+            mMaxSrcImpedence = value[2];
+            mMaxLoadResistance = value[3];
+            mId = value[4];
+            mClass = value[6];
+            mHwRev = value[7];
+            mFwRev = value[8];
+            mMaxDevicesSupported = value[9];
+            mReserved1 = value[10];
+            mReserved2 = value[14];
+        }
+
+        public void print() {
+            Log.v(LOGTAG, "mOptValidity" +  toHex(mOptValidity) +  "mPower" +  toHex(mPower) + "mMaxSrcImpedence" +  toHex(mMaxSrcImpedence) + "mMaxLoadResistance" +  toHex(mMaxLoadResistance));
+            Log.v(LOGTAG, "mId" +  toHex(mId) + "mClass" +  toHex(mClass) + "mHwRev" +  toHex(mHwRev) +  "mFwRev" +  toHex(mFwRev));
+            Log.v(LOGTAG, "mProtocolRev" +  toHex(mProtocolRev) + "mMaxDevicesSupported" +  toHex(mMaxDevicesSupported) + "mReserved1" +  toHex(mReserved1) + "mReserved2" +  toHex(mReserved2));
+        }
+
+        public double getPower() {
+            double val = ((mPower&0xfc)>>2);
+            val = 0.5*(val+1);
+            Log.v(LOGTAG, "getPower<=" + val);
+            if (val > 22) val = 22.0;
+            return val;
+        }
+
+        public double getMaxSrcImpedence() {
+            double val = ((mMaxSrcImpedence&0xf8)>>3);
+            val = 50 + (val*10);
+            Log.v(LOGTAG, "getSrcImpedence<=" + val);
+            if (val > 375) val = 375.0;
+            return val;
+        }
+
+        public double getMaxLoadResistance() {
+            double val = ((mMaxLoadResistance&0xf8)>>3);
+            val = 5 * (val+1);
+            Log.v(LOGTAG, "getMaxLoadResistance<=" + val);
+            if (val > 55) val = 55.0;
+            return val;
+        }
+
+        public float getMaxDevicesSupported() {
+            int val = mMaxDevicesSupported +1;
+            Log.v(LOGTAG, "getMaxDevicesSupported<=" + val);
+            if (val > 8) val = 8;
+            return val;
+        }
+
+        public short getId() {
+            return mId;
+        }
+
+        public int getPtuClass() {
+            return (mClass > 4) ? 5 : (mClass+1);
+        }
+
+        public byte getHwRev () {
+            return mHwRev;
+        }
+
+        public byte getFwRev () {
+            return mFwRev;
+        }
+
+        public byte getProtocolRev () {
+            return mProtocolRev;
+        }
+    }
+
+    public static String toHex(int num) {
+        return String.format("0x%8s", Integer.toHexString(num)).replace(' ', '0');
+    }
+
+    private class PruControl {
+         public byte mEnable;
+         public byte mPermission;
+         public byte mTimeSet;
+         public short mReserved;
+         public PruControl (byte[] value) {
+             mEnable = value[0];
+             mPermission = value[1];
+             mTimeSet = value[2];
+             mReserved = value[3];
+         }
+
+         public void print() {
+             Log.v(LOGTAG, "mEnable: " +  toHex(mEnable));
+             Log.v(LOGTAG, "mPermission: " +  toHex(mPermission));
+             Log.v(LOGTAG, "mTimeSet: " +  toHex(mTimeSet));
+             Log.v(LOGTAG, "mReserved: " +  toHex(mReserved));
+         }
+
+         public boolean getEnablePruOutput() {
+              if ((mEnable&0x80) == 0x80) return true;
+              else return false;
+         }
+
+         public boolean getEnableCharger() {
+              if ((mEnable&0x40) == 0x40) return true;
+              else return false;
+         }
+
+         /* returns 0 Maximum power
+                    1 66%
+                    2 33%
+          */
+         public PowerLevel getReducePower() {
+             PowerLevel res = PowerLevel.POWER_LEVEL_MINIMUM;
+             int val = ((mEnable & 0x30) >> 4 );
+             if (val == 0) {
+                 res = PowerLevel.POWER_LEVEL_MAXIMUM;
+             } else if (val == 1 && val == 3) {
+                 res = PowerLevel.POWER_LEVEL_MEDIUM;
+             } else if (val == 2) {
+                 res = PowerLevel.POWER_LEVEL_MINIMUM;
+             }
+             return res;
+         }
+
+         /* returns 0x00 permitted without reason
+                    0x01 Permitted with waiting time due to limited affordable power
+                    0x80 Denied with system error 3
+                    0x81 Denied due to limited affordable power
+                    0x82 Denied due to limited PTU Number of Devices
+                    0x83 Denied due to limited PTU Class support
+          */
+         public boolean getPermission() {
+
+             Log.v(LOGTAG, "getPermission" + mPermission);
+             if ((mPermission&0x80) == 0x80) return false;
+             else return true;
+         }
+
+         /* returns time in ms */
+         public int getSetTime() {
+             return (mTimeSet*10);
+         }
+    };
+
+    private PruAlert mPruAlert;
+    private PruStaticParam mPruStaticParam; //20 bytes
+    private PtuStaticParam mPtuStaticParam; //20 bytes
+    private WipowerDynamicParam mPruDynamicParam; //20 bytes
+    private WipowerManager mWipowerManager;
+
+    public A4wpService() {
+        Log.v(LOGTAG, "A4wpService");
+    }
+
+    static private void cleanupService() {
+        Log.v(LOGTAG, "cleanupService");
+    }
+
+    private int processPruControl(byte[] value) {
+        int status = 0;
+
+        Log.v(LOGTAG, "processPruControl>");
+        PruControl control = new PruControl(value);
+        control.print();
+        if (control.getEnablePruOutput()) {
+            Log.v(LOGTAG, "do Enable PruOutPut");
+            mWipowerManager.startCharging();
+            mWipowerManager.enableAlertNotification(false);
+            mWipowerManager.enableDataNotification(true);
+            stopAdvertising();
+        } else {
+            Log.v(LOGTAG, "do Disable PruOutPut");
+            mWipowerManager.enableDataNotification(false);
+            mWipowerManager.stopCharging();
+        }
+
+        if (control.getEnableCharger()) {
+            Log.v(LOGTAG, "do Enable Charging");
+        } else {
+            Log.v(LOGTAG, "do Disable Charging");
+        }
+
+        PowerLevel val = control.getReducePower();
+        if (val == PowerLevel.POWER_LEVEL_MAXIMUM) {
+            Log.v(LOGTAG, "put to Max Power");
+        } else if (val == PowerLevel.POWER_LEVEL_MEDIUM){
+            Log.v(LOGTAG, "put to Medium Power");
+        } else if (val == PowerLevel.POWER_LEVEL_MINIMUM){
+            Log.v(LOGTAG, "put to Min Power");
+        }
+
+        mWipowerManager.setPowerLevel(val);
+
+        return status;
+    }
+
+    private int processPtuStaticParam(byte[] value) {
+        int status = 0;
+        Log.v(LOGTAG, "processPtuStaticParam>");
+        mPtuStaticParam = new PtuStaticParam(value);
+        mPtuStaticParam.print();
+
+        return status;
+    }
+
+    private static final int OVER_VOLT_BIT = 0x80;
+    private static final byte OVER_CURR_BIT = 0x40;
+    private static final byte OVER_TEMP_BIT = 0x20;
+    private static final byte SELF_PROT_BIT = 0x10;
+    private static final byte CHARGE_COMPLETE_BIT = 0x08;
+    private static final byte WIRED_CHARGE_DETECT = 0x04;
+    private static final byte CHARGE_PORT = 0x02;
+
+    /**
+     * Wipower callbacks
+     */
+    private final WipowerManagerCallback mWipowerCallback = new WipowerManagerCallback() {
+
+        @Override
+        public void onWipowerReady() {
+            Log.v(LOGTAG, "onWipowerReady");
+        }
+
+        @Override
+        public void onWipowerStateChange(WipowerState state) {
+            Log.v(LOGTAG, "onWipowerStateChange" + state);
+        }
+
+
+        @Override
+        public void onWipowerAlert(WipowerAlert alert) {
+            Log.v(LOGTAG, "onWipowerAlert");
+            byte alertVal = 0;
+            if (alert == WipowerAlert.ALERT_OVER_VOLTAGE) {
+                Log.v(LOGTAG, "Over Voltage");
+                alertVal |= OVER_VOLT_BIT&0xff;
+            }
+            else if (alert == WipowerAlert.ALERT_OVER_CURRENT) {
+                Log.v(LOGTAG, "Over Current");
+                alertVal |= OVER_CURR_BIT;
+            }
+            else if (alert == WipowerAlert.ALERT_OVER_TEMPERATURE) {
+                Log.v(LOGTAG, "Over Temperature");
+                alertVal |= OVER_TEMP_BIT;
+            }
+            else if (alert == WipowerAlert.ALERT_SELF_PROTECTION) {
+                Log.v(LOGTAG, "PRU self protection ON");
+                alertVal |= SELF_PROT_BIT;
+            }
+            else if (alert == WipowerAlert.ALERT_CHARGE_COMPLETE) {
+                Log.v(LOGTAG, "Charge complete alert ");
+                alertVal |= CHARGE_COMPLETE_BIT;
+            }
+            else if (alert == WipowerAlert.ALERT_WIRED_CHARGER_DETECTED) {
+                Log.v(LOGTAG, "Wired charger detected");
+                alertVal |= WIRED_CHARGE_DETECT;
+            }
+            else if (alert == WipowerAlert.ALERT_CHARGE_PORT) {
+                Log.v(LOGTAG, "Alert charge port");
+                alertVal |= CHARGE_PORT;
+            }
+        }
+
+
+        @Override
+        public void onWipowerData(WipowerDynamicParam data) {
+            Log.v(LOGTAG, "onWipowerData Alert");
+            byte[] value = data.getValue();
+
+            Log.v(LOGTAG, "calling SetValue");
+            mPruDynamicParam.setValue(value);
+        }
+
+    };
+
+
+    /**
+     * GATT callbacks
+     */
+    private final BluetoothGattServerCallback mGattCallbacks = new BluetoothGattServerCallback() {
+        @Override
+        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
+            mState = newState;
+            if (mState == BluetoothProfile.STATE_DISCONNECTED) {
+                Log.v(LOGTAG, "onConnectionStateChange:");
+                mWipowerManager.enableDataNotification(false);
+                mWipowerManager.stopCharging();
+                //startAdvertising();
+            }
+        }
+
+        @Override
+        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
+                BluetoothGattCharacteristic characteristic,
+                boolean preparedWrite, boolean responseNeeded,
+                int offset, byte[] value) {
+
+                UUID id = characteristic.getUuid();
+                int status =0;
+
+                Log.v(LOGTAG, "onCharacteristicWriteRequest:" + id);
+                if (id == A4WP_PRU_CTRL_UUID)
+                {
+                     status = processPruControl(value);
+                }
+                else if(id == A4WP_PTU_STATIC_UUID)
+                {
+                     status = processPtuStaticParam(value);
+                }
+                if (responseNeeded == true) {
+                    mBluetoothGattServer.sendResponse(device, requestId, status,
+                                       offset, value);
+                }
+        }
+
+        @Override
+        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
+                        int offset, BluetoothGattCharacteristic characteristic) {
+
+                UUID id = characteristic.getUuid();
+                byte[] value = {0};
+                int status = 0;
+
+                Log.v(LOGTAG, "onCharacteristicReadRequest:" + id);
+                if (id == A4WP_PRU_ALERT_UUID)
+                {
+                    value = mPruAlert.getValue();
+                }
+                else if(id == A4WP_PRU_STATIC_UUID)
+                {
+                    value = mPruStaticParam.getValue();
+                }
+                else if (id == A4WP_PRU_DYNAMIC_UUID) {
+                    if (mPruDynamicParam == null) {
+                         Log.e(LOGTAG, "mPruDynamicParam is NULL");
+                         return;
+                    }
+                    value = mPruDynamicParam.getValue();
+                }
+                if (value != null)
+                {
+                     Log.v(LOGTAG, "device:" + id + "requestId:" + requestId + "status:" + status + "offset:" + offset + "value" + value);
+                     mBluetoothGattServer.sendResponse(device, requestId, status, offset, value);
+                }
+        }
+
+        @Override
+        public void onServiceAdded(final int status, BluetoothGattService service) {
+                Log.i(LOGTAG, "Service added");
+        }
+    };
+
+    private void closeServer() {
+        if (mBluetoothGattServer != null) {
+            if (mDevice != null) mBluetoothGattServer.cancelConnection(mDevice);
+            mBluetoothGattServer.close();
+        }
+    }
+
+    private void startAdvertising()
+    {
+        byte[] wipowerData=new byte[6];
+        wipowerData[0]=(byte)0xFE;
+        wipowerData[1]=(byte)0xFF;
+        wipowerData[2]=(byte)0x28;
+        wipowerData[3]=(byte)0x00;
+        wipowerData[4]=(byte)0xFF;
+        wipowerData[5]=(byte)0x60;
+        QBluetoothAdapter mQAdapter=QBluetoothAdapter.getDefaultAdapter();
+        if ((mQAdapter != null)) {
+           int modeAd=mQAdapter.getLEAdvMode();
+           Log.d(LOGTAG,"Adv mode is:"+ modeAd);
+
+           mQAdapter.setLEServiceData(wipowerData);
+           mQAdapter.setLEAdvMask(false, false, false, false, true);
+           boolean retval=mQAdapter.setLEAdvMode(QBluetoothAdapter.ADV_IND_LIMITED_CONNECTABLE);
+           Log.d(LOGTAG,"Return value of set adv enable is:"+retval);
+        } else {
+           boolean retval=mQAdapter.setLEAdvMode(QBluetoothAdapter.ADV_MODE_NONE);
+           Log.d(LOGTAG,"Return value of set adv enable is:"+retval);
+        }
+    }
+
+    private void stopAdvertising()
+    {
+        QBluetoothAdapter mQAdapter=QBluetoothAdapter.getDefaultAdapter();
+        if ((mQAdapter != null)) {
+           boolean retval=mQAdapter.setLEAdvMode(QBluetoothAdapter.ADV_MODE_NONE);
+           Log.d(LOGTAG,"Return value of set adv enable is:"+retval);
+        }
+    }
+
+    private boolean startServer() {
+        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+        if (bluetoothManager == null) return false;
+
+        mBluetoothGattServer = bluetoothManager.openGattServer(this, mGattCallbacks);
+        Log.d(LOGTAG,"calling start server......");
+        if (mBluetoothGattServer == null) return false;
+
+        BluetoothGattCharacteristic pruControl = new BluetoothGattCharacteristic(
+                A4WP_PRU_CTRL_UUID,
+                BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ,
+                BluetoothGattCharacteristic.PERMISSION_WRITE |
+                BluetoothGattCharacteristic.PERMISSION_READ);
+
+        BluetoothGattCharacteristic ptuStatic = new BluetoothGattCharacteristic(
+                A4WP_PTU_STATIC_UUID,
+                BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ,
+                BluetoothGattCharacteristic.PERMISSION_WRITE |
+                BluetoothGattCharacteristic.PERMISSION_READ);
+
+        BluetoothGattCharacteristic pruAlert = new BluetoothGattCharacteristic(
+                A4WP_PRU_ALERT_UUID,
+                BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
+                BluetoothGattCharacteristic.PERMISSION_READ );
+
+        BluetoothGattCharacteristic pruStatic = new BluetoothGattCharacteristic(
+                A4WP_PRU_STATIC_UUID,
+                BluetoothGattCharacteristic.PROPERTY_READ,
+                BluetoothGattCharacteristic.PERMISSION_READ);
+
+        BluetoothGattCharacteristic pruDynamic = new BluetoothGattCharacteristic(
+                A4WP_PRU_DYNAMIC_UUID,
+                BluetoothGattCharacteristic.PROPERTY_READ,
+                BluetoothGattCharacteristic.PERMISSION_READ);
+
+
+        BluetoothGattDescriptor pruAlertDesc = new BluetoothGattDescriptor(
+                A4WP_PRU_ALERT_DESC_UUID,
+                BluetoothGattCharacteristic.PERMISSION_READ |
+                BluetoothGattCharacteristic.PERMISSION_WRITE);
+
+        pruAlert.addDescriptor(pruAlertDesc);
+
+        BluetoothGattService a4wpService = new BluetoothGattService(
+                A4WP_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
+
+        a4wpService.addCharacteristic(pruControl);
+        a4wpService.addCharacteristic(ptuStatic);
+        a4wpService.addCharacteristic(pruAlert);
+        a4wpService.addCharacteristic(pruStatic);
+        a4wpService.addCharacteristic(pruDynamic);
+
+
+        mBluetoothGattServer.addService(a4wpService);
+        Log.d(LOGTAG,"time to start advertising....:");
+
+        //startAdvertising();
+
+        return true;
+    }
+
+    @Override
+    public void onCreate() {
+        Log.v(LOGTAG, "onCreate");
+        super.onCreate();
+
+        // Ensure Bluetooth is enabled
+        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
+            Log.d(LOGTAG, "Bluetooth is not available or enabled - exiting...");
+            return;
+        }
+
+        Log.v(LOGTAG, "calling startService");
+        startServer();
+        //Initialize PRU Static param
+        mPruStaticParam = new PruStaticParam();
+        mPruDynamicParam = new WipowerDynamicParam();
+
+        mWipowerManager = WipowerManager.getWipowerManger(this, mWipowerCallback);
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.v(LOGTAG, "onDestroy");
+        if (mWipowerManager != null)
+             mWipowerManager.unregisterCallback(mWipowerCallback);
+    }
+
+    @Override
+    public IBinder onBind(Intent in) {
+        Log.v(LOGTAG, "onBind");
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.d(LOGTAG, "onStart Command called!!");
+        //Make this restarable service by
+        //Android app manager
+        return START_STICKY;
+   }
+}
diff --git a/src/org/codeaurora/bluetooth/a4wp/BTEventHandler.java b/src/org/codeaurora/bluetooth/a4wp/BTEventHandler.java
new file mode 100644
index 0000000..ce959cd
--- /dev/null
+++ b/src/org/codeaurora/bluetooth/a4wp/BTEventHandler.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2013, 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:
+ *        * Redistributions of source code must retain the above copyright
+ *            notice, this list of conditions and the following disclaimer.
+ *        * Redistributions in binary form must reproduce the above copyright
+ *            notice, this list of conditions and the following disclaimer in the
+ *            documentation and/or other materials provided with the distribution.
+ *        * Neither the name of The Linux Foundation nor
+ *            the names of its contributors may be used to endorse or promote
+ *            products derived from this software without specific prior written
+ *            permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.    IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.codeaurora.bluetooth.a4wp;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.lang.Object;
+
+public class BTEventHandler extends BroadcastReceiver {
+    private static final String TAG = "BTEventHandler";
+    private static final boolean V = true/*Constants.VERBOSE*/;
+    private int state;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if(SystemProperties.getBoolean("ro.bluetooth.a4wp", false) == false) {
+            Log.e(TAG, "A4WP is not supported");
+            return;
+        }
+
+        String action = intent.getAction();
+
+
+        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+            state = intent.getIntExtra
+                           (BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
+            if (BluetoothAdapter.STATE_ON == state) {
+                if (V) Log.v(TAG, "Received BLUETOOTH_STATE_ON");
+                ComponentName service = context.startService
+                                      (new Intent(context, A4wpService.class));
+                if (service != null) {
+                    Log.e(TAG, "A4wp service started successfully");
+                } else {
+                    Log.e(TAG, "Could Not Start A4wp Service");
+                    return;
+                }
+            } else if (BluetoothAdapter.STATE_OFF == state) {
+                if (V) Log.v(TAG, "Received BLUETOOTH_STATE_OFF");
+                context.stopService(new Intent(context, A4wpService.class));
+
+           }
+        }
+    }
+}
diff --git a/src/org/codeaurora/bluetooth/ftp/BluetoothFtpObexServer.java b/src/org/codeaurora/bluetooth/ftp/BluetoothFtpObexServer.java
index 4a9acd8..5d05769 100644
--- a/src/org/codeaurora/bluetooth/ftp/BluetoothFtpObexServer.java
+++ b/src/org/codeaurora/bluetooth/ftp/BluetoothFtpObexServer.java
@@ -642,22 +642,33 @@
          * return ResponseCodes.OBEX_HTTP_NOT_FOUND
          */
         if ((current_path_tmp != null  && current_path_tmp.length() != 0)) {
-            if (create) {
-                if (FileUtils.doesPathExist(current_path_tmp)) {
-                    if (D) Log.d(TAG, "Folder already exists");
-                    return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
-                } else {
+            if (!FileUtils.doesPathExist(current_path_tmp)) {
+                if (create) {
                     File filecreate = new File(current_path_tmp);
                     if (filecreate != null && !filecreate.mkdir()) {
                         Log.e(TAG, "Could not create " + tmp_path);
                         return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
                     }
-                }
-            } else {
-                if (!FileUtils.doesPathExist(current_path_tmp)) {
+                } else {
                     Log.e(TAG, "path: " +  current_path_tmp + " not found");
                     return ResponseCodes.OBEX_HTTP_NOT_FOUND;
                 }
+            } else {
+                /* Check if the folder to be created or set is not having same
+                 * name as existing file in same location. If file with same name is
+                 * present, return error to Client. */
+                File file = new File(current_path_tmp);
+                if (file.isFile()) {
+                    if (create) {
+                        Log.e(TAG, "File already exists with same name, " +
+                            "can't create folder with same name");
+                        return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+                    } else {
+                        Log.e(TAG, "Path is not valid, path being set is " +
+                            "for file not folder");
+                        return ResponseCodes.OBEX_HTTP_NOT_FOUND;
+                    }
+                }
             }
         } else if (current_path_tmp == null && tmp_path != null) {
             if (create) {
diff --git a/src/org/codeaurora/bluetooth/pxpservice/PxpMonitorService.java b/src/org/codeaurora/bluetooth/pxpservice/PxpMonitorService.java
index 59614f2..780a9b7 100644
--- a/src/org/codeaurora/bluetooth/pxpservice/PxpMonitorService.java
+++ b/src/org/codeaurora/bluetooth/pxpservice/PxpMonitorService.java
@@ -1111,10 +1111,18 @@
 
         @Override
         public void onAlert(int evtType, int rssi) {
+            int alertLevelValue = 0;
             Log.d(TAG, "onAlert in PxpMonitorService:: evtType::"+evtType+"::rssi::"+rssi);
 
             DeviceProperties deviceProp = mHashMapDevice.get(mDevice);
-            int alertLevelValue = getAlertLevelValue(evtType);
+            if(deviceProp.minPathLossThreshold == deviceProp.maxPathLossThreshold) {
+                if(evtType == BluetoothLwPwrProximityMonitor.RSSI_HIGH_ALERT) {
+                    alertLevelValue = deviceProp.pathLossAlertLevel;
+                }
+            }
+            else {
+                alertLevelValue = getAlertLevelValue(evtType);
+            }
 
             deviceProp.iasAlertLevelCh.setValue(alertLevelValue,
                     BluetoothGattCharacteristic.FORMAT_UINT8, 0);