Merge "Don't drop log about excessive O anomaly." into pi-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 5dd22c2..74a18ea 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3137,6 +3137,8 @@
android:value="com.android.settings.accounts.AccountDashboardFragment"/>
<meta-data android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.homepage"/>
+ <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+ android:value="true" />
</activity>
<activity
diff --git a/res/layout/condition_header.xml b/res/layout/condition_header.xml
index 2551b65..f214319 100644
--- a/res/layout/condition_header.xml
+++ b/res/layout/condition_header.xml
@@ -71,7 +71,7 @@
android:singleLine="true"
android:ellipsize="end"
android:textAppearance="@style/TextAppearance.SuggestionTitle"
- android:textColor="?android:attr/colorAccent" />
+ android:textColor="?android:attr/textColorPrimary" />
<LinearLayout
android:id="@+id/additional_icons"
diff --git a/res/layout/ownerinfo.xml b/res/layout/ownerinfo.xml
index c5eaff5..29e0840 100644
--- a/res/layout/ownerinfo.xml
+++ b/res/layout/ownerinfo.xml
@@ -25,6 +25,7 @@
android:id="@+id/owner_info_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:minHeight="@dimen/min_tap_target_size"
android:gravity="top"
android:hint="@string/owner_info_settings_edit_text_hint"
android:inputType="textMultiLine|textCapSentences"
diff --git a/res/layout/radio_info.xml b/res/layout/radio_info.xml
index 502505c..0ec1f10 100644
--- a/res/layout/radio_info.xml
+++ b/res/layout/radio_info.xml
@@ -91,6 +91,30 @@
<TextView android:id="@+id/roaming" style="@style/info_value" />
</LinearLayout>
+ <!-- Link Bandwidth -->
+ <LinearLayout style="@style/entry_layout" android:orientation="horizontal">
+ <TextView android:text="@string/radio_info_dl_kbps" style="@style/info_label" />
+ <TextView android:id="@+id/dl_kbps" style="@style/info_value" />
+ </LinearLayout>
+
+ <!-- Link Bandwidth -->
+ <LinearLayout style="@style/entry_layout" android:orientation="horizontal">
+ <TextView android:text="@string/radio_info_ul_kbps" style="@style/info_label" />
+ <TextView android:id="@+id/ul_kbps" style="@style/info_value" />
+ </LinearLayout>
+
+ <!-- Physical Channel Config -->
+ <LinearLayout style="@style/entry_layout">
+ <TextView android:text="@string/radio_info_phy_chan_config" style="@style/info_label" />
+ <TextView android:id="@+id/phy_chan_config" style="@style/info_value" />
+ </LinearLayout>
+
+ <!-- Horizontal Rule -->
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:background="#000000" />
+
<!-- Preferred Network Type -->
<TextView
android:layout_width="match_parent"
diff --git a/res/layout/wifi_dialog.xml b/res/layout/wifi_dialog.xml
index 16c8c22..fe891e1 100644
--- a/res/layout/wifi_dialog.xml
+++ b/res/layout/wifi_dialog.xml
@@ -291,7 +291,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/wifi_item_content"
- android:textSize="14sp"
android:text="@string/wifi_show_password" />
</LinearLayout>
</LinearLayout>
diff --git a/res/values/config.xml b/res/values/config.xml
index e3ec74f..e204b7f 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -131,4 +131,7 @@
<!-- List of a11y components on the device allowed to be enabled by Settings Slices -->
<string-array name="config_settings_slices_accessibility_components" translatable="false"/>
+ <!-- Whether or not to show the night light suggestion. -->
+ <bool name="config_night_light_suggestion_enabled">true</bool>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ca11c9b..f617df1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -472,10 +472,16 @@
<string name="proxy_url_title">"PAC URL: "</string>
<!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
+ <string name="radio_info_dl_kbps">DL Bandwidth (kbps):</string>
+ <!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
+ <string name="radio_info_ul_kbps">UL Bandwidth (kbps):</string>
+ <!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="radio_info_signal_location_label">Cell Location Info (deprecated):</string>
<!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="radio_info_neighboring_location_label">Neighbor Cell Info (deprecated):</string>
<!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
+ <string name="radio_info_phy_chan_config">LTE Physical Channel Configuration:</string>
+ <!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="radio_info_cell_info_refresh_rate">Cell Info Refresh Rate:</string>
<!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="radio_info_cellinfo_label">All Cell Measurement Info:</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 763d8fa..8052616 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -200,6 +200,7 @@
<item name="android:textAlignment">viewStart</item>
<item name="android:textAppearance">@android:style/TextAppearance.Material.Subhead</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:minHeight">@dimen/min_tap_target_size</item>
</style>
<style name="wifi_item_spinner" parent="wifi_item_content">
@@ -219,6 +220,7 @@
<item name="android:layout_marginStart">4dip</item>
<item name="android:textSize">18sp</item>
<item name="android:textAlignment">viewStart</item>
+ <item name="android:minHeight">@dimen/min_tap_target_size</item>
</style>
<style name="wifi_section">
@@ -285,6 +287,7 @@
<item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
<item name="android:singleLine">true</item>
<item name="android:textAlignment">viewStart</item>
+ <item name="android:minHeight">@dimen/min_tap_target_size</item>
</style>
<style name="vpn_warning">
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 762b434..8c38649 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -284,6 +284,7 @@
<style name="Widget.SwitchBar.Switch" parent="@android:style/Widget.Material.CompoundButton.Switch">
<item name="android:trackTint">@color/switchbar_switch_track_tint</item>
<item name="android:thumbTint">@color/switchbar_switch_thumb_tint</item>
+ <item name="android:minHeight">@dimen/min_tap_target_size</item>
</style>
<style name="Theme.CryptKeeper" parent="@android:style/Theme.Material.NoActionBar">
diff --git a/res/xml/bluetooth_pairing_detail.xml b/res/xml/bluetooth_pairing_detail.xml
index e654a3c..86fb9e4 100644
--- a/res/xml/bluetooth_pairing_detail.xml
+++ b/res/xml/bluetooth_pairing_detail.xml
@@ -16,12 +16,14 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/bluetooth_pairing_pref_title">
<Preference
android:key="bt_pair_rename_devices"
android:title="@string/bluetooth_device_name"
- android:summary="@string/summary_placeholder" />
+ android:summary="@string/summary_placeholder"
+ settings:controller="com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController"/>
<com.android.settings.bluetooth.BluetoothProgressCategory
android:key="available_devices"
diff --git a/res/xml/bluetooth_screen.xml b/res/xml/bluetooth_screen.xml
index 9f09a8a..5679cd4 100644
--- a/res/xml/bluetooth_screen.xml
+++ b/res/xml/bluetooth_screen.xml
@@ -19,6 +19,12 @@
android:key="bluetooth_switchbar_screen"
android:title="@string/bluetooth_settings_title">
+ <Preference
+ android:key="bluetooth_screen_bt_pair_rename_devices"
+ android:title="@string/bluetooth_device_name"
+ android:summary="@string/summary_placeholder"
+ settings:controller="com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController"/>
+
<com.android.settingslib.RestrictedPreference
android:key="bluetooth_screen_add_bt_devices"
android:title="@string/bluetooth_pairing_pref_title"
diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml
index 6d25c58..54de927 100644
--- a/res/xml/connected_devices.xml
+++ b/res/xml/connected_devices.xml
@@ -46,22 +46,8 @@
android:title="@string/connected_device_previously_connected_title"
android:icon="@drawable/ic_devices_other_black"
android:fragment="com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment"
- settings:allowDividerAbove="true"/>
-
- <Preference
- android:fragment="com.android.settings.connecteddevice.BluetoothDashboardFragment"
- android:key="bluetooth_settings"
- android:title="@string/bluetooth_settings_title"
- android:icon="@drawable/ic_settings_bluetooth"/>
-
- <PreferenceCategory
- android:key="dashboard_tile_placeholder" />
-
- <SwitchPreference
- android:key="toggle_nfc"
- android:title="@string/nfc_quick_toggle_title"
- android:icon="@drawable/ic_nfc"
- android:summary="@string/nfc_quick_toggle_summary"/>
+ settings:allowDividerAbove="true"
+ settings:controller="com.android.settings.connecteddevice.PreviouslyConnectedDevicePreferenceController"/>
<Preference
android:key="connection_preferences"
diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml
index 1917df1..f81fd79 100644
--- a/res/xml/connected_devices_advanced.xml
+++ b/res/xml/connected_devices_advanced.xml
@@ -20,12 +20,26 @@
android:key="connected_devices_advanced_screen"
android:title="@string/connected_device_connections_title">
+ <Preference
+ android:fragment="com.android.settings.connecteddevice.BluetoothDashboardFragment"
+ android:key="bluetooth_settings"
+ android:title="@string/bluetooth_settings_title"
+ android:icon="@drawable/ic_settings_bluetooth"
+ android:order="-9"/>
+
+ <SwitchPreference
+ android:key="toggle_nfc"
+ android:title="@string/nfc_quick_toggle_title"
+ android:icon="@drawable/ic_nfc"
+ android:summary="@string/nfc_quick_toggle_summary"
+ android:order="-7"/>
+
<com.android.settingslib.RestrictedPreference
android:fragment="com.android.settings.nfc.AndroidBeam"
android:key="android_beam_settings"
android:title="@string/android_beam_settings_title"
android:icon="@drawable/ic_android"
- android:order="-4"/>
+ android:order="-6"/>
<SwitchPreference
android:key="bluetooth_on_while_driving"
@@ -33,7 +47,7 @@
android:icon="@drawable/ic_settings_bluetooth"
android:summary="@string/bluetooth_on_while_driving_summary"
settings:controller="com.android.settings.connecteddevice.BluetoothOnWhileDrivingPreferenceController"
- android:order="-2"/>
+ android:order="-4"/>
<com.android.settingslib.RestrictedPreference
android:key="connected_device_printing"
@@ -41,7 +55,7 @@
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_settings_print"
android:fragment="com.android.settings.print.PrintSettingsFragment"
- android:order="-1"/>
+ android:order="-3"/>
<Preference
android:key="bt_received_files"
@@ -50,6 +64,6 @@
<PreferenceCategory
android:key="dashboard_tile_placeholder"
- android:order="50"/>
+ android:order="-8"/>
</PreferenceScreen>
diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml
index a70c85d..353d1f1 100644
--- a/res/xml/sound_settings.xml
+++ b/res/xml/sound_settings.xml
@@ -109,8 +109,7 @@
android:dialogTitle="@string/ringtone_title"
android:summary="@string/summary_placeholder"
android:ringtoneType="ringtone"
- android:order="-100"
- settings:allowDividerAbove="true"/>
+ android:order="-100"/>
<!-- Default notification ringtone -->
<com.android.settings.DefaultRingtonePreference
diff --git a/src/com/android/settings/RadioInfo.java b/src/com/android/settings/RadioInfo.java
index b885483..170db16 100644
--- a/src/com/android/settings/RadioInfo.java
+++ b/src/com/android/settings/RadioInfo.java
@@ -16,6 +16,8 @@
package com.android.settings;
+import static android.net.ConnectivityManager.NetworkCallback;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -27,6 +29,10 @@
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Typeface;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.net.TrafficStats;
import android.net.Uri;
import android.os.AsyncResult;
@@ -52,12 +58,14 @@
import android.telephony.NeighboringCellInfo;
import android.telephony.PreciseCallState;
import android.telephony.PhoneStateListener;
+import android.telephony.PhysicalChannelConfig;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
+import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -193,7 +201,10 @@
private TextView mPingHostnameV4;
private TextView mPingHostnameV6;
private TextView mHttpClientTest;
+ private TextView mPhyChanConfig;
private TextView dnsCheckState;
+ private TextView mDownlinkKbps;
+ private TextView mUplinkKbps;
private EditText smsc;
private Switch radioPowerOnSwitch;
private Button cellInfoRefreshRateButton;
@@ -211,6 +222,7 @@
private Spinner preferredNetworkType;
private Spinner cellInfoRefreshRateSpinner;
+ private ConnectivityManager mConnectivityManager;
private TelephonyManager mTelephonyManager;
private ImsManager mImsManager = null;
private Phone phone = null;
@@ -228,6 +240,19 @@
private int mPreferredNetworkTypeResult;
private int mCellInfoRefreshRateIndex;
+ private final NetworkRequest mDefaultNetworkRequest = new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
+
+ private final NetworkCallback mNetworkCallback = new NetworkCallback() {
+ public void onCapabilitiesChanged(Network n, NetworkCapabilities nc) {
+ int dlbw = nc.getLinkDownstreamBandwidthKbps();
+ int ulbw = nc.getLinkUpstreamBandwidthKbps();
+ updateBandwidths(dlbw, ulbw);
+ }
+ };
+
private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onDataConnectionStateChanged(int state) {
@@ -295,8 +320,29 @@
updateNetworkType();
updateImsProvisionedState();
}
+
+ @Override
+ public void onPhysicalChannelConfigurationChanged(
+ List<PhysicalChannelConfig> configs) {
+ updatePhysicalChannelConfiguration(configs);
+ }
+
};
+ private void updatePhysicalChannelConfiguration(List<PhysicalChannelConfig> configs) {
+ StringBuilder sb = new StringBuilder();
+ String div = "";
+ sb.append("{");
+ if (configs != null) {
+ for(PhysicalChannelConfig c : configs) {
+ sb.append(div).append(c);
+ div = ",";
+ }
+ }
+ sb.append("}");
+ mPhyChanConfig.setText(sb.toString());
+ }
+
private void updatePreferredNetworkType(int type) {
if (type >= mPreferredNetworkLabels.length || type < 0) {
log("EVENT_QUERY_PREFERRED_TYPE_DONE: unknown " +
@@ -365,6 +411,7 @@
log("Started onCreate");
mTelephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
+ mConnectivityManager = (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);
phone = PhoneFactory.getDefaultPhone();
//TODO: Need to update this if the default phoneId changes?
@@ -399,6 +446,8 @@
mPingHostnameV6 = (TextView) findViewById(R.id.pingHostnameV6);
mHttpClientTest = (TextView) findViewById(R.id.httpClientTest);
+ mPhyChanConfig = (TextView) findViewById(R.id.phy_chan_config);
+
preferredNetworkType = (Spinner) findViewById(R.id.preferredNetworkType);
ArrayAdapter<String> adapter = new ArrayAdapter<String> (this,
android.R.layout.simple_spinner_item, mPreferredNetworkLabels);
@@ -418,6 +467,10 @@
radioPowerOnSwitch = (Switch) findViewById(R.id.radio_power);
+ mDownlinkKbps = (TextView) findViewById(R.id.dl_kbps);
+ mUplinkKbps = (TextView) findViewById(R.id.ul_kbps);
+ updateBandwidths(0, 0);
+
pingTestButton = (Button) findViewById(R.id.ping_test);
pingTestButton.setOnClickListener(mPingButtonHandler);
updateSmscButton = (Button) findViewById(R.id.update_smsc);
@@ -501,7 +554,10 @@
| PhoneStateListener.LISTEN_CELL_INFO
| PhoneStateListener.LISTEN_SERVICE_STATE
| PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
- | PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO);
+ | PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION);
+
+ mConnectivityManager.registerNetworkCallback(
+ mDefaultNetworkRequest, mNetworkCallback, mHandler);
smsc.clearFocus();
}
@@ -514,6 +570,8 @@
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
mTelephonyManager.setCellInfoListRate(CELL_INFO_LIST_RATE_DISABLED);
+ mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+
}
private void restoreFromBundle(Bundle b) {
@@ -593,6 +651,14 @@
"0.0.0.0 allowed" :"0.0.0.0 not allowed");
}
+ private void updateBandwidths(int dlbw, int ulbw) {
+ dlbw = (dlbw < 0 || dlbw == Integer.MAX_VALUE) ? -1 : dlbw;
+ ulbw = (ulbw < 0 || ulbw == Integer.MAX_VALUE) ? -1 : ulbw;
+ mDownlinkKbps.setText(String.format("%-5d", dlbw));
+ mUplinkKbps.setText(String.format("%-5d", ulbw));
+ }
+
+
private final void
updateSignalStrength(SignalStrength signalStrength) {
Resources r = getResources();
@@ -673,12 +739,34 @@
return (i != Long.MAX_VALUE) ? Long.toString(i) : "";
}
+ private final String getConnectionStatusString(CellInfo ci) {
+ String regStr = "";
+ String connStatStr = "";
+ String connector = "";
+
+ if (ci.isRegistered()) {
+ regStr = "R";
+ }
+ switch (ci.getCellConnectionStatus()) {
+ case CellInfo.CONNECTION_PRIMARY_SERVING: connStatStr = "P"; break;
+ case CellInfo.CONNECTION_SECONDARY_SERVING: connStatStr = "S"; break;
+ case CellInfo.CONNECTION_NONE: connStatStr = "N"; break;
+ case CellInfo.CONNECTION_UNKNOWN: /* Field is unsupported */ break;
+ default: break;
+ }
+ if (!TextUtils.isEmpty(regStr) && !TextUtils.isEmpty(connStatStr)) {
+ connector = "+";
+ }
+
+ return regStr + connector + connStatStr;
+ }
+
private final String buildCdmaInfoString(CellInfoCdma ci) {
CellIdentityCdma cidCdma = ci.getCellIdentity();
CellSignalStrengthCdma ssCdma = ci.getCellSignalStrength();
return String.format("%-3.3s %-5.5s %-5.5s %-5.5s %-6.6s %-6.6s %-6.6s %-6.6s %-5.5s",
- ci.isRegistered() ? "S " : " ",
+ getConnectionStatusString(ci),
getCellInfoDisplayString(cidCdma.getSystemId()),
getCellInfoDisplayString(cidCdma.getNetworkId()),
getCellInfoDisplayString(cidCdma.getBasestationId()),
@@ -694,7 +782,7 @@
CellSignalStrengthGsm ssGsm = ci.getCellSignalStrength();
return String.format("%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-4.4s %-4.4s\n",
- ci.isRegistered() ? "S " : " ",
+ getConnectionStatusString(ci),
getCellInfoDisplayString(cidGsm.getMcc()),
getCellInfoDisplayString(cidGsm.getMnc()),
getCellInfoDisplayString(cidGsm.getLac()),
@@ -709,14 +797,15 @@
CellSignalStrengthLte ssLte = ci.getCellSignalStrength();
return String.format(
- "%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-3.3s %-6.6s %-4.4s %-4.4s %-2.2s\n",
- ci.isRegistered() ? "S " : " ",
+ "%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-3.3s %-6.6s %-2.2s %-4.4s %-4.4s %-2.2s\n",
+ getConnectionStatusString(ci),
getCellInfoDisplayString(cidLte.getMcc()),
getCellInfoDisplayString(cidLte.getMnc()),
getCellInfoDisplayString(cidLte.getTac()),
getCellInfoDisplayString(cidLte.getCi()),
getCellInfoDisplayString(cidLte.getPci()),
getCellInfoDisplayString(cidLte.getEarfcn()),
+ getCellInfoDisplayString(cidLte.getBandwidth()),
getCellInfoDisplayString(ssLte.getDbm()),
getCellInfoDisplayString(ssLte.getRsrq()),
getCellInfoDisplayString(ssLte.getTimingAdvance()));
@@ -727,7 +816,7 @@
CellSignalStrengthWcdma ssWcdma = ci.getCellSignalStrength();
return String.format("%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-3.3s %-4.4s\n",
- ci.isRegistered() ? "S " : " ",
+ getConnectionStatusString(ci),
getCellInfoDisplayString(cidWcdma.getMcc()),
getCellInfoDisplayString(cidWcdma.getMnc()),
getCellInfoDisplayString(cidWcdma.getLac()),
@@ -759,17 +848,21 @@
}
if (lteCells.length() != 0) {
value += String.format(
- "LTE\n%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-3.3s %-6.6s %-4.4s %-4.4s %-2.2s\n",
- "SRV", "MCC", "MNC", "TAC", "CID", "PCI", "EARFCN", "RSRP", "RSRQ", "TA");
+ "LTE\n%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-3.3s"
+ + " %-6.6s %-2.2s %-4.4s %-4.4s %-2.2s\n",
+ "SRV", "MCC", "MNC", "TAC", "CID", "PCI",
+ "EARFCN", "BW", "RSRP", "RSRQ", "TA");
value += lteCells.toString();
}
if (wcdmaCells.length() != 0) {
- value += String.format("WCDMA\n%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-3.3s %-4.4s\n",
+ value += String.format(
+ "WCDMA\n%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-3.3s %-4.4s\n",
"SRV", "MCC", "MNC", "LAC", "CID", "UARFCN", "PSC", "RSCP");
value += wcdmaCells.toString();
}
if (gsmCells.length() != 0) {
- value += String.format("GSM\n%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-4.4s %-4.4s\n",
+ value += String.format(
+ "GSM\n%-3.3s %-3.3s %-3.3s %-5.5s %-5.5s %-6.6s %-4.4s %-4.4s\n",
"SRV", "MCC", "MNC", "LAC", "CID", "ARFCN", "BSIC", "RSSI");
value += gsmCells.toString();
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceController.java b/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceController.java
index 8827a71..05b5a8a 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceController.java
@@ -32,7 +32,6 @@
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
@@ -44,16 +43,16 @@
LifecycleObserver, OnStart, OnStop {
private static final String TAG = "BluetoothNamePrefCtrl";
- public static final String KEY_DEVICE_NAME = "device_name";
-
-
@VisibleForTesting
Preference mPreference;
private LocalBluetoothManager mLocalManager;
private LocalBluetoothAdapter mLocalAdapter;
- public BluetoothDeviceNamePreferenceController(Context context, Lifecycle lifecycle) {
- this(context, (LocalBluetoothAdapter) null);
+ /**
+ * Constructor exclusively used for Slice.
+ */
+ public BluetoothDeviceNamePreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
mLocalManager = Utils.getLocalBtManager(context);
if (mLocalManager == null) {
@@ -61,22 +60,12 @@
return;
}
mLocalAdapter = mLocalManager.getBluetoothAdapter();
-
- if (lifecycle != null) {
- lifecycle.addObserver(this);
- }
- }
-
- /**
- * Constructor exclusively used for Slice.
- */
- public BluetoothDeviceNamePreferenceController(Context context) {
- this(context, (Lifecycle) null);
}
@VisibleForTesting
- BluetoothDeviceNamePreferenceController(Context context, LocalBluetoothAdapter localAdapter) {
- super(context, KEY_DEVICE_NAME);
+ BluetoothDeviceNamePreferenceController(Context context, LocalBluetoothAdapter localAdapter,
+ String preferenceKey) {
+ super(context, preferenceKey);
mLocalAdapter = localAdapter;
}
@@ -103,11 +92,6 @@
}
@Override
- public String getPreferenceKey() {
- return KEY_DEVICE_NAME;
- }
-
- @Override
public void updateState(Preference preference) {
updateDeviceName(preference);
}
@@ -134,7 +118,7 @@
public Preference createBluetoothDeviceNamePreference(PreferenceScreen screen, int order) {
mPreference = new Preference(screen.getContext());
mPreference.setOrder(order);
- mPreference.setKey(KEY_DEVICE_NAME);
+ mPreference.setKey(getPreferenceKey());
screen.addPreference(mPreference);
return mPreference;
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java b/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java
index 262d6b3..21f0487 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java
@@ -26,44 +26,35 @@
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import com.android.settingslib.core.lifecycle.Lifecycle;
public class BluetoothDeviceRenamePreferenceController extends
BluetoothDeviceNamePreferenceController {
- private final Fragment mFragment;
- private String mPrefKey;
+ private Fragment mFragment;
private MetricsFeatureProvider mMetricsFeatureProvider;
- public BluetoothDeviceRenamePreferenceController(Context context, String prefKey,
- Fragment fragment, Lifecycle lifecycle) {
- super(context, lifecycle);
- mPrefKey = prefKey;
- mFragment = fragment;
- mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
- }
-
/**
* Constructor exclusively used for Slice.
*/
- public BluetoothDeviceRenamePreferenceController(Context context, String prefKey) {
- super(context, (Lifecycle) null);
- mPrefKey = prefKey;
- mFragment = null;
- }
-
- @VisibleForTesting
- BluetoothDeviceRenamePreferenceController(Context context, String prefKey, Fragment fragment,
- LocalBluetoothAdapter localAdapter) {
- super(context, localAdapter);
- mPrefKey = prefKey;
- mFragment = fragment;
+ public BluetoothDeviceRenamePreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
}
- @Override
- public String getPreferenceKey() {
- return mPrefKey;
+ @VisibleForTesting
+ BluetoothDeviceRenamePreferenceController(Context context, LocalBluetoothAdapter localAdapter,
+ String preferenceKey) {
+ super(context, localAdapter, preferenceKey);
+ mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+ }
+
+ /**
+ * Set the {@link Fragment} that used to show {@link LocalDeviceNameDialogFragment}
+ * in {@code handlePreferenceTreeClick}
+ */
+ @VisibleForTesting
+ public void setFragment(Fragment fragment) {
+ mFragment = fragment;
}
@Override
@@ -78,7 +69,7 @@
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
- if (TextUtils.equals(mPrefKey, preference.getKey()) && mFragment != null) {
+ if (TextUtils.equals(getPreferenceKey(), preference.getKey()) && mFragment != null) {
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_BLUETOOTH_RENAME);
LocalDeviceNameDialogFragment.newInstance()
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDetail.java b/src/com/android/settings/bluetooth/BluetoothPairingDetail.java
index b31d4c8..1ab7f87 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingDetail.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDetail.java
@@ -30,12 +30,8 @@
import com.android.settings.search.Indexable;
import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.widget.FooterPreference;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* BluetoothPairingDetail is a page to scan bluetooth devices and pair them.
*/
@@ -47,7 +43,6 @@
static final String KEY_AVAIL_DEVICES = "available_devices";
@VisibleForTesting
static final String KEY_FOOTER_PREF = "footer_preference";
- private static final String KEY_RENAME_DEVICES = "bt_pair_rename_devices";
@VisibleForTesting
BluetoothProgressCategory mAvailableDevicesCategory;
@@ -80,6 +75,12 @@
mAvailableDevicesCategory.setProgress(mLocalAdapter.isDiscovering());
}
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ use(BluetoothDeviceRenamePreferenceController.class).setFragment(this);
+ }
+
@VisibleForTesting
void updateBluetooth() {
if (mLocalAdapter.isEnabled()) {
@@ -200,16 +201,6 @@
}
@Override
- protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
- final List<AbstractPreferenceController> controllers = new ArrayList<>();
- controllers.add(
- new BluetoothDeviceRenamePreferenceController(context, KEY_RENAME_DEVICES, this,
- getLifecycle()));
-
- return controllers;
- }
-
- @Override
public String getDeviceListKey() {
return KEY_AVAIL_DEVICES;
}
diff --git a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
index 45794c5..a64a430 100644
--- a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
@@ -24,6 +24,7 @@
import com.android.settings.bluetooth.BluetoothFilesPreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.nfc.AndroidBeamPreferenceController;
+import com.android.settings.nfc.NfcPreferenceController;
import com.android.settings.print.PrintSettingPreferenceController;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -78,10 +79,16 @@
final PrintSettingPreferenceController printerController =
new PrintSettingPreferenceController(context);
+ final NfcPreferenceController nfcPreferenceController =
+ new NfcPreferenceController(context);
+
if (lifecycle != null) {
lifecycle.addObserver(beamPreferenceController);
lifecycle.addObserver(printerController);
+ lifecycle.addObserver(nfcPreferenceController);
}
+
+ controllers.add(nfcPreferenceController);
controllers.add(printerController);
return controllers;
diff --git a/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java b/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java
index 77b75c5..3b24271 100644
--- a/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java
@@ -24,6 +24,7 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController;
import com.android.settings.bluetooth.BluetoothSwitchPreferenceController;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.core.TogglePreferenceController;
@@ -79,6 +80,12 @@
}
@Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ use(BluetoothDeviceRenamePreferenceController.class).setFragment(this);
+ }
+
+ @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
index 227fd9b..26ff930 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
@@ -26,10 +26,7 @@
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.nfc.NfcPreferenceController;
import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -63,29 +60,11 @@
}
@Override
- protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
- return buildPreferenceControllers(context, getLifecycle());
- }
-
- private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
- Lifecycle lifecycle) {
- final List<AbstractPreferenceController> controllers = new ArrayList<>();
- final NfcPreferenceController nfcPreferenceController =
- new NfcPreferenceController(context);
- controllers.add(nfcPreferenceController);
-
- if (lifecycle != null) {
- lifecycle.addObserver(nfcPreferenceController);
- }
-
- return controllers;
- }
-
- @Override
public void onAttach(Context context) {
super.onAttach(context);
use(AvailableMediaDeviceGroupController.class).init(this);
use(ConnectedDeviceGroupController.class).init(this);
+ use(PreviouslyConnectedDevicePreferenceController.class).init(this);
}
@VisibleForTesting
@@ -139,12 +118,6 @@
}
@Override
- public List<AbstractPreferenceController> createPreferenceControllers(Context
- context) {
- return buildPreferenceControllers(context, null /* lifecycle */);
- }
-
- @Override
public List<String> getNonIndexableKeys(Context context) {
List<String> keys = super.getNonIndexableKeys(context);
// Disable because they show dynamic data
diff --git a/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java b/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java
new file mode 100644
index 0000000..ba3ee1f
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2018 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.connecteddevice;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import android.util.Log;
+import com.android.settings.bluetooth.BluetoothDeviceUpdater;
+import com.android.settings.bluetooth.SavedBluetoothDeviceUpdater;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.dashboard.DashboardFragment;
+
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.utils.ThreadUtils;
+
+public class PreviouslyConnectedDevicePreferenceController extends BasePreferenceController
+ implements LifecycleObserver, OnStart, OnStop, DevicePreferenceCallback {
+
+ private Preference mPreference;
+ private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
+ private int mPreferenceSize;
+
+ public PreviouslyConnectedDevicePreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
+ ? AVAILABLE
+ : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ if (isAvailable()) {
+ mPreference = screen.findPreference(getPreferenceKey());
+ mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
+ }
+ }
+
+ @Override
+ public void onStart() {
+ mBluetoothDeviceUpdater.registerCallback();
+ updatePreferenceOnSizeChanged();
+ }
+
+ @Override
+ public void onStop() {
+ mBluetoothDeviceUpdater.unregisterCallback();
+ }
+
+ public void init(DashboardFragment fragment) {
+ mBluetoothDeviceUpdater = new SavedBluetoothDeviceUpdater(fragment.getContext(),
+ fragment, PreviouslyConnectedDevicePreferenceController.this);
+ }
+
+ @Override
+ public void onDeviceAdded(Preference preference) {
+ mPreferenceSize++;
+ updatePreferenceOnSizeChanged();
+ }
+
+ @Override
+ public void onDeviceRemoved(Preference preference) {
+ mPreferenceSize--;
+ updatePreferenceOnSizeChanged();
+ }
+
+ @VisibleForTesting
+ void setBluetoothDeviceUpdater(BluetoothDeviceUpdater bluetoothDeviceUpdater) {
+ mBluetoothDeviceUpdater = bluetoothDeviceUpdater;
+ }
+
+ @VisibleForTesting
+ void setPreferenceSize(int size) {
+ mPreferenceSize = size;
+ }
+
+ @VisibleForTesting
+ void setPreference(Preference preference) {
+ mPreference = preference;
+ }
+
+ private void updatePreferenceOnSizeChanged() {
+ if (isAvailable()) {
+ mPreference.setEnabled(mPreferenceSize != 0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/display/NightDisplayPreferenceController.java b/src/com/android/settings/display/NightDisplayPreferenceController.java
index 5e8dfe0..0bbab93 100644
--- a/src/com/android/settings/display/NightDisplayPreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayPreferenceController.java
@@ -18,6 +18,7 @@
import com.android.internal.app.ColorDisplayController;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settings.R;
public class NightDisplayPreferenceController extends AbstractPreferenceController implements
PreferenceControllerMixin {
@@ -29,6 +30,12 @@
}
public static boolean isSuggestionComplete(Context context) {
+ final boolean isEnabled = context.getResources().getBoolean(
+ R.bool.config_night_light_suggestion_enabled);
+ // The suggestion is always complete if not enabled.
+ if (!isEnabled) {
+ return true;
+ }
final ColorDisplayController controller = new ColorDisplayController(context);
return controller.getAutoMode() != ColorDisplayController.AUTO_MODE_DISABLED;
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index e727521..b76aef0 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -131,6 +131,7 @@
@Override
public boolean isSmartBatterySupported() {
- return false;
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_smart_battery_available);
}
}
diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java
index 7fffb76..1005d20 100644
--- a/src/com/android/settings/notification/SoundSettings.java
+++ b/src/com/android/settings/notification/SoundSettings.java
@@ -26,16 +26,22 @@
import android.preference.SeekBarVolumizer;
import android.provider.SearchIndexableResource;
import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.text.TextUtils;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.RingtonePreference;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.sound.HandsFreeProfileOutputPreferenceController;
+import com.android.settings.sound.MediaOutputPreferenceController;
import com.android.settings.widget.PreferenceCategoryController;
+import com.android.settings.widget.UpdatableListPreferenceDialogFragment;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
@@ -68,6 +74,9 @@
};
private RingtonePreference mRequestPreference;
+ private UpdatableListPreferenceDialogFragment mDialogFragment;
+ private String mMediaOutputControllerKey;
+ private String mHfpOutputControllerKey;
@Override
public int getMetricsCategory() {
@@ -82,6 +91,11 @@
if (!TextUtils.isEmpty(selectedPreference)) {
mRequestPreference = (RingtonePreference) findPreference(selectedPreference);
}
+
+ UpdatableListPreferenceDialogFragment dialogFragment =
+ (UpdatableListPreferenceDialogFragment) getFragmentManager()
+ .findFragmentByTag(TAG);
+ mDialogFragment = dialogFragment;
}
}
@@ -112,6 +126,23 @@
}
@Override
+ public void onDisplayPreferenceDialog(Preference preference) {
+ final int metricsCategory;
+ if (mHfpOutputControllerKey.equals(preference.getKey())) {
+ metricsCategory = MetricsProto.MetricsEvent.DIALOG_SWITCH_HFP_DEVICES;
+ } else if (mMediaOutputControllerKey.equals(preference.getKey())) {
+ metricsCategory = MetricsProto.MetricsEvent.DIALOG_SWITCH_A2DP_DEVICES;
+ } else {
+ metricsCategory = Instrumentable.METRICS_CATEGORY_UNKNOWN;
+ }
+
+ mDialogFragment = UpdatableListPreferenceDialogFragment.
+ newInstance(preference.getKey(), metricsCategory);
+ mDialogFragment.setTargetFragment(this, 0);
+ mDialogFragment.show(getFragmentManager(), TAG);
+ }
+
+ @Override
protected String getLogTag() {
return TAG;
}
@@ -152,6 +183,14 @@
volumeControllers.add(use(NotificationVolumePreferenceController.class));
volumeControllers.add(use(CallVolumePreferenceController.class));
+ use(MediaOutputPreferenceController.class).setCallback(listPreference ->
+ onPreferenceDataChanged(listPreference));
+ mMediaOutputControllerKey = use(MediaOutputPreferenceController.class).getPreferenceKey();
+ use(HandsFreeProfileOutputPreferenceController.class).setCallback(listPreference ->
+ onPreferenceDataChanged(listPreference));
+ mHfpOutputControllerKey =
+ use(HandsFreeProfileOutputPreferenceController.class).getPreferenceKey();
+
for (VolumeSeekBarPreferenceController controller : volumeControllers) {
controller.setCallback(mVolumeCallback);
getLifecycle().addObserver(controller);
@@ -287,4 +326,10 @@
workSoundController.enableWorkSync();
}
}
-}
+
+ private void onPreferenceDataChanged(ListPreference preference) {
+ if (mDialogFragment != null) {
+ mDialogFragment.onListPreferenceUpdated(preference);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/notification/ZenModeSliceBuilder.java b/src/com/android/settings/notification/ZenModeSliceBuilder.java
new file mode 100644
index 0000000..0edf214
--- /dev/null
+++ b/src/com/android/settings/notification/ZenModeSliceBuilder.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2018 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.notification;
+
+import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
+
+import android.annotation.ColorInt;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.provider.Settings;
+import android.provider.SettingsSlicesContract;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.SubSettings;
+import com.android.settings.Utils;
+import com.android.settings.search.DatabaseIndexingUtils;
+import com.android.settings.slices.SettingsSliceProvider;
+import com.android.settings.slices.SliceBroadcastReceiver;
+import com.android.settings.slices.SliceBuilderUtils;
+
+import androidx.slice.Slice;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+
+import android.support.v4.graphics.drawable.IconCompat;
+
+public class ZenModeSliceBuilder {
+
+ private static final String TAG = "ZenModeSliceBuilder";
+
+ private static final String ZEN_MODE_KEY = "zen_mode";
+
+ /**
+ * Backing Uri for the Zen Mode Slice.
+ */
+ public static final Uri ZEN_MODE_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(ZEN_MODE_KEY)
+ .build();
+
+ /**
+ * Action notifying a change on the Zen Mode Slice.
+ */
+ public static final String ACTION_ZEN_MODE_SLICE_CHANGED =
+ "com.android.settings.notification.ZEN_MODE_CHANGED";
+
+ public static final IntentFilter INTENT_FILTER = new IntentFilter();
+
+ static {
+ INTENT_FILTER.addAction(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
+ INTENT_FILTER.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
+ INTENT_FILTER.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL);
+ }
+
+ private ZenModeSliceBuilder() {
+ }
+
+ /**
+ * Return a ZenMode Slice bound to {@link #ZEN_MODE_URI}.
+ * <p>
+ * Note that you should register a listener for {@link #INTENT_FILTER} to get changes for
+ * ZenMode.
+ */
+ public static Slice getSlice(Context context) {
+ final boolean isZenModeEnabled = isZenModeEnabled(context);
+ final CharSequence title = context.getText(R.string.zen_mode_settings_title);
+ @ColorInt final int color = Utils.getColorAccent(context);
+ final PendingIntent toggleAction = getBroadcastIntent(context);
+ final PendingIntent primaryAction = getPrimaryAction(context);
+ final SliceAction primarySliceAction = new SliceAction(primaryAction,
+ (IconCompat) null /* icon */, title);
+ final SliceAction toggleSliceAction = new SliceAction(toggleAction, null /* actionTitle */,
+ isZenModeEnabled);
+
+ return new ListBuilder(context, ZEN_MODE_URI, ListBuilder.INFINITY)
+ .setAccentColor(color)
+ .addRow(b -> b
+ .setTitle(title)
+ .addEndItem(toggleSliceAction)
+ .setPrimaryAction(primarySliceAction))
+ .build();
+ }
+
+ /**
+ * Update the current ZenMode status to the boolean value keyed by
+ * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}.
+ */
+ public static void handleUriChange(Context context, Intent intent) {
+ final boolean zenModeOn = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, false);
+ final int zenMode;
+ if (zenModeOn) {
+ zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ } else {
+ zenMode = Settings.Global.ZEN_MODE_OFF;
+ }
+ NotificationManager.from(context).setZenMode(zenMode, null /* conditionId */, TAG);
+ // Do not notifyChange on Uri. The service takes longer to update the current value than it
+ // does for the Slice to check the current value again. Let {@link SliceBroadcastRelay}
+ // handle it.
+ }
+
+ private static boolean isZenModeEnabled(Context context) {
+ final NotificationManager manager = context.getSystemService(NotificationManager.class);
+ final int zenMode = manager.getZenMode();
+
+ switch (zenMode) {
+ case Settings.Global.ZEN_MODE_ALARMS:
+ case Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+ case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
+ return true;
+ case Settings.Global.ZEN_MODE_OFF:
+ default:
+ return false;
+ }
+ }
+
+ private static PendingIntent getPrimaryAction(Context context) {
+ final String screenTitle = context.getText(R.string.zen_mode_settings_title).toString();
+ final Uri contentUri = new Uri.Builder().appendPath(ZEN_MODE_KEY).build();
+ final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
+ ZenModeSettings.class.getName(), ZEN_MODE_KEY, screenTitle,
+ MetricsEvent.NOTIFICATION_ZEN_MODE)
+ .setClassName(context.getPackageName(), SubSettings.class.getName())
+ .setData(contentUri);
+
+ return PendingIntent.getActivity(context, 0 /* requestCode */,
+ intent, 0 /* flags */);
+ }
+
+ private static PendingIntent getBroadcastIntent(Context context) {
+ final Intent intent = new Intent(ACTION_ZEN_MODE_SLICE_CHANGED)
+ .setClass(context, SliceBroadcastReceiver.class);
+ return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+}
diff --git a/src/com/android/settings/search/DeviceIndexFeatureProvider.java b/src/com/android/settings/search/DeviceIndexFeatureProvider.java
index 8e64d79..bf75ee8 100644
--- a/src/com/android/settings/search/DeviceIndexFeatureProvider.java
+++ b/src/com/android/settings/search/DeviceIndexFeatureProvider.java
@@ -24,8 +24,10 @@
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
+import android.util.Log;
import com.android.settings.R;
+import com.android.settings.Utils;
import com.android.settings.slices.SettingsSliceProvider;
import java.util.List;
@@ -48,6 +50,12 @@
default void updateIndex(Context context, boolean force) {
if (!isIndexingEnabled()) {
+ Log.w(TAG, "Skipping: device index is not enabled");
+ return;
+ }
+
+ if (!Utils.isDeviceProvisioned(context)) {
+ Log.w(TAG, "Skipping: device is not provisioned");
return;
}
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index 8f07447..44f57f8 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -18,41 +18,40 @@
import static android.Manifest.permission.READ_SEARCH_INDEXABLES;
-import static com.android.settings.wifi.calling.WifiCallingSliceHelper.PATH_WIFI_CALLING;
-
-import android.app.PendingIntent;
import android.app.slice.SliceManager;
import android.content.ContentResolver;
-import android.content.Context;
import android.content.Intent;
-import android.graphics.drawable.Icon;
+import android.content.IntentFilter;
+import android.content.Context;
import android.net.Uri;
-import android.net.wifi.WifiManager;
-import android.provider.Settings;
import android.provider.SettingsSlicesContract;
import android.support.annotation.VisibleForTesting;
import android.support.v4.graphics.drawable.IconCompat;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
-import androidx.slice.Slice;
-import androidx.slice.SliceProvider;
-import androidx.slice.builders.ListBuilder;
-import androidx.slice.builders.SliceAction;
-
-import com.android.settings.R;
import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.wifi.WifiSliceBuilder;
+import com.android.settings.wifi.calling.WifiCallingSliceHelper;
+import com.android.settings.notification.ZenModeSliceBuilder;
+import com.android.settingslib.SliceBroadcastRelay;
import com.android.settingslib.utils.ThreadUtils;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
+import androidx.slice.Slice;
+import androidx.slice.SliceProvider;
+
/**
* A {@link SliceProvider} for Settings to enabled inline results in system apps.
*
@@ -84,10 +83,6 @@
*/
public static final String SLICE_AUTHORITY = "com.android.settings.slices";
- public static final String PATH_WIFI = "wifi";
- public static final String ACTION_WIFI_CHANGED =
- "com.android.settings.slice.action.WIFI_CHANGED";
-
/**
* Action passed for changes to Toggle Slices.
*/
@@ -111,8 +106,6 @@
public static final String EXTRA_SLICE_PLATFORM_DEFINED =
"com.android.settings.slice.extra.platform";
- // TODO -- Associate slice URI with search result instead of separate hardcoded thing
-
@VisibleForTesting
SlicesDatabaseAccessor mSlicesDatabaseAccessor;
@@ -121,6 +114,8 @@
@VisibleForTesting
Map<Uri, SliceData> mSliceDataCache;
+ final Set<Uri> mRegisteredUris = new ArraySet<>();
+
public SettingsSliceProvider() {
super(READ_SEARCH_INDEXABLES);
}
@@ -146,28 +141,43 @@
@Override
public void onSlicePinned(Uri sliceUri) {
+ if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) {
+ registerIntentToUri(WifiSliceBuilder.INTENT_FILTER , sliceUri);
+ // TODO (b/) Register IntentFilters for database entries.
+ mRegisteredUris.add(sliceUri);
+ return;
+ } else if (ZenModeSliceBuilder.ZEN_MODE_URI.equals(sliceUri)) {
+ registerIntentToUri(ZenModeSliceBuilder.INTENT_FILTER, sliceUri);
+ mRegisteredUris.add(sliceUri);
+ return;
+ }
+
// Start warming the slice, we expect someone will want it soon.
loadSliceInBackground(sliceUri);
}
@Override
public void onSliceUnpinned(Uri sliceUri) {
+ if (mRegisteredUris.contains(sliceUri)) {
+ SliceBroadcastRelay.unregisterReceivers(getContext(), sliceUri);
+ mRegisteredUris.remove(sliceUri);
+ }
mSliceDataCache.remove(sliceUri);
}
@Override
public Slice onBindSlice(Uri sliceUri) {
- String path = sliceUri.getPath();
// If adding a new Slice, do not directly match Slice URIs.
// Use {@link SlicesDatabaseAccessor}.
- switch (path) {
- case "/" + PATH_WIFI:
- return createWifiSlice(sliceUri);
- case "/" + PATH_WIFI_CALLING:
- return FeatureFactory.getFactory(getContext())
- .getSlicesFeatureProvider()
- .getNewWifiCallingSliceHelper(getContext())
- .createWifiCallingSlice(sliceUri);
+ if (WifiCallingSliceHelper.WIFI_CALLING_URI.equals(sliceUri)) {
+ return FeatureFactory.getFactory(getContext())
+ .getSlicesFeatureProvider()
+ .getNewWifiCallingSliceHelper(getContext())
+ .createWifiCallingSlice(sliceUri);
+ } else if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) {
+ return WifiSliceBuilder.getSlice(getContext());
+ } else if (ZenModeSliceBuilder.ZEN_MODE_URI.equals(sliceUri)) {
+ return ZenModeSliceBuilder.getSlice(getContext());
}
SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri);
@@ -223,11 +233,12 @@
true /* isPlatformSlice */);
final List<String> oemKeys = mSlicesDatabaseAccessor.getSliceKeys(
false /* isPlatformSlice */);
- final List<Uri> allUris = buildUrisFromKeys(platformKeys,
- SettingsSlicesContract.AUTHORITY);
- allUris.addAll(buildUrisFromKeys(oemKeys, SettingsSliceProvider.SLICE_AUTHORITY));
+ descendants.addAll(buildUrisFromKeys(platformKeys, SettingsSlicesContract.AUTHORITY));
+ descendants.addAll(buildUrisFromKeys(oemKeys, SettingsSliceProvider.SLICE_AUTHORITY));
+ descendants.addAll(getSpecialCaseUris(true /* isPlatformSlice */));
+ descendants.addAll(getSpecialCaseUris(false /* isPlatformSlice */));
- return allUris;
+ return descendants;
}
// Path is anything but empty, "action", or "intent". Return empty list.
@@ -242,7 +253,9 @@
// Can assume authority belongs to the provider. Return all Uris for the authority.
final boolean isPlatformUri = TextUtils.equals(authority, SettingsSlicesContract.AUTHORITY);
final List<String> keys = mSlicesDatabaseAccessor.getSliceKeys(isPlatformUri);
- return buildUrisFromKeys(keys, authority);
+ descendants.addAll(buildUrisFromKeys(keys, authority));
+ descendants.addAll(getSpecialCaseUris(isPlatformUri));
+ return descendants;
}
private List<Uri> buildUrisFromKeys(List<String> keys, String authority) {
@@ -295,55 +308,32 @@
return new Slice.Builder(uri).build();
}
- // TODO (b/70622039) remove this when the proper wifi slice is enabled.
- private Slice createWifiSlice(Uri sliceUri) {
- // Get wifi state
- WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
- int wifiState = wifiManager.getWifiState();
- boolean wifiEnabled = false;
- String state;
- switch (wifiState) {
- case WifiManager.WIFI_STATE_DISABLED:
- case WifiManager.WIFI_STATE_DISABLING:
- state = getContext().getString(R.string.disconnected);
- break;
- case WifiManager.WIFI_STATE_ENABLED:
- case WifiManager.WIFI_STATE_ENABLING:
- state = wifiManager.getConnectionInfo().getSSID();
- wifiEnabled = true;
- break;
- case WifiManager.WIFI_STATE_UNKNOWN:
- default:
- state = ""; // just don't show anything?
- break;
+ private List<Uri> getSpecialCaseUris(boolean isPlatformUri) {
+ if (isPlatformUri) {
+ return getSpecialCasePlatformUris();
}
-
- boolean finalWifiEnabled = wifiEnabled;
- return new ListBuilder(getContext(), sliceUri)
- .setColor(R.color.material_blue_500)
- .addRow(b -> b
- .setTitle(getContext().getString(R.string.wifi_settings))
- .setTitleItem(Icon.createWithResource(getContext(), R.drawable.wifi_signal))
- .setSubtitle(state)
- .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED),
- null, finalWifiEnabled))
- .setPrimaryAction(
- new SliceAction(getIntent(Settings.ACTION_WIFI_SETTINGS),
- (IconCompat) null, null)))
- .build();
+ return getSpecialCaseOemUris();
}
- private PendingIntent getIntent(String action) {
- Intent intent = new Intent(action);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0);
- return pi;
+ private List<Uri> getSpecialCasePlatformUris() {
+ return Arrays.asList(
+ WifiSliceBuilder.WIFI_URI
+ );
}
- private PendingIntent getBroadcastIntent(String action) {
- Intent intent = new Intent(action);
- intent.setClass(getContext(), SliceBroadcastReceiver.class);
- return PendingIntent.getBroadcast(getContext(), 0, intent,
- PendingIntent.FLAG_CANCEL_CURRENT);
+ private List<Uri> getSpecialCaseOemUris() {
+ return Arrays.asList(
+ ZenModeSliceBuilder.ZEN_MODE_URI
+ );
+ }
+
+ @VisibleForTesting
+ /**
+ * Registers an IntentFilter in SysUI to notify changes to {@param sliceUri} when broadcasts to
+ * {@param intentFilter} happen.
+ */
+ void registerIntentToUri(IntentFilter intentFilter, Uri sliceUri) {
+ SliceBroadcastRelay.registerReceiver(getContext(), sliceUri, SliceBroadcastReceiver.class,
+ intentFilter);
}
}
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index 0409734..b9f3b00 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -16,20 +16,19 @@
package com.android.settings.slices;
+import static com.android.settings.notification.ZenModeSliceBuilder.ACTION_ZEN_MODE_SLICE_CHANGED;
import static com.android.settings.slices.SettingsSliceProvider.ACTION_SLIDER_CHANGED;
import static com.android.settings.slices.SettingsSliceProvider.ACTION_TOGGLE_CHANGED;
-import static com.android.settings.slices.SettingsSliceProvider.ACTION_WIFI_CHANGED;
import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY;
import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_PLATFORM_DEFINED;
import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED;
+import static com.android.settings.wifi.WifiSliceBuilder.ACTION_WIFI_SLICE_CHANGED;
import android.app.slice.Slice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
import android.provider.SettingsSlicesContract;
import android.text.TextUtils;
import android.util.Log;
@@ -39,7 +38,10 @@
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.SliderPreferenceController;
import com.android.settings.core.TogglePreferenceController;
+import com.android.settings.notification.ZenModeSliceBuilder;
import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.wifi.WifiSliceBuilder;
+import com.android.settingslib.SliceBroadcastRelay;
/**
* Responds to actions performed on slices and notifies slices of updates in state changes.
@@ -48,9 +50,6 @@
private static String TAG = "SettSliceBroadcastRec";
- /**
- * TODO (b/) move wifi action into generalized case.
- */
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
@@ -67,25 +66,24 @@
final int newPosition = intent.getIntExtra(Slice.EXTRA_RANGE_VALUE, -1);
handleSliderAction(context, key, newPosition, isPlatformSlice);
break;
- case ACTION_WIFI_CHANGED:
- WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- boolean newState = intent.getBooleanExtra(Slice.EXTRA_TOGGLE_STATE,
- wm.isWifiEnabled());
- wm.setWifiEnabled(newState);
- // Wait a bit for wifi to update (TODO: is there a better way to do this?)
- Handler h = new Handler();
- h.postDelayed(() -> {
- Uri uri = SliceBuilderUtils.getUri(SettingsSliceProvider.PATH_WIFI,
- false /* isPlatformSlice */);
- context.getContentResolver().notifyChange(uri, null);
- }, 1000);
+ case ACTION_WIFI_SLICE_CHANGED:
+ WifiSliceBuilder.handleUriChange(context, intent);
break;
case ACTION_WIFI_CALLING_CHANGED:
FeatureFactory.getFactory(context)
- .getSlicesFeatureProvider()
- .getNewWifiCallingSliceHelper(context)
- .handleWifiCallingChanged(intent);
+ .getSlicesFeatureProvider()
+ .getNewWifiCallingSliceHelper(context)
+ .handleWifiCallingChanged(intent);
break;
+ case ACTION_ZEN_MODE_SLICE_CHANGED:
+ ZenModeSliceBuilder.handleUriChange(context, intent);
+ break;
+ default:
+ final String uriString = intent.getStringExtra(SliceBroadcastRelay.EXTRA_URI);
+ if (!TextUtils.isEmpty(uriString)) {
+ final Uri uri = Uri.parse(uriString);
+ context.getContentResolver().notifyChange(uri, null /* observer */);
+ }
}
}
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index d744fbd..feb7042 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -39,7 +39,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
-import com.android.settings.SettingsActivity;
import com.android.settings.SubSettings;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
@@ -47,6 +46,7 @@
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.DatabaseIndexingUtils;
+import com.android.settingslib.SliceBroadcastRelay;
import com.android.settingslib.core.AbstractPreferenceController;
import android.support.v4.graphics.drawable.IconCompat;
@@ -54,6 +54,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
@@ -345,7 +346,10 @@
final String keywordString = data.getKeywords();
if (keywordString != null) {
final String[] keywordArray = keywordString.split(",");
- keywords.addAll(Arrays.asList(keywordArray));
+ final List<String> strippedKeywords = Arrays.stream(keywordArray)
+ .map(s -> s = s.trim())
+ .collect(Collectors.toList());
+ keywords.addAll(strippedKeywords);
}
return keywords;
diff --git a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
index d02431c..7f1a0f3 100644
--- a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
+++ b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
@@ -45,7 +45,11 @@
// This shouldn't matter since the slice is shown instead of the device
// index caring about the launch uri.
Uri slice = Uri.parse(intent.getStringExtra(EXTRA_SLICE));
- Log.e(TAG, "Slice intent launched: " + slice);
+ SlicesDatabaseAccessor slicesDatabaseAccessor = new SlicesDatabaseAccessor(this);
+ // Sadly have to block here because we don't know where to go.
+ final SliceData sliceData = slicesDatabaseAccessor.getSliceDataFromUri(slice);
+ Intent launchIntent = SliceBuilderUtils.getContentIntent(this, sliceData);
+ startActivity(launchIntent);
} else {
startActivity(intent);
}
diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
index dde2b30..6d9d3a4 100644
--- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java
+++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
@@ -78,6 +78,7 @@
protected final LocalBluetoothProfileManager mProfileManager;
protected int mSelectedIndex;
protected Preference mPreference;
+ protected AudioSwitchCallback mAudioSwitchPreferenceCallback;
private final AudioManagerAudioDeviceCallback mAudioManagerAudioDeviceCallback;
private final LocalBluetoothManager mLocalBluetoothManager;
@@ -85,6 +86,10 @@
private final WiredHeadsetBroadcastReceiver mReceiver;
private final Handler mHandler;
+ public interface AudioSwitchCallback {
+ void onPreferenceDataChanged(ListPreference preference);
+ }
+
public AudioSwitchPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@@ -207,6 +212,10 @@
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
}
+ public void setCallback(AudioSwitchCallback callback) {
+ mAudioSwitchPreferenceCallback = callback;
+ }
+
protected boolean isStreamFromOutputDevice(int streamType, int device) {
return (device & mAudioManager.getDevicesForStream(streamType)) != 0;
}
@@ -335,6 +344,7 @@
listPreference.setEntryValues(mediaValues);
listPreference.setValueIndex(mSelectedIndex);
listPreference.setSummary(mediaOutputs[mSelectedIndex]);
+ mAudioSwitchPreferenceCallback.onPreferenceDataChanged(listPreference);
}
private int getConnectedDeviceIndex(String hardwareAddress) {
diff --git a/src/com/android/settings/widget/UpdatableListPreferenceDialogFragment.java b/src/com/android/settings/widget/UpdatableListPreferenceDialogFragment.java
new file mode 100644
index 0000000..9369778
--- /dev/null
+++ b/src/com/android/settings/widget/UpdatableListPreferenceDialogFragment.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2018 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.widget;
+
+import android.app.AlertDialog;
+import android.content.res.TypedArray;
+import android.os.Bundle;
+import android.support.annotation.VisibleForTesting;
+import android.support.v14.preference.PreferenceDialogFragment;
+import android.support.v7.preference.ListPreference;
+import android.widget.ArrayAdapter;
+import com.android.settingslib.core.instrumentation.Instrumentable;
+
+import java.util.ArrayList;
+
+/**
+ * {@link PreferenceDialogFragment} that updates the available options
+ * when {@code onListPreferenceUpdated} is called."
+ */
+public class UpdatableListPreferenceDialogFragment extends PreferenceDialogFragment implements
+ Instrumentable {
+
+ private static final String SAVE_STATE_INDEX = "UpdatableListPreferenceDialogFragment.index";
+ private static final String SAVE_STATE_ENTRIES =
+ "UpdatableListPreferenceDialogFragment.entries";
+ private static final String SAVE_STATE_ENTRY_VALUES =
+ "UpdatableListPreferenceDialogFragment.entryValues";
+ private static final String METRICS_CATEGORY_KEY = "metrics_category_key";
+ private ArrayAdapter mAdapter;
+ private int mClickedDialogEntryIndex;
+ private ArrayList<CharSequence> mEntries;
+ private CharSequence[] mEntryValues;
+ private int mMetricsCategory = Instrumentable.METRICS_CATEGORY_UNKNOWN;
+
+ public static UpdatableListPreferenceDialogFragment newInstance(
+ String key, int metricsCategory) {
+ UpdatableListPreferenceDialogFragment fragment =
+ new UpdatableListPreferenceDialogFragment();
+ Bundle args = new Bundle(1);
+ args.putString(ARG_KEY, key);
+ args.putInt(METRICS_CATEGORY_KEY, metricsCategory);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final Bundle bundle = getArguments();
+ mMetricsCategory =
+ bundle.getInt(METRICS_CATEGORY_KEY, Instrumentable.METRICS_CATEGORY_UNKNOWN);
+ if (savedInstanceState == null) {
+ mEntries = new ArrayList<>();
+ setPreferenceData(getListPreference());
+ } else {
+ mClickedDialogEntryIndex = savedInstanceState.getInt(SAVE_STATE_INDEX, 0);
+ mEntries = savedInstanceState.getCharSequenceArrayList(SAVE_STATE_ENTRIES);
+ mEntryValues =
+ savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRY_VALUES);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(SAVE_STATE_INDEX, mClickedDialogEntryIndex);
+ outState.putCharSequenceArrayList(SAVE_STATE_ENTRIES, mEntries);
+ outState.putCharSequenceArray(SAVE_STATE_ENTRY_VALUES, mEntryValues);
+ }
+
+ @Override
+ public void onDialogClosed(boolean positiveResult) {
+ final ListPreference preference = getListPreference();
+ if (positiveResult && mClickedDialogEntryIndex >= 0) {
+ final String value = mEntryValues[mClickedDialogEntryIndex].toString();
+ if (preference.callChangeListener(value)) {
+ preference.setValue(value);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ void setAdapter(ArrayAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ @VisibleForTesting
+ void setEntries(ArrayList<CharSequence> entries) {
+ mEntries = entries;
+ }
+
+ @VisibleForTesting
+ ArrayAdapter getAdapter() {
+ return mAdapter;
+ }
+
+ @VisibleForTesting
+ void setMetricsCategory(Bundle bundle) {
+ mMetricsCategory =
+ bundle.getInt(METRICS_CATEGORY_KEY, Instrumentable.METRICS_CATEGORY_UNKNOWN);
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+ super.onPrepareDialogBuilder(builder);
+ final TypedArray a = getContext().obtainStyledAttributes(
+ null,
+ com.android.internal.R.styleable.AlertDialog,
+ com.android.internal.R.attr.alertDialogStyle, 0);
+
+ mAdapter = new ArrayAdapter<>(
+ getContext(),
+ a.getResourceId(
+ com.android.internal.R.styleable.AlertDialog_singleChoiceItemLayout,
+ com.android.internal.R.layout.select_dialog_singlechoice),
+ mEntries);
+
+ builder.setSingleChoiceItems(mAdapter, mClickedDialogEntryIndex,
+ (dialog, which) -> {
+ mClickedDialogEntryIndex = which;
+ onClick(dialog, -1);
+ dialog.dismiss();
+ });
+ builder.setPositiveButton(null, null);
+ a.recycle();
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return mMetricsCategory;
+ }
+
+ private ListPreference getListPreference() {
+ return (ListPreference) getPreference();
+ }
+
+ private void setPreferenceData(ListPreference preference) {
+ mEntries.clear();
+ mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue());
+ for (CharSequence entry : preference.getEntries()) {
+ mEntries.add(entry);
+ }
+ mEntryValues = preference.getEntryValues();
+ }
+
+ public void onListPreferenceUpdated(ListPreference preference) {
+ if (mAdapter != null) {
+ setPreferenceData(preference);
+ mAdapter.notifyDataSetChanged();
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiSliceBuilder.java b/src/com/android/settings/wifi/WifiSliceBuilder.java
new file mode 100644
index 0000000..96d1b82
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiSliceBuilder.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2018 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.wifi;
+
+import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
+import static android.provider.SettingsSlicesContract.KEY_WIFI;
+
+import android.annotation.ColorInt;
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiSsid;
+import android.provider.SettingsSlicesContract;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.SubSettings;
+import com.android.settings.Utils;
+import com.android.settings.search.DatabaseIndexingUtils;
+import com.android.settings.slices.SliceBroadcastReceiver;
+import com.android.settings.slices.SliceBuilderUtils;
+
+import androidx.slice.Slice;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+
+import android.support.v4.graphics.drawable.IconCompat;
+import android.text.TextUtils;
+
+/**
+ * Utility class to build a Wifi Slice, and handle all associated actions.
+ */
+public class WifiSliceBuilder {
+
+ /**
+ * Backing Uri for the Wifi Slice.
+ */
+ public static final Uri WIFI_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(KEY_WIFI)
+ .build();
+
+ /**
+ * Action notifying a change on the Wifi Slice.
+ */
+ public static final String ACTION_WIFI_SLICE_CHANGED =
+ "com.android.settings.wifi.action.WIFI_CHANGED";
+
+ public static final IntentFilter INTENT_FILTER = new IntentFilter();
+
+ static {
+ INTENT_FILTER.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ INTENT_FILTER.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ }
+
+ private WifiSliceBuilder() {
+ }
+
+ /**
+ * Return a Wifi Slice bound to {@link #WIFI_URI}.
+ * <p>
+ * Note that you should register a listener for {@link #INTENT_FILTER} to get changes for Wifi.
+ */
+ public static Slice getSlice(Context context) {
+ final boolean isWifiEnabled = isWifiEnabled(context);
+ final IconCompat icon = IconCompat.createWithResource(context,
+ R.drawable.ic_settings_wireless);
+ final String title = context.getString(R.string.wifi_settings);
+ final CharSequence summary = getSummary(context);
+ @ColorInt final int color = Utils.getColorAccent(context);
+ final PendingIntent toggleAction = getBroadcastIntent(context);
+ final PendingIntent primaryAction = getPrimaryAction(context);
+ final SliceAction primarySliceAction = new SliceAction(primaryAction, icon, title);
+ final SliceAction toggleSliceAction = new SliceAction(toggleAction, null /* actionTitle */,
+ isWifiEnabled);
+
+ return new ListBuilder(context, WIFI_URI, ListBuilder.INFINITY)
+ .setAccentColor(color)
+ .addRow(b -> b
+ .setTitle(title)
+ .setSubtitle(summary)
+ .addEndItem(toggleSliceAction)
+ .setPrimaryAction(primarySliceAction))
+ .build();
+ }
+
+ /**
+ * Update the current wifi status to the boolean value keyed by
+ * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}.
+ */
+ public static void handleUriChange(Context context, Intent intent) {
+ final WifiManager wifiManager = context.getSystemService(WifiManager.class);
+ final boolean newState = intent.getBooleanExtra(EXTRA_TOGGLE_STATE,
+ wifiManager.isWifiEnabled());
+ wifiManager.setWifiEnabled(newState);
+ // Do not notifyChange on Uri. The service takes longer to update the current value than it
+ // does for the Slice to check the current value again. Let {@link SliceBroadcastRelay}
+ // handle it.
+ }
+
+ private static boolean isWifiEnabled(Context context) {
+ final WifiManager wifiManager = context.getSystemService(WifiManager.class);
+
+ switch (wifiManager.getWifiState()) {
+ case WifiManager.WIFI_STATE_ENABLED:
+ case WifiManager.WIFI_STATE_ENABLING:
+ return true;
+ case WifiManager.WIFI_STATE_DISABLED:
+ case WifiManager.WIFI_STATE_DISABLING:
+ case WifiManager.WIFI_STATE_UNKNOWN:
+ default:
+ return false;
+ }
+ }
+
+ private static CharSequence getSummary(Context context) {
+ final WifiManager wifiManager = context.getSystemService(WifiManager.class);
+
+ switch (wifiManager.getWifiState()) {
+ case WifiManager.WIFI_STATE_ENABLED:
+ final String ssid = WifiInfo.removeDoubleQuotes(wifiManager.getConnectionInfo()
+ .getSSID());
+ if (TextUtils.equals(ssid, WifiSsid.NONE)) {
+ return context.getText(R.string.disconnected);
+ }
+ return ssid;
+ case WifiManager.WIFI_STATE_ENABLING:
+ return context.getText(R.string.disconnected);
+ case WifiManager.WIFI_STATE_DISABLED:
+ case WifiManager.WIFI_STATE_DISABLING:
+ return context.getText(R.string.switch_off_text);
+ case WifiManager.WIFI_STATE_UNKNOWN:
+ default:
+ return "";
+ }
+ }
+
+ private static PendingIntent getPrimaryAction(Context context) {
+ final String screenTitle = context.getText(R.string.wifi_settings).toString();
+ final Uri contentUri = new Uri.Builder().appendPath(KEY_WIFI).build();
+ final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
+ WifiSettings.class.getName(), KEY_WIFI, screenTitle,
+ MetricsEvent.DIALOG_WIFI_AP_EDIT);
+ intent.setClassName(context.getPackageName(), SubSettings.class.getName());
+ intent.setData(contentUri);
+
+ return PendingIntent.getActivity(context, 0 /* requestCode */,
+ intent, 0 /* flags */);
+ }
+
+ private static PendingIntent getBroadcastIntent(Context context) {
+ final Intent intent = new Intent(ACTION_WIFI_SLICE_CHANGED);
+ intent.setClass(context, SliceBroadcastReceiver.class);
+ return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+}
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java
index 7213148..a554e74 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java
@@ -20,6 +20,7 @@
import android.app.PendingIntent;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -38,6 +39,7 @@
import com.android.ims.ImsManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
+import com.android.settings.slices.SettingsSliceProvider;
import com.android.settings.slices.SliceBroadcastReceiver;
import com.android.settings.slices.SliceBuilderUtils;
@@ -77,15 +79,19 @@
"android.settings.WIFI_CALLING_SETTINGS";
/**
+ * Full {@link Uri} for the Wifi Calling Slice.
+ */
+ public static final Uri WIFI_CALLING_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(PATH_WIFI_CALLING)
+ .build();
+
+ /**
* Timeout for querying wifi calling setting from ims manager.
*/
private static final int TIMEOUT_MILLIS = 2000;
- /**
- * Time for which data contained in the slice can remain fresh.
- */
- private static final int SLICE_TTL_MILLIS = 60000;
-
protected SubscriptionManager mSubscriptionManager;
private final Context mContext;
@@ -182,7 +188,7 @@
final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
final String title = mContext.getString(R.string.wifi_calling_settings_title);
- return new ListBuilder(mContext, sliceUri, SLICE_TTL_MILLIS)
+ return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
.setColor(R.color.material_blue_500)
.addRow(b -> b
.setTitle(title)
@@ -260,7 +266,7 @@
private Slice getNonActionableWifiCallingSlice(String title, String subtitle, Uri sliceUri,
PendingIntent primaryActionIntent) {
final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
- return new ListBuilder(mContext, sliceUri, SLICE_TTL_MILLIS)
+ return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
.setColor(R.color.material_blue_500)
.addRow(b -> b
.setTitle(title)
diff --git a/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
index 1d9d3cd..9764a45 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
@@ -44,6 +44,7 @@
private static final String WIFI_TETHER_SETTINGS = "wifi_tether";
private static final IntentFilter AIRPLANE_INTENT_FILTER = new IntentFilter(
Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ private static final int ID_NULL = -1;
private final ConnectivityManager mConnectivityManager;
private final String[] mWifiRegexs;
@@ -152,7 +153,7 @@
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
- clearSummaryForAirplaneMode();
+ clearSummaryForAirplaneMode(R.string.wifi_hotspot_off_subtext);
}
}
};
@@ -194,10 +195,16 @@
}
private void clearSummaryForAirplaneMode() {
+ clearSummaryForAirplaneMode(ID_NULL);
+ }
+
+ private void clearSummaryForAirplaneMode(int defaultId) {
boolean isAirplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
if (isAirplaneMode) {
mPreference.setSummary(R.string.wifi_tether_disabled_by_airplane);
+ } else if (defaultId != ID_NULL){
+ mPreference.setSummary(defaultId);
}
}
//
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceControllerTest.java
index f5070ef..1d37883 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceControllerTest.java
@@ -43,6 +43,7 @@
private static final String DEVICE_NAME = "Nightshade";
private static final int ORDER = 1;
+ private static final String KEY_DEVICE_NAME = "test_key_name";
private Context mContext;
@Mock
@@ -61,8 +62,9 @@
when(mPreferenceScreen.getContext()).thenReturn(mContext);
mPreference = new Preference(mContext);
- mPreference.setKey(BluetoothDeviceNamePreferenceController.KEY_DEVICE_NAME);
- mController = spy(new BluetoothDeviceNamePreferenceController(mContext, mLocalAdapter));
+ mPreference.setKey(KEY_DEVICE_NAME);
+ mController = spy(new BluetoothDeviceNamePreferenceController(mContext, mLocalAdapter,
+ KEY_DEVICE_NAME));
doReturn(DEVICE_NAME).when(mController).getDeviceName();
}
@@ -82,7 +84,7 @@
Preference preference =
mController.createBluetoothDeviceNamePreference(mPreferenceScreen, ORDER);
- assertThat(preference.getKey()).isEqualTo(mController.KEY_DEVICE_NAME);
+ assertThat(preference.getKey()).isEqualTo(mController.getPreferenceKey());
assertThat(preference.getOrder()).isEqualTo(ORDER);
verify(mPreferenceScreen).addPreference(preference);
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java
index 6ba8593..65eae2c 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java
@@ -67,8 +67,9 @@
mPreference = new Preference(mContext);
mPreference.setKey(PREF_KEY);
- mController = spy(new BluetoothDeviceRenamePreferenceController(
- mContext, PREF_KEY, mFragment, mLocalAdapter));
+ mController = spy(new BluetoothDeviceRenamePreferenceController(mContext, mLocalAdapter,
+ PREF_KEY));
+ mController.setFragment(mFragment);
doReturn(DEVICE_NAME).when(mController).getDeviceName();
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java
new file mode 100644
index 0000000..444728a
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2018 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.connecteddevice;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import android.support.v7.preference.Preference;
+
+import com.android.settings.bluetooth.BluetoothDeviceUpdater;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.*;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class PreviouslyConnectedDevicePreferenceControllerTest {
+
+ private final String KEY = "test_key";
+
+ @Mock
+ private DashboardFragment mDashboardFragment;
+ @Mock
+ private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
+ @Mock
+ private PackageManager mPackageManager;
+
+ private Context mContext;
+ private PreviouslyConnectedDevicePreferenceController mPreConnectedDeviceController;
+ private Preference mPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ doReturn(mContext).when(mDashboardFragment).getContext();
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ mPreConnectedDeviceController =
+ new PreviouslyConnectedDevicePreferenceController(mContext, KEY);
+ mPreConnectedDeviceController.setBluetoothDeviceUpdater(mBluetoothDeviceUpdater);
+
+ mPreference = new Preference(mContext);
+ mPreConnectedDeviceController.setPreference(mPreference);
+ }
+
+ @Test
+ public void callbackCanRegisterAndUnregister() {
+ // register the callback in onStart()
+ mPreConnectedDeviceController.onStart();
+ verify(mBluetoothDeviceUpdater).registerCallback();
+
+ // unregister the callback in onStop()
+ mPreConnectedDeviceController.onStop();
+ verify(mBluetoothDeviceUpdater).unregisterCallback();
+ }
+
+ @Test
+ public void getAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
+ doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
+ assertThat(mPreConnectedDeviceController.getAvailabilityStatus()).isEqualTo(
+ CONDITIONALLY_UNAVAILABLE);
+ }
+ @Test
+ public void getAvailabilityStatus_hasBluetoothFeature_returnSupported() {
+ doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
+ assertThat(mPreConnectedDeviceController.getAvailabilityStatus()).isEqualTo(
+ AVAILABLE);
+ }
+
+ @Test
+ public void onDeviceAdded_addFirstDevice_preferenceIsEnable() {
+ doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
+ mPreConnectedDeviceController.setPreferenceSize(0);
+ mPreConnectedDeviceController.onDeviceAdded(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void onDeviceRemoved_removeLastDevice_preferenceIsDisable() {
+ doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
+ mPreConnectedDeviceController.setPreferenceSize(1);
+ mPreConnectedDeviceController.onDeviceRemoved(mPreference);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java
index bb68c0d..c62f63d 100644
--- a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java
@@ -163,13 +163,6 @@
}
@Test
- public void nightDisplaySuggestion_isNotCompleted_byDefault() {
- final ComponentName componentName =
- new ComponentName(mContext, NightDisplaySuggestionActivity.class);
- assertThat(mProvider.isSuggestionComplete(mContext, componentName)).isFalse();
- }
-
- @Test
public void testGetSmartSuggestionEnabledTaggedData_disabled() {
assertThat(mProvider.getLoggingTaggedData(mContext)).asList().containsExactly(
Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0));
diff --git a/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java
index 3bc7d52..7440f63 100644
--- a/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java
@@ -6,15 +6,22 @@
import android.content.ComponentName;
import android.provider.Settings.Secure;
import com.android.internal.app.ColorDisplayController;
+import com.android.settings.R;
import com.android.settings.Settings.NightDisplaySuggestionActivity;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
+@Config(shadows = {
+ SettingsShadowResources.class
+})
public class NightDisplayPreferenceControllerTest {
private NightDisplayPreferenceController mPreferenceController;
@@ -27,6 +34,7 @@
@After
public void tearDown() {
mPreferenceController = null;
+ SettingsShadowResources.reset();
}
@Test
@@ -58,4 +66,16 @@
new ComponentName(context, NightDisplaySuggestionActivity.class);
assertThat(mPreferenceController.isSuggestionComplete(context)).isTrue();
}
+
+ @Test
+ public void nightDisplaySuggestion_isCompleted_ifDisabled() {
+ final Application context = RuntimeEnvironment.application;
+ Secure.putInt(context.getContentResolver(),
+ Secure.NIGHT_DISPLAY_AUTO_MODE, ColorDisplayController.AUTO_MODE_DISABLED);
+ SettingsShadowResources.overrideResource(R.bool.config_night_light_suggestion_enabled, false);
+
+ final ComponentName componentName =
+ new ComponentName(context, NightDisplaySuggestionActivity.class);
+ assertThat(mPreferenceController.isSuggestionComplete(context)).isTrue();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index 70acb73..6d18109 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -17,6 +17,7 @@
package com.android.settings.fuelgauge;
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -29,6 +30,7 @@
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;
@@ -43,7 +45,7 @@
private static final String[] PACKAGES_MEDIA = {"com.android.providers.media"};
private static final String[] PACKAGES_SYSTEMUI = {"com.android.systemui"};
- @Mock
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
@Mock
private BatterySipper mBatterySipper;
@@ -55,6 +57,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mContext.getApplicationContext()).thenReturn(mContext);
mPowerFeatureProvider = new PowerUsageFeatureProviderImpl(mContext);
when(mPackageManager.getPackagesForUid(UID_CALENDAR)).thenReturn(PACKAGES_CALENDAR);
when(mPackageManager.getPackagesForUid(UID_MEDIA)).thenReturn(PACKAGES_MEDIA);
@@ -138,7 +141,18 @@
}
@Test
- public void testIsSmartBatterySupported_returnFalse() {
+ public void testIsSmartBatterySupported_smartBatterySupported_returnTrue() {
+ when(mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_smart_battery_available)).thenReturn(true);
+
+ assertThat(mPowerFeatureProvider.isSmartBatterySupported()).isTrue();
+ }
+
+ @Test
+ public void testIsSmartBatterySupported_smartBatteryNotSupported_returnFalse() {
+ when(mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_smart_battery_available)).thenReturn(false);
+
assertThat(mPowerFeatureProvider.isSmartBatterySupported()).isFalse();
}
}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeSliceBuilderTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeSliceBuilderTest.java
new file mode 100644
index 0000000..ba5ab82
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeSliceBuilderTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 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.notification;
+
+import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.provider.Settings;
+import android.support.v4.graphics.drawable.IconCompat;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.SliceTester;
+import com.android.settings.testutils.shadow.ShadowNotificationManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.List;
+
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.SliceMetadata;
+import androidx.slice.SliceProvider;
+import androidx.slice.core.SliceAction;
+import androidx.slice.widget.SliceLiveData;
+
+@Config(shadows = ShadowNotificationManager.class)
+@RunWith(SettingsRobolectricTestRunner.class)
+public class ZenModeSliceBuilderTest {
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+
+ // Prevent crash in SliceMetadata.
+ Resources resources = spy(mContext.getResources());
+ doReturn(60).when(resources).getDimensionPixelSize(anyInt());
+ doReturn(resources).when(mContext).getResources();
+
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ }
+
+ @Test
+ public void getZenModeSlice_correctSliceContent() {
+ final Slice dndSlice = ZenModeSliceBuilder.getSlice(mContext);
+ final SliceMetadata metadata = SliceMetadata.from(mContext, dndSlice);
+
+ final List<SliceAction> toggles = metadata.getToggles();
+ assertThat(toggles).hasSize(1);
+
+ final SliceAction primaryAction = metadata.getPrimaryAction();
+ assertThat(primaryAction.getIcon()).isNull();
+
+ final List<SliceItem> sliceItems = dndSlice.getItems();
+ SliceTester.assertTitle(sliceItems, mContext.getString(R.string.zen_mode_settings_title));
+ }
+
+ @Test
+ public void handleUriChange_turnOn_zenModeTurnsOn() {
+ final Intent intent = new Intent();
+ intent.putExtra(EXTRA_TOGGLE_STATE, true);
+ NotificationManager.from(mContext).setZenMode(Settings.Global.ZEN_MODE_OFF, null, "");
+
+ ZenModeSliceBuilder.handleUriChange(mContext, intent);
+
+ final int zenMode = NotificationManager.from(mContext).getZenMode();
+ assertThat(zenMode).isEqualTo(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ }
+
+ @Test
+ public void handleUriChange_turnOff_zenModeTurnsOff() {
+ final Intent intent = new Intent();
+ intent.putExtra(EXTRA_TOGGLE_STATE, false);
+ NotificationManager.from(mContext).setZenMode(
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, "");
+
+ ZenModeSliceBuilder.handleUriChange(mContext, intent);
+
+ final int zenMode = NotificationManager.from(mContext).getZenMode();
+ assertThat(zenMode).isEqualTo(Settings.Global.ZEN_MODE_OFF);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java b/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java
index 26c2830..d4c1580 100644
--- a/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java
+++ b/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java
@@ -15,7 +15,6 @@
package com.android.settings.search;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -24,6 +23,7 @@
import android.app.Activity;
import android.app.job.JobScheduler;
+import android.provider.Settings;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -47,7 +47,7 @@
}
@Test
- public void verifyDisabled() {
+ public void updateIndex_disabled_shouldDoNothing() {
when(mProvider.isIndexingEnabled()).thenReturn(false);
mProvider.updateIndex(mActivity, false);
@@ -55,7 +55,20 @@
}
@Test
- public void verifyIndexing() {
+ public void updateIndex_enabled_unprovisioned_shouldDoNothing() {
+ when(mProvider.isIndexingEnabled()).thenReturn(true);
+ Settings.Global.putInt(mActivity.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 0);
+
+ mProvider.updateIndex(mActivity, false);
+
+ verify(mProvider, never()).index(any(), any(), any(), any(), any());
+ }
+
+ @Test
+ public void updateIndex_enabled_provisioned_shouldIndex() {
+ Settings.Global.putInt(mActivity.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 1);
JobScheduler jobScheduler = mock(JobScheduler.class);
when(mProvider.isIndexingEnabled()).thenReturn(true);
when(mActivity.getSystemService(JobScheduler.class)).thenReturn(jobScheduler);
diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
index a0bd33a..9d8e6b4 100644
--- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
@@ -19,6 +19,7 @@
import static android.content.ContentResolver.SCHEME_CONTENT;
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -31,6 +32,8 @@
import android.os.StrictMode;
import android.provider.SettingsSlicesContract;
+import com.android.settings.wifi.WifiSliceBuilder;
+import com.android.settings.notification.ZenModeSliceBuilder;
import com.android.settings.testutils.DatabaseTestUtils;
import com.android.settings.testutils.FakeToggleController;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -45,6 +48,8 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import androidx.slice.Slice;
@@ -70,6 +75,14 @@
private SQLiteDatabase mDb;
private SliceManager mManager;
+ private static final List<Uri> SPECIAL_CASE_PLATFORM_URIS = Arrays.asList(
+ WifiSliceBuilder.WIFI_URI
+ );
+
+ private static final List<Uri> SPECIAL_CASE_OEM_URIS = Arrays.asList(
+ ZenModeSliceBuilder.ZEN_MODE_URI
+ );
+
@Before
public void setUp() {
mContext = spy(RuntimeEnvironment.application);
@@ -114,7 +127,7 @@
}
@Test
- public void testLoadSlice_doesntCacheWithoutPin() {
+ public void testLoadSlice_doesNotCacheWithoutPin() {
insertSpecialCase(KEY);
Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false);
@@ -213,6 +226,7 @@
.build();
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+ descendants.removeAll(SPECIAL_CASE_OEM_URIS);
assertThat(descendants).isEmpty();
}
@@ -226,6 +240,7 @@
.build();
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+ descendants.removeAll(SPECIAL_CASE_PLATFORM_URIS);
assertThat(descendants).isEmpty();
}
@@ -239,6 +254,7 @@
.build();
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+ descendants.removeAll(SPECIAL_CASE_OEM_URIS);
assertThat(descendants).isEmpty();
}
@@ -252,16 +268,18 @@
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.build();
- final Uri expectedUri = new Uri.Builder()
+ final Collection<Uri> expectedUris = new HashSet<>();
+ expectedUris.addAll(SPECIAL_CASE_OEM_URIS);
+ expectedUris.add(new Uri.Builder()
.scheme(SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(key)
- .build();
+ .build());
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
- assertThat(descendants).containsExactly(expectedUri);
+ assertThat(descendants).containsExactlyElementsIn(expectedUris);
}
@Test
@@ -272,16 +290,18 @@
.scheme(SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.build();
- final Uri expectedUri = new Uri.Builder()
+ final Collection<Uri> expectedUris = new HashSet<>();
+ expectedUris.addAll(SPECIAL_CASE_OEM_URIS);
+ expectedUris.add(new Uri.Builder()
.scheme(SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(key)
- .build();
+ .build());
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
- assertThat(descendants).containsExactly(expectedUri);
+ assertThat(descendants).containsExactlyElementsIn(expectedUris);
}
@Test
@@ -293,16 +313,18 @@
.authority(SettingsSlicesContract.AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.build();
- final Uri expectedUri = new Uri.Builder()
+ final Collection<Uri> expectedUris = new HashSet<>();
+ expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS);
+ expectedUris.add(new Uri.Builder()
.scheme(SCHEME_CONTENT)
.authority(SettingsSlicesContract.AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(key)
- .build();
+ .build());
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
- assertThat(descendants).containsExactly(expectedUri);
+ assertThat(descendants).containsExactlyElementsIn(expectedUris);
}
@Test
@@ -313,16 +335,18 @@
.scheme(SCHEME_CONTENT)
.authority(SettingsSlicesContract.AUTHORITY)
.build();
- final Uri expectedUri = new Uri.Builder()
+ final Collection<Uri> expectedUris = new HashSet<>();
+ expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS);
+ expectedUris.add(new Uri.Builder()
.scheme(SCHEME_CONTENT)
.authority(SettingsSlicesContract.AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(key)
- .build();
+ .build());
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
- assertThat(descendants).containsExactly(expectedUri);
+ assertThat(descendants).containsExactlyElementsIn(expectedUris);
}
@Test
@@ -334,22 +358,32 @@
final Uri uri = new Uri.Builder()
.scheme(SCHEME_CONTENT)
.build();
- final Uri expectedPlatformUri = new Uri.Builder()
+ final Collection<Uri> expectedUris = new HashSet<>();
+ expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS);
+ expectedUris.addAll(SPECIAL_CASE_OEM_URIS);
+ expectedUris.add(new Uri.Builder()
.scheme(SCHEME_CONTENT)
.authority(SettingsSlicesContract.AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(platformKey)
- .build();
- final Uri expectedOemUri = new Uri.Builder()
+ .build());
+ expectedUris.add(new Uri.Builder()
.scheme(SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(oemKey)
- .build();
+ .build());
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
- assertThat(descendants).containsExactly(expectedPlatformUri, expectedOemUri);
+ assertThat(descendants).containsExactlyElementsIn(expectedUris);
+ }
+
+ @Test
+ public void bindSlice_wifiSlice_returnsWifiSlice() {
+ final Slice wifiSlice = mProvider.onBindSlice(WifiSliceBuilder.WIFI_URI);
+
+ assertThat(wifiSlice.getUri()).isEqualTo(WifiSliceBuilder.WIFI_URI);
}
private void insertSpecialCase(String key) {
diff --git a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
index db09eab..6a573e0 100644
--- a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
@@ -16,7 +16,6 @@
package com.android.settings.sound;
-
import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID;
import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
@@ -93,6 +92,8 @@
private HeadsetProfile mHeadsetProfile;
@Mock
private HearingAidProfile mHearingAidProfile;
+ @Mock
+ private AudioSwitchPreferenceController.AudioSwitchCallback mAudioSwitchPreferenceCallback;
private Context mContext;
private PreferenceScreen mScreen;
@@ -156,6 +157,7 @@
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
mScreen.addPreference(mPreference);
mController.displayPreference(mScreen);
+ mController.setCallback(mAudioSwitchPreferenceCallback);
}
@After
diff --git a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
index b777239..6aec5ef 100644
--- a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
@@ -94,6 +94,8 @@
private A2dpProfile mA2dpProfile;
@Mock
private HearingAidProfile mHearingAidProfile;
+ @Mock
+ private AudioSwitchPreferenceController.AudioSwitchCallback mAudioSwitchPreferenceCallback;
private Context mContext;
private PreferenceScreen mScreen;
@@ -157,6 +159,7 @@
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
mScreen.addPreference(mPreference);
mController.displayPreference(mScreen);
+ mController.setCallback(mAudioSwitchPreferenceCallback);
}
@After
diff --git a/tests/robotests/src/com/android/settings/testutils/SliceTester.java b/tests/robotests/src/com/android/settings/testutils/SliceTester.java
index 4c4b040..f617aa9 100644
--- a/tests/robotests/src/com/android/settings/testutils/SliceTester.java
+++ b/tests/robotests/src/com/android/settings/testutils/SliceTester.java
@@ -35,6 +35,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import androidx.slice.Slice;
import androidx.slice.SliceItem;
@@ -211,7 +212,7 @@
assertKeywords(metadata, sliceData);
}
- private static void assertTitle(List<SliceItem> sliceItems, String title) {
+ public static void assertTitle(List<SliceItem> sliceItems, String title) {
boolean hasTitle = false;
for (SliceItem item : sliceItems) {
List<SliceItem> titleItems = SliceQuery.findAll(item, FORMAT_TEXT, HINT_TITLE,
@@ -230,8 +231,9 @@
private static void assertKeywords(SliceMetadata metadata, SliceData data) {
final List<String> keywords = metadata.getSliceKeywords();
- final Set<String> expectedKeywords = new HashSet<>(
- Arrays.asList(data.getKeywords().split(",")));
+ final Set<String> expectedKeywords = Arrays.stream(data.getKeywords().split(","))
+ .map(s -> s = s.trim())
+ .collect(Collectors.toSet());
expectedKeywords.add(data.getTitle());
expectedKeywords.add(data.getScreenTitle().toString());
assertThat(keywords).containsExactlyElementsIn(expectedKeywords);
diff --git a/tests/robotests/src/com/android/settings/widget/UpdatableListPreferenceDialogFragmentTest.java b/tests/robotests/src/com/android/settings/widget/UpdatableListPreferenceDialogFragmentTest.java
new file mode 100644
index 0000000..cd57654
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/widget/UpdatableListPreferenceDialogFragmentTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2018 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.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.support.v7.preference.ListPreference;
+import android.widget.ArrayAdapter;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+
+import static org.mockito.Mockito.spy;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(shadows = ShadowBluetoothUtils.class)
+public class UpdatableListPreferenceDialogFragmentTest {
+
+ private Context mContext;
+ private UpdatableListPreferenceDialogFragment mUpdatableListPrefDlgFragment;
+ private static final String KEY = "Test_Key";
+ private ArrayAdapter mAdapter;
+ private ArrayList<CharSequence> mEntries;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+
+ mUpdatableListPrefDlgFragment = UpdatableListPreferenceDialogFragment
+ .newInstance(KEY, MetricsProto.MetricsEvent.DIALOG_SWITCH_A2DP_DEVICES);
+ mEntries = spy(new ArrayList<>());
+ mUpdatableListPrefDlgFragment.setEntries(mEntries);
+ mUpdatableListPrefDlgFragment.
+ setMetricsCategory(mUpdatableListPrefDlgFragment.getArguments());
+ initAdapter();
+ }
+
+ private void initAdapter() {
+ mAdapter = spy(new ArrayAdapter<>(
+ mContext,
+ com.android.internal.R.layout.select_dialog_singlechoice,
+ mEntries));
+ mUpdatableListPrefDlgFragment.setAdapter(mAdapter);
+ }
+
+ @Test
+ public void getMetricsCategory() {
+ assertThat(mUpdatableListPrefDlgFragment.getMetricsCategory())
+ .isEqualTo(MetricsProto.MetricsEvent.DIALOG_SWITCH_A2DP_DEVICES);
+ }
+
+ @Test
+ public void onListPreferenceUpdated_verifyAdapterCanBeUpdate() {
+ assertThat(mUpdatableListPrefDlgFragment.getAdapter().getCount()).
+ isEqualTo(0);
+
+ ListPreference listPreference = new ListPreference(mContext);
+ final CharSequence[] charSequences = {"Test_DEVICE_1", "Test_DEVICE_2"};
+ listPreference.setEntries(charSequences);
+ mUpdatableListPrefDlgFragment.onListPreferenceUpdated(listPreference);
+
+ assertThat(mUpdatableListPrefDlgFragment.getAdapter().getCount()).
+ isEqualTo(2);
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiSliceBuilderTest.java b/tests/robotests/src/com/android/settings/wifi/WifiSliceBuilderTest.java
new file mode 100644
index 0000000..e4a3dfb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/WifiSliceBuilderTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 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.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.wifi.WifiSliceBuilder;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.SliceTester;
+
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.wifi.WifiManager;
+import android.support.v4.graphics.drawable.IconCompat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.List;
+
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.SliceMetadata;
+import androidx.slice.SliceProvider;
+import androidx.slice.core.SliceAction;
+import androidx.slice.widget.SliceLiveData;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class WifiSliceBuilderTest {
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+
+ // Prevent crash in SliceMetadata.
+ Resources resources = spy(mContext.getResources());
+ doReturn(60).when(resources).getDimensionPixelSize(anyInt());
+ doReturn(resources).when(mContext).getResources();
+
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ }
+
+ @Test
+ public void getWifiSlice_correctData() {
+ final Slice wifiSlice = WifiSliceBuilder.getSlice(mContext);
+ final SliceMetadata metadata = SliceMetadata.from(mContext, wifiSlice);
+
+ final List<SliceAction> toggles = metadata.getToggles();
+ assertThat(toggles).hasSize(1);
+
+ final SliceAction primaryAction = metadata.getPrimaryAction();
+ final IconCompat expectedToggleIcon = IconCompat.createWithResource(mContext,
+ R.drawable.ic_settings_wireless);
+ assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedToggleIcon.toString());
+
+ final List<SliceItem> sliceItems = wifiSlice.getItems();
+ SliceTester.assertTitle(sliceItems, mContext.getString(R.string.wifi_settings));
+ }
+
+ @Test
+ public void handleUriChange_updatesWifi() {
+ final Intent intent = new Intent(WifiSliceBuilder.ACTION_WIFI_SLICE_CHANGED);
+ intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true);
+ final WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
+
+ WifiSliceBuilder.handleUriChange(mContext, intent);
+
+ assertThat(wifiManager.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_ENABLED);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java
index b5d0f9d..149cd22 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java
@@ -123,7 +123,7 @@
}
@Test
- public void testReceiver_goingToAirplaneMode_shouldClearPreferenceSummary() {
+ public void testReceiver_turnOnAirplaneMode_clearPreferenceSummary() {
final ContentResolver cr = mock(ContentResolver.class);
when(mContext.getContentResolver()).thenReturn(cr);
Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, 1);
@@ -138,6 +138,21 @@
}
@Test
+ public void testReceiver_turnOffAirplaneMode_displayOffSummary() {
+ final ContentResolver cr = mock(ContentResolver.class);
+ when(mContext.getContentResolver()).thenReturn(cr);
+ Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, 0);
+ mController.displayPreference(mScreen);
+ final BroadcastReceiver receiver = ReflectionHelpers.getField(mController, "mReceiver");
+ final Intent broadcast = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+
+ receiver.onReceive(RuntimeEnvironment.application, broadcast);
+
+ assertThat(mPreference.getSummary().toString()).isEqualTo(
+ "Not sharing internet or content with other devices");
+ }
+
+ @Test
public void testHandleWifiApStateChanged_stateEnabling_showEnablingSummary() {
mController.handleWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0 /* reason */);