Merge "Add NPE check for method assignDefaultPhoto in Utils.java"
diff --git a/res/layout/preference_iconless_slider.xml b/res/layout/preference_iconless_slider.xml
deleted file mode 100644
index 8e2b8f3..0000000
--- a/res/layout/preference_iconless_slider.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:gravity="center_vertical"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip">
-
- <TextView android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAppearance="@android:style/TextAppearance.Material.Subhead"
- android:textColor="?android:attr/textColorPrimary"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="6dip">
-
- <SeekBar android:id="@*android:id/seekbar"
- android:layout_gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- </LinearLayout>
-
-</FrameLayout>
diff --git a/res/layout/preference_tts_engine.xml b/res/layout/preference_tts_engine.xml
index 277fc23..8f4036b 100644
--- a/res/layout/preference_tts_engine.xml
+++ b/res/layout/preference_tts_engine.xml
@@ -18,22 +18,19 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingStart="@dimen/preference_no_icon_padding_start"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:layout_gravity="center_vertical">
<RadioButton
android:id="@+id/tts_engine_radiobutton"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:clickable="true"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <View
android:layout_width="0dp"
android:layout_height="match_parent"
+ android:clickable="true"
android:layout_weight="1"
- android:background="@android:drawable/divider_horizontal_dark" />
+ android:maxLines="2"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:ellipsize="marquee"/>
<ImageView
android:id="@+id/tts_engine_settings"
@@ -46,5 +43,5 @@
android:layout_centerVertical="true"
android:clickable="true"
android:focusable="true"
- android:background="?android:attr/selectableItemBackground" />
+ android:background="?android:attr/selectableItemBackground"/>
</LinearLayout>
diff --git a/res/layout/preference_widget_seekbar_settings.xml b/res/layout/preference_widget_seekbar_settings.xml
new file mode 100644
index 0000000..77c27a4
--- /dev/null
+++ b/res/layout/preference_widget_seekbar_settings.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<!-- Layout used by SeekBarPreference for the seekbar widget style. -->
+<!-- Same as frameworks/base/core/res/res/layout/preference_widget_seekbar_material.xml with
+ reserved icon space -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <LinearLayout
+ android:id="@+id/icon_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="60dp"
+ android:gravity="start|center_vertical"
+ android:orientation="horizontal"
+ android:paddingEnd="12dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp">
+ <com.android.internal.widget.PreferenceImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxWidth="48dp"
+ android:maxHeight="48dp"/>
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="?android:attr/textColorPrimary"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"/>
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="4"/>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_below="@android:id/summary"
+ android:layout_alignStart="@android:id/title"
+ android:gravity="center"
+ android:orientation="vertical"/>
+
+ <SeekBar
+ android:id="@*android:id/seekbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/summary"
+ android:layout_toEndOf="@android:id/widget_frame"
+ android:layout_alignParentEnd="true"/>
+
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index dd89e71..955b8cc 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5369,9 +5369,9 @@
<string name="vpn_not_supported_by_this_app">Not supported by this app</string>
<!-- Preference title for forcing all network connections to go through VPN. -->
<string name="vpn_require_connection">Only allow connections through VPN</string>
- <!-- Preference summary for network connections being forced to go through VPN. -->
+ <!-- Preference summary when the preference to force all network connections to go through a VPN is enabled, blocking all other network traffic. In this case apps must use the VPN for all connections. -->
<string name="vpn_lockdown_active">Lockdown active</string>
- <!-- Preference summary for network connections not being forced to go through VPN. -->
+ <!-- Preference summary when the preference to force all network connections to go through a VPN is disabled. In this case use of the VPN is optional for apps. -->
<string name="vpn_lockdown_inactive">Lockdown inactive</string>
<!-- Summary describing the always-on VPN feature. [CHAR LIMIT=NONE] -->
diff --git a/res/values/styles_preference.xml b/res/values/styles_preference.xml
index 1eedd4d..a78d87b 100644
--- a/res/values/styles_preference.xml
+++ b/res/values/styles_preference.xml
@@ -49,6 +49,10 @@
<item name="android:layout">@layout/preference_category_material_settings</item>
</style>
+ <style name="SettingsSeekBarPreference">
+ <item name="android:layout">@layout/preference_widget_seekbar_settings</item>
+ </style>
+
<style name="SettingsSwitchPreference" parent="SettingsPreference">
<item name="widgetLayout">@*android:layout/preference_widget_switch</item>
<item name="switchTextOn">@*android:string/capital_on</item>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 02bf523..6438e70 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -90,6 +90,7 @@
<item name="preferenceCategoryStyle">@style/SettingsPreferenceCategory</item>
<item name="preferenceFragmentStyle">@style/PreferenceFragmentStyle</item>
<item name="preferenceStyle">@style/SettingsPreference</item>
+ <item name="seekBarPreferenceStyle">@style/SettingsSeekBarPreference</item>
<item name="switchPreferenceStyle">@style/SettingsSwitchPreference</item>
</style>
diff --git a/res/xml/accessibility_autoclick_settings.xml b/res/xml/accessibility_autoclick_settings.xml
index 39b9736..f774335 100644
--- a/res/xml/accessibility_autoclick_settings.xml
+++ b/res/xml/accessibility_autoclick_settings.xml
@@ -15,12 +15,11 @@
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- android:title="@string/accessibility_autoclick_preference_title" >
+ android:title="@string/accessibility_autoclick_preference_title">
<com.android.settings.SeekBarPreference
android:key="autoclick_delay"
- android:title="@string/accessibility_autoclick_delay_preference_title"
- android:layout="@layout/preference_iconless_slider" />
+ android:title="@string/accessibility_autoclick_delay_preference_title"/>
</PreferenceScreen>
diff --git a/res/xml/tts_settings.xml b/res/xml/tts_settings.xml
index a74431d..31d2b17 100644
--- a/res/xml/tts_settings.xml
+++ b/res/xml/tts_settings.xml
@@ -31,16 +31,14 @@
android:title="@string/tts_default_rate_title"
android:summary="@string/tts_default_rate_summary"
android:defaultValue="50"
- android:max="600"
- android:layout="@layout/preference_iconless_slider" />
+ android:max="600"/>
<com.android.settings.SeekBarPreference
android:key="tts_default_pitch"
android:title="@string/tts_default_pitch_title"
android:summary="@string/tts_default_pitch_summary"
android:defaultValue="100"
- android:max="400"
- android:layout="@layout/preference_iconless_slider" />
+ android:max="400"/>
<Preference android:key="reset_speech_rate"
android:persistent="false"
diff --git a/src/com/android/settings/DeviceInfoSettings.java b/src/com/android/settings/DeviceInfoSettings.java
index ec34947..0da44cd 100644
--- a/src/com/android/settings/DeviceInfoSettings.java
+++ b/src/com/android/settings/DeviceInfoSettings.java
@@ -28,6 +28,7 @@
import android.os.UserManager;
import android.provider.SearchIndexableResource;
import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.text.TextUtils;
@@ -38,6 +39,7 @@
import com.android.settings.deviceinfo.AdditionalSystemUpdatePreferenceController;
import com.android.settings.deviceinfo.BuildNumberPreferenceController;
import com.android.settings.deviceinfo.SystemUpdatePreferenceController;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settingslib.DeviceInfoUtils;
@@ -55,6 +57,7 @@
private static final String KEY_MANUAL = "manual";
private static final String KEY_REGULATORY_INFO = "regulatory_info";
+ private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings";
private static final String PROPERTY_URL_SAFETYLEGAL = "ro.url.safetylegal";
private static final String PROPERTY_SELINUX_STATUS = "ro.build.selinux";
private static final String KEY_KERNEL_VERSION = "kernel_version";
@@ -102,7 +105,6 @@
super.onCreate(icicle);
final Activity activity = getActivity();
mUm = UserManager.get(activity);
- mSystemUpdatePreferenceController = new SystemUpdatePreferenceController(activity, mUm);
mAdditionalSystemUpdatePreferenceController =
new AdditionalSystemUpdatePreferenceController(activity);
mBuildNumberPreferenceController =
@@ -160,7 +162,7 @@
* Settings is a generic app and should not contain any device-specific
* info.
*/
- mSystemUpdatePreferenceController.displayPreference(getPreferenceScreen());
+ displaySystemUpdates(activity);
mAdditionalSystemUpdatePreferenceController.displayPreference(getPreferenceScreen());
// Remove manual entry if none present.
@@ -220,10 +222,23 @@
} else if (preference.getKey().equals(KEY_DEVICE_FEEDBACK)) {
sendFeedback();
}
- mSystemUpdatePreferenceController.handlePreferenceTreeClick(preference);
+ if (mSystemUpdatePreferenceController != null) {
+ mSystemUpdatePreferenceController.handlePreferenceTreeClick(preference);
+ }
return super.onPreferenceTreeClick(preference);
}
+ @VisibleForTesting
+ void displaySystemUpdates(Context context) {
+ if (!FeatureFactory.getFactory(context).getDashboardFeatureProvider(context).isEnabled()) {
+ mSystemUpdatePreferenceController
+ = new SystemUpdatePreferenceController(context, UserManager.get(context));
+ mSystemUpdatePreferenceController.displayPreference(getPreferenceScreen());
+ } else {
+ getPreferenceScreen().removePreference(findPreference(KEY_SYSTEM_UPDATE_SETTINGS));
+ }
+ }
+
private void removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup,
String preference, String property ) {
if (SystemProperties.get(property).equals("")) {
diff --git a/src/com/android/settings/SeekBarPreference.java b/src/com/android/settings/SeekBarPreference.java
index ef28ed7..26b69db 100644
--- a/src/com/android/settings/SeekBarPreference.java
+++ b/src/com/android/settings/SeekBarPreference.java
@@ -20,6 +20,7 @@
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.v4.content.res.TypedArrayUtils;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
@@ -64,7 +65,9 @@
}
public SeekBarPreference(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.seekBarPreferenceStyle);
+ this(context, attrs, TypedArrayUtils.getAttr(context,
+ android.support.v7.preference.R.attr.seekBarPreferenceStyle,
+ com.android.internal.R.attr.seekBarPreferenceStyle));
}
public SeekBarPreference(Context context) {
diff --git a/src/com/android/settings/SettingsDumpService.java b/src/com/android/settings/SettingsDumpService.java
index 472a2eb..67a8f50 100644
--- a/src/com/android/settings/SettingsDumpService.java
+++ b/src/com/android/settings/SettingsDumpService.java
@@ -16,14 +16,18 @@
import android.app.Service;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.net.ConnectivityManager;
import android.net.NetworkTemplate;
+import android.net.Uri;
import android.os.IBinder;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.applications.ProcStatsData;
import com.android.settingslib.net.DataUsageController;
import org.json.JSONArray;
@@ -35,6 +39,13 @@
import java.io.PrintWriter;
public class SettingsDumpService extends Service {
+ @VisibleForTesting static final String KEY_SERVICE = "service";
+ @VisibleForTesting static final String KEY_STORAGE = "storage";
+ @VisibleForTesting static final String KEY_DATAUSAGE = "datausage";
+ @VisibleForTesting static final String KEY_MEMORY = "memory";
+ @VisibleForTesting static final String KEY_DEFAULT_BROWSER_APP = "default_browser_app";
+ @VisibleForTesting static final Intent BROWSER_INTENT =
+ new Intent("android.intent.action.VIEW", Uri.parse("http://"));
@Override
public IBinder onBind(Intent intent) {
@@ -46,10 +57,11 @@
JSONObject dump = new JSONObject();
try {
- dump.put("service", "Settings State");
- dump.put("storage", dumpStorage());
- dump.put("datausage", dumpDataUsage());
- dump.put("memory", dumpMemory());
+ dump.put(KEY_SERVICE, "Settings State");
+ dump.put(KEY_STORAGE, dumpStorage());
+ dump.put(KEY_DATAUSAGE, dumpDataUsage());
+ dump.put(KEY_MEMORY, dumpMemory());
+ dump.put(KEY_DEFAULT_BROWSER_APP, dumpDefaultBrowser());
} catch (Exception e) {
e.printStackTrace();
}
@@ -127,4 +139,16 @@
}
return obj;
}
+
+ @VisibleForTesting
+ String dumpDefaultBrowser() {
+ final ResolveInfo resolveInfo = getPackageManager().resolveActivity(
+ BROWSER_INTENT, PackageManager.MATCH_DEFAULT_ONLY);
+
+ if (resolveInfo == null || resolveInfo.activityInfo.packageName.equals("android")) {
+ return null;
+ } else {
+ return resolveInfo.activityInfo.packageName;
+ }
+ }
}
diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java
index 5c18d66..2a1341e 100644
--- a/src/com/android/settings/bluetooth/BluetoothSettings.java
+++ b/src/com/android/settings/bluetooth/BluetoothSettings.java
@@ -27,7 +27,7 @@
import android.content.res.Resources;
import android.os.Bundle;
import android.provider.Settings;
-import android.support.v7.preference.Preference;
+import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
@@ -58,6 +58,7 @@
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Set;
@@ -105,7 +106,7 @@
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
final int state =
- intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
+ intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
if (action.equals(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)) {
updateDeviceName(context);
@@ -122,8 +123,8 @@
final Locale locale = res.getConfiguration().getLocales().get(0);
final BidiFormatter bidiFormatter = BidiFormatter.getInstance(locale);
mMyDevicePreference.setTitle(res.getString(
- R.string.bluetooth_is_visible_message,
- bidiFormatter.unicodeWrap(mLocalAdapter.getName())));
+ R.string.bluetooth_is_visible_message,
+ bidiFormatter.unicodeWrap(mLocalAdapter.getName())));
}
}
};
@@ -230,7 +231,7 @@
boolean bluetoothIsEnabled = mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON;
boolean isDiscovering = mLocalAdapter.isDiscovering();
int textId = isDiscovering ? R.string.bluetooth_searching_for_devices :
- R.string.bluetooth_search_for_devices;
+ R.string.bluetooth_search_for_devices;
menu.add(Menu.NONE, MENU_ID_SCAN, 0, textId)
.setEnabled(bluetoothIsEnabled && !isDiscovering)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
@@ -356,8 +357,8 @@
final Locale locale = res.getConfiguration().getLocales().get(0);
final BidiFormatter bidiFormatter = BidiFormatter.getInstance(locale);
mMyDevicePreference.setTitle(res.getString(
- R.string.bluetooth_is_visible_message,
- bidiFormatter.unicodeWrap(mLocalAdapter.getName())));
+ R.string.bluetooth_is_visible_message,
+ bidiFormatter.unicodeWrap(mLocalAdapter.getName())));
getActivity().invalidateOptionsMenu();
@@ -438,8 +439,9 @@
super.onBluetoothStateChanged(bluetoothState);
// If BT is turned off/on staying in the same BT Settings screen
// discoverability to be set again
- if (BluetoothAdapter.STATE_ON == bluetoothState)
+ if (BluetoothAdapter.STATE_ON == bluetoothState) {
mInitiateDiscoverable = true;
+ }
updateContent(bluetoothState);
}
@@ -481,6 +483,7 @@
/**
* Add a listener, which enables the advanced settings icon.
+ *
* @param preference the newly added preference
*/
@Override
@@ -497,7 +500,8 @@
return R.string.help_url_bluetooth;
}
- private static class SummaryProvider
+ @VisibleForTesting
+ static class SummaryProvider
implements SummaryLoader.SummaryProvider, BluetoothCallback {
private final LocalBluetoothManager mBluetoothManager;
@@ -505,10 +509,11 @@
private final SummaryLoader mSummaryLoader;
private boolean mEnabled;
- private boolean mConnected;
+ private int mConnectionState;
- public SummaryProvider(Context context, SummaryLoader summaryLoader) {
- mBluetoothManager = Utils.getLocalBtManager(context);
+ public SummaryProvider(Context context, SummaryLoader summaryLoader,
+ LocalBluetoothManager bluetoothManager) {
+ mBluetoothManager = bluetoothManager;
mContext = context;
mSummaryLoader = summaryLoader;
}
@@ -519,8 +524,7 @@
if (defaultAdapter == null) return;
if (listening) {
mEnabled = defaultAdapter.isEnabled();
- mConnected =
- defaultAdapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED;
+ mConnectionState = defaultAdapter.getConnectionState();
mSummaryLoader.setSummary(this, getSummary());
mBluetoothManager.getEventManager().registerCallback(this);
} else {
@@ -529,20 +533,26 @@
}
private CharSequence getSummary() {
- return mContext.getString(!mEnabled ? R.string.bluetooth_disabled
- : mConnected ? R.string.bluetooth_connected
- : R.string.bluetooth_disconnected);
+ if (!mEnabled) {
+ return mContext.getString(R.string.bluetooth_disabled);
+ } else if (mConnectionState == BluetoothAdapter.STATE_CONNECTED) {
+ return mContext.getString(R.string.bluetooth_connected);
+ } else {
+ return mContext.getString(R.string.bluetooth_disconnected);
+ }
}
@Override
public void onBluetoothStateChanged(int bluetoothState) {
- mEnabled = bluetoothState == BluetoothAdapter.STATE_ON;
+ mEnabled = bluetoothState == BluetoothAdapter.STATE_ON
+ || bluetoothState == BluetoothAdapter.STATE_TURNING_ON;
mSummaryLoader.setSummary(this, getSummary());
}
@Override
public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
- mConnected = state == BluetoothAdapter.STATE_CONNECTED;
+ mConnectionState = state;
+ updateConnected();
mSummaryLoader.setSummary(this, getSummary());
}
@@ -565,49 +575,84 @@
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
}
+
+ private void updateConnected() {
+ // Make sure our connection state is up to date.
+ int state = mBluetoothManager.getBluetoothAdapter().getConnectionState();
+ if (state != mConnectionState) {
+ mConnectionState = state;
+ return;
+ }
+ final Collection<CachedBluetoothDevice> devices = getDevices();
+ if (devices == null) {
+ mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
+ return;
+ }
+ if (mConnectionState == BluetoothAdapter.STATE_CONNECTED) {
+ CachedBluetoothDevice connectedDevice = null;
+ for (CachedBluetoothDevice device : devices) {
+ if (device.isConnected()) {
+ connectedDevice = device;
+ }
+ }
+ if (connectedDevice == null) {
+ // If somehow we think we are connected, but have no connected devices, we
+ // aren't connected.
+ mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
+ }
+ }
+ }
+
+ private Collection<CachedBluetoothDevice> getDevices() {
+ return mBluetoothManager != null
+ ? mBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()
+ : null;
+ }
}
public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
= new SummaryLoader.SummaryProviderFactory() {
@Override
public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity,
- SummaryLoader summaryLoader) {
- return new SummaryProvider(activity, summaryLoader);
+ SummaryLoader summaryLoader) {
+
+ return new SummaryProvider(activity, summaryLoader, Utils.getLocalBtManager(activity));
}
};
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider() {
- @Override
- public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
+ new BaseSearchIndexProvider() {
+ @Override
+ public List<SearchIndexableRaw> getRawDataToIndex(Context context,
+ boolean enabled) {
- final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
+ final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
- final Resources res = context.getResources();
+ final Resources res = context.getResources();
- // Add fragment title
- SearchIndexableRaw data = new SearchIndexableRaw(context);
- data.title = res.getString(R.string.bluetooth_settings);
- data.screenTitle = res.getString(R.string.bluetooth_settings);
- result.add(data);
+ // Add fragment title
+ SearchIndexableRaw data = new SearchIndexableRaw(context);
+ data.title = res.getString(R.string.bluetooth_settings);
+ data.screenTitle = res.getString(R.string.bluetooth_settings);
+ result.add(data);
- // Add cached paired BT devices
- LocalBluetoothManager lbtm = Utils.getLocalBtManager(context);
- // LocalBluetoothManager.getInstance can return null if the device does not
- // support bluetooth (e.g. the emulator).
- if (lbtm != null) {
- Set<BluetoothDevice> bondedDevices =
- lbtm.getBluetoothAdapter().getBondedDevices();
+ // Add cached paired BT devices
+ LocalBluetoothManager lbtm = Utils.getLocalBtManager(context);
+ // LocalBluetoothManager.getInstance can return null if the device does not
+ // support bluetooth (e.g. the emulator).
+ if (lbtm != null) {
+ Set<BluetoothDevice> bondedDevices =
+ lbtm.getBluetoothAdapter().getBondedDevices();
- for (BluetoothDevice device : bondedDevices) {
- data = new SearchIndexableRaw(context);
- data.title = device.getName();
- data.screenTitle = res.getString(R.string.bluetooth_settings);
- data.enabled = enabled;
- result.add(data);
+ for (BluetoothDevice device : bondedDevices) {
+ data = new SearchIndexableRaw(context);
+ data.title = device.getName();
+ data.screenTitle = res.getString(R.string.bluetooth_settings);
+ data.enabled = enabled;
+ result.add(data);
+ }
}
+ return result;
}
- return result;
- }
- };
+ };
}
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index ab1ec13..9afe4b2 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -330,5 +330,6 @@
mDashboardTilePrefKeys.remove(key);
mProgressiveDisclosureMixin.removePreference(screen, key);
}
+ mSummaryLoader.setListening(true);
}
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 14e6693..c4b97d4 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -30,6 +30,7 @@
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.text.TextUtils;
+import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.Menu;
@@ -359,10 +360,8 @@
userHandle);
final CharSequence contentDescription = mUm.getBadgedLabelForUser(entry.getLabel(),
userHandle);
- final String key = sipper.drainType == DrainType.APP ? sipper.getPackages() != null
- ? TextUtils.concat(sipper.getPackages()).toString()
- : String.valueOf(sipper.getUid())
- : sipper.drainType.toString();
+
+ final String key = extractKeyFromSipper(sipper);
PowerGaugePreference pref = (PowerGaugePreference) getCachedPreference(key);
if (pref == null) {
pref = new PowerGaugePreference(getPrefContext(), badgedIcon,
@@ -376,9 +375,6 @@
pref.setTitle(entry.getLabel());
pref.setOrder(i + 1);
pref.setPercent(percentOfMax, percentOfTotal);
- if (sipper.uidObj != null) {
- pref.setKey(Integer.toString(sipper.uidObj.getUid()));
- }
if ((sipper.drainType != DrainType.APP || sipper.uidObj.getUid() == 0)
&& sipper.drainType != DrainType.USER) {
pref.setTint(colorControl);
@@ -399,6 +395,20 @@
BatteryEntry.startRequestQueue();
}
+ @VisibleForTesting
+ String extractKeyFromSipper(BatterySipper sipper) {
+ if (sipper.uidObj != null) {
+ return Integer.toString(sipper.getUid());
+ } else if (sipper.drainType != DrainType.APP) {
+ return sipper.drainType.toString();
+ } else if (sipper.getPackages() != null) {
+ return TextUtils.concat(sipper.getPackages()).toString();
+ } else {
+ Log.w(TAG, "Inappropriate BatterySipper without uid and package names: " + sipper);
+ return "-1";
+ }
+ }
+
private static List<BatterySipper> getFakeStats() {
ArrayList<BatterySipper> stats = new ArrayList<>();
float use = 5;
diff --git a/src/com/android/settings/search/Index.java b/src/com/android/settings/search/Index.java
index bff841b..cd6e562 100644
--- a/src/com/android/settings/search/Index.java
+++ b/src/com/android/settings/search/Index.java
@@ -217,20 +217,20 @@
*/
public static Index getInstance(Context context) {
if (sInstance == null) {
- sInstance = new Index(context.getApplicationContext(), BASE_AUTHORITY);
+ synchronized (Index.class) {
+ if (sInstance == null) {
+ sInstance = new Index(context.getApplicationContext(), BASE_AUTHORITY);
+ }
+ }
}
return sInstance;
}
- public Index(Context context, String baseAuthority) {
+ private Index(Context context, String baseAuthority) {
mContext = context;
mBaseAuthority = baseAuthority;
}
- public void setContext(Context context) {
- mContext = context;
- }
-
public boolean isAvailable() {
return mIsAvailable.get();
}
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index 567ae95..a794953 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -54,6 +54,7 @@
import android.view.View.OnClickListener;
import android.widget.SimpleAdapter;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.ChooseLockGeneric;
@@ -66,6 +67,7 @@
import com.android.settings.accounts.AddUserWhenLockedPreferenceController;
import com.android.settings.accounts.EmergencyInfoPreferenceController;
import com.android.settings.dashboard.SummaryLoader;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;
@@ -137,6 +139,7 @@
private UserPreference mMePreference;
private DimmableIconPreference mAddUser;
private PreferenceGroup mLockScreenSettings;
+ private RestrictedSwitchPreference mAddUserWhenLocked;
private Preference mEmergencyInfoPreference;
private int mRemovingUserId = -1;
private int mAddedUserId = 0;
@@ -235,10 +238,14 @@
mAddUser.setTitle(R.string.user_add_user_menu);
}
}
- mLockScreenSettings = (PreferenceGroup) findPreference("lock_screen_settings");
- mEmergencyInfoPreference = findPreference(KEY_EMERGENCY_INFO);
- mEnergencyInfoController = new EmergencyInfoPreferenceController(context);
- mAddUserWhenLockedController = new AddUserWhenLockedPreferenceController(context);
+ if (showEmergencyInfoAndAddUsersWhenLock(context)) {
+ mLockScreenSettings = (PreferenceGroup) findPreference("lock_screen_settings");
+ mAddUserWhenLocked =
+ (RestrictedSwitchPreference) findPreference("add_users_when_locked");
+ mEmergencyInfoPreference = findPreference(KEY_EMERGENCY_INFO);
+ mEnergencyInfoController = new EmergencyInfoPreferenceController(context);
+ mAddUserWhenLockedController = new AddUserWhenLockedPreferenceController(context);
+ }
setHasOptionsMenu(true);
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
@@ -653,6 +660,11 @@
}
}
+ @VisibleForTesting
+ boolean showEmergencyInfoAndAddUsersWhenLock(Context context) {
+ return !FeatureFactory.getFactory(context).getDashboardFeatureProvider(context).isEnabled();
+ }
+
private static boolean emergencyInfoActivityPresent(Context context) {
Intent intent = new Intent(ACTION_EDIT_EMERGENCY_INFO).setPackage("com.android.emergency");
List<ResolveInfo> infos = context.getPackageManager().queryIntentActivities(intent, 0);
@@ -893,15 +905,19 @@
}
}
- if (mAddUserWhenLockedController.isAvailable()) {
- mLockScreenSettings.setOrder(Preference.DEFAULT_ORDER);
- preferenceScreen.addPreference(mLockScreenSettings);
- }
+ if (showEmergencyInfoAndAddUsersWhenLock(context)) {
+ if (mAddUserWhenLockedController.isAvailable()) {
+ mLockScreenSettings.setOrder(Preference.DEFAULT_ORDER);
+ preferenceScreen.addPreference(mLockScreenSettings);
+ mAddUserWhenLockedController.updateState(mAddUserWhenLocked);
+ mAddUserWhenLocked.setOnPreferenceChangeListener(mAddUserWhenLockedController);
+ }
- if (emergencyInfoActivityPresent(getContext())) {
- mEmergencyInfoPreference.setOnPreferenceClickListener(this);
- mEmergencyInfoPreference.setOrder(Preference.DEFAULT_ORDER);
- preferenceScreen.addPreference(mEmergencyInfoPreference);
+ if (emergencyInfoActivityPresent(getContext())) {
+ mEmergencyInfoPreference.setOnPreferenceClickListener(this);
+ mEmergencyInfoPreference.setOrder(Preference.DEFAULT_ORDER);
+ preferenceScreen.addPreference(mEmergencyInfoPreference);
+ }
}
}
@@ -983,7 +999,7 @@
} else {
onAddUserClicked(USER_TYPE_USER);
}
- } else {
+ } else if (mEnergencyInfoController != null) {
mEnergencyInfoController.handlePreferenceTreeClick(pref);
}
return false;
diff --git a/tests/robotests/src/com/android/settings/DeviceInfoSettingsTest.java b/tests/robotests/src/com/android/settings/DeviceInfoSettingsTest.java
index c66c2b4..c3365b8 100644
--- a/tests/robotests/src/com/android/settings/DeviceInfoSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/DeviceInfoSettingsTest.java
@@ -16,17 +16,56 @@
package com.android.settings;
+import android.content.Context;
+import android.os.UserManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+
import com.android.settingslib.DeviceInfoUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class DeviceInfoSettingsTest extends AndroidTestCase {
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Context mContext;
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private UserManager mUserManager;
+
+ private FakeFeatureFactory mFeatureFactory;
+ private DeviceInfoSettings mSettings;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ FakeFeatureFactory.setupForTest(mContext);
+ mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ mSettings = spy(new DeviceInfoSettings());
+ doReturn(mScreen).when(mSettings).getPreferenceScreen();
+ }
+
@Test
public void testGetFormattedKernelVersion() throws Exception {
if ("Unavailable".equals(DeviceInfoUtils.getFormattedKernelVersion())) {
@@ -65,4 +104,20 @@
"version 3.8.275480 (based on LLVM 3.8.275480)) " +
"#5 SMP PREEMPT Fri Oct 28 14:38:13 PDT 2016"));
}
+
+ @Test
+ public void testShowSystemUpdatesWhenIADisabled() throws Exception {
+ when(mFeatureFactory.dashboardFeatureProvider.isEnabled()).thenReturn(true);
+ mSettings.displaySystemUpdates(mContext);
+
+ verify(mScreen).removePreference(any(Preference.class));
+ }
+
+ @Test
+ public void testHideSystemUpdatesWhenIAEnabled() throws Exception {
+ when(mFeatureFactory.dashboardFeatureProvider.isEnabled()).thenReturn(false);
+ mSettings.displaySystemUpdates(mContext);
+
+ verify(mScreen, never()).removePreference(any(Preference.class));
+ }
}
diff --git a/tests/robotests/src/com/android/settings/SettingsDumpServiceTest.java b/tests/robotests/src/com/android/settings/SettingsDumpServiceTest.java
new file mode 100644
index 0000000..043b0fe
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/SettingsDumpServiceTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 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.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.support.annotation.NonNull;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SettingsDumpServiceTest {
+ private static final String PACKAGE_BROWSER = "com.android.test.browser";
+ private static final String PACKAGE_NULL = "android";
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private ResolveInfo mResolveInfo;
+ private TestService mTestService;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mPackageManager.resolveActivity(TestService.BROWSER_INTENT,
+ PackageManager.MATCH_DEFAULT_ONLY)).thenReturn(mResolveInfo);
+ mTestService = new TestService();
+ mTestService.setPackageManager(mPackageManager);
+ }
+
+ @Test
+ public void testDumpDefaultBrowser_DefaultBrowser_ReturnBrowserName() {
+ mResolveInfo.activityInfo = new ActivityInfo();
+ mResolveInfo.activityInfo.packageName = PACKAGE_BROWSER;
+
+ assertThat(mTestService.dumpDefaultBrowser()).isEqualTo(PACKAGE_BROWSER);
+ }
+
+ @Test
+ public void testDumpDefaultBrowser_NoDefault_ReturnNull() {
+ mResolveInfo.activityInfo = new ActivityInfo();
+ mResolveInfo.activityInfo.packageName = PACKAGE_NULL;
+
+ assertThat(mTestService.dumpDefaultBrowser()).isEqualTo(null);
+ }
+
+ @Test
+ public void testDump_ReturnJsonObject() throws JSONException {
+ mResolveInfo.activityInfo = new ActivityInfo();
+ mResolveInfo.activityInfo.packageName = PACKAGE_BROWSER;
+ TestPrintWriter printWriter = new TestPrintWriter(System.out);
+
+ mTestService.dump(null, printWriter, null);
+ JSONObject object = (JSONObject)printWriter.getPrintObject();
+
+ assertThat(object.get(TestService.KEY_SERVICE)).isNotNull();
+ }
+
+ /**
+ * Test service used to pass in the mock {@link PackageManager}
+ */
+ private class TestService extends SettingsDumpService {
+ private PackageManager mPm;
+
+ public void setPackageManager(PackageManager pm) {
+ mPm = pm;
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ return mPm;
+ }
+ }
+
+ /**
+ * Test printWriter to store the object to be printed
+ */
+ private class TestPrintWriter extends PrintWriter {
+ private Object mPrintObject;
+
+ public TestPrintWriter(@NonNull OutputStream out) {
+ super(out);
+ }
+
+ @Override
+ public void println(Object object) {
+ mPrintObject = object;
+ }
+
+ public Object getPrintObject() {
+ return mPrintObject;
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothSettingsSummaryProviderTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSettingsSummaryProviderTest.java
new file mode 100644
index 0000000..7ac7cb1
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSettingsSummaryProviderTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 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.bluetooth.BluetoothAdapter;
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.dashboard.SummaryLoader;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowBluetoothAdapter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class BluetoothSettingsSummaryProviderTest {
+
+ private Context mContext;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private LocalBluetoothManager mBluetoothManager;
+ @Mock
+ private SummaryLoader mSummaryLoader;
+
+ private BluetoothSettings.SummaryProvider mSummaryProvider;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application.getApplicationContext();
+ mSummaryProvider = new BluetoothSettings.SummaryProvider(mContext, mSummaryLoader,
+ mBluetoothManager);
+ }
+
+ @Test
+ public void setListening_shouldUpdateSummary() {
+ mSummaryProvider.setListening(true);
+
+ verify(mBluetoothManager.getEventManager()).registerCallback(mSummaryProvider);
+ verify(mSummaryLoader).setSummary(eq(mSummaryProvider), anyString());
+ }
+
+ @Test
+ public void setNotListening_shouldUnregister() {
+ mSummaryProvider.setListening(false);
+
+ verify(mBluetoothManager.getEventManager()).unregisterCallback(mSummaryProvider);
+ }
+
+ @Test
+ public void updateSummary_btDisabled_shouldShowDisabledMessage() {
+ ShadowBluetoothAdapter.getDefaultAdapter().disable();
+ mSummaryProvider.setListening(true);
+
+ verify(mSummaryLoader).setSummary(mSummaryProvider,
+ mContext.getString(R.string.bluetooth_disabled));
+ }
+
+ @Test
+ public void updateSummary_btEnabled_noDevice_shouldShowDisconnectedMessage() {
+ ShadowBluetoothAdapter.getDefaultAdapter().enable();
+ mSummaryProvider.setListening(true);
+
+ verify(mSummaryLoader).setSummary(mSummaryProvider,
+ mContext.getString(R.string.bluetooth_disconnected));
+ }
+
+ @Test
+ public void updateState_btEnabled_noDevice_shouldShowDisconnectedMessage() {
+ ShadowBluetoothAdapter.getDefaultAdapter().enable();
+ mSummaryProvider.onBluetoothStateChanged(BluetoothAdapter.STATE_TURNING_ON);
+
+ verify(mSummaryLoader).setSummary(mSummaryProvider,
+ mContext.getString(R.string.bluetooth_disconnected));
+ }
+
+ @Test
+ public void updateState_btDisabled_shouldShowDisabledMessage() {
+ ShadowBluetoothAdapter.getDefaultAdapter().enable();
+ mSummaryProvider.onBluetoothStateChanged(BluetoothAdapter.STATE_TURNING_OFF);
+
+ verify(mSummaryLoader).setSummary(mSummaryProvider,
+ mContext.getString(R.string.bluetooth_disabled));
+ }
+
+ @Test
+ public void updateConnectionState_disconnected_shouldShowDisconnectedMessage() {
+ ShadowBluetoothAdapter.getDefaultAdapter().enable();
+ when(mBluetoothManager.getBluetoothAdapter().getConnectionState())
+ .thenReturn(BluetoothAdapter.STATE_DISCONNECTED);
+
+ mSummaryProvider.setListening(true);
+ mSummaryProvider.onConnectionStateChanged(null /* device */,
+ BluetoothAdapter.STATE_DISCONNECTED);
+
+ verify(mSummaryLoader, times(2)).setSummary(mSummaryProvider,
+ mContext.getString(R.string.bluetooth_disconnected));
+ }
+
+
+ @Test
+ public void updateConnectionState_connected_shouldShowConnectedMessage() {
+ ShadowBluetoothAdapter.getDefaultAdapter().enable();
+ when(mBluetoothManager.getBluetoothAdapter().getConnectionState())
+ .thenReturn(BluetoothAdapter.STATE_CONNECTED);
+ final List<CachedBluetoothDevice> devices = new ArrayList<>();
+ devices.add(mock(CachedBluetoothDevice.class));
+ when(devices.get(0).isConnected()).thenReturn(true);
+ when(mBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy())
+ .thenReturn(devices);
+
+ mSummaryProvider.setListening(true);
+ mSummaryProvider.onConnectionStateChanged(null /* device */,
+ BluetoothAdapter.STATE_CONNECTED);
+
+ verify(mSummaryLoader).setSummary(mSummaryProvider,
+ mContext.getString(R.string.bluetooth_connected));
+ }
+
+ @Test
+ public void updateConnectionState_inconsistentState_shouldShowDisconnectedMessage() {
+ ShadowBluetoothAdapter.getDefaultAdapter().enable();
+ when(mBluetoothManager.getBluetoothAdapter().getConnectionState())
+ .thenReturn(BluetoothAdapter.STATE_CONNECTED);
+
+ mSummaryProvider.setListening(true);
+ mSummaryProvider.onConnectionStateChanged(null /* device */,
+ BluetoothAdapter.STATE_CONNECTED);
+
+ verify(mSummaryLoader, times(2)).setSummary(mSummaryProvider,
+ mContext.getString(R.string.bluetooth_disconnected));
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
index ff84741..1cf83f1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
@@ -1,10 +1,28 @@
+/*
+ * Copyright (C) 2016 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.fuelgauge;
import android.content.Context;
import android.content.Intent;
+import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import com.android.internal.os.BatterySipper;
+import com.android.internal.os.BatteryStatsImpl;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.testutils.FakeFeatureFactory;
@@ -32,6 +50,8 @@
@RunWith(RobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class PowerUsageSummaryTest {
+ private static final String[] PACKAGE_NAMES = {"com.app1", "com.app2"};
+ private static final int UID = 123;
private static final Intent ADDITIONAL_BATTERY_INFO_INTENT =
new Intent("com.example.app.ADDITIONAL_BATTERY_INFO");
@@ -46,13 +66,17 @@
private MenuItem mAdditionalBatteryInfoMenu;
@Mock
private MenuInflater mMenuInflater;
+ @Mock
+ private BatterySipper mBatterySipper;
private TestFragment mFragment;
private FakeFeatureFactory mFeatureFactory;
+ private PowerUsageSummary mPowerUsageSummary;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+
FakeFeatureFactory.setupForTest(mContext);
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
@@ -67,6 +91,11 @@
.thenReturn(MENU_ADDITIONAL_BATTERY_INFO);
when(mFeatureFactory.powerUsageFeatureProvider.getAdditionalBatteryInfoIntent())
.thenReturn(ADDITIONAL_BATTERY_INFO_INTENT);
+
+ mPowerUsageSummary = new PowerUsageSummary();
+
+ when(mBatterySipper.getPackages()).thenReturn(PACKAGE_NAMES);
+ when(mBatterySipper.getUid()).thenReturn(UID);
}
@Test
@@ -96,6 +125,33 @@
Menu.NONE, R.string.additional_battery_info);
}
+ @Test
+ public void testExtractKeyFromSipper_TypeAPPUidObjectNull_ReturnPackageNames() {
+ mBatterySipper.uidObj = null;
+ mBatterySipper.drainType = BatterySipper.DrainType.APP;
+
+ final String key = mPowerUsageSummary.extractKeyFromSipper(mBatterySipper);
+ assertThat(key).isEqualTo(TextUtils.concat(mBatterySipper.getPackages()).toString());
+ }
+
+ @Test
+ public void testExtractKeyFromSipper_TypeOther_ReturnDrainType() {
+ mBatterySipper.uidObj = null;
+ mBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
+
+ final String key = mPowerUsageSummary.extractKeyFromSipper(mBatterySipper);
+ assertThat(key).isEqualTo(mBatterySipper.drainType.toString());
+ }
+
+ @Test
+ public void testExtractKeyFromSipper_TypeAPPUidObjectNotNull_ReturnUid() {
+ mBatterySipper.uidObj = new BatteryStatsImpl.Uid(new BatteryStatsImpl(), UID);
+ mBatterySipper.drainType = BatterySipper.DrainType.APP;
+
+ final String key = mPowerUsageSummary.extractKeyFromSipper(mBatterySipper);
+ assertThat(key).isEqualTo(Integer.toString(mBatterySipper.getUid()));
+ }
+
public static class TestFragment extends PowerUsageSummary {
private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/users/UserSettingsTest.java b/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
new file mode 100644
index 0000000..005ac19
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/users/UserSettingsTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 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.users;
+
+import android.content.Context;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class UserSettingsTest {
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Context mContext;
+
+ private FakeFeatureFactory mFeatureFactory;
+ private UserSettings mSetting;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ FakeFeatureFactory.setupForTest(mContext);
+ mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
+ mSetting = new UserSettings();
+ }
+
+ @Test
+ public void testShowEmergencyInfoAndAddUsers_IAEnabled_shouldReturnFalse() {
+ when(mFeatureFactory.dashboardFeatureProvider.isEnabled()).thenReturn(true);
+ assertThat(mSetting.showEmergencyInfoAndAddUsersWhenLock(mContext)).isFalse();
+ }
+
+ @Test
+ public void testShowEmergencyInfoAndAddUsers_IADisabled_shouldReturnTrue() {
+ when(mFeatureFactory.dashboardFeatureProvider.isEnabled()).thenReturn(false);
+ assertThat(mSetting.showEmergencyInfoAndAddUsersWhenLock(mContext)).isTrue();
+ }
+
+}