diff options
author | Wei Wang <weiwa@google.com> | 2013-11-19 01:32:10 -0800 |
---|---|---|
committer | Matthew Xie <mattx@google.com> | 2014-01-14 18:06:42 -0800 |
commit | f4f8d9f34669bc67b8cd93e7dc060dfddf3a7e51 (patch) | |
tree | 4850c8be007e4ec5a59cbf209a83ec9ef6a1a79d | |
parent | fc8d25567124965671a3f32b87d52562918230c5 (diff) | |
download | packages_apps_Settings-f4f8d9f34669bc67b8cd93e7dc060dfddf3a7e51.zip packages_apps_Settings-f4f8d9f34669bc67b8cd93e7dc060dfddf3a7e51.tar.gz packages_apps_Settings-f4f8d9f34669bc67b8cd93e7dc060dfddf3a7e51.tar.bz2 |
BLE peripheral mode (4/4): Settings change for advertising preference.
Change-Id: I5721f136267fe25e55f764bb4a6c53acd45b318b
17 files changed, 581 insertions, 53 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7c4be12..40a64b1 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1271,6 +1271,8 @@ <intent-filter> <action android:name="android.bluetooth.adapter.action.REQUEST_DISCOVERABLE" /> <action android:name="android.bluetooth.adapter.action.REQUEST_ENABLE" /> + <action android:name="android.bluetooth.adapter.action.START_ADVERTISING" /> + <action android:name="android.bluetooth.adapter.action.STOP_ADVERTISING" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> diff --git a/res/layout/bluetooth_advertising.xml b/res/layout/bluetooth_advertising.xml new file mode 100644 index 0000000..8095514 --- /dev/null +++ b/res/layout/bluetooth_advertising.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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:paddingStart="6dip" + android:paddingEnd="6dip" + android:layout_width="match_parent" android:layout_height="wrap_content" + android:scrollbars="vertical" > + + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fillViewport="true"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView android:id="@+id/bluetooth_broadcasting_explaination" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="20dip" + android:gravity="top" + android:text="@string/bluetooth_broadcasting_explaination" + android:textAppearance="?android:attr/textAppearanceMedium" + /> + </LinearLayout> + + </ScrollView> + +</LinearLayout> + diff --git a/res/values/strings.xml b/res/values/strings.xml index 7a14051..9c274ed 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -226,13 +226,13 @@ <!-- Used as setting title (for checkbox) on second screen after selecting Bluetooth settings --> <string name="bluetooth">Bluetooth</string> <!-- Bluetooth settings screen, summary after selecting Discoverable check box [CHAR LIMIT=50] --> - <string name="bluetooth_is_discoverable">Visible to all nearby Bluetooth devices (<xliff:g id="discoverable_time_period">%1$s</xliff:g>)</string> + <string name="bluetooth_is_discoverable">Accepting pairing requests (<xliff:g id="discoverable_time_period">%1$s</xliff:g>)</string> <!-- Bluetooth settings screen, summary when Discoverable duration is set to "forever" [CHAR LIMIT=50] --> - <string name="bluetooth_is_discoverable_always">Visible to all nearby Bluetooth devices</string> + <string name="bluetooth_is_discoverable_always">Accepting pairing requests</string> <!-- Bluetooth settings screen, summary text when not discoverable and no paired devices [CHAR LIMIT=50] --> - <string name="bluetooth_not_visible_to_other_devices">Not visible to other Bluetooth devices</string> + <string name="bluetooth_not_visible_to_other_devices">Not accepting pairing requests</string> <!-- Bluetooth settings screen, summary text when not discoverable with paired devices [CHAR LIMIT=50] --> - <string name="bluetooth_only_visible_to_paired_devices">Only visible to paired devices</string> + <string name="bluetooth_only_visible_to_paired_devices">Not accepting pairing requests</string> <!-- Bluetooth settings screen, option name to pick discoverability timeout duration (a list dialog comes up) --> <string name="bluetooth_visibility_timeout">Visibility timeout</string> <!-- Bluetooth settings screen, check box label whether or not to allow @@ -267,6 +267,11 @@ <!-- Bluetooth broadcasting settings, option to enable/disable broadcasting --> <string name="bluetooth_broadcasting">Broadcasting</string> + <!-- Enabled state of bluetooth broadcasting --> + <string name="bluetooth_broadcasting_state_on">On</string> + <!-- Disabled state of bluetooth broadcasting --> + <string name="bluetooth_broadcasting_state_off">Off</string> + <!-- Bluetooth settings. Dialog title to disable a single profile of a device. [CHAR LIMIT=40] --> <string name="bluetooth_disable_profile_title">Disable profile?</string> <!-- Bluetooth settings. Message for disabling a profile of a bluetooth device. [CHAR LIMIT=NONE] --> @@ -325,22 +330,16 @@ <string name="bluetooth_ask_lasting_discovery" product="tablet">An app wants to make your tablet visible to other Bluetooth devices. You can change this later in Bluetooth settings.</string> <string name="bluetooth_ask_lasting_discovery" product="default">An app wants to make your phone visible to other Bluetooth devices. You can change this later in Bluetooth settings.</string> + <!-- Strings for asking to the user whether to allow an app to enable bluetooth and discovery mode --> + <string name="bluetooth_ask_enablement_and_lasting_discovery" product="tablet">An app wants to turn on Bluetooth and make your tablet visible to other devices. You can change this later in Bluetooth settings.</string> + <string name="bluetooth_ask_enablement_and_lasting_discovery" product="default">An app wants to turn on Bluetooth and make your phone visible to other devices. You can change this later in Bluetooth settings.</string> + <!-- Strings for asking to the user whether to allow an app to start broadcasting --> <string name="bluetooth_ask_start_broadcast" product="default"><xliff:g id="app_name">%1$s</xliff:g> wants to turn on Bluetooth broadcasting to communicate with other devices nearby. You can change this later in Bluetooth settings.</string> <!-- Strings for asking to the user whether to allow an app to enable bluetooth and start broadcasting --> - <string name="bluetooth_ask_enablement_and_start_broadcast" product="default"><xliff:g id="app_name">%1$s</xliff:g> wants to turn on Bluetooth and Bluetooth broadcasting to communicate with other devices nearby. You can change this later in Bluetooth settings.</string> + <string name="bluetooth_ask_enablement_and_start_broadcast" product="default"><xliff:g id="app_name">%1$s</xliff:g> wants to turn on Bluetooth and Bluetooth broadcasting to communicate with otherdevices nearby. You can change this later in Bluetooth settings.</string> <!-- Strings for bluetooth broadcasting explanation --> <string name="bluetooth_broadcasting_explaination" product="default">When this feature is turned on, your phone can communicate with other devices nearby.\n\nBroadcasting uses low-power Bluetooth signals.</string> - - <!-- Strings for asking to the user whether to allow an app to enable bluetooth and discovery mode --> - <string name="bluetooth_ask_enablement_and_discovery" product="tablet">An app wants to turn on Bluetooth and make your tablet visible to other devices for <xliff:g id="timeout">%1$d</xliff:g> seconds.</string> - <!-- Strings for asking to the user whether to allow an app to enable bluetooth and discovery mode --> - <string name="bluetooth_ask_enablement_and_discovery" product="default">An app wants to turn on Bluetooth and make your phone visible to other devices for <xliff:g id="timeout">%1$d</xliff:g> seconds.</string> - - <!-- Strings for asking to the user whether to allow an app to enable bluetooth and discovery mode --> - <string name="bluetooth_ask_enablement_and_lasting_discovery" product="tablet">An app wants to turn on Bluetooth and make your tablet visible to other devices. You can change this later in Bluetooth settings.</string> - <string name="bluetooth_ask_enablement_and_lasting_discovery" product="default">An app wants to turn on Bluetooth and make your phone visible to other devices. You can change this later in Bluetooth settings.</string> - <!-- Strings for msg to display to user while bluetooth is turning on [CHAR LIMIT=60] --> <string name="bluetooth_turning_on">"Turning Bluetooth on\u2026"</string> diff --git a/res/xml/bluetooth_local_device_profile.xml b/res/xml/bluetooth_local_device_profile.xml new file mode 100644 index 0000000..95a110e --- /dev/null +++ b/res/xml/bluetooth_local_device_profile.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 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. +--> + +<PreferenceScreen + xmlns:android="http://schemas.android.com/apk/res/android" + android:title="@string/bluetooth_broadcasting"> + + <Preference + android:key="rename_device" + android:title="@string/bluetooth_rename_device" /> + + <Preference + android:key="visibility_timeout" + android:title="@string/bluetooth_visibility_timeout"/> + + <PreferenceScreen + android:fragment="com.android.settings.bluetooth.BluetoothAdvertisingFragment" + android:key="broadcasting" + android:title="@string/bluetooth_broadcasting"/> + +</PreferenceScreen> diff --git a/src/com/android/settings/bluetooth/BluetoothAdvertisingEnabler.java b/src/com/android/settings/bluetooth/BluetoothAdvertisingEnabler.java new file mode 100644 index 0000000..b9e4ee2 --- /dev/null +++ b/src/com/android/settings/bluetooth/BluetoothAdvertisingEnabler.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package com.android.settings.bluetooth; + +import android.content.Context; +import android.preference.PreferenceScreen; + +import com.android.settings.R; + +/** + * BluetoothAdvertisingEnabler helps manager change of bluetooth advertising preferences. + */ +final class BluetoothAdvertisingEnabler { + + private final Context mContext; + private final PreferenceScreen mBluetoothAdvertisingPreference; + + public BluetoothAdvertisingEnabler(Context context, PreferenceScreen bluetoothBroadcast) { + mContext = context; + mBluetoothAdvertisingPreference = bluetoothBroadcast; + } + + public void resume() { + boolean isBroadcastingEnable = LocalBluetoothPreferences.isAdvertisingEnabled(mContext); + handleAdvertisingStateChange(isBroadcastingEnable); + } + + private void handleAdvertisingStateChange(boolean isBroadcastingEnable) { + mBluetoothAdvertisingPreference.setSummary(isBroadcastingEnable ? + R.string.bluetooth_broadcasting_state_on : + R.string.bluetooth_broadcasting_state_off); + } +} diff --git a/src/com/android/settings/bluetooth/BluetoothAdvertisingFragment.java b/src/com/android/settings/bluetooth/BluetoothAdvertisingFragment.java new file mode 100644 index 0000000..ea6adb0 --- /dev/null +++ b/src/com/android/settings/bluetooth/BluetoothAdvertisingFragment.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +package com.android.settings.bluetooth; + +import android.app.ActionBar; +import android.app.Activity; +import android.app.Fragment; +import android.bluetooth.BluetoothAdapter; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.preference.PreferenceActivity; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CompoundButton; +import android.widget.Switch; + +import com.android.settings.R; + +/** + * Fragment to display and let the user change advertising preference. + */ +public class BluetoothAdvertisingFragment extends Fragment + implements CompoundButton.OnCheckedChangeListener { + + private static final String TAG = "BluetoothAdvertisingFragment"; + private View mView; + private Switch mActionBarSwitch; + private Activity mActivity; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mActivity = getActivity(); + mActionBarSwitch = new Switch(mActivity); + if (mActivity instanceof PreferenceActivity) { + final int padding = mActivity.getResources().getDimensionPixelSize( + R.dimen.action_bar_switch_padding); + mActionBarSwitch.setPaddingRelative(0, 0, padding, 0); + mActivity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, + ActionBar.DISPLAY_SHOW_CUSTOM); + mActivity.getActionBar().setCustomView(mActionBarSwitch, new ActionBar.LayoutParams( + ActionBar.LayoutParams.WRAP_CONTENT, + ActionBar.LayoutParams.WRAP_CONTENT, + Gravity.CENTER_VERTICAL | Gravity.END)); + mActivity.getActionBar().setTitle(R.string.bluetooth_broadcasting); + } + mActionBarSwitch.setChecked( + LocalBluetoothPreferences.isAdvertisingEnabled(mActivity.getApplicationContext())); + + mActionBarSwitch.setOnCheckedChangeListener(this); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + mView = inflater.inflate(R.layout.bluetooth_advertising, container, false); + initView(mView); + return mView; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + getActivity().getActionBar().setCustomView(null); + } + + private void initView(View view) { + mActionBarSwitch.setOnCheckedChangeListener(this); + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean desiredState) { + mActionBarSwitch.setChecked(desiredState); + Context context = getActivity(); + LocalBluetoothPreferences.setAdvertisingEnabled(context, desiredState); + if (!desiredState) { + LocalBluetoothAdapter adapter = + LocalBluetoothManager.getInstance(context).getBluetoothAdapter(); + // Stop advertising if advertising is in process. + if (adapter.isAdvertising()) { + Intent intent = new Intent(BluetoothAdapter.ACTION_STOP_ADVERTISING); + getActivity().startActivity(intent); + } + } + } +} diff --git a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java index d687136..a040bf2 100755 --- a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java +++ b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java @@ -25,13 +25,10 @@ import android.content.SharedPreferences; import android.os.Handler; import android.os.SystemProperties; import android.preference.Preference; -import android.text.format.DateUtils; +import android.util.Log; import com.android.settings.R; -import android.text.format.Time; -import android.util.Log; - /** * BluetoothDiscoverableEnabler is a helper to manage the "Discoverable" * checkbox. It sets/unsets discoverability and keeps track of how much time @@ -63,6 +60,8 @@ final class BluetoothDiscoverableEnabler implements Preference.OnPreferenceClick private final Context mContext; private final Handler mUiHandler; private final Preference mDiscoveryPreference; + // Preference for visibility time out. Not final as it needs to be set through setter. + private Preference mVisibilityTimeoutPreference; private final LocalBluetoothAdapter mLocalAdapter; @@ -102,6 +101,10 @@ final class BluetoothDiscoverableEnabler implements Preference.OnPreferenceClick discoveryPreference.setPersistent(false); } + public void setVisibilityPreference(Preference visibilityPreference) { + mVisibilityTimeoutPreference = visibilityPreference; + } + public void resume() { if (mLocalAdapter == null) { return; @@ -111,6 +114,7 @@ final class BluetoothDiscoverableEnabler implements Preference.OnPreferenceClick mContext.registerReceiver(mReceiver, filter); mDiscoveryPreference.setOnPreferenceClickListener(this); handleModeChanged(mLocalAdapter.getScanMode()); + updateVisibilityTimeoutDisplay(); } public void pause() { @@ -121,6 +125,9 @@ final class BluetoothDiscoverableEnabler implements Preference.OnPreferenceClick mUiHandler.removeCallbacks(mUpdateCountdownSummaryRunnable); mContext.unregisterReceiver(mReceiver); mDiscoveryPreference.setOnPreferenceClickListener(null); + if (mVisibilityTimeoutPreference != null) { + mVisibilityTimeoutPreference.setOnPreferenceClickListener(null); + } } public boolean onPreferenceClick(Preference preference) { @@ -148,6 +155,23 @@ final class BluetoothDiscoverableEnabler implements Preference.OnPreferenceClick mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE); BluetoothDiscoverableTimeoutReceiver.cancelDiscoverableAlarm(mContext); } + updateVisibilityTimeoutDisplay(); + } + + // Update visibility timeout preference. + private void updateVisibilityTimeoutDisplay() { + if (mVisibilityTimeoutPreference == null) { + return; + } + int index = getDiscoverableTimeoutIndex(); + + String visibilitySummary = ""; + CharSequence[] timeoutChoices = + mContext.getResources().getTextArray(R.array.bluetooth_visibility_timeout_entries); + if (index >= 0 && index < timeoutChoices.length) { + visibilitySummary = timeoutChoices[index].toString(); + } + mVisibilityTimeoutPreference.setSummary(visibilitySummary); } private void updateTimerDisplay(int timeout) { diff --git a/src/com/android/settings/bluetooth/BluetoothLocalDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothLocalDevicePreference.java new file mode 100644 index 0000000..403c3b4 --- /dev/null +++ b/src/com/android/settings/bluetooth/BluetoothLocalDevicePreference.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package com.android.settings.bluetooth; + +import android.content.Context; +import android.preference.Preference; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageView; + +import com.android.settings.R; + +/** + * A preference screen to show information for local device. + */ +public class BluetoothLocalDevicePreference extends Preference { + private static OnClickListener mSettingsListener; + + public BluetoothLocalDevicePreference(Context context, OnClickListener settingsListener) { + super(context); + mSettingsListener = settingsListener; + setWidgetLayoutResource(R.layout.preference_bluetooth); + } + + @Override + protected void onBindView(View view) { + ImageView deviceDetails = (ImageView) view.findViewById( + R.id.deviceDetails); + deviceDetails.setOnClickListener(mSettingsListener); + super.onBindView(view); + } +} diff --git a/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java index b80e42a..0af9c4e 100644 --- a/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java +++ b/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java @@ -26,6 +26,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; +import android.preference.PreferenceActivity; import android.text.Editable; import android.text.InputFilter; import android.text.TextWatcher; @@ -179,6 +180,8 @@ public final class BluetoothNameDialogFragment extends DialogFragment implements mDeviceNameEdited = false; mDeviceNameView.setText(mLocalAdapter.getName()); } + PreferenceActivity activity = (PreferenceActivity)getActivity(); + activity.showBreadCrumbs(mLocalAdapter.getName(), ""); } public void afterTextChanged(Editable s) { diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java index 529ee79..4cb36c8 100755 --- a/src/com/android/settings/bluetooth/BluetoothSettings.java +++ b/src/com/android/settings/bluetooth/BluetoothSettings.java @@ -51,9 +51,7 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment { private static final String TAG = "BluetoothSettings"; private static final int MENU_ID_SCAN = Menu.FIRST; - private static final int MENU_ID_RENAME_DEVICE = Menu.FIRST + 1; - private static final int MENU_ID_VISIBILITY_TIMEOUT = Menu.FIRST + 2; - private static final int MENU_ID_SHOW_RECEIVED = Menu.FIRST + 3; + private static final int MENU_ID_SHOW_RECEIVED = Menu.FIRST + 1; /* Private intent to show the list of received files */ private static final String BTOPP_ACTION_OPEN_RECEIVED_FILES = @@ -178,12 +176,6 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment { menu.add(Menu.NONE, MENU_ID_SCAN, 0, textId) .setEnabled(bluetoothIsEnabled && !isDiscovering) .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - menu.add(Menu.NONE, MENU_ID_RENAME_DEVICE, 0, R.string.bluetooth_rename_device) - .setEnabled(bluetoothIsEnabled) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - menu.add(Menu.NONE, MENU_ID_VISIBILITY_TIMEOUT, 0, R.string.bluetooth_visibility_timeout) - .setEnabled(bluetoothIsEnabled) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); menu.add(Menu.NONE, MENU_ID_SHOW_RECEIVED, 0, R.string.bluetooth_show_received_files) .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); super.onCreateOptionsMenu(menu, inflater); @@ -198,16 +190,6 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment { } return true; - case MENU_ID_RENAME_DEVICE: - new BluetoothNameDialogFragment().show( - getFragmentManager(), "rename device"); - return true; - - case MENU_ID_VISIBILITY_TIMEOUT: - new BluetoothVisibilityTimeoutFragment().show( - getFragmentManager(), "visibility timeout"); - return true; - case MENU_ID_SHOW_RECEIVED: Intent intent = new Intent(BTOPP_ACTION_OPEN_RECEIVED_FILES); getActivity().sendBroadcast(intent); @@ -252,7 +234,8 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment { // This device if (mMyDevicePreference == null) { - mMyDevicePreference = new Preference(getActivity()); + mMyDevicePreference = new BluetoothLocalDevicePreference( + getActivity(), mLocalDeviceProfilesListener); } mMyDevicePreference.setTitle(mLocalAdapter.getName()); if (getResources().getBoolean(com.android.internal.R.bool.config_voice_capable)) { @@ -360,6 +343,18 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment { updateContent(mLocalAdapter.getBluetoothState(), false); } + // Listener for local device profile fragment. + private final View.OnClickListener mLocalDeviceProfilesListener = new View.OnClickListener() { + public void onClick(View v) { + if (isRestrictedAndNotPinProtected()) return; + + ((PreferenceActivity) getActivity()).startPreferencePanel( + LocalDeviceProfilesSettings.class.getName(), null, + 0, mLocalAdapter.getName(), null, 0); + } + }; + + private final View.OnClickListener mDeviceProfilesListener = new View.OnClickListener() { public void onClick(View v) { // User clicked on advanced options icon for a device in the list diff --git a/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java b/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java index 013171c..041ecb7 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java @@ -118,6 +118,9 @@ public final class LocalBluetoothAdapter { return mAdapter.isDiscovering(); } + boolean isAdvertising() { + return mAdapter.isAdvertising(); + } boolean isEnabled() { return mAdapter.isEnabled(); } @@ -126,6 +129,14 @@ public final class LocalBluetoothAdapter { mAdapter.setDiscoverableTimeout(timeout); } + boolean startAdvertising() { + return mAdapter.startAdvertising(); + } + + boolean stopAdvertising() { + return mAdapter.stopAdvertisting(); + } + void setName(String name) { mAdapter.setName(name); } diff --git a/src/com/android/settings/bluetooth/LocalBluetoothManager.java b/src/com/android/settings/bluetooth/LocalBluetoothManager.java index ae8dec2..265cabb 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothManager.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothManager.java @@ -37,6 +37,7 @@ public final class LocalBluetoothManager { private Context mForegroundActivity; private BluetoothDiscoverableEnabler mDiscoverableEnabler; + private BluetoothAdvertisingEnabler mAdvertisingEnabler; private final LocalBluetoothAdapter mLocalAdapter; @@ -70,6 +71,14 @@ public final class LocalBluetoothManager { return mDiscoverableEnabler; } + public void setBluetoothAdvertisingEnabler(BluetoothAdvertisingEnabler advertisingEnabler) { + this.mAdvertisingEnabler = advertisingEnabler; + } + + public BluetoothAdvertisingEnabler getAdvertisingEnabler() { + return mAdvertisingEnabler; + } + private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) { mContext = context; mLocalAdapter = adapter; diff --git a/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java b/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java index f00b801..f862f72 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothPreferences.java @@ -17,8 +17,10 @@ package com.android.settings.bluetooth; import android.app.QueuedWork; +import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; import android.content.res.Configuration; import android.util.Log; @@ -46,6 +48,10 @@ final class LocalBluetoothPreferences { private static final String KEY_DISCOVERABLE_END_TIMESTAMP = "discoverable_end_timestamp"; + private static final String KEY_ADVERTISEMENT_PREFERENCE = "bt_advertisement_perference"; + + private static final boolean DEFAULT_ADVERTISING_ENABLED = false; + private LocalBluetoothPreferences() { } @@ -58,6 +64,17 @@ final class LocalBluetoothPreferences { KEY_DISCOVERABLE_END_TIMESTAMP, 0); } + static boolean isAdvertisingEnabled(Context context) { + return getSharedPreferences(context).getBoolean( + KEY_ADVERTISEMENT_PREFERENCE, DEFAULT_ADVERTISING_ENABLED); + } + + static void setAdvertisingEnabled(Context context, boolean advertisingEnabled) { + Editor preferenceEditor = getSharedPreferences(context).edit(); + preferenceEditor.putBoolean(KEY_ADVERTISEMENT_PREFERENCE, advertisingEnabled); + preferenceEditor.apply(); + } + static boolean shouldShowDialogInForeground(Context context, String deviceAddress) { LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context); diff --git a/src/com/android/settings/bluetooth/LocalDeviceProfilesSettings.java b/src/com/android/settings/bluetooth/LocalDeviceProfilesSettings.java new file mode 100644 index 0000000..f01bbf5 --- /dev/null +++ b/src/com/android/settings/bluetooth/LocalDeviceProfilesSettings.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +package com.android.settings.bluetooth; + +import android.os.Bundle; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; +import android.preference.PreferenceActivity; +import android.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.SettingsPreferenceFragment; + +/** + * This preference fragment presents the user with the profiles of the local devices and allow them + * to be modified. + */ +public final class LocalDeviceProfilesSettings extends SettingsPreferenceFragment { + private static final String TAG = "LocalDeviceProfilesSettings"; + + private static final String KEY_RENAME_DEVICE = "rename_device"; + private static final String KEY_BROADCASTING = "broadcasting"; + private static final String KEY_VISIBILITY_TIMEOUT = "visibility_timeout"; + + private LocalBluetoothManager mManager; + private BluetoothDiscoverableEnabler mDiscoverableEnabler; + private BluetoothAdvertisingEnabler mAdvertisingEnabler; + + private Preference mDeviceNamePref; + private Preference mVisibilityPref; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.bluetooth_local_device_profile); + getPreferenceScreen().setOrderingAsAdded(true); + mDeviceNamePref = findPreference(KEY_RENAME_DEVICE); + mDeviceNamePref.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + new BluetoothNameDialogFragment().show(getFragmentManager(), "rename device"); + return true; + } + }); + + mVisibilityPref = findPreference(KEY_VISIBILITY_TIMEOUT); + mVisibilityPref.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + new BluetoothVisibilityTimeoutFragment().show( + getFragmentManager(), "visibility timeout"); + return true; + } + }); + + mManager = LocalBluetoothManager.getInstance(getActivity()); + mDiscoverableEnabler = mManager.getDiscoverableEnabler(); + // Set the visibility timeout preference to the enabler so the visibility timeout + // preference can be updated when the timeout changes. + mDiscoverableEnabler.setVisibilityPreference(mVisibilityPref); + + PreferenceActivity mActivity = (PreferenceActivity)getActivity(); + mActivity.showBreadCrumbs(mManager.getBluetoothAdapter().getName(), ""); + PreferenceScreen bluetoothBroadcast = (PreferenceScreen)findPreference(KEY_BROADCASTING); + mAdvertisingEnabler = new BluetoothAdvertisingEnabler(getActivity(), bluetoothBroadcast); + mManager.setBluetoothAdvertisingEnabler(mAdvertisingEnabler); + } + + @Override + public void onResume() { + super.onResume(); + mManager.setForegroundActivity(getActivity()); + mAdvertisingEnabler.resume(); + mDiscoverableEnabler.resume(); + } + + @Override + public void onPause() { + super.onPause(); + mManager.setForegroundActivity(null); + if (mDiscoverableEnabler != null) { + mDiscoverableEnabler.pause(); + } + } + +} diff --git a/src/com/android/settings/bluetooth/RequestPermissionActivity.java b/src/com/android/settings/bluetooth/RequestPermissionActivity.java index 9f266a5..1b105de 100644 --- a/src/com/android/settings/bluetooth/RequestPermissionActivity.java +++ b/src/com/android/settings/bluetooth/RequestPermissionActivity.java @@ -16,8 +16,6 @@ package com.android.settings.bluetooth; -import com.android.settings.R; - import android.app.Activity; import android.app.AlertDialog; import android.bluetooth.BluetoothAdapter; @@ -28,17 +26,22 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; +import android.os.UserHandle; import android.util.Log; +import com.android.settings.R; + /** - * RequestPermissionActivity asks the user whether to enable discovery. This is - * usually started by an application wanted to start bluetooth and or discovery + * RequestPermissionActivity asks the user whether to enable bluetooth, discovery or advertisement. + * This is usually started by an application wanted to start bluetooth, discovery or advertisement. */ public class RequestPermissionActivity extends Activity implements DialogInterface.OnClickListener { // Command line to test this // adb shell am start -a android.bluetooth.adapter.action.REQUEST_ENABLE // adb shell am start -a android.bluetooth.adapter.action.REQUEST_DISCOVERABLE + // adb shell am start -a android.bluetooth.adapter.action.START_ADVERTISING + // adb shell am start -a android.bluetooth.adapter.action.STOP_ADVERTISING private static final String TAG = "RequestPermissionActivity"; @@ -50,6 +53,11 @@ public class RequestPermissionActivity extends Activity implements private static final int REQUEST_CODE_START_BT = 1; + private static final int EXTRA_INTENT_NONE = 0; + private static final int EXTRA_INTENT_DISCOVERY = 1; + private static final int EXTRA_INTENT_START_ADVERTISING = 2; + private static final int EXTRA_INTENT_STOP_ADVERTISING = 3; + private LocalBluetoothAdapter mLocalAdapter; private int mTimeout = BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT; @@ -67,10 +75,14 @@ public class RequestPermissionActivity extends Activity implements // False if requesting BT to be turned on + discoverable mode private boolean mEnableOnly; + private int mExtraIntent = EXTRA_INTENT_NONE; + private boolean mUserConfirmed; private AlertDialog mDialog; + private Context mContext; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -94,6 +106,8 @@ public class RequestPermissionActivity extends Activity implements protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mContext = getApplicationContext(); + // Note: initializes mLocalAdapter and returns true on error if (parseIntent()) { finish(); @@ -125,21 +139,27 @@ public class RequestPermissionActivity extends Activity implements intent.setClass(this, RequestPermissionHelperActivity.class); if (mEnableOnly) { intent.setAction(RequestPermissionHelperActivity.ACTION_INTERNAL_REQUEST_BT_ON); - } else { + } else if (mExtraIntent == EXTRA_INTENT_DISCOVERY) { intent.setAction(RequestPermissionHelperActivity. ACTION_INTERNAL_REQUEST_BT_ON_AND_DISCOVERABLE); intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, mTimeout); + } else if (mExtraIntent == EXTRA_INTENT_START_ADVERTISING) { + intent.setAction(RequestPermissionHelperActivity. + ACTION_INTERNAL_REQUEST_BT_ON_AND_START_ADVERTISE); + } else if (mExtraIntent == EXTRA_INTENT_STOP_ADVERTISING) { + // Nothing to do. Advertising cannot be in process with bluetooth disabled. } + startActivityForResult(intent, REQUEST_CODE_START_BT); mNeededToEnableBluetooth = true; break; case BluetoothAdapter.STATE_ON: - if (mEnableOnly) { - // Nothing to do. Already enabled. - proceedAndFinish(); - } else { - // Ask the user about enabling discovery mode + if (needAskUserPermission()) { + // Ask the user for permissions of bluetooth operations. createDialog(); + } else { + // No need to ask for permission, just proceed. + proceedAndFinish(); } break; default: @@ -147,6 +167,19 @@ public class RequestPermissionActivity extends Activity implements } } + private boolean needAskUserPermission() { + if (mEnableOnly) { + return false; + } + if (mExtraIntent == EXTRA_INTENT_STOP_ADVERTISING) { + return false; + } + if (mExtraIntent == EXTRA_INTENT_START_ADVERTISING) { + return !LocalBluetoothPreferences.isAdvertisingEnabled(mContext); + } + return true; + } + private void createDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); @@ -155,7 +188,7 @@ public class RequestPermissionActivity extends Activity implements // to turn on BT builder.setMessage(getString(R.string.bluetooth_turning_on)); builder.setCancelable(false); - } else { + } else if (mExtraIntent == EXTRA_INTENT_DISCOVERY) { // Ask the user whether to turn on discovery mode or not // For lasting discoverable mode there is a different message if (mTimeout == BluetoothDiscoverableEnabler.DISCOVERABLE_TIMEOUT_NEVER) { @@ -167,6 +200,11 @@ public class RequestPermissionActivity extends Activity implements } builder.setPositiveButton(getString(R.string.allow), this); builder.setNegativeButton(getString(R.string.deny), this); + } else if (mExtraIntent == EXTRA_INTENT_START_ADVERTISING) { + builder.setMessage(getString(R.string.bluetooth_ask_start_broadcast, + Utils.getCallingApp(this))); + builder.setPositiveButton(getString(R.string.allow), this); + builder.setNegativeButton(getString(R.string.deny), this); } mDialog = builder.create(); @@ -223,7 +261,8 @@ public class RequestPermissionActivity extends Activity implements if (mEnableOnly) { // BT enabled. Done returnCode = RESULT_OK; - } else if (mLocalAdapter.setScanMode( + } else if (mExtraIntent == EXTRA_INTENT_DISCOVERY + && mLocalAdapter.setScanMode( BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, mTimeout)) { // If already in discoverable mode, this will extend the timeout. long endTime = System.currentTimeMillis() + (long) mTimeout * 1000; @@ -237,6 +276,22 @@ public class RequestPermissionActivity extends Activity implements if (returnCode < RESULT_FIRST_USER) { returnCode = RESULT_FIRST_USER; } + } else if (mExtraIntent == EXTRA_INTENT_START_ADVERTISING) { + // Advertise allowed as user said yes. + LocalBluetoothPreferences.setAdvertisingEnabled(mContext, true); + if (mLocalAdapter.startAdvertising()) { + returnCode = RESULT_OK; + Intent intent = new Intent(BluetoothAdapter.ACTION_BLUETOOTH_ADVERTISING_STARTED); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + } else { + returnCode = RESULT_CANCELED; + } + } else if (mExtraIntent == EXTRA_INTENT_STOP_ADVERTISING + && mLocalAdapter.isAdvertising() + && mLocalAdapter.stopAdvertising()) { + Intent intent = new Intent(BluetoothAdapter.ACTION_BLUETOOTH_ADVERTISING_STOPPED); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + returnCode = RESULT_OK; } else { returnCode = RESULT_CANCELED; } @@ -259,6 +314,7 @@ public class RequestPermissionActivity extends Activity implements mEnableOnly = true; } else if (intent != null && intent.getAction().equals(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)) { + mExtraIntent = EXTRA_INTENT_DISCOVERY; mTimeout = intent.getIntExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT); @@ -267,6 +323,12 @@ public class RequestPermissionActivity extends Activity implements if (mTimeout < 0 || mTimeout > MAX_DISCOVERABLE_TIMEOUT) { mTimeout = BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT; } + } else if (intent != null + && intent.getAction().equals(BluetoothAdapter.ACTION_START_ADVERTISING)) { + mExtraIntent = EXTRA_INTENT_START_ADVERTISING; + } else if (intent != null + && intent.getAction().equals(BluetoothAdapter.ACTION_STOP_ADVERTISING)) { + mExtraIntent = EXTRA_INTENT_STOP_ADVERTISING; } else { Log.e(TAG, "Error: this activity may be started only with intent " + BluetoothAdapter.ACTION_REQUEST_ENABLE + " or " diff --git a/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java b/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java index f108513..34874b3 100644 --- a/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java +++ b/src/com/android/settings/bluetooth/RequestPermissionHelperActivity.java @@ -30,7 +30,7 @@ import android.view.View; import android.widget.TextView; /** - * RequestPermissionHelperActivity asks the user whether to enable discovery. + * RequestPermissionHelperActivity asks the user whether to enable discovery or advertisement. * This is usually started by RequestPermissionActivity. */ public class RequestPermissionHelperActivity extends AlertActivity implements @@ -43,6 +43,9 @@ public class RequestPermissionHelperActivity extends AlertActivity implements public static final String ACTION_INTERNAL_REQUEST_BT_ON_AND_DISCOVERABLE = "com.android.settings.bluetooth.ACTION_INTERNAL_REQUEST_BT_ON_AND_DISCOVERABLE"; + public static final String ACTION_INTERNAL_REQUEST_BT_ON_AND_START_ADVERTISE = + "com.android.settings.bluetooth.ACTION_INTERNAL_REQUEST_BT_ON_AND_ADVERTISE"; + private LocalBluetoothAdapter mLocalAdapter; private int mTimeout; @@ -50,6 +53,7 @@ public class RequestPermissionHelperActivity extends AlertActivity implements // True if requesting BT to be turned on // False if requesting BT to be turned on + discoverable mode private boolean mEnableOnly; + private boolean mDiscovery; @Override protected void onCreate(Bundle savedInstanceState) { @@ -75,12 +79,15 @@ public class RequestPermissionHelperActivity extends AlertActivity implements if (mEnableOnly) { p.mMessage = getString(R.string.bluetooth_ask_enablement); - } else { + } else if (mDiscovery) { if (mTimeout == BluetoothDiscoverableEnabler.DISCOVERABLE_TIMEOUT_NEVER) { p.mMessage = getString(R.string.bluetooth_ask_enablement_and_lasting_discovery); } else { p.mMessage = getString(R.string.bluetooth_ask_enablement_and_discovery, mTimeout); } + } else { + p.mMessage = getString(R.string.bluetooth_ask_enablement_and_start_broadcast, + Utils.getCallingApp(this)); } p.mPositiveButtonText = getString(R.string.allow); @@ -138,9 +145,14 @@ public class RequestPermissionHelperActivity extends AlertActivity implements } else if (intent != null && intent.getAction().equals(ACTION_INTERNAL_REQUEST_BT_ON_AND_DISCOVERABLE)) { mEnableOnly = false; + mDiscovery = true; // Value used for display purposes. Not range checking. mTimeout = intent.getIntExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, BluetoothDiscoverableEnabler.DEFAULT_DISCOVERABLE_TIMEOUT); + } else if (intent != null + && intent.getAction().equals(ACTION_INTERNAL_REQUEST_BT_ON_AND_START_ADVERTISE)) { + mEnableOnly = false; + mDiscovery = false; } else { setResult(RESULT_CANCELED); return true; diff --git a/src/com/android/settings/bluetooth/Utils.java b/src/com/android/settings/bluetooth/Utils.java index fb44d5a..6590b06 100755 --- a/src/com/android/settings/bluetooth/Utils.java +++ b/src/com/android/settings/bluetooth/Utils.java @@ -16,11 +16,15 @@ package com.android.settings.bluetooth; +import android.app.Activity; import android.app.AlertDialog; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.DialogInterface; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.widget.Toast; import com.android.settings.R; @@ -102,4 +106,18 @@ final class Utils { Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } } + + /** + * Get application name of the calling activity. Returns empty string on errors. + */ + static String getCallingApp(Activity activity) { + final PackageManager pm = activity.getApplicationContext().getPackageManager(); + ApplicationInfo applicationInfo; + try { + applicationInfo = pm.getApplicationInfo(activity.getCallingPackage(), 0); + } catch (final NameNotFoundException e) { + applicationInfo = null; + } + return (applicationInfo == null) ? "" : pm.getApplicationLabel(applicationInfo).toString(); + } } |