diff --git a/res/values/strings.xml b/res/values/strings.xml index 38c2790e17a..bfde0c8a67c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1241,6 +1241,12 @@ Advanced Bluetooth When Bluetooth is turned on, your device can communicate with other nearby Bluetooth devices. + + To improve location accuracy, Google services will scan for + Bluetooth devices, even when Bluetooth is off. You can change this in LINK_BEGINscanning + settingsLINK_END. @@ -1411,8 +1417,12 @@ Choose assistant Install certificates - To improve location accuracy and for other purposes, Google and other apps may scan for nearby networks, even when Wi-Fi is off. If you don\'t want this to happen, go to Advanced > Scanning always available. - Apps may scan for nearby networks, even when Wi-Fi is off. If you don\'t want this to happen, go to Advanced > Scanning always available. + + To improve location accuracy, Google services will scan for + Wi\u2011Fi networks, even when Wi\u2011Fi is off. You can change this in LINK_BEGINscanning + settingsLINK_END. Don\'t show again diff --git a/src/com/android/settings/LinkifyUtils.java b/src/com/android/settings/LinkifyUtils.java new file mode 100644 index 00000000000..5550db5216e --- /dev/null +++ b/src/com/android/settings/LinkifyUtils.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2015 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; + +import android.text.Spannable; +import android.text.TextPaint; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; +import android.view.View; +import android.widget.TextView; +import android.widget.TextView.BufferType; + +/** + * Utility class to create clickable links inside {@link TextView TextViews}. + */ +public class LinkifyUtils { + private static final String PLACE_HOLDER_LINK_BEGIN = "LINK_BEGIN"; + private static final String PLACE_HOLDER_LINK_END = "LINK_END"; + + private LinkifyUtils() { + } + + /** Interface that handles the click event of the link */ + public interface OnClickListener { + void onClick(); + } + + /** + * Applies the text into the {@link TextView} and part of it a clickable link. + * The text surrounded with "LINK_BEGIN" and "LINK_END" will become a clickable link. Only + * supports at most one link. + * @return true if the link has been successfully applied, or false if the original text + * contains no link place holders. + */ + public static boolean linkify(TextView textView, StringBuilder text, + final OnClickListener listener) { + // Remove place-holders from the string and record their positions + final int beginIndex = text.indexOf(PLACE_HOLDER_LINK_BEGIN); + if (beginIndex == -1) { + textView.setText(text); + return false; + } + text.delete(beginIndex, beginIndex + PLACE_HOLDER_LINK_BEGIN.length()); + final int endIndex = text.indexOf(PLACE_HOLDER_LINK_END); + if (endIndex == -1) { + textView.setText(text); + return false; + } + text.delete(endIndex, endIndex + PLACE_HOLDER_LINK_END.length()); + + textView.setText(text.toString(), BufferType.SPANNABLE); + textView.setMovementMethod(LinkMovementMethod.getInstance()); + Spannable spannableContent = (Spannable) textView.getText(); + ClickableSpan spannableLink = new ClickableSpan() { + @Override + public void onClick(View widget) { + listener.onClick(); + } + + @Override + public void updateDrawState(TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + }; + spannableContent.setSpan(spannableLink, beginIndex, endIndex, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + return true; + } +} diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java index b1eed512f1e..1d0dc7e482e 100755 --- a/src/com/android/settings/bluetooth/BluetoothSettings.java +++ b/src/com/android/settings/bluetooth/BluetoothSettings.java @@ -33,7 +33,10 @@ import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; +import android.text.Spannable; +import android.text.style.TextAppearanceSpan; import android.util.Log; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -45,8 +48,10 @@ import android.widget.EditText; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; +import com.android.settings.LinkifyUtils; import com.android.settings.R; import com.android.settings.SettingsActivity; +import com.android.settings.location.ScanningSettings; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settings.search.SearchIndexableRaw; @@ -136,6 +141,7 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment implem mEmptyView = (TextView) getView().findViewById(android.R.id.empty); getListView().setEmptyView(mEmptyView); + mEmptyView.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); final SettingsActivity activity = (SettingsActivity) getActivity(); mSwitchBar = activity.getSwitchBar(); @@ -352,7 +358,7 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment implem break; case BluetoothAdapter.STATE_OFF: - messageId = R.string.bluetooth_empty_list_bluetooth_off; + setOffMessage(); if (isUiRestricted()) { messageId = R.string.bluetooth_empty_list_user_restricted; } @@ -366,12 +372,39 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment implem setDeviceListGroup(preferenceScreen); removeAllDevices(); - mEmptyView.setText(messageId); + if (messageId != 0) { + mEmptyView.setText(messageId); + } if (!isUiRestricted()) { getActivity().invalidateOptionsMenu(); } } + private void setOffMessage() { + if (mEmptyView == null) { + return; + } + final CharSequence briefText = getText(R.string.bluetooth_empty_list_bluetooth_off); + final StringBuilder contentBuilder = new StringBuilder(); + contentBuilder.append(briefText); + contentBuilder.append("\n\n"); + contentBuilder.append(getText(R.string.ble_scan_notify_text)); + getPreferenceScreen().removeAll(); + LinkifyUtils.linkify(mEmptyView, contentBuilder, new LinkifyUtils.OnClickListener() { + @Override + public void onClick() { + final SettingsActivity activity = + (SettingsActivity) BluetoothSettings.this.getActivity(); + activity.startPreferencePanel(ScanningSettings.class.getName(), null, + R.string.location_scanning_screen_title, null, null, 0); + } + }); + Spannable boldSpan = (Spannable) mEmptyView.getText(); + boldSpan.setSpan( + new TextAppearanceSpan(getActivity(), android.R.style.TextAppearance_Medium), 0, + briefText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + @Override public void onBluetoothStateChanged(int bluetoothState) { super.onBluetoothStateChanged(bluetoothState); diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java index 238db69435c..cb6be536afe 100644 --- a/src/com/android/settings/wifi/WifiSettings.java +++ b/src/com/android/settings/wifi/WifiSettings.java @@ -18,6 +18,7 @@ package com.android.settings.wifi; import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; import static android.os.UserManager.DISALLOW_CONFIG_WIFI; + import android.app.Activity; import android.app.Dialog; import android.content.Context; @@ -25,7 +26,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.content.res.TypedArray; -import android.location.LocationManager; +import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.State; @@ -36,21 +37,27 @@ import android.nfc.NfcAdapter; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceScreen; +import android.text.Spannable; +import android.text.style.TextAppearanceSpan; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; +import android.view.Gravity; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.TextView; +import android.widget.TextView.BufferType; import android.widget.Toast; import com.android.internal.logging.MetricsLogger; +import com.android.settings.LinkifyUtils; import com.android.settings.R; import com.android.settings.RestrictedSettingsFragment; import com.android.settings.SettingsActivity; +import com.android.settings.location.ScanningSettings; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settings.search.SearchIndexableRaw; @@ -608,27 +615,41 @@ public class WifiSettings extends RestrictedSettingsFragment protected TextView initEmptyView() { TextView emptyView = (TextView) getActivity().findViewById(android.R.id.empty); + emptyView.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); getListView().setEmptyView(emptyView); return emptyView; } private void setOffMessage() { - if (mEmptyView != null) { - mEmptyView.setText(R.string.wifi_empty_list_wifi_off); - if (android.provider.Settings.Global.getInt(getActivity().getContentResolver(), - android.provider.Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1) { - mEmptyView.append("\n\n"); - int resId; - if (android.provider.Settings.Secure.isLocationProviderEnabled( - getActivity().getContentResolver(), LocationManager.NETWORK_PROVIDER)) { - resId = R.string.wifi_scan_notify_text_location_on; - } else { - resId = R.string.wifi_scan_notify_text_location_off; - } - CharSequence charSeq = getText(resId); - mEmptyView.append(charSeq); - } + if (mEmptyView == null) { + return; } + + final CharSequence briefText = getText(R.string.wifi_empty_list_wifi_off); + if (isUiRestricted()) { + // Show only the brief text if the user is not allowed to configure scanning settings. + mEmptyView.setText(briefText, BufferType.SPANNABLE); + } else { + // Append the description of scanning settings with link. + final StringBuilder contentBuilder = new StringBuilder(); + contentBuilder.append(briefText); + contentBuilder.append("\n\n"); + contentBuilder.append(getText(R.string.wifi_scan_notify_text)); + LinkifyUtils.linkify(mEmptyView, contentBuilder, new LinkifyUtils.OnClickListener() { + @Override + public void onClick() { + final SettingsActivity activity = + (SettingsActivity) WifiSettings.this.getActivity(); + activity.startPreferencePanel(ScanningSettings.class.getName(), null, + R.string.location_scanning_screen_title, null, null, 0); + } + }); + } + // Embolden and enlarge the brief description anyway. + Spannable boldSpan = (Spannable) mEmptyView.getText(); + boldSpan.setSpan( + new TextAppearanceSpan(getActivity(), android.R.style.TextAppearance_Medium), 0, + briefText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); getPreferenceScreen().removeAll(); }