diff options
author | Satish kumar sugasi <ssugas@codeaurora.org> | 2013-11-21 16:48:40 -0800 |
---|---|---|
committer | Subramanian Srinivasan <subrsrin@codeaurora.org> | 2013-12-16 15:22:35 -0800 |
commit | 9a41f62ea7933ad2ed1e663ef731780741aa39c8 (patch) | |
tree | 5461399cd2e791eb0f2bfa8e96f23675c549c63a /pxp-monitor | |
parent | 4e389ad19c8d49cd2072ecbc2f9f6fa6e44a127d (diff) | |
download | android_packages_apps_BluetoothExt-9a41f62ea7933ad2ed1e663ef731780741aa39c8.tar.gz android_packages_apps_BluetoothExt-9a41f62ea7933ad2ed1e663ef731780741aa39c8.tar.bz2 android_packages_apps_BluetoothExt-9a41f62ea7933ad2ed1e663ef731780741aa39c8.zip |
Bluetooth: Add support for LE proximity profile
This Enables Proximity service and pxp monitor test application
Change-Id: I7be72defcae8c1d926e55aa29c744d7e64425f93
CRs-fixed: 580130
Diffstat (limited to 'pxp-monitor')
42 files changed, 3898 insertions, 0 deletions
diff --git a/pxp-monitor/.gitignore b/pxp-monitor/.gitignore new file mode 100644 index 0000000..5e8706a --- /dev/null +++ b/pxp-monitor/.gitignore @@ -0,0 +1,30 @@ +lt application files +*.apk +*.ap_ + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +bin/ +gen/ + +# Local configuration file (sdk path, etc) +local.properties + +# Eclipse project files +.classpath +.project + +# Proguard folder generated by Eclipse +proguard/ + +# Intellij project files +*.iml +*.ipr +*.iws +.idea/ + diff --git a/pxp-monitor/Android.mk b/pxp-monitor/Android.mk new file mode 100644 index 0000000..5cedf1a --- /dev/null +++ b/pxp-monitor/Android.mk @@ -0,0 +1,19 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := \ + $(call all-java-files-under, src) \ + src/org/codeaurora/bluetooth/pxpservice/IPxpService.aidl + +LOCAL_PACKAGE_NAME := pxp-monitor +LOCAL_CERTIFICATE := platform + +LOCAL_MODULE_OWNER := qcom + +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/pxp-monitor/AndroidManifest.xml b/pxp-monitor/AndroidManifest.xml new file mode 100644 index 0000000..c984c0a --- /dev/null +++ b/pxp-monitor/AndroidManifest.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. + */ +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.codeaurora.bluetooth.pxpmonitor" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk + android:minSdkVersion="18" + android:targetSdkVersion="18" /> + + <uses-permission android:name="android.permission.BLUETOOTH" /> + <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> + + <uses-feature + android:name="android.hardware.bluetooth_le" + android:required="true" /> + + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@android:style/Theme.Holo" > + <activity + android:name=".MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <action android:name="android.bluetooth.devicepicker.action.DEVICE_SELECTED" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity android:name=".DeviceActivity" /> + <activity android:name=".ScanDevicesActivity" /> + <activity android:name=".PariedDevicesActivity" /> + <activity android:name=".ConnectedDevicesActivity" /> + <activity android:name=".AlertsHistory" /> + + <service + android:name="org.codeaurora.bluetooth.pxpmonitor.PxpServiceProxy" + android:exported="false" > + </service> + </application> + +</manifest> diff --git a/pxp-monitor/res/drawable-hdpi/ic_launcher.png b/pxp-monitor/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..f7d13f1 --- /dev/null +++ b/pxp-monitor/res/drawable-hdpi/ic_launcher.png diff --git a/pxp-monitor/res/drawable-hdpi/search.png b/pxp-monitor/res/drawable-hdpi/search.png Binary files differnew file mode 100644 index 0000000..f7d13f1 --- /dev/null +++ b/pxp-monitor/res/drawable-hdpi/search.png diff --git a/pxp-monitor/res/drawable-mdpi/ic_launcher.png b/pxp-monitor/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..347779c --- /dev/null +++ b/pxp-monitor/res/drawable-mdpi/ic_launcher.png diff --git a/pxp-monitor/res/drawable-mdpi/search.png b/pxp-monitor/res/drawable-mdpi/search.png Binary files differnew file mode 100644 index 0000000..f7d13f1 --- /dev/null +++ b/pxp-monitor/res/drawable-mdpi/search.png diff --git a/pxp-monitor/res/drawable-xhdpi/ic_launcher.png b/pxp-monitor/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..f7d13f1 --- /dev/null +++ b/pxp-monitor/res/drawable-xhdpi/ic_launcher.png diff --git a/pxp-monitor/res/drawable-xhdpi/search.png b/pxp-monitor/res/drawable-xhdpi/search.png Binary files differnew file mode 100644 index 0000000..f7d13f1 --- /dev/null +++ b/pxp-monitor/res/drawable-xhdpi/search.png diff --git a/pxp-monitor/res/drawable-xxhdpi/ic_launcher.png b/pxp-monitor/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..f7d13f1 --- /dev/null +++ b/pxp-monitor/res/drawable-xxhdpi/ic_launcher.png diff --git a/pxp-monitor/res/drawable-xxhdpi/search.png b/pxp-monitor/res/drawable-xxhdpi/search.png Binary files differnew file mode 100755 index 0000000..f7d13f1 --- /dev/null +++ b/pxp-monitor/res/drawable-xxhdpi/search.png diff --git a/pxp-monitor/res/layout/activity_alerts_history.xml b/pxp-monitor/res/layout/activity_alerts_history.xml new file mode 100644 index 0000000..8dafa94 --- /dev/null +++ b/pxp-monitor/res/layout/activity_alerts_history.xml @@ -0,0 +1,62 @@ +<!-- + * 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. + */ +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" > + + <TextView + android:id="@+id/device_name" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="20dp" + android:textSize="22sp" + android:textStyle="bold" /> + + <TextView + android:id="@+id/device_address" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="16sp" /> + + <TextView + android:id="@+id/alert_time" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:textSize="20sp" /> + + <TextView + android:id="@+id/device_rssi" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:textSize="20sp" /> + +</LinearLayout>
\ No newline at end of file diff --git a/pxp-monitor/res/layout/activity_device.xml b/pxp-monitor/res/layout/activity_device.xml new file mode 100644 index 0000000..cc8edd4 --- /dev/null +++ b/pxp-monitor/res/layout/activity_device.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. + */ +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + + <fragment class="org.codeaurora.bluetooth.pxpmonitor.DeviceInfoFragment" + android:id="@+id/device_info_fragment" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="35" /> + + <fragment class="org.codeaurora.bluetooth.pxpmonitor.LinkLossFragment" + android:id="@+id/link_loss_fragment" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="35" /> + + <fragment class="org.codeaurora.bluetooth.pxpmonitor.PathLossFragment" + android:id="@+id/path_loss_fragment" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="35" /> + +</LinearLayout> diff --git a/pxp-monitor/res/layout/activity_list_devices.xml b/pxp-monitor/res/layout/activity_list_devices.xml new file mode 100644 index 0000000..cbef9ce --- /dev/null +++ b/pxp-monitor/res/layout/activity_list_devices.xml @@ -0,0 +1,62 @@ +<!-- + * 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. + */ +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" > + + <TextView + android:id="@+id/device_name" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="30dp" + android:textSize="24sp" /> + + <TextView + android:id="@+id/device_address" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:textSize="12sp" /> + + <TextView + android:id="@+id/device_rssi" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:textSize="12sp" /> + + <TextView + android:id="@+id/device_adv_data" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:textSize="12sp" /> + +</LinearLayout>
\ No newline at end of file diff --git a/pxp-monitor/res/layout/activity_main.xml b/pxp-monitor/res/layout/activity_main.xml new file mode 100644 index 0000000..4162de7 --- /dev/null +++ b/pxp-monitor/res/layout/activity_main.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. + */ +--> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical" > + + <Button + android:id="@+id/button3" + android:layout_width="300dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:layout_centerHorizontal="true" + android:layout_centerVertical="true" + android:onClick="searchForDevices" + android:text="@string/scan" + android:textSize="24sp" /> + + <Button + android:id="@+id/button2" + android:layout_width="300dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:layout_centerHorizontal="true" + android:layout_above="@id/button3" + android:onClick="showPairedDevices" + android:text="@string/paired" + android:textSize="24sp" /> + + <Button + android:id="@+id/button1" + android:layout_width="300dp" + android:layout_height="wrap_content" + android:layout_above="@id/button2" + android:layout_alignLeft="@+id/button2" + android:layout_alignRight="@+id/button2" + android:onClick="showConnectedDevices" + android:text="@string/connected" + android:textSize="24sp" /> + + <Button + android:id="@+id/button4" + android:layout_width="300dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:layout_centerHorizontal="true" + android:layout_below="@+id/button3" + android:onClick="connectToDevice" + android:text="@string/connect_to" + android:textSize="24sp" /> + + <Button + android:id="@+id/button5" + android:layout_width="300dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:layout_centerHorizontal="true" + android:layout_below="@+id/button4" + android:onClick="showAlertHistory" + android:text="@string/history" + android:textSize="24sp" /> + +</RelativeLayout>
\ No newline at end of file diff --git a/pxp-monitor/res/layout/connect_to_device_dialog_fragment.xml b/pxp-monitor/res/layout/connect_to_device_dialog_fragment.xml new file mode 100644 index 0000000..09dcce7 --- /dev/null +++ b/pxp-monitor/res/layout/connect_to_device_dialog_fragment.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. + */ +--> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + + <EditText + android:id="@+id/device_address" + android:layout_width="250dp" + android:layout_height="wrap_content" + android:ems="10" + android:inputType="text" + android:layout_marginTop="10dp" + android:layout_marginBottom="10dp" + android:layout_centerHorizontal="true"/> + +</RelativeLayout> diff --git a/pxp-monitor/res/layout/device_info_fragment.xml b/pxp-monitor/res/layout/device_info_fragment.xml new file mode 100644 index 0000000..a5eba15 --- /dev/null +++ b/pxp-monitor/res/layout/device_info_fragment.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. + */ +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + + <TextView android:id="@+id/device_name" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="24sp" + android:layout_marginTop="8dp"/> + + <TextView android:id="@+id/device_address" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="12sp" + android:layout_marginTop="8dp"/> + +</LinearLayout> diff --git a/pxp-monitor/res/layout/link_loss_fragment.xml b/pxp-monitor/res/layout/link_loss_fragment.xml new file mode 100644 index 0000000..a57a96a --- /dev/null +++ b/pxp-monitor/res/layout/link_loss_fragment.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. + */ +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + + <TextView + android:id="@+id/link_loss" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="@string/link" + android:textSize="18sp" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" > + + <ToggleButton + android:id="@+id/link_off" + android:layout_width="110dp" + android:layout_height="wrap_content" + android:checked="false" + android:text="@string/off" + android:textOff="@string/off" + android:textOn="@string/off" + android:layout_marginTop="8dp" + android:layout_marginLeft="8dp"/> + + <ToggleButton + android:id="@+id/link_mild" + android:layout_width="110dp" + android:layout_height="wrap_content" + android:checked="false" + android:text="@string/mild" + android:textOff="@string/mild" + android:textOn="@string/mild" + android:layout_marginTop="8dp"/> + + <ToggleButton + android:id="@+id/link_high" + android:layout_width="110dp" + android:layout_height="wrap_content" + android:checked="false" + android:text="@string/high" + android:textOff="@string/high" + android:textOn="@string/high" + android:layout_marginTop="8dp"/> + + </LinearLayout> +</LinearLayout> + diff --git a/pxp-monitor/res/layout/path_loss_fragment.xml b/pxp-monitor/res/layout/path_loss_fragment.xml new file mode 100644 index 0000000..58b7273 --- /dev/null +++ b/pxp-monitor/res/layout/path_loss_fragment.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. + */ +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:focusable="true" + android:focusableInTouchMode="true" + android:orientation="vertical" > + + <TextView + android:id="@+id/path_loss" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="@string/path" + android:textSize="18sp" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" > + + <ToggleButton + android:id="@+id/path_off" + android:layout_width="110dp" + android:layout_height="wrap_content" + android:layout_marginLeft="8dp" + android:layout_marginTop="8dp" + android:checked="false" + android:text="@string/off" + android:textOff="@string/off" + android:textOn="@string/off" /> + + <ToggleButton + android:id="@+id/path_mild" + android:layout_width="110dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:checked="false" + android:text="@string/mild" + android:textOff="@string/mild" + android:textOn="@string/mild" /> + + <ToggleButton + android:id="@+id/path_high" + android:layout_width="110dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:checked="false" + android:text="@string/high" + android:textOff="@string/high" + android:textOn="@string/high" /> + </LinearLayout> + + <TextView + android:id="@+id/set_threshold" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="100dp" + android:text="@string/threshold" + android:textSize="18sp" /> + + <TextView + android:id="@+id/threshold_min" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="@string/threshold_min" + android:textSize="18sp" /> + + <EditText + android:id="@+id/threshold_min_value" + android:layout_width="155dp" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:ems="10" + android:inputType="numberSigned" /> + + <TextView + android:id="@+id/threshold_max" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:text="@string/threshold_max" + android:textSize="18sp" /> + + <EditText + android:id="@+id/threshold_max_value" + android:layout_width="155dp" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:ems="10" + android:inputType="numberSigned" /> + +</LinearLayout>
\ No newline at end of file diff --git a/pxp-monitor/res/menu/device.xml b/pxp-monitor/res/menu/device.xml new file mode 100644 index 0000000..3a2d30d --- /dev/null +++ b/pxp-monitor/res/menu/device.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. + */ +--> +<menu xmlns:android="http://schemas.android.com/apk/res/android" > + <item android:id="@+id/action_settings" + android:orderInCategory="1" + android:showAsAction="ifRoom" + android:title="@string/action_settings"/> + + <item android:id="@+id/menu_disconnect" + android:title="@string/menu_disconnect" + android:orderInCategory="100" + android:showAsAction="ifRoom|withText"/> + + <item android:id="@+id/menu_connect" + android:title="@string/menu_connect" + android:orderInCategory="101" + android:showAsAction="ifRoom|withText"/> +</menu> diff --git a/pxp-monitor/res/menu/main.xml b/pxp-monitor/res/menu/main.xml new file mode 100644 index 0000000..95c3298 --- /dev/null +++ b/pxp-monitor/res/menu/main.xml @@ -0,0 +1,34 @@ +<!-- + * 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. + */ +--> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/action_settings" + android:orderInCategory="100" + android:showAsAction="ifRoom" + android:title="@string/action_settings"/> +</menu> diff --git a/pxp-monitor/res/menu/scan.xml b/pxp-monitor/res/menu/scan.xml new file mode 100644 index 0000000..18359cd --- /dev/null +++ b/pxp-monitor/res/menu/scan.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. + */ +--> +<menu xmlns:android="http://schemas.android.com/apk/res/android" > + <item android:id="@+id/action_search" + android:icon="@drawable/search" + android:orderInCategory="100" + android:showAsAction="ifRoom" /> + + <item android:id="@+id/menu_stop" + android:title="@string/menu_stop" + android:orderInCategory="101" + android:showAsAction="ifRoom|withText"/> +</menu> diff --git a/pxp-monitor/res/values-sw600dp/dimens.xml b/pxp-monitor/res/values-sw600dp/dimens.xml new file mode 100644 index 0000000..8b8679c --- /dev/null +++ b/pxp-monitor/res/values-sw600dp/dimens.xml @@ -0,0 +1,36 @@ +<!-- + * 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. + */ +--> +<resources> + + <!-- + Customize dimensions originally defined in res/values/dimens.xml (such as + screen margins) for sw600dp devices (e.g. 7" tablets) here. + --> + +</resources> diff --git a/pxp-monitor/res/values-sw720dp-land/dimens.xml b/pxp-monitor/res/values-sw720dp-land/dimens.xml new file mode 100644 index 0000000..dcb6433 --- /dev/null +++ b/pxp-monitor/res/values-sw720dp-land/dimens.xml @@ -0,0 +1,37 @@ +<!-- + * 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. + */ +--> +<resources> + + <!-- + Customize dimensions originally defined in res/values/dimens.xml (such as + screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. + --> + <dimen name="activity_horizontal_margin">128dp</dimen> + +</resources> diff --git a/pxp-monitor/res/values-v11/styles.xml b/pxp-monitor/res/values-v11/styles.xml new file mode 100644 index 0000000..77efabc --- /dev/null +++ b/pxp-monitor/res/values-v11/styles.xml @@ -0,0 +1,39 @@ +<!-- + * 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. + */ +--> +<resources> + + <!-- + Base application theme for API 11+. This theme completely replaces + AppBaseTheme from res/values/styles.xml on API 11+ devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Holo.Light"> + <!-- API 11 theme customizations can go here. --> + </style> + +</resources> diff --git a/pxp-monitor/res/values-v14/styles.xml b/pxp-monitor/res/values-v14/styles.xml new file mode 100644 index 0000000..165ee27 --- /dev/null +++ b/pxp-monitor/res/values-v14/styles.xml @@ -0,0 +1,40 @@ +<!-- + * 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. + */ +--> +<resources> + + <!-- + Base application theme for API 14+. This theme completely replaces + AppBaseTheme from BOTH res/values/styles.xml and + res/values-v11/styles.xml on API 14+ devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar"> + <!-- API 14 theme customizations can go here. --> + </style> + +</resources> diff --git a/pxp-monitor/res/values/dimens.xml b/pxp-monitor/res/values/dimens.xml new file mode 100644 index 0000000..c64c4c0 --- /dev/null +++ b/pxp-monitor/res/values/dimens.xml @@ -0,0 +1,35 @@ +<!-- + * 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. + */ +--> +<resources> + + <!-- Default screen margins, per the Android Design guidelines. --> + <dimen name="activity_horizontal_margin">16dp</dimen> + <dimen name="activity_vertical_margin">16dp</dimen> + +</resources> diff --git a/pxp-monitor/res/values/strings.xml b/pxp-monitor/res/values/strings.xml new file mode 100644 index 0000000..d15d12e --- /dev/null +++ b/pxp-monitor/res/values/strings.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * 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. + */ +--> +<resources> + + <string name="off">OFF</string> + <string name="mild">MILD</string> + <string name="high">HIGH</string> + <string name="link">Link Loss Level</string> + <string name="path">Path Loss Level</string> + <string name="threshold">Set threshold</string> + <string name="threshold_min">Min threshold</string> + <string name="threshold_max">Max threshold</string> + <string name="app_name">Proximity Monitor</string> + <string name="action_settings">Settings</string> + <string name="menu_disconnect">Disconnect</string> + <string name="menu_connect">Connect</string> + <string name="menu_stop">Stop</string> + <string name="connected">Connected devices</string> + <string name="paired">Connect to paired dvice</string> + <string name="scan">Scan for a device</string> + <string name="connect_to">Connect to device</string> + <string name="history">Alert history</string> + <string name="device_address">Connect to</string> + <string name="title">Insert bluetooth device address</string> + <string name="connect">Connect</string> + +</resources>
\ No newline at end of file diff --git a/pxp-monitor/res/values/styles.xml b/pxp-monitor/res/values/styles.xml new file mode 100644 index 0000000..cbf3ff2 --- /dev/null +++ b/pxp-monitor/res/values/styles.xml @@ -0,0 +1,48 @@ +<!-- + * 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. + */ +--> +<resources> + + <!-- + Base application theme, dependent on API level. This theme is replaced + by AppBaseTheme from res/values-vXX/styles.xml on newer devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Light"> + <!-- + Theme customizations available in newer API levels can go in + res/values-vXX/styles.xml, while customizations related to + backward-compatibility can go here. + --> + </style> + + <!-- Application theme. --> + <style name="AppTheme" parent="AppBaseTheme"> + <!-- All customizations that are NOT specific to a particular API-level can go here. --> + </style> + +</resources> diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/AlertInformation.java b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/AlertInformation.java new file mode 100644 index 0000000..af36c7b --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/AlertInformation.java @@ -0,0 +1,37 @@ +/* + * 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.pxpmonitor; + +import android.bluetooth.BluetoothDevice; + +public class AlertInformation { + public BluetoothDevice device; + public String date; + public int rssi; +} diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/AlertsHistory.java b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/AlertsHistory.java new file mode 100644 index 0000000..f17c2e7 --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/AlertsHistory.java @@ -0,0 +1,235 @@ +/* + * 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.pxpmonitor; + +import android.app.Activity; +import android.app.ListActivity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Iterator; + +public class AlertsHistory extends ListActivity { + + private static final String TAG = AlertsHistory.class.getSimpleName(); + + private static final int REQUEST_ENABLE_BT = 1; + + private static AlertHistoryAdapter mAlertHistoryAdapter = null; + + private BluetoothAdapter mBluetoothAdapter = null; + + private PxpServiceProxy mPxpServiceProxy = null; + + private final ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + mPxpServiceProxy = ((PxpServiceProxy.LocalBinder) service).getService(); + + if (mPxpServiceProxy == null) { + return; + } + listAlerts(); + } + + @Override + public void onServiceDisconnected(ComponentName className) { + mPxpServiceProxy = null; + } + }; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getActionBar().setTitle("Alert History"); + + Log.d(TAG, "On create: new intent BluetoothService"); + Intent gattServiceIntent = new Intent(this, PxpServiceProxy.class); + + if (bindService(gattServiceIntent, mConnection, BIND_AUTO_CREATE) == false) { + Log.e(TAG, "Unable to bind"); + } + + final BluetoothManager bluetoothManager = + (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + mBluetoothAdapter = bluetoothManager.getAdapter(); + + mAlertHistoryAdapter = new AlertHistoryAdapter(this); + setListAdapter(mAlertHistoryAdapter); + } + + @Override + protected void onResume() { + super.onResume(); + + if (!mBluetoothAdapter.isEnabled()) { + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); + } + + if (mPxpServiceProxy != null) { + mAlertHistoryAdapter.clear(); + listAlerts(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + unbindService(mConnection); + mPxpServiceProxy = null; + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) { + finish(); + return; + } + + if (mPxpServiceProxy != null) { + listAlerts(); + } + } + + private void listAlerts() { + Iterator<AlertInformation> iterator = + mPxpServiceProxy.mAlertHistory.iterator(); + + while (iterator.hasNext()) { + mAlertHistoryAdapter.addAlert(iterator.next()); + mAlertHistoryAdapter.notifyDataSetChanged(); + } + + } + + private class AlertHistoryAdapter extends BaseAdapter { + + private ArrayList<AlertInformation> mAlertInf; + + private LayoutInflater mInflater; + + private TextView mDeviceName; + + private TextView mDeviceAddress; + + private TextView mTime; + + private TextView mRssi; + + public AlertHistoryAdapter(Context context) { + super(); + + mAlertInf = new ArrayList<AlertInformation>(); + mInflater = LayoutInflater.from(context); + } + + public void addAlert(AlertInformation alert) { + if (!mAlertInf.contains(alert)) { + mAlertInf.add(alert); + } + } + + public void clear() { + mAlertInf.clear(); + this.notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mAlertInf.size(); + } + + @Override + public Object getItem(int i) { + return mAlertInf.get(i); + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + + if (view == null) { + view = mInflater.inflate(R.layout.activity_alerts_history, null); + } + + mDeviceName = (TextView) view.findViewById(R.id.device_name); + mDeviceAddress = (TextView) view.findViewById(R.id.device_address); + mTime = (TextView) view.findViewById(R.id.alert_time); + mRssi = (TextView) view.findViewById(R.id.device_rssi); + + Log.e(TAG, "i: " + i); + + AlertInformation alert = mAlertInf.get(i); + + final String deviceName = alert.device.getName(); + + if (deviceName != null && deviceName.length() > 0) { + mDeviceName.setText(deviceName); + + } else { + mDeviceName.setText("Unknow device"); + } + + mDeviceAddress.setText(alert.device.getAddress()); + + mTime.setText(alert.date); + mRssi.setText("RSSI = " + String.valueOf(alert.rssi) + "dBm"); + + return view; + } + } +} diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/ConnectToDeviceDialogFragment.java b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/ConnectToDeviceDialogFragment.java new file mode 100644 index 0000000..b3e5ca2 --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/ConnectToDeviceDialogFragment.java @@ -0,0 +1,87 @@ +/* + * 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.pxpmonitor; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; + +public class ConnectToDeviceDialogFragment extends DialogFragment { + + private EditText mEditText; + + private ConnectToDeviceDialogListener mListener; + + public interface ConnectToDeviceDialogListener { + public void onConnectToDeviceDialogPositive(String address); + }; + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + + LayoutInflater inflater = getActivity().getLayoutInflater(); + + View view = inflater.inflate(R.layout.connect_to_device_dialog_fragment, null); + + mEditText = (EditText) view.findViewById(R.id.device_address); + + builder.setTitle(R.string.title); + builder.setView(view) + .setPositiveButton(R.string.connect, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + String address = mEditText.getText().toString();; + + mListener.onConnectToDeviceDialogPositive(address); + } + }) + .setNegativeButton(android.R.string.cancel, null); + return builder.create(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + try { + mListener = (MainActivity) activity; + } catch (ClassCastException e) { + throw new ClassCastException(this.getClass().getSimpleName() + + " can be only attached to " + MainActivity.class.getSimpleName()); + } + } +} diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/ConnectedDevicesActivity.java b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/ConnectedDevicesActivity.java new file mode 100644 index 0000000..4968123 --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/ConnectedDevicesActivity.java @@ -0,0 +1,247 @@ +/* + * 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.pxpmonitor; + +import android.app.Activity; +import android.app.ListActivity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class ConnectedDevicesActivity extends ListActivity { + + private static final String TAG = ConnectedDevicesActivity.class.getSimpleName(); + + public static final String DEVICE_CONNECTED_SELECTED = "android.bluetooth.devicepicker.action.DEVICE_SELECTED"; + + private static final int REQUEST_ENABLE_BT = 1; + + private ConnectedDeviceAdapter mConnectedDeviceAdapter; + + private BluetoothAdapter mBluetoothAdapter = null; + + private PxpServiceProxy mPxpServiceProxy = null; + + private final ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + mPxpServiceProxy = ((PxpServiceProxy.LocalBinder) service).getService(); + + if (mPxpServiceProxy == null) { + return; + } + + listConnectedDevices(); + } + + @Override + public void onServiceDisconnected(ComponentName className) { + mPxpServiceProxy = null; + } + }; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Log.d(TAG, "On create: new intent BluetoothService"); + Intent gattServiceIntent = new Intent(this, PxpServiceProxy.class); + + if (bindService(gattServiceIntent, mConnection, BIND_AUTO_CREATE) == false) { + Log.e(TAG, "Unable to bind"); + } + + final BluetoothManager bluetoothManager = + (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + mBluetoothAdapter = bluetoothManager.getAdapter(); + + mConnectedDeviceAdapter = new ConnectedDeviceAdapter(this); + setListAdapter(mConnectedDeviceAdapter); + } + + @Override + protected void onResume() { + super.onResume(); + + if (!mBluetoothAdapter.isEnabled()) { + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); + } + + if (mPxpServiceProxy != null) { + mConnectedDeviceAdapter.clear(); + listConnectedDevices(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + unbindService(mConnection); + mPxpServiceProxy = null; + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) { + finish(); + return; + } + + if (mPxpServiceProxy != null) { + listConnectedDevices(); + } + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + + final BluetoothDevice leDevice = mConnectedDeviceAdapter.getDevice(position); + + if (leDevice == null) { + return; + } + + final Intent intent = new Intent(this, DeviceActivity.class); + + intent.setAction(DEVICE_CONNECTED_SELECTED); + intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + intent.putExtra(DeviceActivity.EXTRAS_DEVICE, leDevice); + + startActivity(intent); + } + + private synchronized void listConnectedDevices() { + + List<BluetoothDevice> connectedDevices = mPxpServiceProxy.getConnectedDevices(); + + Iterator<BluetoothDevice> iterator = connectedDevices.iterator(); + + while (iterator.hasNext()) { + mConnectedDeviceAdapter.addDevice(iterator.next()); + mConnectedDeviceAdapter.notifyDataSetChanged(); + } + } + + private class ConnectedDeviceAdapter extends BaseAdapter { + + private ArrayList<BluetoothDevice> mLeDevices; + + private LayoutInflater mInflater; + + private TextView mDeviceName; + + private TextView mDeviceAddress; + + public ConnectedDeviceAdapter(Context context) { + super(); + + mLeDevices = new ArrayList<BluetoothDevice>(); + mInflater = LayoutInflater.from(context); + } + + public void addDevice(BluetoothDevice device) { + + if (!mLeDevices.contains(device)) { + mLeDevices.add(device); + } + } + + public BluetoothDevice getDevice(int position) { + return mLeDevices.get(position); + } + + public void clear() { + mLeDevices.clear(); + this.notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mLeDevices.size(); + } + + @Override + public Object getItem(int i) { + return mLeDevices.get(i); + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + + if (view == null) { + view = mInflater.inflate(R.layout.activity_list_devices, null); + } + + mDeviceName = (TextView) view.findViewById(R.id.device_name); + mDeviceAddress = (TextView) view.findViewById(R.id.device_address); + + BluetoothDevice device = mLeDevices.get(i); + + final String deviceName = device.getName(); + + if (deviceName != null && deviceName.length() > 0) { + mDeviceName.setText(deviceName); + + } else { + mDeviceName.setText("Unknow device"); + } + + mDeviceAddress.setText(device.getAddress()); + + return view; + } + } +} diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/DeviceActivity.java b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/DeviceActivity.java new file mode 100644 index 0000000..ab12551 --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/DeviceActivity.java @@ -0,0 +1,365 @@ +/* + * 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.pxpmonitor; + +import android.app.Activity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.util.Log; +import android.view.Gravity; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.Toast; + +public class DeviceActivity extends Activity { + + private static final String TAG = DeviceActivity.class.getSimpleName(); + + public static final String EXTRAS_DEVICE = "BLUETOOTH_DEVICE"; + + private static final int REQUEST_ENABLE_BT = 1; + + private BluetoothAdapter mBluetoothAdapter = null; + + protected PxpServiceProxy mPxpServiceProxy = null; + + protected BluetoothDevice mLeDevice = null; + + private DeviceInfoFragment mDeviceInfoFragment = null; + + private LinkLossFragment mLinkLossFragment = null; + + private PathLossFragment mPathLossFragment = null; + + private Uri mLinkNotification = null; + + private Uri mPathNotification = null; + + private Ringtone mLinkRingtone = null; + + private Ringtone mPathRingtone = null; + + private final ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + Log.d(TAG, "Connecting to service"); + mPxpServiceProxy = ((PxpServiceProxy.LocalBinder) service).getService(); + + if (mPxpServiceProxy == null) { + return; + } + + PxpServiceProxy.registerClient(mHandler); + + Intent intent = getIntent(); + String action = intent.getAction(); + + if (ConnectedDevicesActivity.DEVICE_CONNECTED_SELECTED. + equals(action)) { + mLeDevice = (BluetoothDevice) intent.getParcelableExtra(EXTRAS_DEVICE); + + } else if (PairedDevicesActivity.DEVICE_PAIRED_SELECTED. + equals(action)) { + mLeDevice = (BluetoothDevice) intent.getParcelableExtra(EXTRAS_DEVICE); + + if (mLeDevice != null && mPxpServiceProxy.connect(mLeDevice)) { + Log.d(TAG, "Pxp device connected"); + } + + } else if (ScanDevicesActivity.DEVICE_NOT_CONNECTED_SELECTED. + equals(action)) { + mLeDevice = (BluetoothDevice) intent.getParcelableExtra(EXTRAS_DEVICE); + + if (mLeDevice != null && mPxpServiceProxy.connect(mLeDevice)) { + Log.d(TAG, "Pxp device connected"); + } + return; + + } else if (MainActivity.DEVICE_BY_ADDRESS_SELECTED. + equals(action)) { + mLeDevice = (BluetoothDevice) intent.getParcelableExtra(EXTRAS_DEVICE); + + if (mLeDevice != null && mPxpServiceProxy.connect(mLeDevice)) { + Log.d(TAG, "Pxp device connected"); + } + } + + if (mLeDevice != null && mPxpServiceProxy.isPropertiesSet(mLeDevice)) { + setInfo(); + invalidateOptionsMenu(); + } + } + + @Override + public void onServiceDisconnected(ComponentName className) { + mPxpServiceProxy = null; + } + }; + + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + CharSequence toastText = null; + + switch (msg.what) { + + case PxpServiceProxy.MSG_DEVICE_CONNECTED: + Log.d(TAG, "PxpServiceProxy.MSG_DEVICE_CONNECTED"); + + mLeDevice = (BluetoothDevice) msg.obj; + + if (mLinkRingtone.isPlaying()) { + mLinkRingtone.stop(); + } + + this.removeMessages(PxpServiceProxy.MSG_LINK_LOSS_TIMEOUT); + + toastText = "Connected"; + + if (mPxpServiceProxy.isPropertiesSet(mLeDevice)) { + setInfo(); + } + break; + + case PxpServiceProxy.MSG_DEVICE_DISCONNECTED: + Log.d(TAG, "PxpServiceProxy.MSG_DEVICE_DISCONNECTED"); + + mLeDevice = (BluetoothDevice) msg.obj; + + if (mLeDevice.equals(mLeDevice)) { + toastText = "Disconnected"; + mLinkLossFragment.init(); + mPathLossFragment.init(); + } + break; + + case PxpServiceProxy.MSG_MISSING_LLS_SERVICE: + Log.d(TAG, "PxpServiceProxy.MSG_MISSING_LLS_SERVICE"); + toastText = "Device not connected - Link Loss Service not found"; + break; + + case PxpServiceProxy.MSG_LINKLOSS_ALERT: + Log.d(TAG, "PxpServiceProxy.MSG_LINKLOSS_ALERT"); + + int llsAlertValue = (Integer) msg.obj; + mLinkLossFragment.init(); + mPathLossFragment.init(); + + // No alerting if alertLevel == 0 + if (llsAlertValue == 0) { + return; + } + + this.sendMessageDelayed( + this.obtainMessage(PxpServiceProxy.MSG_LINK_LOSS_TIMEOUT), + PxpServiceProxy.LINK_LOSS_ALERT_TIMEOUT); + + mLinkRingtone.play(); + break; + + case PxpServiceProxy.MSG_PATHLOSS_ALERT: + if (!mPathRingtone.isPlaying()) { + mPathRingtone.play(); + } + break; + + case PxpServiceProxy.MSG_LINK_LOSS_TIMEOUT: + mLinkRingtone.stop(); + break; + + case PxpServiceProxy.MSG_ALERT_FINISH: + if (mPathRingtone.isPlaying()) { + mPathRingtone.stop(); + } + break; + + default: + super.handleMessage(msg); + } + + if (toastText != null) { + Toast toast = Toast.makeText(DeviceActivity.this, toastText, Toast.LENGTH_SHORT); + toast.setGravity(Gravity.CENTER, 0, 0); + toast.show(); + } + + invalidateOptionsMenu(); + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_device); + + mDeviceInfoFragment = (DeviceInfoFragment) getFragmentManager().findFragmentById( + R.id.device_info_fragment); + mLinkLossFragment = (LinkLossFragment) getFragmentManager().findFragmentById( + R.id.link_loss_fragment); + mPathLossFragment = (PathLossFragment) getFragmentManager().findFragmentById( + R.id.path_loss_fragment); + + Log.d(TAG, "On create: new intent BluetoothService"); + Intent gattServiceIntent = new Intent(this, PxpServiceProxy.class); + + if (bindService(gattServiceIntent, mConnection, BIND_AUTO_CREATE) == false) { + Log.e(TAG, "Unable to bind"); + } + + final BluetoothManager bluetoothManager = + (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + mBluetoothAdapter = bluetoothManager.getAdapter(); + + mLinkNotification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); + mLinkRingtone = RingtoneManager.getRingtone(getApplicationContext(), mLinkNotification); + + mPathNotification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE); + mPathRingtone = RingtoneManager.getRingtone(getApplicationContext(), mPathNotification); + + } + + @Override + protected void onResume() { + super.onResume(); + + if (!mBluetoothAdapter.isEnabled()) { + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); + } + + if (mLeDevice != null && mPxpServiceProxy.isPropertiesSet(mLeDevice)) { + setInfo(); + invalidateOptionsMenu(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + if (mLinkRingtone.isPlaying()) { + mLinkRingtone.stop(); + } + + mLinkRingtone = null; + mLinkNotification = null; + + if (mPathRingtone.isPlaying()) { + mPathRingtone.stop(); + } + + mPathRingtone = null; + mPathNotification = null; + + unbindService(mConnection); + mPxpServiceProxy = null; + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + + if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) { + finish(); + return; + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.device, menu); + + if (!mPxpServiceProxy.isPropertiesSet(mLeDevice)) { + return false; + } + + if (mPxpServiceProxy.getConnectionState(mLeDevice)) { + menu.findItem(R.id.menu_disconnect).setVisible(true); + menu.findItem(R.id.menu_connect).setVisible(false); + + } else { + menu.findItem(R.id.menu_disconnect).setVisible(false); + menu.findItem(R.id.menu_connect).setVisible(true); + } + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_disconnect: + Log.d(TAG, "Disconnecting"); + mPxpServiceProxy.disconnect(mLeDevice); + break; + + case R.id.menu_connect: + Log.d(TAG, "Connecting"); + if (mPxpServiceProxy.connect(mLeDevice) == true) { + setInfo(); + } + invalidateOptionsMenu(); + break; + } + return true; + } + + void setInfo() { + + final int LinkLossService = 0; + final int ImmediateAlertService = 1; + final int TxPowerService = 2; + + mDeviceInfoFragment.setDeviceInfo(mLeDevice.getName(), mLeDevice.getAddress()); + + mLinkLossFragment.onServiceFound(mPxpServiceProxy.checkServiceStatus(mLeDevice, + LinkLossService)); + + mPathLossFragment.onServiceFound( + mPxpServiceProxy.checkServiceStatus(mLeDevice, ImmediateAlertService), + mPxpServiceProxy.checkServiceStatus(mLeDevice, TxPowerService)); + } +} diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/DeviceInfoFragment.java b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/DeviceInfoFragment.java new file mode 100644 index 0000000..0174355 --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/DeviceInfoFragment.java @@ -0,0 +1,60 @@ +/* + * 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.pxpmonitor; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +public class DeviceInfoFragment extends Fragment { + + private TextView mDeviceName; + + private TextView mDeviceAddress; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View view = inflater.inflate(R.layout.device_info_fragment, container, false); + + mDeviceName = ((TextView) view.findViewById(R.id.device_name)); + mDeviceAddress = ((TextView) view.findViewById(R.id.device_address)); + + return view; + } + + public void setDeviceInfo(String deviceName, String deviceAdress) { + mDeviceName.setText(deviceName); + mDeviceAddress.setText(deviceAdress); + } +} diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/LinkLossFragment.java b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/LinkLossFragment.java new file mode 100644 index 0000000..ce877d7 --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/LinkLossFragment.java @@ -0,0 +1,165 @@ +/* + * 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.pxpmonitor; + +import android.app.Activity; +import android.app.Fragment; +import android.content.Context; +import android.os.Bundle; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; +import android.widget.ToggleButton; + +public class LinkLossFragment extends Fragment implements View.OnClickListener { + + private static final String TAG = LinkLossFragment.class.getSimpleName(); + + private DeviceActivity mActivity; + + private ToggleButton mLinkLossButtons[] = new ToggleButton[3]; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.link_loss_fragment, container, false); + + mLinkLossButtons[0] = (ToggleButton) view.findViewById(R.id.link_off); + mLinkLossButtons[1] = (ToggleButton) view.findViewById(R.id.link_mild); + mLinkLossButtons[2] = (ToggleButton) view.findViewById(R.id.link_high); + + for (ToggleButton btn : mLinkLossButtons) { + btn.setEnabled(false); + btn.setOnClickListener(this); + } + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + try { + mActivity = (DeviceActivity) activity; + } catch (ClassCastException e) { + throw new ClassCastException(this.getClass().getSimpleName() + + " can be only attached to " + MainActivity.class.getSimpleName()); + } + } + + public void init() { + + for (ToggleButton btn : mLinkLossButtons) { + btn.setEnabled(false); + } + } + + public void onServiceFound(boolean state) { + Log.d(TAG, "LLS service" + state); + + if (state) { + mLinkLossButtons[0].setEnabled(true); + mLinkLossButtons[1].setEnabled(true); + mLinkLossButtons[2].setEnabled(true); + + int linkLossLevel = 0; + + if (mActivity.mPxpServiceProxy.getLinkLossAlertLevel(mActivity.mLeDevice) < 0) { + mActivity.mPxpServiceProxy.setLinkLossAlertLevel(mActivity.mLeDevice, + linkLossLevel); + + } else { + linkLossLevel = mActivity.mPxpServiceProxy. + getLinkLossAlertLevel(mActivity.mLeDevice); + } + + for (int i = 0; i < mLinkLossButtons.length; i++) { + mLinkLossButtons[i].setChecked(linkLossLevel == i); + } + + } else { + init(); + Context context = getActivity(); + CharSequence text = "Link Loss Service not found"; + + Toast toast = Toast.makeText(context, text, Toast.LENGTH_SHORT); + toast.setGravity(Gravity.CENTER, 0, 0); + toast.show(); + } + } + + @Override + public void onClick(View v) { + ToggleButton clickedButton = (ToggleButton) v; + + if (!mActivity.mPxpServiceProxy.getConnectionState(mActivity.mLeDevice)) { + return; + } + + int idx; + + switch (clickedButton.getId()) { + case R.id.link_off: + idx = 0; + break; + + case R.id.link_mild: + idx = 1; + break; + + case R.id.link_high: + idx = 2; + break; + + default: + return; + } + + for (int i = 0; i < mLinkLossButtons.length; i++) { + ToggleButton btn = mLinkLossButtons[i]; + + if (mLinkLossButtons[idx].isChecked()) { + + if (i != idx) { + btn.setChecked(false); + } + + } else { + btn.setChecked(i == 0); + idx = 0; + } + } + + mActivity.mPxpServiceProxy.setLinkLossAlertLevel(mActivity.mLeDevice, idx); + } +} diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/MainActivity.java b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/MainActivity.java new file mode 100644 index 0000000..63813a1 --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/MainActivity.java @@ -0,0 +1,188 @@ +/* + * 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.pxpmonitor; + +import android.app.Activity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; +import android.view.Menu; +import android.view.View; +import android.widget.Toast; + +import org.codeaurora.bluetooth.pxpmonitor.ConnectToDeviceDialogFragment.ConnectToDeviceDialogListener; + +public class MainActivity extends Activity implements ConnectToDeviceDialogListener { + + private static final String TAG = MainActivity.class.getSimpleName();; + + private static final int REQUEST_ENABLE_BT = 1; + + public static final String DEVICE_BY_ADDRESS_SELECTED = + "android.bluetooth.devicepicker.action.DEVICE_BY_ADDRESS_SELECTED"; + + protected BluetoothAdapter mBluetoothAdapter = null; + + protected PxpServiceProxy mPxpServiceProxy = null; + + protected Intent intent = null; + + private final ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + mPxpServiceProxy = ((PxpServiceProxy.LocalBinder) service).getService(); + } + + @Override + public void onServiceDisconnected(ComponentName className) { + mPxpServiceProxy = null; + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + Toast.makeText(this, "BLE not supported", Toast.LENGTH_SHORT).show(); + finish(); + } + + final BluetoothManager bluetoothManager = + (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + mBluetoothAdapter = bluetoothManager.getAdapter(); + + Log.d(TAG, "On create: new intent BluetoothService"); + Intent gattServiceIntent = new Intent(this, PxpServiceProxy.class); + + if (bindService(gattServiceIntent, mConnection, BIND_AUTO_CREATE) == false) { + Log.e(TAG, "Unable to bind"); + } + } + + @Override + protected void onResume() { + super.onResume(); + + if (!mBluetoothAdapter.isEnabled()) { + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + + if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) { + finish(); + return; + } + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onDestroy() { + + if (mPxpServiceProxy != null) { + mPxpServiceProxy.disconnectDevices(); + } + + unbindService(mConnection); + mPxpServiceProxy = null; + super.onDestroy(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + public void searchForDevices(View view) { + final Intent intent = new Intent(this, ScanDevicesActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + startActivity(intent); + } + + public void showConnectedDevices(View view) { + final Intent intent = new Intent(this, ConnectedDevicesActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + startActivity(intent); + } + + public void showPairedDevices(View view) { + final Intent intent = new Intent(this, PairedDevicesActivity.class); + startActivity(intent); + } + + public void connectToDevice(View view) { + ConnectToDeviceDialogFragment newFragment = new ConnectToDeviceDialogFragment(); + newFragment.show(getFragmentManager(), "address"); + } + + public void showAlertHistory(View view) { + final Intent intent = new Intent(this, AlertsHistory.class); + intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + startActivity(intent); + } + + @Override + public void onConnectToDeviceDialogPositive(String address) { + BluetoothDevice leDevice = null; + + if (BluetoothAdapter.checkBluetoothAddress(address)) { + + leDevice = mBluetoothAdapter.getRemoteDevice(address); + + final Intent intent = new Intent(this, DeviceActivity.class); + intent.setAction(DEVICE_BY_ADDRESS_SELECTED); + intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + intent.putExtra(DeviceActivity.EXTRAS_DEVICE, leDevice); + startActivity(intent); + + } else { + Log.w(TAG, "Wrong device address"); + } + + } +} diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/PairedDevicesActivity.java b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/PairedDevicesActivity.java new file mode 100644 index 0000000..d010790 --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/PairedDevicesActivity.java @@ -0,0 +1,236 @@ +/* + * 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.pxpmonitor; + +import android.app.ListActivity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Set; + +public class PairedDevicesActivity extends ListActivity { + + private static final String TAG = PairedDevicesActivity.class.getSimpleName(); + + private static final int REQUEST_ENABLE_BT = 1; + + public static final String DEVICE_PAIRED_SELECTED = + "android.bluetooth.devicepicker.action.DEVICE_PAIRED_SELECTED"; + + private PairedDevicesListAdapter mPairedDeviceListAdapter; + + private BluetoothAdapter mAdapter = null; + + private PxpServiceProxy mPxpServiceProxy = null; + + private final ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + Log.d(TAG, "Connecting to service"); + mPxpServiceProxy = ((PxpServiceProxy.LocalBinder) service).getService(); + } + + @Override + public void onServiceDisconnected(ComponentName className) { + mPxpServiceProxy = null; + } + }; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getActionBar().setTitle("Paired Devices"); + + Log.d(TAG, "On create: new intent BluetoothService"); + Intent gattServiceIntent = new Intent(this, PxpServiceProxy.class); + + if (bindService(gattServiceIntent, mConnection, BIND_AUTO_CREATE) == false) { + Log.e(TAG, "Unable to bind"); + } + + final BluetoothManager bluetoothManager = + (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + mAdapter = bluetoothManager.getAdapter(); + + mPairedDeviceListAdapter = new PairedDevicesListAdapter(this); + setListAdapter(mPairedDeviceListAdapter); + getPairedDevices(); + } + + @Override + protected void onResume() { + super.onResume(); + + if (!mAdapter.isEnabled()) { + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); + } + + mPairedDeviceListAdapter.clear(); + getPairedDevices(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == REQUEST_ENABLE_BT) { + getPairedDevices(); + } + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + + final BluetoothDevice leDevice = mPairedDeviceListAdapter.getDevice(position); + + if (leDevice == null) { + return; + } + + Log.d(TAG, "Trying to connect to paired device :" + leDevice.getAddress()); + + final Intent intent = new Intent(this, DeviceActivity.class); + intent.setAction(DEVICE_PAIRED_SELECTED); + intent.putExtra(DeviceActivity.EXTRAS_DEVICE, leDevice); + startActivity(intent); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + unbindService(mConnection); + mPxpServiceProxy = null; + } + + private void getPairedDevices() { + Set<BluetoothDevice> devices = mAdapter.getBondedDevices(); + + for (BluetoothDevice device : devices) { + mPairedDeviceListAdapter.addDevice(device); + mPairedDeviceListAdapter.notifyDataSetChanged(); + } + } + + private class PairedDevicesListAdapter extends BaseAdapter { + + private ArrayList<BluetoothDevice> mLeDevices; + + private LayoutInflater mInflater; + + private TextView mDeviceName; + + private TextView mDeviceAddress; + + public PairedDevicesListAdapter(Context context) { + super(); + mLeDevices = new ArrayList<BluetoothDevice>(); + mInflater = LayoutInflater.from(context); + } + + public void addDevice(BluetoothDevice device) { + if (!mLeDevices.contains(device)) { + mLeDevices.add(device); + } + } + + public BluetoothDevice getDevice(int position) { + return mLeDevices.get(position); + } + + public void clear() { + mLeDevices.clear(); + this.notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mLeDevices.size(); + } + + @Override + public Object getItem(int i) { + return mLeDevices.get(i); + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + + if (view == null) { + view = mInflater.inflate(R.layout.activity_list_devices, null); + } + + mDeviceName = (TextView) view.findViewById(R.id.device_name); + mDeviceAddress = (TextView) view.findViewById(R.id.device_address); + + BluetoothDevice device = mLeDevices.get(i); + + final String deviceName = device.getName(); + + if (deviceName != null && deviceName.length() > 0) { + mDeviceName.setText(deviceName); + + } else { + mDeviceName.setText("Unknown device"); + } + + mDeviceAddress.setText(device.getAddress()); + + return view; + } + } +} diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/PathLossFragment.java b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/PathLossFragment.java new file mode 100644 index 0000000..dc2f7ba --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/PathLossFragment.java @@ -0,0 +1,299 @@ +/* + * 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.pxpmonitor; + +import android.app.Activity; +import android.app.Fragment; +import android.content.Context; +import android.os.Bundle; +import android.util.Log; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.ToggleButton; + +public class PathLossFragment extends Fragment implements View.OnClickListener { + + private static final String TAG = PathLossFragment.class.getSimpleName(); + + private static final short TX_POWER_MIN = -100; + + private static final short TX_POWER_MAX = 20; + + private static final short RSSI_MIN = -127; + + private static final short RSSI_MAX = 20; + + private static final short THRESHOLD_MIN = TX_POWER_MIN - RSSI_MAX; // -120 + + private static final short THRESHOLD_MAX = TX_POWER_MAX - RSSI_MIN; // 147 + + private DeviceActivity mActivity; + + private ToggleButton mPathLossButtons[] = new ToggleButton[3]; + + private EditText mMinValue; + + private EditText mMaxValue; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.path_loss_fragment, null, false); + + mPathLossButtons[0] = (ToggleButton) view.findViewById(R.id.path_off); + mPathLossButtons[1] = (ToggleButton) view.findViewById(R.id.path_mild); + mPathLossButtons[2] = (ToggleButton) view.findViewById(R.id.path_high); + mMinValue = (EditText) view.findViewById(R.id.threshold_min_value); + mMaxValue = (EditText) view.findViewById(R.id.threshold_max_value); + + mMinValue.setOnEditorActionListener(new EditText.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + + CharSequence text = null; + + if (actionId == EditorInfo.IME_ACTION_DONE) { + int threshold = Integer.parseInt(mMinValue.getText().toString()); + + if (threshold > THRESHOLD_MAX) { + + text = "Threshold is to big. Changing to " + + Integer.toString(THRESHOLD_MAX); + + threshold = THRESHOLD_MAX; + mMinValue.setText(String.valueOf(threshold)); + + } else if (threshold < THRESHOLD_MIN) { + + text = "Threshold is to small. Changing to " + + Integer.toString(THRESHOLD_MIN); + + threshold = THRESHOLD_MIN; + mMinValue.setText(String.valueOf(threshold)); + } + + if (text != null) { + Context context = getActivity(); + + Toast toast = Toast.makeText(context, text, Toast.LENGTH_SHORT); + toast.setGravity(Gravity.CENTER, 0, 0); + toast.show(); + } + + mActivity.mPxpServiceProxy.setMinPathLossThreshold(mActivity.mLeDevice, + threshold); + + final InputMethodManager imm = (InputMethodManager) getActivity() + .getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(getView().getWindowToken(), 0); + + return true; + } + return false; + } + }); + + mMaxValue.setOnEditorActionListener(new EditText.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + + CharSequence text = null; + + if (actionId == EditorInfo.IME_ACTION_DONE) { + int threshold = Integer.parseInt(mMaxValue.getText().toString()); + + if (threshold > THRESHOLD_MAX) { + + text = "Threshold is to big. Changing to " + + Integer.toString(THRESHOLD_MAX); + + threshold = THRESHOLD_MAX; + mMaxValue.setText(String.valueOf(threshold)); + + } else if (threshold < THRESHOLD_MIN) { + + text = "Threshold is to small. Changing to " + + Integer.toString(THRESHOLD_MIN); + + threshold = THRESHOLD_MIN; + mMaxValue.setText(String.valueOf(threshold)); + } + + if (text != null) { + Context context = getActivity(); + + Toast toast = Toast.makeText(context, text, Toast.LENGTH_SHORT); + toast.setGravity(Gravity.CENTER, 0, 0); + toast.show(); + } + + mActivity.mPxpServiceProxy.setMaxPathLossThreshold(mActivity.mLeDevice, + threshold); + + final InputMethodManager imm = (InputMethodManager) getActivity() + .getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(getView().getWindowToken(), 0); + + return true; + } + return false; + } + }); + + for (ToggleButton btn : mPathLossButtons) { + btn.setEnabled(false); + btn.setOnClickListener(this); + } + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + try { + mActivity = (DeviceActivity) activity; + } catch (ClassCastException e) { + throw new ClassCastException(this.getClass().getSimpleName() + + " can be only attached to " + MainActivity.class.getSimpleName()); + } + } + + public void init() { + + for (ToggleButton btn : mPathLossButtons) { + btn.setEnabled(false); + } + + mMinValue.setEnabled(false); + mMaxValue.setEnabled(false); + } + + public void onServiceFound(boolean llsService, boolean tpsService) { + + Log.v(TAG, "IAS service = " + llsService + " TPS service = " + tpsService); + + if (mActivity.mPxpServiceProxy.checkFailedReadTxPowerLevel(mActivity.mLeDevice)) { + Context context = getActivity(); + CharSequence text = "TX Power level not found"; + + Toast toast = Toast.makeText(context, text, Toast.LENGTH_SHORT); + toast.setGravity(Gravity.CENTER, 0, 0); + toast.show(); + + } else if (llsService && tpsService) { + + mPathLossButtons[0].setEnabled(true); + mPathLossButtons[1].setEnabled(true); + mPathLossButtons[2].setEnabled(true); + mMinValue.setEnabled(true); + mMaxValue.setEnabled(true); + + int pathLossLevel; + + pathLossLevel = mActivity.mPxpServiceProxy + .getPathLossAlertLevel(mActivity.mLeDevice); + + for (int i = 0; i < mPathLossButtons.length; i++) { + mPathLossButtons[i].setChecked(pathLossLevel == i); + } + + int minThresholdValue; + int maxThresholdValue; + + minThresholdValue = mActivity.mPxpServiceProxy + .getMinPathLossThreshold(mActivity.mLeDevice); + + mMinValue.setText(String.format("%d", minThresholdValue)); + + maxThresholdValue = mActivity.mPxpServiceProxy + .getMaxPathLossThreshold(mActivity.mLeDevice); + + mMaxValue.setText(String.format("%d", maxThresholdValue)); + + } else { + init(); + } + + } + + @Override + public void onClick(View v) { + ToggleButton clickedButton = (ToggleButton) v; + + if (!mActivity.mPxpServiceProxy.getConnectionState(mActivity.mLeDevice)) { + return; + } + + int idx; + + switch (clickedButton.getId()) { + case R.id.path_off: + idx = 0; + break; + + case R.id.path_mild: + idx = 1; + break; + + case R.id.path_high: + idx = 2; + break; + + default: + return; + } + + for (int i = 0; i < mPathLossButtons.length; i++) { + ToggleButton btn = mPathLossButtons[i]; + + if (mPathLossButtons[idx].isChecked()) { + + if (i != idx) { + btn.setChecked(false); + } + + } else { + btn.setChecked(i == 0); + idx = 0; + } + } + + mActivity.mPxpServiceProxy.setPathLossAlertLevel(mActivity.mLeDevice, idx); + } +} diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/PxpServiceProxy.java b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/PxpServiceProxy.java new file mode 100644 index 0000000..8707ec7 --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/PxpServiceProxy.java @@ -0,0 +1,393 @@ +/* + * 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.pxpmonitor; + +import android.app.Service; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; + +import org.codeaurora.bluetooth.pxpservice.IPxpService; + +import java.util.ArrayList; +import java.util.List; + +public class PxpServiceProxy extends Service { + + private static final String TAG = PxpServiceProxy.class.getSimpleName(); + + public static final String DEVICE_CONNECTED = "android.bluetooth.action.DEVICE_CONNECTED"; + + public static final String DEVICE_DISCONNECTED = "android.bluetooth.action.DEVICE_DISCONNECTED"; + + public static final String MISSING_LLS_SERVICE = "android.bluetooth.action.DEVICE_MISSING_LLS_SERVICE"; + + public static final String LINKLOSS_ALERT = "android.bluetooth.action.LINKLOSS_ALERT"; + + public static final String DEVICE_ALLERT = "action.DEVICE_ALLERT"; + + public static final String PATHLOSS_ALLERT = "action.PATHLOSS_ALLERT"; + + public static final String PATHLOSS_ALLERT_FINISH = "action.ALLERT_FINISH"; + + public static final String EXTRAS_DEVICE = "BLUETOOTH_DEVICE"; + + public static final String EXTRAS_TIME = "ALERT_TIME"; + + public static final String EXTRAS_RSSI = "DEVICE_RSSI"; + + public static final String EXTRAS_LLS_ALERT_VALUE = "LLS_ALERT_VALUE"; + + public static final int MSG_REGISTER_CLIENT = 1; + + public static final int MSG_UNREGISTER_CLIENT = 2; + + public static final int MSG_DEVICE_CONNECTED = 1; + + public static final int MSG_MISSING_LLS_SERVICE = 2; + + public static final int MSG_LINKLOSS_ALERT = 3; + + public static final int MSG_DEVICE_DISCONNECTED = 4; + + public static final int MSG_LINK_LOSS_TIMEOUT = 5; + + public static final int MSG_PATHLOSS_ALERT = 6; + + public static final int MSG_ALERT_FINISH = 7; + + public static final int LINK_LOSS_ALERT_TIMEOUT = 15000; + + private IPxpService mPxpMonitorService = null; + + private static Handler mHandler = null; + + private final LocalBinder mBinder = new LocalBinder(); + + protected ArrayList<AlertInformation> mAlertHistory = null; + + public class LocalBinder extends Binder { + PxpServiceProxy getService() { + return PxpServiceProxy.this; + } + } + + public static void registerClient(Handler handler) { + mHandler = handler; + } + + private final ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + mPxpMonitorService = IPxpService.Stub.asInterface((IBinder) service); + + Log.d(TAG, "Connected to Service"); + } + + @Override + public void onServiceDisconnected(ComponentName className) { + mPxpMonitorService = null; + + Log.d(TAG, "Disconnected from Service"); + } + }; + + @Override + public void onCreate() { + super.onCreate(); + + Log.d(TAG, "On create: new intent BluetoothService"); + Intent gattServiceIntent = new Intent(); + gattServiceIntent.setAction("org.codeaurora.bluetooth.pxpservice.PxpMonitorService"); + bindService(gattServiceIntent, mConnection, BIND_AUTO_CREATE); + + mAlertHistory = new ArrayList<AlertInformation>(); + + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(DEVICE_ALLERT); + intentFilter.addAction(DEVICE_CONNECTED); + intentFilter.addAction(DEVICE_DISCONNECTED); + intentFilter.addAction(MISSING_LLS_SERVICE); + intentFilter.addAction(LINKLOSS_ALERT); + intentFilter.addAction(PATHLOSS_ALLERT); + intentFilter.addAction(PATHLOSS_ALLERT_FINISH); + + registerReceiver(mDataReceiver, intentFilter); + } + + @Override + public void onDestroy() { + Log.d(TAG, "onDestroy"); + super.onDestroy(); + + unregisterReceiver(mDataReceiver); + + Log.d(TAG, "UnbindService()"); + unbindService(mConnection); + mPxpMonitorService = null; + } + + @Override + public IBinder onBind(Intent arg0) { + Log.v(TAG, "onBind()"); + return mBinder; + } + + @Override + public boolean onUnbind(Intent intent) { + Log.v(TAG, "onUnbind()"); + return super.onUnbind(intent); + } + + public synchronized boolean connect(BluetoothDevice leDevice) { + try { + return mPxpMonitorService.connect(leDevice); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + return false; + } + + public synchronized void disconnect(BluetoothDevice leDevice) { + try { + mPxpMonitorService.disconnect(leDevice); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } + + public synchronized int getLinkLossAlertLevel(BluetoothDevice leDevice) { + try { + return mPxpMonitorService.getLinkLossAlertLevel(leDevice); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + return 0; + } + + public synchronized boolean setLinkLossAlertLevel(BluetoothDevice leDevice, int level) { + try { + return mPxpMonitorService.setLinkLossAlertLevel(leDevice, level); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + return false; + } + + public synchronized int getPathLossAlertLevel(BluetoothDevice leDevice) { + try { + return mPxpMonitorService.getPathLossAlertLevel(leDevice); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + return 0; + } + + public synchronized boolean setPathLossAlertLevel(BluetoothDevice leDevice, int level) { + try { + return mPxpMonitorService.setPathLossAlertLevel(leDevice, level); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + + return false; + } + + public synchronized int getMaxPathLossThreshold(BluetoothDevice leDevice) { + try { + return mPxpMonitorService.getMaxPathLossThreshold(leDevice); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + return 0; + } + + public synchronized void setMaxPathLossThreshold(BluetoothDevice leDevice, int threshold) { + try { + mPxpMonitorService.setMaxPathLossThreshold(leDevice, threshold); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } + + public synchronized int getMinPathLossThreshold(BluetoothDevice leDevice) { + try { + return mPxpMonitorService.getMinPathLossThreshold(leDevice); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + return 0; + } + + public synchronized void setMinPathLossThreshold(BluetoothDevice leDevice, int threshold) { + try { + mPxpMonitorService.setMinPathLossThreshold(leDevice, threshold); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } + + public synchronized boolean isPropertiesSet(BluetoothDevice leDevice) { + try { + return mPxpMonitorService.isPropertiesSet(leDevice); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + return false; + } + + public synchronized boolean getConnectionState(BluetoothDevice leDevice) { + try { + + return mPxpMonitorService.getConnectionState(leDevice); + + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + return false; + } + + public synchronized boolean checkServiceStatus(BluetoothDevice leDevice, int service) { + try { + return mPxpMonitorService.checkServiceStatus(leDevice, service); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + return false; + } + + public synchronized boolean checkFailedReadTxPowerLevel(BluetoothDevice leDevice) { + try { + return mPxpMonitorService.checkFailedReadTxPowerLevel(leDevice); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + return false; + } + + public synchronized void disconnectDevices() { + try { + mPxpMonitorService.disconnectDevices(); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } + + public synchronized List<BluetoothDevice> getConnectedDevices() { + try { + return mPxpMonitorService.getConnectedDevices(); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + return null; + } + + private final BroadcastReceiver mDataReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(Context context, Intent intent) { + BluetoothDevice mLeDevice; + String action = intent.getAction(); + + Message msg = null; + + if (DEVICE_CONNECTED.equals(action)) { + Log.d(TAG, "Acton = DEVICE_CONNECTED"); + mLeDevice = (BluetoothDevice) intent.getParcelableExtra(EXTRAS_DEVICE); + Log.d(TAG, "After reading mLeDevice"); + msg = Message.obtain(null, + MSG_DEVICE_CONNECTED, mLeDevice); + + } else if (MISSING_LLS_SERVICE.equals(action)) { + Log.d(TAG, "Action = MISSING_LLS_SERVICE"); + mLeDevice = (BluetoothDevice) intent.getParcelableExtra(EXTRAS_DEVICE); + msg = Message.obtain(null, + MSG_MISSING_LLS_SERVICE, mLeDevice); + + } else if (LINKLOSS_ALERT.equals(action)) { + Log.d(TAG, "Action = LINKLOSS_ALERT"); + mLeDevice = (BluetoothDevice) intent.getParcelableExtra(EXTRAS_DEVICE); + int llsAlertValue = intent.getIntExtra(EXTRAS_LLS_ALERT_VALUE, 0); + + msg = Message.obtain(null, + MSG_LINKLOSS_ALERT, llsAlertValue); + + } else if (DEVICE_DISCONNECTED.equals(action)) { + Log.d(TAG, "Action = DEVICE_DISCONNECTED"); + mLeDevice = (BluetoothDevice) intent + .getParcelableExtra(EXTRAS_DEVICE); + msg = Message.obtain(null, + MSG_DEVICE_DISCONNECTED, mLeDevice); + + } else if (DEVICE_ALLERT.equals(action)) { + Log.d(TAG, "DEVICE_ALLERT"); + + AlertInformation alertInfo = new AlertInformation(); + alertInfo.device = (BluetoothDevice) intent.getParcelableExtra(EXTRAS_DEVICE); + alertInfo.date = intent.getStringExtra(EXTRAS_TIME); + alertInfo.rssi = intent.getIntExtra(EXTRAS_RSSI, 0); + mAlertHistory.add(alertInfo); + + } else if (PATHLOSS_ALLERT.equals(action)) { + Log.d(TAG, "PATHLOSS_ALLERT"); + + mLeDevice = (BluetoothDevice) intent + .getParcelableExtra(EXTRAS_DEVICE); + msg = Message.obtain(null, + MSG_PATHLOSS_ALERT, mLeDevice); + } else if (PATHLOSS_ALLERT_FINISH.equals(action)) { + Log.d(TAG, "DEVICE_ALLERT_FINISH"); + + mLeDevice = (BluetoothDevice) intent + .getParcelableExtra(EXTRAS_DEVICE); + msg = Message.obtain(null, + MSG_ALERT_FINISH, mLeDevice); + } + + if (msg == null) { + return; + } + + if (mHandler != null) { + mHandler.sendMessage(msg); + } + } + }; +} diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/ScanDevicesActivity.java b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/ScanDevicesActivity.java new file mode 100644 index 0000000..cfdf371 --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpmonitor/ScanDevicesActivity.java @@ -0,0 +1,326 @@ +/* + * 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.pxpmonitor; + +import android.app.Activity; +import android.app.ListActivity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +public class ScanDevicesActivity extends ListActivity { + private static final String TAG = ScanDevicesActivity.class.getSimpleName(); + + public static final String DEVICE_NOT_CONNECTED_SELECTED = + "android.bluetooth.devicepicker.action.NOT_CONNECTED_DEVICE_SELECTED"; + + private static final int REQUEST_ENABLE_BT = 1; + + private BluetoothAdapter mBluetoothAdapter = null; + + private ScanDevicesListAdapter mDeviceListAdapter = null; + + private PxpServiceProxy mPxpServiceProxy = null; + + private Handler mHandler; + + private boolean mScanning; + + private static final long SCAN_PERIOD = 30000; // 30sec for now + + private final ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + Log.d(TAG, "Connecting to service"); + mPxpServiceProxy = ((PxpServiceProxy.LocalBinder) service).getService(); + } + + @Override + public void onServiceDisconnected(ComponentName className) { + mPxpServiceProxy = null; + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getActionBar().setTitle("Scan for Devices"); + + Log.d(TAG, "On create: new intent BluetoothService"); + Intent gattServiceIntent = new Intent(this, PxpServiceProxy.class); + + if (bindService(gattServiceIntent, mConnection, BIND_AUTO_CREATE) == false) { + Log.e(TAG, "Unable to bind"); + } + + mHandler = new Handler(); + + final BluetoothManager bluetoothManager = + (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + mBluetoothAdapter = bluetoothManager.getAdapter(); + + mDeviceListAdapter = new ScanDevicesListAdapter(this); + setListAdapter(mDeviceListAdapter); + scanDevice(true); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.scan, menu); + + if (mScanning) { + menu.findItem(R.id.menu_stop).setVisible(true); + menu.findItem(R.id.action_search).setVisible(false); + + } else { + menu.findItem(R.id.menu_stop).setVisible(false); + menu.findItem(R.id.action_search).setVisible(true); + } + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_search: + mDeviceListAdapter.clear(); + scanDevice(true); + break; + + case R.id.menu_stop: + scanDevice(false); + break; + } + return true; + } + + @Override + protected void onResume() { + super.onResume(); + scanDevice(true); + } + + @Override + protected void onPause() { + super.onPause(); + + if (!mBluetoothAdapter.isEnabled()) { + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); + } + + scanDevice(false); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + + if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) { + finish(); + return; + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + + unbindService(mConnection); + mPxpServiceProxy = null; + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + final BluetoothDevice leDevice = mDeviceListAdapter.getDevice(position); + + if (mScanning) { + scanDevice(false); + } + + final Intent intent = new Intent(this, DeviceActivity.class); + intent.setAction(DEVICE_NOT_CONNECTED_SELECTED); + intent.putExtra(DeviceActivity.EXTRAS_DEVICE, leDevice); + startActivity(intent); + } + + private void scanDevice(final boolean enable) { + + Runnable scan = new Runnable() { + + @Override + public void run() { + mScanning = false; + mBluetoothAdapter.stopLeScan(mLeScanCallback); + invalidateOptionsMenu(); + } + }; + + if (enable) { + mHandler.postDelayed(scan, SCAN_PERIOD); + mScanning = true; + mBluetoothAdapter.startLeScan(mLeScanCallback); + + } else { + mScanning = false; + mBluetoothAdapter.stopLeScan(mLeScanCallback); + mHandler.removeCallbacks(scan); + } + invalidateOptionsMenu(); + } + + private class ScanDevicesListAdapter extends BaseAdapter { + private ArrayList<BluetoothDevice> mLeDevices; + private LayoutInflater mInflater; + private Map<BluetoothDevice, DeviceInfo> mHashMapDevice; + private TextView mDeviceName; + private TextView mDeviceAddress; + private TextView mDeviceRssi; + private TextView mDeviceAdvData; + + public ScanDevicesListAdapter(Context context) { + super(); + mLeDevices = new ArrayList<BluetoothDevice>(); + mInflater = LayoutInflater.from(context); + mHashMapDevice = new HashMap<BluetoothDevice, DeviceInfo>(); + } + + public void addDevice(BluetoothDevice device, int rssi, String advData) { + + if (!mLeDevices.contains(device)) { + mLeDevices.add(device); + DeviceInfo deviceInfo = new DeviceInfo(rssi, advData); + mHashMapDevice.put(device, deviceInfo); + } + this.notifyDataSetChanged(); + } + + public BluetoothDevice getDevice(int position) { + return mLeDevices.get(position); + } + + public void clear() { + mLeDevices.clear(); + this.notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mLeDevices.size(); + } + + @Override + public Object getItem(int i) { + return mLeDevices.get(i); + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + + if (view == null) { + view = mInflater.inflate(R.layout.activity_list_devices, null); + } + mDeviceName = (TextView) view.findViewById(R.id.device_name); + mDeviceAddress = (TextView) view.findViewById(R.id.device_address); + mDeviceRssi = (TextView) view.findViewById(R.id.device_rssi); + mDeviceAdvData = (TextView) view.findViewById(R.id.device_adv_data); + + BluetoothDevice device = mLeDevices.get(i); + + DeviceInfo deviceInfo = mHashMapDevice.get(device); + + final String deviceName = device.getName(); + + if (deviceName != null && deviceName.length() > 0) { + mDeviceName.setText(deviceName); + + } else { + mDeviceName.setText("Unknow device"); + } + + mDeviceAddress.setText(device.getAddress()); + mDeviceRssi.setText("RSSI = " + String.valueOf(deviceInfo.mRssi) + "dBm"); + mDeviceAdvData.setText("Adv data: " + deviceInfo.mAdvData); + + return view; + } + + private class DeviceInfo { + private int mRssi; + private String mAdvData; + + DeviceInfo(int rssi, String advData) { + mRssi = rssi; + mAdvData = advData; + } + } + } + + private BluetoothAdapter.LeScanCallback mLeScanCallback = + new BluetoothAdapter.LeScanCallback() { + + @Override + public void onLeScan(final BluetoothDevice device, final int rssi, + final byte[] scanRecord) { + runOnUiThread(new Runnable() { + @Override + public void run() { + mDeviceListAdapter.addDevice(device, rssi, Arrays.toString(scanRecord)); + } + }); + } + }; +} diff --git a/pxp-monitor/src/org/codeaurora/bluetooth/pxpservice/IPxpService.aidl b/pxp-monitor/src/org/codeaurora/bluetooth/pxpservice/IPxpService.aidl new file mode 100644 index 0000000..d747819 --- /dev/null +++ b/pxp-monitor/src/org/codeaurora/bluetooth/pxpservice/IPxpService.aidl @@ -0,0 +1,170 @@ +/* + * 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.pxpservice; + +import android.bluetooth.BluetoothDevice; + +import java.util.List; + +interface IPxpService +{ + /** + * Connect to the GATT service hosted on proximity reporter. The result of + * connect operation is reported asynchronously through the Bluetooth GATT + * callback. + * + * @param leDevice Bluetooth device + * @return Return true if the connection where initiated successfully. + */ + boolean connect(in BluetoothDevice leDevice); + + /** + * Disconnect an existing connection with proximity reporter. The result of + * disconnect operation is reported asynchronously through the Bluetooth + * GATT callback. + * + * @param leDevice Bluetooth device + * @return void + */ + void disconnect(in BluetoothDevice leDevice); + + /** + * Write link loss alert level to the remote device. + * + * @param leDevice Bluetooth remote device + * @param level Alert level (0, 1 or 2). + * @return Return true if the write operation was successful. + */ + boolean setLinkLossAlertLevel(in BluetoothDevice leDevice, in int level); + + /** + * Read link loss alert level from the remote device. + * + * @param leDevice Bluetooth remote device + * @return Return value of link loss alert Level: 0 - off alert level 1 - + * mild alert level 2 - high alert level + */ + int getLinkLossAlertLevel(in BluetoothDevice leDevice); + + /** + * Set max value of path loss threshold. + * + * @param leDevice Bluetooth remote device + * @return void + */ + void setMaxPathLossThreshold(in BluetoothDevice leDevice, in int threshold); + + /** + * Get max path loss threshold value. + * + * @param leDevice Bluetooth remote device + * @return Return threshold value. + */ + int getMaxPathLossThreshold(in BluetoothDevice leDevice); + + /** + * Set max value of path loss threshold. + * + * @param leDevice Bluetooth remote device + * @return void + */ + void setMinPathLossThreshold(in BluetoothDevice leDevice, in int threshold); + + /** + * Get min path loss threshold value. + * + * @param leDevice Bluetooth remote device + * @return Return threshold value. + */ + int getMinPathLossThreshold(in BluetoothDevice leDevice); + + /** + * Write path loss alert level to the remote device. + * + * @param leDevice Bluetooth remote device + * @param level Alert level (0, 1 or 2). + * @return Return true if the write operation where initiated successfully. + */ + boolean setPathLossAlertLevel(in BluetoothDevice leDevice, in int level); + + /** + * Read path loss alert level from the remote device. + * + * @param leDevice Bluetooth remote device + * @return Return value path loss alert Level: 0 - off alert level 1 - mild + * alert level 2 - high alert level + */ + int getPathLossAlertLevel(in BluetoothDevice leDevice); + + /** + * Get current connection state for a given device. + * + * @param leDevice Bluetooth remote device + * @return true if device is connected + */ + boolean getConnectionState(in BluetoothDevice leDevice); + + /** + * Check if variable deviceProp for current device is set. + * + * @param leDevice Bluetooth remote device + * @return true if is set + */ + boolean isPropertiesSet(in BluetoothDevice leDevice); + + /** + * Check if remote service was found on a given device + * + * @param leDevice Bluetooth remote device + * @param service remote service + * @return true if remote service was found + */ + boolean checkServiceStatus(in BluetoothDevice leDevice, in int service); + + /** + * Check status of reading Tx Power level characteristic operation. + * + * @param leDevice Bluetooth remote device + * @return true if reading operation failed. + */ + boolean checkFailedReadTxPowerLevel(in BluetoothDevice leDevice); + + /** + * Disconnect all connected devices. + */ + void disconnectDevices(); + + /** + * List connected devices to the proximity monitor. + * + * @return Return List<BluetoothDevice> of the connected devices. + */ + List<BluetoothDevice> getConnectedDevices(); +} + |