diff options
author | Trevor Johns <trevorjohns@google.com> | 2015-05-08 19:29:42 -0700 |
---|---|---|
committer | Trevor Johns <trevorjohns@google.com> | 2015-05-08 19:29:42 -0700 |
commit | 434d41c45df023fd543a94e88b0bda2dc5c7844d (patch) | |
tree | 11589625b30085c4803f5edb544de3305c2fa3fe /samples/browseable/BluetoothAdvertisements | |
parent | 03236391f11efe2a9ce89ab92602c58ba717f626 (diff) | |
download | android_development-434d41c45df023fd543a94e88b0bda2dc5c7844d.tar.gz android_development-434d41c45df023fd543a94e88b0bda2dc5c7844d.tar.bz2 android_development-434d41c45df023fd543a94e88b0bda2dc5c7844d.zip |
Update samples prebuilts for lmp-mr1-ub-docs
Synced to developers/samples/android commit
54bab34b386e343e9d0ea75a5fb8d13db2c71eb5.
Change-Id: I1c9d9d2c1f53a051d7b4d85303d5c01ab6f16e68
Diffstat (limited to 'samples/browseable/BluetoothAdvertisements')
29 files changed, 1160 insertions, 0 deletions
diff --git a/samples/browseable/BluetoothAdvertisements/AndroidManifest.xml b/samples/browseable/BluetoothAdvertisements/AndroidManifest.xml new file mode 100644 index 000000000..48084fc97 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/AndroidManifest.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.bluetoothadvertisements" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> + <uses-permission android:name="android.permission.BLUETOOTH"/> + + <application android:allowBackup="true" + android:label="@string/app_name" + android:icon="@drawable/ic_launcher" + android:theme="@style/AppTheme"> + + <activity android:name=".MainActivity" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> diff --git a/samples/browseable/BluetoothAdvertisements/_index.jd b/samples/browseable/BluetoothAdvertisements/_index.jd new file mode 100644 index 000000000..27296b0ce --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/_index.jd @@ -0,0 +1,10 @@ +page.tags="BluetoothAdvertisements" +sample.group=Connectivity +@jd:body + +<p> + +This samples demonstrates how to use the Bluetooth Low Power Advertisements API +with a single device acting as both scanner and advertiser. + + </p> diff --git a/samples/browseable/BluetoothAdvertisements/res/drawable-hdpi/ic_action_refresh.png b/samples/browseable/BluetoothAdvertisements/res/drawable-hdpi/ic_action_refresh.png Binary files differnew file mode 100644 index 000000000..dae27903e --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/drawable-hdpi/ic_action_refresh.png diff --git a/samples/browseable/BluetoothAdvertisements/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BluetoothAdvertisements/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..b1efaf4b2 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/drawable-hdpi/ic_launcher.png diff --git a/samples/browseable/BluetoothAdvertisements/res/drawable-hdpi/tile.9.png b/samples/browseable/BluetoothAdvertisements/res/drawable-hdpi/tile.9.png Binary files differnew file mode 100644 index 000000000..135862883 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/drawable-hdpi/tile.9.png diff --git a/samples/browseable/BluetoothAdvertisements/res/drawable-mdpi/ic_action_refresh.png b/samples/browseable/BluetoothAdvertisements/res/drawable-mdpi/ic_action_refresh.png Binary files differnew file mode 100644 index 000000000..94ab6f4c5 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/drawable-mdpi/ic_action_refresh.png diff --git a/samples/browseable/BluetoothAdvertisements/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BluetoothAdvertisements/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..f5f9244f2 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/drawable-mdpi/ic_launcher.png diff --git a/samples/browseable/BluetoothAdvertisements/res/drawable-xhdpi/ic_action_refresh.png b/samples/browseable/BluetoothAdvertisements/res/drawable-xhdpi/ic_action_refresh.png Binary files differnew file mode 100644 index 000000000..ab4ab9da6 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/drawable-xhdpi/ic_action_refresh.png diff --git a/samples/browseable/BluetoothAdvertisements/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BluetoothAdvertisements/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..5d07b3f06 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/drawable-xhdpi/ic_launcher.png diff --git a/samples/browseable/BluetoothAdvertisements/res/drawable-xxhdpi/ic_action_refresh.png b/samples/browseable/BluetoothAdvertisements/res/drawable-xxhdpi/ic_action_refresh.png Binary files differnew file mode 100644 index 000000000..44ee117ee --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/drawable-xxhdpi/ic_action_refresh.png diff --git a/samples/browseable/BluetoothAdvertisements/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BluetoothAdvertisements/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..6ef21e1f4 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/drawable-xxhdpi/ic_launcher.png diff --git a/samples/browseable/BluetoothAdvertisements/res/layout/activity_main.xml b/samples/browseable/BluetoothAdvertisements/res/layout/activity_main.xml new file mode 100755 index 000000000..817cccc48 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/layout/activity_main.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:id="@+id/sample_main_layout"> + + <FrameLayout + android:id="@+id/scanner_fragment_container" + android:layout_weight="1" + android:layout_width="match_parent" + android:layout_height="0px" > + + <TextView + android:id="@+id/error_textview" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:freezesText="true" /> + + </FrameLayout> + + <FrameLayout + android:id="@+id/advertiser_fragment_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <!--<fragment--> + <!--android:name="com.example.android.bluetoothadvertisements.ScannerFragment"--> + <!--android:id="@+id/scanner_fragment"--> + <!--android:layout_width="match_parent"--> + <!--android:layout_height="wrap_content" />--> + + <!--<fragment--> + <!--android:name="com.example.android.bluetoothadvertisements.AdvertiserFragment"--> + <!--android:id="@+id/advertiser_fragment"--> + <!--android:layout_width="match_parent"--> + <!--android:layout_height="wrap_content" />--> + +</LinearLayout> diff --git a/samples/browseable/BluetoothAdvertisements/res/layout/fragment_advertiser.xml b/samples/browseable/BluetoothAdvertisements/res/layout/fragment_advertiser.xml new file mode 100644 index 000000000..4031b8d7e --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/layout/fragment_advertiser.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:context="com.example.android.bluetoothadvertisements.AdvertiserFragment"> + + <!-- Horizontal Divider --> + <View + android:layout_width="250dp" + android:layout_height="1dp" + android:layout_centerHorizontal="true" + android:layout_alignParentTop="true" + android:background="@android:color/darker_gray"/> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_centerInParent="true" + android:paddingTop="20dp" + android:paddingBottom="20dp" > + + <TextView + android:text="@string/broadcast_device" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:minWidth="100dp" + android:padding="5dp"/> + + <Switch + android:id="@+id/advertise_switch" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:switchMinWidth="80dp" /> + + </LinearLayout> + +</RelativeLayout> diff --git a/samples/browseable/BluetoothAdvertisements/res/layout/listitem_scanresult.xml b/samples/browseable/BluetoothAdvertisements/res/layout/listitem_scanresult.xml new file mode 100644 index 000000000..ff5956fbc --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/layout/listitem_scanresult.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + > + +<LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="20dp" + android:paddingLeft="100dp" + android:paddingRight="100dp"> + <TextView android:id="@+id/device_name" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="16dp"/> + + <TextView android:id="@+id/device_address" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="12dp"/> + <TextView android:id="@+id/last_seen" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="12dp"/> +</LinearLayout> +</RelativeLayout>
\ No newline at end of file diff --git a/samples/browseable/BluetoothAdvertisements/res/menu-v21/scanner_menu.xml b/samples/browseable/BluetoothAdvertisements/res/menu-v21/scanner_menu.xml new file mode 100644 index 000000000..8dda284cb --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/menu-v21/scanner_menu.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/refresh" + android:title="@string/refresh" + android:showAsAction="always" + android:icon="@drawable/ic_action_refresh" + /> +</menu>
\ No newline at end of file diff --git a/samples/browseable/BluetoothAdvertisements/res/values-sw600dp/template-dimens.xml b/samples/browseable/BluetoothAdvertisements/res/values-sw600dp/template-dimens.xml new file mode 100644 index 000000000..22074a2bd --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/values-sw600dp/template-dimens.xml @@ -0,0 +1,24 @@ +<!-- + Copyright 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources> + + <!-- Semantic definitions --> + + <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen> + <dimen name="vertical_page_margin">@dimen/margin_medium</dimen> + +</resources> diff --git a/samples/browseable/BluetoothAdvertisements/res/values-sw600dp/template-styles.xml b/samples/browseable/BluetoothAdvertisements/res/values-sw600dp/template-styles.xml new file mode 100644 index 000000000..03d197418 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/values-sw600dp/template-styles.xml @@ -0,0 +1,25 @@ +<!-- + Copyright 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources> + + <style name="Widget.SampleMessage"> + <item name="android:textAppearance">?android:textAppearanceLarge</item> + <item name="android:lineSpacingMultiplier">1.2</item> + <item name="android:shadowDy">-6.5</item> + </style> + +</resources> diff --git a/samples/browseable/BluetoothAdvertisements/res/values-v11/template-styles.xml b/samples/browseable/BluetoothAdvertisements/res/values-v11/template-styles.xml new file mode 100644 index 000000000..8c1ea66f2 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/values-v11/template-styles.xml @@ -0,0 +1,22 @@ +<!-- + Copyright 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources> + + <!-- Activity themes --> + <style name="Theme.Base" parent="android:Theme.Holo.Light" /> + +</resources> diff --git a/samples/browseable/BluetoothAdvertisements/res/values-v21/base-colors.xml b/samples/browseable/BluetoothAdvertisements/res/values-v21/base-colors.xml new file mode 100644 index 000000000..d90237837 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/values-v21/base-colors.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + + <color name="colorPrimary">#434AB3</color> + <color name="colorPrimaryDark">#34379D</color> + <color name="textColorPrimary">#FFFFFF</color> + +</resources> diff --git a/samples/browseable/BluetoothAdvertisements/res/values-v21/base-template-styles.xml b/samples/browseable/BluetoothAdvertisements/res/values-v21/base-template-styles.xml new file mode 100644 index 000000000..023485609 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/values-v21/base-template-styles.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + + <!-- Activity themes --> + <style name="Theme.Base" parent="android:Theme.Material.Light"> + <item name="android:colorPrimary">@color/colorPrimary</item> + <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item> + <item name="android:textColorPrimary">@color/textColorPrimary</item> + </style> + +</resources> diff --git a/samples/browseable/BluetoothAdvertisements/res/values/base-strings.xml b/samples/browseable/BluetoothAdvertisements/res/values/base-strings.xml new file mode 100644 index 000000000..6bfd4139b --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/values/base-strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + <string name="app_name">BluetoothAdvertisements</string> + <string name="intro_message"> + <![CDATA[ + + +This samples demonstrates how to use the Bluetooth Low Power Advertisements API +with a single device acting as both scanner and advertiser. + + + ]]> + </string> +</resources> diff --git a/samples/browseable/BluetoothAdvertisements/res/values/strings.xml b/samples/browseable/BluetoothAdvertisements/res/values/strings.xml new file mode 100644 index 000000000..197178d00 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/values/strings.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="bt_not_enabled_leaving">User declined to enable Bluetooth, exiting Bluetooth Advertisements.</string> + <string name="activity_main_title">Nearby Devices</string> + <string name="broadcast_device">Broadcast Device</string> + + <string name="bt_not_supported">Bluetooth is not supported on this device.</string> + <string name="bt_ads_not_supported">Bluetooth Advertisements are not supported on this device.</string> + + <string name="refresh">Refresh</string> + <string name="start_error_prefix">Start Advertising failed: </string> + <string name="start_error_already_started">already started.</string> + <string name="start_error_too_large">data packet exceeded 31 Byte limit.</string> + <string name="start_error_unsupported">not supported on this device.</string> + <string name="start_error_internal">internal error.</string> + <string name="start_error_too_many">too many advertisers.</string> + <string name="bt_null">Error: Bluetooth object null</string> + <string name="last_seen">Last Seen:</string> + <string name="just_now">just now</string> + <string name="minute_ago">minute ago</string> + <string name="hour_ago">hour ago</string> + <string name="seconds_ago">seconds ago</string> + <string name="minutes_ago">minutes ago</string> + <string name="hours_ago">hours ago</string> + <string name="empty_list">No devices found - refresh to try again.</string> + <string name="seconds">seconds.</string> + <string name="scan_start_toast">Scanning for</string> + <string name="already_scanning">Scanning already started.</string> + +</resources>
\ No newline at end of file diff --git a/samples/browseable/BluetoothAdvertisements/res/values/template-dimens.xml b/samples/browseable/BluetoothAdvertisements/res/values/template-dimens.xml new file mode 100644 index 000000000..39e710b5c --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/values/template-dimens.xml @@ -0,0 +1,32 @@ +<!-- + Copyright 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources> + + <!-- Define standard dimensions to comply with Holo-style grids and rhythm. --> + + <dimen name="margin_tiny">4dp</dimen> + <dimen name="margin_small">8dp</dimen> + <dimen name="margin_medium">16dp</dimen> + <dimen name="margin_large">32dp</dimen> + <dimen name="margin_huge">64dp</dimen> + + <!-- Semantic definitions --> + + <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen> + <dimen name="vertical_page_margin">@dimen/margin_medium</dimen> + +</resources> diff --git a/samples/browseable/BluetoothAdvertisements/res/values/template-styles.xml b/samples/browseable/BluetoothAdvertisements/res/values/template-styles.xml new file mode 100644 index 000000000..6e7d593dd --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/res/values/template-styles.xml @@ -0,0 +1,42 @@ +<!-- + Copyright 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources> + + <!-- Activity themes --> + + <style name="Theme.Base" parent="android:Theme.Light" /> + + <style name="Theme.Sample" parent="Theme.Base" /> + + <style name="AppTheme" parent="Theme.Sample" /> + <!-- Widget styling --> + + <style name="Widget" /> + + <style name="Widget.SampleMessage"> + <item name="android:textAppearance">?android:textAppearanceMedium</item> + <item name="android:lineSpacingMultiplier">1.1</item> + </style> + + <style name="Widget.SampleMessageTile"> + <item name="android:background">@drawable/tile</item> + <item name="android:shadowColor">#7F000000</item> + <item name="android:shadowDy">-3.5</item> + <item name="android:shadowRadius">2</item> + </style> + +</resources> diff --git a/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/AdvertiserFragment.java b/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/AdvertiserFragment.java new file mode 100644 index 000000000..f8daefb04 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/AdvertiserFragment.java @@ -0,0 +1,190 @@ +package com.example.android.bluetoothadvertisements; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.le.AdvertiseCallback; +import android.bluetooth.le.AdvertiseData; +import android.bluetooth.le.AdvertiseSettings; +import android.bluetooth.le.BluetoothLeAdvertiser; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Switch; +import android.widget.Toast; + +/** + * Allows user to start & stop Bluetooth LE Advertising of their device. + */ +public class AdvertiserFragment extends Fragment { + + private BluetoothAdapter mBluetoothAdapter; + + private BluetoothLeAdvertiser mBluetoothLeAdvertiser; + + private AdvertiseCallback mAdvertiseCallback; + + private Switch mSwitch; + + /** + * Must be called after object creation by MainActivity. + * + * @param btAdapter the local BluetoothAdapter + */ + public void setBluetoothAdapter(BluetoothAdapter btAdapter) { + this.mBluetoothAdapter = btAdapter; + mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View view = inflater.inflate(R.layout.fragment_advertiser, container, false); + + mSwitch = (Switch) view.findViewById(R.id.advertise_switch); + mSwitch.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onSwitchClicked(v); + } + }); + + return view; + } + + @Override + public void onStop() { + super.onStop(); + + if(mAdvertiseCallback != null){ + stopAdvertising(); + } + } + + /** + * Called when switch is toggled - starts or stops advertising. + * + * @param view is the Switch View object + */ + public void onSwitchClicked(View view) { + + // Is the toggle on? + boolean on = ((Switch) view).isChecked(); + + if (on) { + startAdvertising(); + } else { + stopAdvertising(); + } + } + + /** + * Starts BLE Advertising. + */ + private void startAdvertising() { + + mAdvertiseCallback = new SampleAdvertiseCallback(); + + if (mBluetoothLeAdvertiser != null) { + mBluetoothLeAdvertiser.startAdvertising(buildAdvertiseSettings(), buildAdvertiseData(), + mAdvertiseCallback); + } else { + mSwitch.setChecked(false); + Toast.makeText(getActivity(), getString(R.string.bt_null), Toast.LENGTH_LONG).show(); + } + } + + /** + * Stops BLE Advertising. + */ + private void stopAdvertising() { + + if (mBluetoothLeAdvertiser != null) { + + mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback); + mAdvertiseCallback = null; + + } else { + mSwitch.setChecked(false); + Toast.makeText(getActivity(), getString(R.string.bt_null), Toast.LENGTH_LONG).show(); + } + } + + /** + * Returns an AdvertiseData object which includes the Service UUID and Device Name. + */ + private AdvertiseData buildAdvertiseData() { + + // Note: There is a strict limit of 31 Bytes on packets sent over BLE Advertisements. + // This includes everything put into AdvertiseData including UUIDs, device info, & + // arbitrary service or manufacturer data. + // Attempting to send packets over this limit will result in a failure with error code + // AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE. Catch this error in the + // onStartFailure() method of an AdvertiseCallback implementation. + + AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder(); + dataBuilder.addServiceUuid(Constants.Service_UUID); + dataBuilder.setIncludeDeviceName(true); + + return dataBuilder.build(); + } + + /** + * Returns an AdvertiseSettings object set to use low power (to help preserve battery life). + */ + private AdvertiseSettings buildAdvertiseSettings() { + AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder(); + settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER); + + return settingsBuilder.build(); + } + + /** + * Custom callback after Advertising succeeds or fails to start. + */ + private class SampleAdvertiseCallback extends AdvertiseCallback { + + @Override + public void onStartFailure(int errorCode) { + super.onStartFailure(errorCode); + + mSwitch.setChecked(false); + + String errorMessage = getString(R.string.start_error_prefix); + switch (errorCode) { + case AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED: + errorMessage += " " + getString(R.string.start_error_already_started); + break; + case AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE: + errorMessage += " " + getString(R.string.start_error_too_large); + break; + case AdvertiseCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED: + errorMessage += " " + getString(R.string.start_error_unsupported); + break; + case AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR: + errorMessage += " " + getString(R.string.start_error_internal); + break; + case AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS: + errorMessage += " " + getString(R.string.start_error_too_many); + break; + } + + Toast.makeText(getActivity(), errorMessage, Toast.LENGTH_LONG).show(); + + } + + @Override + public void onStartSuccess(AdvertiseSettings settingsInEffect) { + super.onStartSuccess(settingsInEffect); + // Don't need to do anything here, advertising successfully started. + } + } + +} diff --git a/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/Constants.java b/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/Constants.java new file mode 100644 index 000000000..d3941e2ab --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/Constants.java @@ -0,0 +1,22 @@ +package com.example.android.bluetoothadvertisements; + +import android.os.ParcelUuid; + +/** + * Constants for use in the Bluetooth Advertisements sample + */ +public class Constants { + + /** + * UUID identified with this app - set as Service UUID for BLE Advertisements. + * + * Bluetooth requires a certain format for UUIDs associated with Services. + * The official specification can be found here: + * {@link https://www.bluetooth.org/en-us/specification/assigned-numbers/service-discovery} + */ + public static final ParcelUuid Service_UUID = ParcelUuid + .fromString("0000b81d-0000-1000-8000-00805f9b34fb"); + + public static final int REQUEST_ENABLE_BT = 1; + +} diff --git a/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/MainActivity.java b/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/MainActivity.java new file mode 100644 index 000000000..f0044a3e8 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/MainActivity.java @@ -0,0 +1,130 @@ +/* +* Copyright 2013 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package com.example.android.bluetoothadvertisements; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothManager; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentTransaction; +import android.widget.TextView; +import android.widget.Toast; + +/** + * Setup display fragments and ensure the device supports Bluetooth. + */ +public class MainActivity extends FragmentActivity { + + private BluetoothAdapter mBluetoothAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + setTitle(R.string.activity_main_title); + + if (savedInstanceState == null ) { + + mBluetoothAdapter = ((BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE)) + .getAdapter(); + + // Is Bluetooth supported on this device? + if (mBluetoothAdapter != null) { + + // Is Bluetooth turned on? + if (mBluetoothAdapter.isEnabled()) { + + // Are Bluetooth Advertisements supported on this device? + if (mBluetoothAdapter.isMultipleAdvertisementSupported()) { + + // Everything is supported and enabled, load the fragments. + setupFragments(); + + } else { + + // Bluetooth Advertisements are not supported. + showErrorText(R.string.bt_ads_not_supported); + } + } else { + + // Prompt user to turn on Bluetooth (logic continues in onActivityResult()). + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableBtIntent, Constants.REQUEST_ENABLE_BT); + } + } else { + + // Bluetooth is not supported. + showErrorText(R.string.bt_not_supported); + } + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + switch (requestCode) { + case Constants.REQUEST_ENABLE_BT: + + if (resultCode == RESULT_OK) { + + // Bluetooth is now Enabled, are Bluetooth Advertisements supported on + // this device? + if (mBluetoothAdapter.isMultipleAdvertisementSupported()) { + + // Everything is supported and enabled, load the fragments. + setupFragments(); + + } else { + + // Bluetooth Advertisements are not supported. + showErrorText(R.string.bt_ads_not_supported); + } + } else { + + // User declined to enable Bluetooth, exit the app. + Toast.makeText(this, R.string.bt_not_enabled_leaving, + Toast.LENGTH_SHORT).show(); + finish(); + } + + default: + super.onActivityResult(requestCode, resultCode, data); + } + } + + private void setupFragments() { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + + ScannerFragment scannerFragment = new ScannerFragment(); + scannerFragment.setBluetoothAdapter(mBluetoothAdapter); + transaction.replace(R.id.scanner_fragment_container, scannerFragment); + + AdvertiserFragment advertiserFragment = new AdvertiserFragment(); + advertiserFragment.setBluetoothAdapter(mBluetoothAdapter); + transaction.replace(R.id.advertiser_fragment_container, advertiserFragment); + + transaction.commit(); + } + + private void showErrorText(int messageId) { + + TextView view = (TextView) findViewById(R.id.error_textview); + view.setText(getString(messageId)); + } +}
\ No newline at end of file diff --git a/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/ScanResultAdapter.java b/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/ScanResultAdapter.java new file mode 100644 index 000000000..0f905ea7a --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/ScanResultAdapter.java @@ -0,0 +1,147 @@ +package com.example.android.bluetoothadvertisements; + +import android.bluetooth.le.ScanResult; +import android.content.Context; +import android.os.SystemClock; +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.concurrent.TimeUnit; + +/** + * Holds and displays {@link ScanResult}s, used by {@link ScannerFragment}. + */ +public class ScanResultAdapter extends BaseAdapter { + + private ArrayList<ScanResult> mArrayList; + + private Context mContext; + + private LayoutInflater mInflater; + + ScanResultAdapter(Context context, LayoutInflater inflater) { + super(); + mContext = context; + mInflater = inflater; + mArrayList = new ArrayList<>(); + } + + @Override + public int getCount() { + return mArrayList.size(); + } + + @Override + public Object getItem(int position) { + return mArrayList.get(position); + } + + @Override + public long getItemId(int position) { + return mArrayList.get(position).getDevice().getAddress().hashCode(); + } + + @Override + public View getView(int position, View view, ViewGroup parent) { + + // Reuse an old view if we can, otherwise create a new one. + if (view == null) { + view = mInflater.inflate(R.layout.listitem_scanresult, null); + } + + TextView deviceNameView = (TextView) view.findViewById(R.id.device_name); + TextView deviceAddressView = (TextView) view.findViewById(R.id.device_address); + TextView lastSeenView = (TextView) view.findViewById(R.id.last_seen); + + ScanResult scanResult = mArrayList.get(position); + + deviceNameView.setText(scanResult.getDevice().getName()); + deviceAddressView.setText(scanResult.getDevice().getAddress()); + lastSeenView.setText(getTimeSinceString(mContext, scanResult.getTimestampNanos())); + + return view; + } + + /** + * Search the adapter for an existing device address and return it, otherwise return -1. + */ + private int getPosition(String address) { + int position = -1; + for (int i = 0; i < mArrayList.size(); i++) { + if (mArrayList.get(i).getDevice().getAddress().equals(address)) { + position = i; + break; + } + } + return position; + } + + + /** + * Add a ScanResult item to the adapter if a result from that device isn't already present. + * Otherwise updates the existing position with the new ScanResult. + */ + public void add(ScanResult scanResult) { + + int existingPosition = getPosition(scanResult.getDevice().getAddress()); + + if (existingPosition >= 0) { + // Device is already in list, update its record. + mArrayList.set(existingPosition, scanResult); + } else { + // Add new Device's ScanResult to list. + mArrayList.add(scanResult); + } + } + + /** + * Clear out the adapter. + */ + public void clear() { + mArrayList.clear(); + } + + /** + * Takes in a number of nanoseconds and returns a human-readable string giving a vague + * description of how long ago that was. + */ + public static String getTimeSinceString(Context context, long timeNanoseconds) { + String lastSeenText = context.getResources().getString(R.string.last_seen) + " "; + + long timeSince = SystemClock.elapsedRealtimeNanos() - timeNanoseconds; + long secondsSince = TimeUnit.SECONDS.convert(timeSince, TimeUnit.NANOSECONDS); + + if (secondsSince < 5) { + lastSeenText += context.getResources().getString(R.string.just_now); + } else if (secondsSince < 60) { + lastSeenText += secondsSince + " " + context.getResources() + .getString(R.string.seconds_ago); + } else { + long minutesSince = TimeUnit.MINUTES.convert(secondsSince, TimeUnit.SECONDS); + if (minutesSince < 60) { + if (minutesSince == 1) { + lastSeenText += minutesSince + " " + context.getResources() + .getString(R.string.minute_ago); + } else { + lastSeenText += minutesSince + " " + context.getResources() + .getString(R.string.minutes_ago); + } + } else { + long hoursSince = TimeUnit.HOURS.convert(minutesSince, TimeUnit.MINUTES); + if (hoursSince == 1) { + lastSeenText += hoursSince + " " + context.getResources() + .getString(R.string.hour_ago); + } else { + lastSeenText += hoursSince + " " + context.getResources() + .getString(R.string.hours_ago); + } + } + } + + return lastSeenText; + } +} diff --git a/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/ScannerFragment.java b/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/ScannerFragment.java new file mode 100644 index 000000000..b9ad4d966 --- /dev/null +++ b/samples/browseable/BluetoothAdvertisements/src/com.example.android.bluetoothadvertisements/ScannerFragment.java @@ -0,0 +1,212 @@ +package com.example.android.bluetoothadvertisements; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.le.BluetoothLeScanner; +import android.bluetooth.le.ScanCallback; +import android.bluetooth.le.ScanFilter; +import android.bluetooth.le.ScanResult; +import android.bluetooth.le.ScanSettings; +import android.os.Bundle; +import android.os.Handler; +import android.support.v4.app.ListFragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + + +/** + * Scans for Bluetooth Low Energy Advertisements matching a filter and displays them to the user. + */ +public class ScannerFragment extends ListFragment { + + private static final String TAG = ScannerFragment.class.getSimpleName(); + + /** + * Stops scanning after 5 seconds. + */ + private static final long SCAN_PERIOD = 5000; + + private BluetoothAdapter mBluetoothAdapter; + + private BluetoothLeScanner mBluetoothLeScanner; + + private ScanCallback mScanCallback; + + private ScanResultAdapter mAdapter; + + private Handler mHandler; + + /** + * Must be called after object creation by MainActivity. + * + * @param btAdapter the local BluetoothAdapter + */ + public void setBluetoothAdapter(BluetoothAdapter btAdapter) { + this.mBluetoothAdapter = btAdapter; + mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + setRetainInstance(true); + + // Use getActivity().getApplicationContext() instead of just getActivity() because this + // object lives in a fragment and needs to be kept separate from the Activity lifecycle. + // + // We could get a LayoutInflater from the ApplicationContext but it messes with the + // default theme, so generate it from getActivity() and pass it in separately. + mAdapter = new ScanResultAdapter(getActivity().getApplicationContext(), + LayoutInflater.from(getActivity())); + mHandler = new Handler(); + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + final View view = super.onCreateView(inflater, container, savedInstanceState); + + setListAdapter(mAdapter); + + return view; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + getListView().setDivider(null); + getListView().setDividerHeight(0); + + setEmptyText(getString(R.string.empty_list)); + + // Trigger refresh on app's 1st load + startScanning(); + + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.scanner_menu, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + switch (item.getItemId()) { + case R.id.refresh: + startScanning(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + /** + * Start scanning for BLE Advertisements (& set it up to stop after a set period of time). + */ + public void startScanning() { + if (mScanCallback == null) { + Log.d(TAG, "Starting Scanning"); + + // Will stop the scanning after a set time. + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + stopScanning(); + } + }, SCAN_PERIOD); + + // Kick off a new scan. + mScanCallback = new SampleScanCallback(); + mBluetoothLeScanner.startScan(buildScanFilters(), buildScanSettings(), mScanCallback); + + String toastText = getString(R.string.scan_start_toast) + " " + + TimeUnit.SECONDS.convert(SCAN_PERIOD, TimeUnit.MILLISECONDS) + " " + + getString(R.string.seconds); + Toast.makeText(getActivity(), toastText, Toast.LENGTH_LONG).show(); + } else { + Toast.makeText(getActivity(), R.string.already_scanning, Toast.LENGTH_SHORT); + } + } + + /** + * Stop scanning for BLE Advertisements. + */ + public void stopScanning() { + Log.d(TAG, "Stopping Scanning"); + + // Stop the scan, wipe the callback. + mBluetoothLeScanner.stopScan(mScanCallback); + mScanCallback = null; + + // Even if no new results, update 'last seen' times. + mAdapter.notifyDataSetChanged(); + } + + /** + * Return a List of {@link ScanFilter} objects to filter by Service UUID. + */ + private List<ScanFilter> buildScanFilters() { + List<ScanFilter> scanFilters = new ArrayList<>(); + + ScanFilter.Builder builder = new ScanFilter.Builder(); + builder.setServiceUuid(Constants.Service_UUID); + scanFilters.add(builder.build()); + + return scanFilters; + } + + /** + * Return a {@link ScanSettings} object set to use low power (to preserve battery life). + */ + private ScanSettings buildScanSettings() { + ScanSettings.Builder builder = new ScanSettings.Builder(); + builder.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER); + return builder.build(); + } + + /** + * Custom ScanCallback object - adds to adapter on success, displays error on failure. + */ + private class SampleScanCallback extends ScanCallback { + + @Override + public void onBatchScanResults(List<ScanResult> results) { + super.onBatchScanResults(results); + + for (ScanResult result : results) { + mAdapter.add(result); + } + mAdapter.notifyDataSetChanged(); + } + + @Override + public void onScanResult(int callbackType, ScanResult result) { + super.onScanResult(callbackType, result); + + mAdapter.add(result); + mAdapter.notifyDataSetChanged(); + } + + @Override + public void onScanFailed(int errorCode) { + super.onScanFailed(errorCode); + Toast.makeText(getActivity(), "Scan failed with error: " + errorCode, Toast.LENGTH_LONG) + .show(); + } + } +} |