Merge "Only show first 5 items in sound setting until click More."
diff --git a/res/layout/account_header.xml b/res/layout/account_header.xml
new file mode 100755
index 0000000..7cae95e
--- /dev/null
+++ b/res/layout/account_header.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/EntityHeader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:gravity="center_vertical"
+ android:paddingTop="24dip"
+ android:paddingBottom="24dip"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:id="@+id/icon_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="60dp"
+ android:orientation="horizontal"
+ android:paddingEnd="12dp"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp">
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxWidth="48dp"
+ android:maxHeight="48dp"/>
+ </LinearLayout>
+
+ <TextView
+ android:id="@android:id/title"
+ style="@style/TextAppearance.EntityHeaderTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"/>
+
+</LinearLayout>
diff --git a/res/layout/app_details.xml b/res/layout/app_details.xml
index 4e654fd..7994a4c 100644
--- a/res/layout/app_details.xml
+++ b/res/layout/app_details.xml
@@ -18,7 +18,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/app_snippet"
- style="@style/AppHeader"
+ style="@style/EntityHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top"
@@ -37,7 +37,7 @@
<TextView
android:id="@android:id/title"
- style="@style/TextAppearance.AppHeaderTitle"
+ style="@style/TextAppearance.EntityHeaderTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
diff --git a/res/layout/remove_account_button.xml b/res/layout/remove_account_button.xml
new file mode 100644
index 0000000..6b47c37
--- /dev/null
+++ b/res/layout/remove_account_button.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <Button
+ android:id="@+id/button"
+ android:text="@string/remove_account_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="20dip"
+ android:layout_marginBottom="12dip"
+ android:gravity="center" />
+
+</LinearLayout>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 35b06eb..a3baa21 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -417,7 +417,7 @@
<item name="android:progressDrawable">@drawable/ring_progress</item>
</style>
- <style name="AppHeader">
+ <style name="EntityHeader">
<item name="android:background">@color/card_background_grey</item>
<item name="android:gravity">center_horizontal</item>
<item name="android:paddingTop">16dp</item>
@@ -426,7 +426,7 @@
<item name="android:paddingBottom">8dp</item>
</style>
- <style name="TextAppearance.AppHeaderTitle"
+ <style name="TextAppearance.EntityHeaderTitle"
parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">24sp</item>
diff --git a/res/xml/account_type_settings.xml b/res/xml/account_type_settings.xml
index d6ba9be..91e90fe 100644
--- a/res/xml/account_type_settings.xml
+++ b/res/xml/account_type_settings.xml
@@ -20,6 +20,12 @@
settings:keywords="@string/keywords_accounts">
<Preference
+ android:key="account_header"
+ android:layout="@layout/account_header"
+ android:selectable="false"
+ android:order="0"/>
+
+ <Preference
android:key="account_sync"
android:title="@string/account_sync_title"
android:icon="@drawable/ic_sync"
@@ -29,4 +35,9 @@
android:key="dashboard_tile_placeholder"
android:order="10"/>
+ <com.android.settings.applications.LayoutPreference
+ android:key="remove_account"
+ android:layout="@layout/remove_account_button"
+ android:order="100" />
+
</PreferenceScreen>
diff --git a/res/xml/channel_notification_settings.xml b/res/xml/channel_notification_settings.xml
index c2d1f73..e1d6d55 100644
--- a/res/xml/channel_notification_settings.xml
+++ b/res/xml/channel_notification_settings.xml
@@ -27,15 +27,6 @@
settings:useAdditionalSummary="true"
settings:restrictedSwitchSummary="@string/enabled_by_admin" />
- <!-- Show notification -->
- <com.android.settingslib.RestrictedSwitchPreference
- android:key="show"
- android:title="@string/notification_content_block_title"
- android:summary="@string/notification_content_block_summary"
- android:order="2"
- settings:useAdditionalSummary="true"
- settings:restrictedSwitchSummary="@string/enabled_by_admin" />
-
<!-- Show badge -->
<com.android.settingslib.RestrictedSwitchPreference
android:key="badge"
diff --git a/res/xml/development_prefs.xml b/res/xml/development_prefs.xml
index bdbd86f..3c2bab9 100644
--- a/res/xml/development_prefs.xml
+++ b/res/xml/development_prefs.xml
@@ -196,6 +196,42 @@
android:key="bluetooth_disable_absolute_volume"
android:title="@string/bluetooth_disable_absolute_volume"
android:summary="@string/bluetooth_disable_absolute_volume_summary"/>
+
+ <ListPreference
+ android:key="bluetooth_select_a2dp_codec"
+ android:title="@string/bluetooth_select_a2dp_codec_type"
+ android:dialogTitle="@string/bluetooth_select_a2dp_codec_type_dialog_title"
+ android:entries="@array/bluetooth_a2dp_codec_titles"
+ android:entryValues="@array/bluetooth_a2dp_codec_values" />
+
+ <ListPreference
+ android:key="bluetooth_select_a2dp_sample_rate"
+ android:title="@string/bluetooth_select_a2dp_codec_sample_rate"
+ android:dialogTitle="@string/bluetooth_select_a2dp_codec_sample_rate_dialog_title"
+ android:entries="@array/bluetooth_a2dp_codec_sample_rate_titles"
+ android:entryValues="@array/bluetooth_a2dp_codec_sample_rate_values" />
+
+ <ListPreference
+ android:key="bluetooth_select_a2dp_bits_per_sample"
+ android:title="@string/bluetooth_select_a2dp_codec_bits_per_sample"
+ android:dialogTitle="@string/bluetooth_select_a2dp_codec_bits_per_sample_dialog_title"
+ android:entries="@array/bluetooth_a2dp_codec_bits_per_sample_titles"
+ android:entryValues="@array/bluetooth_a2dp_codec_bits_per_sample_values" />
+
+ <ListPreference
+ android:key="bluetooth_select_a2dp_channel_mode"
+ android:title="@string/bluetooth_select_a2dp_codec_channel_mode"
+ android:dialogTitle="@string/bluetooth_select_a2dp_codec_channel_mode_dialog_title"
+ android:entries="@array/bluetooth_a2dp_codec_channel_mode_titles"
+ android:entryValues="@array/bluetooth_a2dp_codec_channel_mode_values" />
+
+ <ListPreference
+ android:key="bluetooth_select_a2dp_ldac_playback_quality"
+ android:title="@string/bluetooth_select_a2dp_codec_ldac_playback_quality"
+ android:dialogTitle="@string/bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title"
+ android:entries="@array/bluetooth_a2dp_codec_ldac_playback_quality_titles"
+ android:entryValues="@array/bluetooth_a2dp_codec_ldac_playback_quality_values" />
+
</PreferenceCategory>
<PreferenceCategory android:key="debug_input_category"
diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java
index 1ae3380..418c1e2 100644
--- a/src/com/android/settings/DevelopmentSettings.java
+++ b/src/com/android/settings/DevelopmentSettings.java
@@ -25,7 +25,10 @@
import android.app.Dialog;
import android.app.admin.DevicePolicyManager;
import android.app.backup.IBackupManager;
+import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -201,6 +204,12 @@
private static final String BLUETOOTH_DISABLE_ABSOLUTE_VOLUME_PROPERTY =
"persist.bluetooth.disableabsvol";
+ private static final String BLUETOOTH_SELECT_A2DP_CODEC_KEY = "bluetooth_select_a2dp_codec";
+ private static final String BLUETOOTH_SELECT_A2DP_SAMPLE_RATE_KEY = "bluetooth_select_a2dp_sample_rate";
+ private static final String BLUETOOTH_SELECT_A2DP_BITS_PER_SAMPLE_KEY = "bluetooth_select_a2dp_bits_per_sample";
+ private static final String BLUETOOTH_SELECT_A2DP_CHANNEL_MODE_KEY = "bluetooth_select_a2dp_channel_mode";
+ private static final String BLUETOOTH_SELECT_A2DP_LDAC_PLAYBACK_QUALITY_KEY = "bluetooth_select_a2dp_ldac_playback_quality";
+
private static final String INACTIVE_APPS_KEY = "inactive_apps";
private static final String IMMEDIATELY_DESTROY_ACTIVITIES_KEY
@@ -268,8 +277,16 @@
private SwitchPreference mWifiAggressiveHandover;
private SwitchPreference mMobileDataAlwaysOn;
private SwitchPreference mBluetoothDisableAbsVolume;
- private SwitchPreference mOtaDisableAutomaticUpdate;
+ private BluetoothA2dp mBluetoothA2dp;
+ private final Object mBluetoothA2dpLock = new Object();
+ private ListPreference mBluetoothSelectA2dpCodec;
+ private ListPreference mBluetoothSelectA2dpSampleRate;
+ private ListPreference mBluetoothSelectA2dpBitsPerSample;
+ private ListPreference mBluetoothSelectA2dpChannelMode;
+ private ListPreference mBluetoothSelectA2dpLdacPlaybackQuality;
+
+ private SwitchPreference mOtaDisableAutomaticUpdate;
private SwitchPreference mWifiAllowScansWithTraffic;
private SwitchPreference mStrictMode;
private SwitchPreference mPointerLocation;
@@ -470,6 +487,12 @@
mWebViewMultiprocess = findAndInitSwitchPref(WEBVIEW_MULTIPROCESS_KEY);
mBluetoothDisableAbsVolume = findAndInitSwitchPref(BLUETOOTH_DISABLE_ABSOLUTE_VOLUME_KEY);
+ mBluetoothSelectA2dpCodec = addListPreference(BLUETOOTH_SELECT_A2DP_CODEC_KEY);
+ mBluetoothSelectA2dpSampleRate = addListPreference(BLUETOOTH_SELECT_A2DP_SAMPLE_RATE_KEY);
+ mBluetoothSelectA2dpBitsPerSample = addListPreference(BLUETOOTH_SELECT_A2DP_BITS_PER_SAMPLE_KEY);
+ mBluetoothSelectA2dpChannelMode = addListPreference(BLUETOOTH_SELECT_A2DP_CHANNEL_MODE_KEY);
+ mBluetoothSelectA2dpLdacPlaybackQuality = addListPreference(BLUETOOTH_SELECT_A2DP_LDAC_PLAYBACK_QUALITY_KEY);
+
mWindowAnimationScale = addListPreference(WINDOW_ANIMATION_SCALE_KEY);
mTransitionAnimationScale = addListPreference(TRANSITION_ANIMATION_SCALE_KEY);
mAnimatorDurationScale = addListPreference(ANIMATOR_DURATION_SCALE_KEY);
@@ -675,6 +698,20 @@
if (getActivity().registerReceiver(mUsbReceiver, filter) == null) {
updateUsbConfigurationValues();
}
+
+ initBluetoothConfigurationValues();
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ adapter.getProfileProxy(getActivity(),
+ mBluetoothA2dpServiceListener,
+ BluetoothProfile.A2DP);
+ }
+ filter = new IntentFilter();
+ filter.addAction(BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED);
+ if (getActivity().registerReceiver(mBluetoothA2dpReceiver, filter) == null) {
+ updateBluetoothA2dpConfigurationValues();
+ }
+
return super.onCreateView(inflater, container, savedInstanceState);
}
@@ -688,6 +725,12 @@
mSwitchBar.removeOnSwitchChangeListener(this);
mSwitchBar.hide();
getActivity().unregisterReceiver(mUsbReceiver);
+ getActivity().unregisterReceiver(mBluetoothA2dpReceiver);
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ adapter.closeProfileProxy(BluetoothProfile.A2DP, mBluetoothA2dp);
+ mBluetoothA2dp = null;
+ }
}
void updateSwitchPreference(SwitchPreference switchPreference, boolean value) {
@@ -757,6 +800,7 @@
updateColorTemperature();
}
updateBluetoothDisableAbsVolumeOptions();
+ updateBluetoothA2dpConfigurationValues();
}
private void resetDangerousOptions() {
@@ -1737,6 +1781,361 @@
}
}
+ private void initBluetoothConfigurationValues() {
+ String[] values;
+ String[] titles;
+ int index;
+
+ // Init the Codec Type - Default
+ values = getResources().getStringArray(R.array.bluetooth_a2dp_codec_values);
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_titles);
+ index = 0;
+ mBluetoothSelectA2dpCodec.setValue(values[index]);
+ mBluetoothSelectA2dpCodec.setSummary(titles[index]);
+
+ // Init the Sample Rate - Default
+ values = getResources().getStringArray(R.array.bluetooth_a2dp_codec_sample_rate_values);
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_sample_rate_titles);
+ index = 0;
+ mBluetoothSelectA2dpSampleRate.setValue(values[index]);
+ mBluetoothSelectA2dpSampleRate.setSummary(titles[index]);
+
+ // Init the Bits Per Sample - Default
+ values = getResources().getStringArray(R.array.bluetooth_a2dp_codec_bits_per_sample_values);
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_bits_per_sample_titles);
+ index = 0;
+ mBluetoothSelectA2dpBitsPerSample.setValue(values[index]);
+ mBluetoothSelectA2dpBitsPerSample.setSummary(titles[index]);
+
+ // Init the Channel Mode - Default
+ values = getResources().getStringArray(R.array.bluetooth_a2dp_codec_channel_mode_values);
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_channel_mode_titles);
+ index = 0;
+ mBluetoothSelectA2dpChannelMode.setValue(values[index]);
+ mBluetoothSelectA2dpChannelMode.setSummary(titles[index]);
+
+ // Init the LDAC Playback Quality - High
+ values = getResources().getStringArray(R.array.bluetooth_a2dp_codec_ldac_playback_quality_values);
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_ldac_playback_quality_titles);
+ index = 0;
+ mBluetoothSelectA2dpLdacPlaybackQuality.setValue(values[index]);
+ mBluetoothSelectA2dpLdacPlaybackQuality.setSummary(titles[index]);
+ }
+
+ private void updateBluetoothA2dpConfigurationValues() {
+ int index;
+ String[] titles;
+ BluetoothCodecConfig codecConfig = null;
+
+ synchronized (mBluetoothA2dpLock) {
+ if (mBluetoothA2dp != null) {
+ codecConfig = mBluetoothA2dp.getCodecConfig();
+ }
+ }
+ if (codecConfig == null)
+ return;
+
+ // Update the Codec Type
+ index = -1;
+ switch (codecConfig.getCodecType()) {
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC:
+ index = 1;
+ break;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX:
+ index = 2;
+ break;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD:
+ index = 3;
+ break;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC:
+ index = 4;
+ break;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID:
+ default:
+ break;
+ }
+ if (index >= 0) {
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_titles);
+ mBluetoothSelectA2dpCodec.setSummary("Streaming: " + titles[index]);
+ }
+
+ // Update the Sample Rate
+ index = -1;
+ switch (codecConfig.getSampleRate()) {
+ case BluetoothCodecConfig.SAMPLE_RATE_44100:
+ index = 1;
+ break;
+ case BluetoothCodecConfig.SAMPLE_RATE_48000:
+ index = 2;
+ break;
+ case BluetoothCodecConfig.SAMPLE_RATE_88200:
+ index = 3;
+ break;
+ case BluetoothCodecConfig.SAMPLE_RATE_96000:
+ index = 4;
+ break;
+ case BluetoothCodecConfig.SAMPLE_RATE_176400:
+ case BluetoothCodecConfig.SAMPLE_RATE_192000:
+ case BluetoothCodecConfig.SAMPLE_RATE_NONE:
+ default:
+ break;
+ }
+ if (index >= 0) {
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_sample_rate_titles);
+ mBluetoothSelectA2dpSampleRate.setSummary("Streaming: " + titles[index]);
+ }
+
+ // Update the Bits Per Sample
+ index = -1;
+ switch (codecConfig.getBitsPerSample()) {
+ case BluetoothCodecConfig.BITS_PER_SAMPLE_16:
+ index = 1;
+ break;
+ case BluetoothCodecConfig.BITS_PER_SAMPLE_24:
+ index = 2;
+ break;
+ case BluetoothCodecConfig.BITS_PER_SAMPLE_32:
+ index = 3;
+ break;
+ case BluetoothCodecConfig.BITS_PER_SAMPLE_NONE:
+ default:
+ break;
+ }
+ if (index >= 0) {
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_bits_per_sample_titles);
+ mBluetoothSelectA2dpBitsPerSample.setSummary("Streaming: " + titles[index]);
+ }
+
+ // Update the Channel Mode
+ index = -1;
+ switch (codecConfig.getChannelMode()) {
+ case BluetoothCodecConfig.CHANNEL_MODE_MONO:
+ index = 1;
+ break;
+ case BluetoothCodecConfig.CHANNEL_MODE_STEREO:
+ index = 2;
+ break;
+ case BluetoothCodecConfig.CHANNEL_MODE_NONE:
+ default:
+ break;
+ }
+ if (index >= 0) {
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_channel_mode_titles);
+ mBluetoothSelectA2dpChannelMode.setSummary("Streaming: " + titles[index]);
+ }
+
+ // Update the LDAC Playback Quality
+ index = -1;
+ switch ((int)codecConfig.getCodecSpecific1()) {
+ case 1000:
+ index = 0;
+ break;
+ case 1001:
+ index = 1;
+ break;
+ case 1002:
+ index = 2;
+ break;
+ default:
+ break;
+ }
+ if (index >= 0) {
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_ldac_playback_quality_titles);
+ mBluetoothSelectA2dpLdacPlaybackQuality.setSummary("Streaming: " + titles[index]);
+ }
+ }
+
+ private void writeBluetoothConfigurationOption(Preference preference,
+ Object newValue) {
+ String[] titles;
+ int index;
+ int codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID;
+ int codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
+ int sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_NONE;
+ int bitsPerSampleValue = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE;
+ int channelModeValue = BluetoothCodecConfig.CHANNEL_MODE_NONE;
+ long codecSpecific1Value = 0;
+ long codecSpecific2Value = 0;
+ long codecSpecific3Value = 0;
+ long codecSpecific4Value = 0;
+
+ // Codec Type
+ String codecType = mBluetoothSelectA2dpCodec.getValue();
+ if (preference == mBluetoothSelectA2dpCodec) {
+ codecType = newValue.toString();
+ index = mBluetoothSelectA2dpCodec.findIndexOfValue(newValue.toString());
+ if (index >= 0) {
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_titles);
+ mBluetoothSelectA2dpCodec.setSummary(titles[index]);
+ }
+ }
+ index = mBluetoothSelectA2dpCodec.findIndexOfValue(codecType);
+ switch (index) {
+ case 0:
+ // Reset the priority of the current codec to default
+ String oldValue = mBluetoothSelectA2dpCodec.getValue();
+ switch (mBluetoothSelectA2dpCodec.findIndexOfValue(oldValue)) {
+ case 0:
+ break; // No current codec
+ case 1:
+ codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC;
+ break;
+ case 2:
+ codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX;
+ break;
+ case 3:
+ codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD;
+ break;
+ case 4:
+ codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 1:
+ codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC;
+ codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
+ break;
+ case 2:
+ codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX;
+ codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
+ break;
+ case 3:
+ codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD;
+ codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
+ break;
+ case 4:
+ codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC;
+ codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
+ break;
+ default:
+ break;
+ }
+
+ // Sample Rate
+ String sampleRate = mBluetoothSelectA2dpSampleRate.getValue();
+ if (preference == mBluetoothSelectA2dpSampleRate) {
+ sampleRate = newValue.toString();
+ index = mBluetoothSelectA2dpSampleRate.findIndexOfValue(newValue.toString());
+ if (index >= 0) {
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_sample_rate_titles);
+ mBluetoothSelectA2dpSampleRate.setSummary(titles[index]);
+ }
+ }
+ index = mBluetoothSelectA2dpSampleRate.findIndexOfValue(sampleRate);
+ switch (index) {
+ case 0:
+ // Reset to default
+ break;
+ case 1:
+ sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_44100;
+ break;
+ case 2:
+ sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_48000;
+ break;
+ case 3:
+ sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_88200;
+ break;
+ case 4:
+ sampleRateValue = BluetoothCodecConfig.SAMPLE_RATE_96000;
+ break;
+ default:
+ break;
+ }
+
+ // Bits Per Sample
+ String bitsPerSample = mBluetoothSelectA2dpBitsPerSample.getValue();
+ if (preference == mBluetoothSelectA2dpBitsPerSample) {
+ bitsPerSample = newValue.toString();
+ index = mBluetoothSelectA2dpBitsPerSample.findIndexOfValue(newValue.toString());
+ if (index >= 0) {
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_bits_per_sample_titles);
+ mBluetoothSelectA2dpBitsPerSample.setSummary(titles[index]);
+ }
+ }
+ index = mBluetoothSelectA2dpBitsPerSample.findIndexOfValue(bitsPerSample);
+ switch (index) {
+ case 0:
+ // Reset to default
+ break;
+ case 1:
+ bitsPerSampleValue = BluetoothCodecConfig.BITS_PER_SAMPLE_16;
+ break;
+ case 2:
+ bitsPerSampleValue = BluetoothCodecConfig.BITS_PER_SAMPLE_24;
+ break;
+ case 3:
+ bitsPerSampleValue = BluetoothCodecConfig.BITS_PER_SAMPLE_32;
+ break;
+ default:
+ break;
+ }
+
+ // Channel Mode
+ String channelMode = mBluetoothSelectA2dpChannelMode.getValue();
+ if (preference == mBluetoothSelectA2dpChannelMode) {
+ channelMode = newValue.toString();
+ index = mBluetoothSelectA2dpChannelMode.findIndexOfValue(newValue.toString());
+ if (index >= 0) {
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_channel_mode_titles);
+ mBluetoothSelectA2dpChannelMode.setSummary(titles[index]);
+ }
+ }
+ index = mBluetoothSelectA2dpChannelMode.findIndexOfValue(channelMode);
+ switch (index) {
+ case 0:
+ // Reset to default
+ break;
+ case 1:
+ channelModeValue = BluetoothCodecConfig.CHANNEL_MODE_MONO;
+ break;
+ case 2:
+ channelModeValue = BluetoothCodecConfig.CHANNEL_MODE_STEREO;
+ break;
+ default:
+ break;
+ }
+
+ // LDAC Playback Quality
+ String ldacPlaybackQuality = mBluetoothSelectA2dpLdacPlaybackQuality.getValue();
+ if (preference == mBluetoothSelectA2dpLdacPlaybackQuality) {
+ ldacPlaybackQuality = newValue.toString();
+ index = mBluetoothSelectA2dpLdacPlaybackQuality.findIndexOfValue(newValue.toString());
+ if (index >= 0) {
+ titles = getResources().getStringArray(R.array.bluetooth_a2dp_codec_ldac_playback_quality_titles);
+ mBluetoothSelectA2dpLdacPlaybackQuality.setSummary(titles[index]);
+ }
+ }
+ index = mBluetoothSelectA2dpLdacPlaybackQuality.findIndexOfValue(ldacPlaybackQuality);
+ switch (index) {
+ case 0:
+ codecSpecific1Value = 1000;
+ break;
+ case 1:
+ codecSpecific1Value = 1001;
+ break;
+ case 2:
+ codecSpecific1Value = 1002;
+ break;
+ default:
+ break;
+ }
+
+ BluetoothCodecConfig codecConfig =
+ new BluetoothCodecConfig(codecTypeValue, codecPriorityValue,
+ sampleRateValue, bitsPerSampleValue,
+ channelModeValue, codecSpecific1Value,
+ codecSpecific2Value, codecSpecific3Value,
+ codecSpecific4Value);
+
+ synchronized (mBluetoothA2dpLock) {
+ if (mBluetoothA2dp != null) {
+ mBluetoothA2dp.setCodecConfigPreference(codecConfig);
+ }
+ }
+ }
+
private void writeImmediatelyDestroyActivitiesOptions() {
try {
ActivityManager.getService().setAlwaysFinish(
@@ -2115,6 +2514,13 @@
toast.show();
}
return false;
+ } else if ((preference == mBluetoothSelectA2dpCodec) ||
+ (preference == mBluetoothSelectA2dpSampleRate) ||
+ (preference == mBluetoothSelectA2dpBitsPerSample) ||
+ (preference == mBluetoothSelectA2dpChannelMode) ||
+ (preference == mBluetoothSelectA2dpLdacPlaybackQuality)) {
+ writeBluetoothConfigurationOption(preference, newValue);
+ return true;
} else if (preference == mLogdSize) {
writeLogdSizeOption(newValue);
return true;
@@ -2254,6 +2660,31 @@
}
};
+ private BroadcastReceiver mBluetoothA2dpReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateBluetoothA2dpConfigurationValues();
+ }
+ };
+
+ private BluetoothProfile.ServiceListener mBluetoothA2dpServiceListener =
+ new BluetoothProfile.ServiceListener() {
+ public void onServiceConnected(int profile,
+ BluetoothProfile proxy) {
+ synchronized (mBluetoothA2dpLock) {
+ mBluetoothA2dp = (BluetoothA2dp) proxy;
+ }
+ updateBluetoothA2dpConfigurationValues();
+ }
+
+ public void onServiceDisconnected(int profile) {
+ synchronized (mBluetoothA2dpLock) {
+ mBluetoothA2dp = null;
+ }
+ updateBluetoothA2dpConfigurationValues();
+ }
+ };
+
public static class SystemPropPoker extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index d5920e5..33c8eca 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -63,7 +63,6 @@
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.qstile.DevelopmentModeTile;
import com.android.settings.search.DynamicIndexableContentMonitor;
-import com.android.settings.search.Index;
import com.android.settings.search2.SearchFeatureProvider;
import com.android.settings.widget.SwitchBar;
import com.android.settingslib.drawer.DashboardCategory;
@@ -939,56 +938,56 @@
String packageName = getPackageName();
setTileEnabled(new ComponentName(packageName, WifiSettingsActivity.class.getName()),
- pm.hasSystemFeature(PackageManager.FEATURE_WIFI), isAdmin, pm);
+ pm.hasSystemFeature(PackageManager.FEATURE_WIFI), isAdmin);
setTileEnabled(new ComponentName(packageName,
Settings.BluetoothSettingsActivity.class.getName()),
- pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH), isAdmin, pm);
+ pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH), isAdmin);
setTileEnabled(new ComponentName(packageName,
Settings.DataUsageSummaryActivity.class.getName()),
- Utils.isBandwidthControlEnabled(), isAdmin, pm);
+ Utils.isBandwidthControlEnabled(), isAdmin);
setTileEnabled(new ComponentName(packageName,
Settings.SimSettingsActivity.class.getName()),
- Utils.showSimCardTile(this), isAdmin, pm);
+ Utils.showSimCardTile(this), isAdmin);
setTileEnabled(new ComponentName(packageName,
Settings.PowerUsageSummaryActivity.class.getName()),
- mBatteryPresent, isAdmin, pm);
+ mBatteryPresent, isAdmin);
setTileEnabled(new ComponentName(packageName,
Settings.UserSettingsActivity.class.getName()),
UserHandle.MU_ENABLED && UserManager.supportsMultipleUsers()
- && !Utils.isMonkeyRunning(), isAdmin, pm);
+ && !Utils.isMonkeyRunning(), isAdmin);
setTileEnabled(new ComponentName(packageName,
Settings.WirelessSettingsActivity.class.getName()),
- !UserManager.isDeviceInDemoMode(this), isAdmin, pm);
+ !UserManager.isDeviceInDemoMode(this), isAdmin);
setTileEnabled(new ComponentName(packageName,
Settings.DateTimeSettingsActivity.class.getName()),
- !UserManager.isDeviceInDemoMode(this), isAdmin, pm);
+ !UserManager.isDeviceInDemoMode(this), isAdmin);
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
setTileEnabled(new ComponentName(packageName,
Settings.PaymentSettingsActivity.class.getName()),
pm.hasSystemFeature(PackageManager.FEATURE_NFC)
&& pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
- && adapter != null && adapter.isEnabled(), isAdmin, pm);
+ && adapter != null && adapter.isEnabled(), isAdmin);
setTileEnabled(new ComponentName(packageName,
Settings.PrintSettingsActivity.class.getName()),
- pm.hasSystemFeature(PackageManager.FEATURE_PRINTING), isAdmin, pm);
+ pm.hasSystemFeature(PackageManager.FEATURE_PRINTING), isAdmin);
final boolean showDev = mDevelopmentPreferences.getBoolean(
DevelopmentSettings.PREF_SHOW, android.os.Build.TYPE.equals("eng"))
&& !um.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES);
setTileEnabled(new ComponentName(packageName,
Settings.DevelopmentSettingsActivity.class.getName()),
- showDev, isAdmin, pm);
+ showDev, isAdmin);
setTileEnabled(new ComponentName(packageName,
Settings.DevelopmentSettingsActivity.DASHBOARD_ALIAS),
- showDev, isAdmin, pm);
+ showDev, isAdmin);
// Reveal development-only quick settings tiles
setTileEnabled(new ComponentName(this, DevelopmentModeTile.class), showDev);
@@ -1007,7 +1006,7 @@
ComponentName component = tile.intent.getComponent();
if (packageName.equals(component.getPackageName()) && !ArrayUtils.contains(
SETTINGS_FOR_RESTRICTED, component.getClassName())) {
- setTileEnabled(component, false, isAdmin, pm);
+ setTileEnabled(component, false, isAdmin);
}
}
}
@@ -1016,10 +1015,10 @@
String backupIntent = getResources().getString(R.string.config_backup_settings_intent);
boolean useDefaultBackup = TextUtils.isEmpty(backupIntent);
setTileEnabled(new ComponentName(packageName,
- Settings.PrivacySettingsActivity.class.getName()), useDefaultBackup, isAdmin, pm);
+ Settings.PrivacySettingsActivity.class.getName()), useDefaultBackup, isAdmin);
setTileEnabled(new ComponentName(packageName,
"com.android.settings.PrivacyDashboardAlias"),
- useDefaultBackup, isAdmin, pm);
+ useDefaultBackup, isAdmin);
boolean hasBackupActivity = false;
if (!useDefaultBackup) {
@@ -1031,24 +1030,25 @@
}
}
- // Enable/disble BackupSettingsActivity and its alias.
+ // Enable/disable BackupSettingsActivity and its alias.
setTileEnabled(new ComponentName(packageName,
- BackupSettingsActivity.class.getName()), hasBackupActivity, isAdmin, pm);
+ BackupSettingsActivity.class.getName()), hasBackupActivity, isAdmin);
setTileEnabled(new ComponentName(packageName,
- "com.android.settings.BackupResetDashboardAlias"), hasBackupActivity, isAdmin, pm);
+ "com.android.settings.BackupResetDashboardAlias"), hasBackupActivity, isAdmin);
setTileEnabled(new ComponentName(packageName,
Settings.EnterprisePrivacySettingsActivity.class.getName()),
FeatureFactory.getFactory(this).getEnterprisePrivacyFeatureProvider(this)
- .hasDeviceOwner(), isAdmin, pm);
+ .hasDeviceOwner(), isAdmin);
setTileEnabled(new ComponentName(packageName,
"com.android.settings.EnterprisePrivacyDashboardAlias"),
FeatureFactory.getFactory(this).getEnterprisePrivacyFeatureProvider(this)
- .hasDeviceOwner(), isAdmin, pm);
+ .hasDeviceOwner(), isAdmin);
+ // Final step, refresh categories.
+ updateCategories();
}
- private void setTileEnabled(ComponentName component, boolean enabled, boolean isAdmin,
- PackageManager pm) {
+ private void setTileEnabled(ComponentName component, boolean enabled, boolean isAdmin) {
if (UserHandle.MU_ENABLED && !isAdmin && getPackageName().equals(component.getPackageName())
&& !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, component.getClassName())) {
enabled = false;
diff --git a/src/com/android/settings/accounts/AccountDetailDashboardFragment.java b/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
index cf0a0a8..12f78ff 100644
--- a/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
+++ b/src/com/android/settings/accounts/AccountDetailDashboardFragment.java
@@ -23,11 +23,13 @@
import android.os.UserManager;
import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.Preference;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceController;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.accounts.AuthenticatorHelper;
import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.drawer.Tile;
@@ -43,11 +45,16 @@
public static final String KEY_ACCOUNT_TYPE = "account_type";
public static final String KEY_ACCOUNT_LABEL = "account_label";
public static final String KEY_ACCOUNT_TITLE_RES = "account_title_res";
+ public static final String KEY_ACCOUNT_HEADER = "account_header";
+ public static final String KEY_USER_HANDLE = "user_handle";
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ Account mAccount;
private String mAccountLabel;
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
String mAccountType;
private AccountSyncPreferenceController mAccountSynController;
+ private RemoveAccountPreferenceController mRemoveAccountController;
@Override
public void onCreate(Bundle icicle) {
@@ -57,10 +64,9 @@
UserHandle userHandle = Utils.getSecureTargetUser(activity.getActivityToken(),
(UserManager) getSystemService(Context.USER_SERVICE), args,
activity.getIntent().getExtras());
- Account account = null;
if (args != null) {
if (args.containsKey(KEY_ACCOUNT)) {
- account = args.getParcelable(KEY_ACCOUNT);
+ mAccount = args.getParcelable(KEY_ACCOUNT);
}
if (args.containsKey(KEY_ACCOUNT_LABEL)) {
mAccountLabel = args.getString(KEY_ACCOUNT_LABEL);
@@ -69,7 +75,8 @@
mAccountType = args.getString(KEY_ACCOUNT_TYPE);
}
}
- mAccountSynController.init(account, userHandle);
+ mAccountSynController.init(mAccount, userHandle);
+ mRemoveAccountController.setAccount(mAccount);
}
@Override
@@ -78,6 +85,7 @@
if (mAccountLabel != null) {
getActivity().setTitle(mAccountLabel);
}
+ updateAccountHeader();
}
@Override
@@ -105,6 +113,8 @@
final List<PreferenceController> controllers = new ArrayList<>();
mAccountSynController = new AccountSyncPreferenceController(context);
controllers.add(mAccountSynController);
+ mRemoveAccountController = new RemoveAccountPreferenceController(context, this);
+ controllers.add(mRemoveAccountController);
return controllers;
}
@@ -120,4 +130,18 @@
return mAccountType.equals(metadata.getString(METADATA_IA_ACCOUNT));
}
+ @VisibleForTesting
+ void updateAccountHeader() {
+ final Preference headerPreference = findPreference(KEY_ACCOUNT_HEADER);
+ headerPreference.setTitle(mAccount.name);
+ final Context context = getContext();
+ UserHandle userHandle = null;
+ Bundle args = getArguments();
+ if (args != null && args.containsKey(KEY_USER_HANDLE)) {
+ userHandle = args.getParcelable(KEY_USER_HANDLE);
+ }
+ final AuthenticatorHelper helper = new AuthenticatorHelper(context, userHandle, null);
+ headerPreference.setIcon(helper.getDrawableForType(context, mAccountType));
+ }
+
}
\ No newline at end of file
diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java
index 723a1ec..ad3fac1 100644
--- a/src/com/android/settings/accounts/AccountPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountPreferenceController.java
@@ -465,6 +465,8 @@
final Bundle fragmentArguments = new Bundle();
fragmentArguments.putParcelable(AccountDetailDashboardFragment.KEY_ACCOUNT,
account);
+ fragmentArguments.putParcelable(AccountDetailDashboardFragment.KEY_USER_HANDLE,
+ userHandle);
fragmentArguments.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_TYPE,
accountType);
fragmentArguments.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_LABEL,
diff --git a/src/com/android/settings/accounts/RemoveAccountPreferenceController.java b/src/com/android/settings/accounts/RemoveAccountPreferenceController.java
new file mode 100644
index 0000000..c8dbe4c
--- /dev/null
+++ b/src/com/android/settings/accounts/RemoveAccountPreferenceController.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2017 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.accounts;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.Process;
+import android.support.v7.preference.PreferenceScreen;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.applications.LayoutPreference;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+import java.io.IOException;
+
+public class RemoveAccountPreferenceController extends PreferenceController
+ implements OnClickListener {
+
+ private static final String KEY_REMOVE_ACCOUNT = "remove_account";
+
+ private Account mAccount;
+ private Fragment mParentFragment;
+
+ public RemoveAccountPreferenceController(Context context, Fragment parent) {
+ super(context);
+ mParentFragment = parent;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ final LayoutPreference removeAccountPreference =
+ (LayoutPreference) screen.findPreference(KEY_REMOVE_ACCOUNT);
+ Button removeAccountButton = (Button) removeAccountPreference.findViewById(R.id.button);
+ removeAccountButton.setOnClickListener(this);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_REMOVE_ACCOUNT;
+ }
+
+ @Override
+ public void onClick(View v) {
+ ConfirmRemoveAccountDialog.show(mParentFragment, mAccount);
+ }
+
+ public void setAccount(Account account) {
+ mAccount = account;
+ }
+
+ /**
+ * Dialog to confirm with user about account removal
+ */
+ public static class ConfirmRemoveAccountDialog extends InstrumentedDialogFragment implements
+ DialogInterface.OnClickListener {
+ private static final String SAVE_ACCOUNT = "account";
+ private static final String REMOVE_ACCOUNT_DIALOG = "confirmRemoveAccount";
+ private Account mAccount;
+
+ public static ConfirmRemoveAccountDialog show(Fragment parent, Account account) {
+ if (!parent.isAdded()) {
+ return null;
+ }
+ final ConfirmRemoveAccountDialog dialog = new ConfirmRemoveAccountDialog();
+ dialog.mAccount = account;
+ dialog.setTargetFragment(parent, 0);
+ dialog.show(parent.getFragmentManager(), REMOVE_ACCOUNT_DIALOG);
+ return dialog;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Context context = getActivity();
+ if (savedInstanceState != null) {
+ mAccount = (Account) savedInstanceState.getParcelable(SAVE_ACCOUNT);
+ }
+ return new AlertDialog.Builder(context)
+ .setTitle(R.string.really_remove_account_title)
+ .setMessage(R.string.really_remove_account_message)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(R.string.remove_account_label, this)
+ .create();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putParcelable(SAVE_ACCOUNT, mAccount);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsProto.MetricsEvent.DIALOG_ACCOUNT_SYNC_REMOVE;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Activity activity = getTargetFragment().getActivity();
+ AccountManager.get(activity).removeAccountAsUser(mAccount, activity,
+ new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> future) {
+ // If already out of this screen, don't proceed.
+ if (!getTargetFragment().isResumed()) {
+ return;
+ }
+ boolean failed = true;
+ try {
+ if (future.getResult()
+ .getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
+ failed = false;
+ }
+ } catch (OperationCanceledException e) {
+ // handled below
+ } catch (IOException e) {
+ // handled below
+ } catch (AuthenticatorException e) {
+ // handled below
+ }
+ final Activity activity = getTargetFragment().getActivity();
+ if (failed && activity != null && !activity.isFinishing()) {
+ RemoveAccountFailureDialog.show(getTargetFragment());
+ } else {
+ activity.finish();
+ }
+ }
+ }, null, Process.myUserHandle());
+ }
+ }
+
+ /**
+ * Dialog to tell user about account removal failure
+ */
+ public static class RemoveAccountFailureDialog extends InstrumentedDialogFragment {
+
+ private static final String FAILED_REMOVAL_DIALOG = "removeAccountFailed";
+
+ public static void show(Fragment parent) {
+ if (!parent.isAdded()) {
+ return;
+ }
+ final RemoveAccountFailureDialog dialog = new RemoveAccountFailureDialog();
+ dialog.setTargetFragment(parent, 0);
+ dialog.show(parent.getFragmentManager(), FAILED_REMOVAL_DIALOG);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Context context = getActivity();
+
+ return new AlertDialog.Builder(context)
+ .setTitle(R.string.really_remove_account_title)
+ .setMessage(R.string.remove_account_failed)
+ .setPositiveButton(android.R.string.ok, null)
+ .create();
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsProto.MetricsEvent.DIALOG_ACCOUNT_SYNC_FAILED_REMOVAL;
+ }
+
+ }
+}
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index e7d2b58..b5d8a73 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -63,7 +63,7 @@
@Override
public boolean isEnabled() {
- return false;
+ return true;
}
@Override
diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java
index 94e3ac8..6232d2f 100644
--- a/src/com/android/settings/dashboard/DashboardSummary.java
+++ b/src/com/android/settings/dashboard/DashboardSummary.java
@@ -31,7 +31,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
-import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settings.core.InstrumentedFragment;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.dashboard.conditional.ConditionAdapterUtils;
import com.android.settings.dashboard.conditional.ConditionManager;
@@ -46,7 +46,7 @@
import java.util.ArrayList;
import java.util.List;
-public class DashboardSummary extends InstrumentedPreferenceFragment
+public class DashboardSummary extends InstrumentedFragment
implements SettingsDrawerActivity.CategoryListener, ConditionManager.ConditionListener,
FocusRecyclerView.FocusListener {
public static final boolean DEBUG = false;
@@ -93,10 +93,9 @@
((SettingsActivity) getActivity()).getDashboardCategories());
}
- Context context = getContext();
- mConditionManager = ConditionManager.get(context, false);
- mSuggestionParser = new SuggestionParser(context,
- context.getSharedPreferences(SUGGESTIONS, 0), R.xml.suggestion_ordering);
+ mConditionManager = ConditionManager.get(activity, false);
+ mSuggestionParser = new SuggestionParser(activity,
+ activity.getSharedPreferences(SUGGESTIONS, 0), R.xml.suggestion_ordering);
mSuggestionsChecks = new SuggestionsChecks(getContext());
if (savedInstanceState == null) {
mSuggestionsShownLogged = new ArrayList<>();
diff --git a/src/com/android/settings/notification/ChannelNotificationSettings.java b/src/com/android/settings/notification/ChannelNotificationSettings.java
index 77bf6be..e73feb5 100644
--- a/src/com/android/settings/notification/ChannelNotificationSettings.java
+++ b/src/com/android/settings/notification/ChannelNotificationSettings.java
@@ -55,7 +55,6 @@
protected static final String KEY_LIGHTS = "lights";
protected static final String KEY_VIBRATE = "vibrate";
protected static final String KEY_RINGTONE = "ringtone";
- protected static final String KEY_SHOW = "show";
protected static final String KEY_BADGE = "badge";
protected RestrictedSwitchPreference mLights;
@@ -91,7 +90,6 @@
addPreferencesFromResource(R.xml.channel_notification_settings);
mBlock = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BLOCK);
- mShow = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_SHOW);
mBadge = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BADGE);
mImportance = (RestrictedDropDownPreference) findPreference(KEY_IMPORTANCE);
mPriority =
@@ -141,7 +139,6 @@
mPriority.setDisabledByAdmin(mSuspendedAppsAdmin);
mVisibilityOverride.setDisabledByAdmin(mSuspendedAppsAdmin);
mBlock.setDisabledByAdmin(mSuspendedAppsAdmin);
- mShow.setDisabledByAdmin(mSuspendedAppsAdmin);
mBadge.setDisabledByAdmin(mSuspendedAppsAdmin);
}
@@ -192,26 +189,12 @@
protected void setupBlockAndImportance() {
mBlock.setDisabledByAdmin(mSuspendedAppsAdmin);
- mBlock.setChecked(!mChannel.isAllowed());
+ mBlock.setChecked(mChannel.getImportance() == NotificationManager.IMPORTANCE_NONE);
mBlock.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean value = (Boolean) newValue;
- mChannel.setAllowed(!value);
- mChannel.lockFields(NotificationChannel.USER_LOCKED_ALLOWED);
- mBackend.updateChannel(mPkg, mUid, mChannel);
- updateDependents();
- return true;
- }
- });
-
- mShow.setDisabledByAdmin(mSuspendedAppsAdmin);
- mShow.setChecked(mChannel.getImportance() != NotificationManager.IMPORTANCE_NONE);
- mShow.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final boolean value = (Boolean) newValue;
- int importance = value ? IMPORTANCE_LOW : IMPORTANCE_NONE;
+ int importance = value ? IMPORTANCE_NONE : IMPORTANCE_LOW;
mImportance.setValue(String.valueOf(importance));
mChannel.setImportance(importance);
mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
@@ -386,7 +369,8 @@
return lockscreenSecure;
}
- protected boolean checkCanBeVisible(int minImportanceVisible, int importance) {
+ protected boolean checkCanBeVisible(int minImportanceVisible) {
+ int importance = mChannel.getImportance();
if (importance == NotificationManager.IMPORTANCE_UNSPECIFIED) {
return true;
}
@@ -420,23 +404,16 @@
}
private void updateDependents() {
- boolean allowed = mChannel.isAllowed();
- int importance = mChannel.getImportance();
- setVisible(mShow, allowed);
- setVisible(mBadge, allowed);
- setVisible(mImportance, allowed && importance != NotificationManager.IMPORTANCE_NONE);
- setVisible(mLights, allowed && checkCanBeVisible(
- NotificationManager.IMPORTANCE_LOW, importance) && canPulseLight());
- setVisible(mVibrate, allowed
- && checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT, importance));
- setVisible(mRingtone, allowed && checkCanBeVisible(
- NotificationManager.IMPORTANCE_DEFAULT, importance));
- setVisible(mPriority, allowed
- && (checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT, importance)
- || (checkCanBeVisible(NotificationManager.IMPORTANCE_LOW, importance)
- && mDndVisualEffectsSuppressed)));
- setVisible(mVisibilityOverride, allowed
- && checkCanBeVisible(NotificationManager.IMPORTANCE_MIN, importance)
+ setVisible(mBadge, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
+ setVisible(mImportance, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
+ setVisible(mLights, checkCanBeVisible(
+ NotificationManager.IMPORTANCE_LOW) && canPulseLight());
+ setVisible(mVibrate, checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT));
+ setVisible(mRingtone, checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT));
+ setVisible(mPriority, checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT)
+ || (checkCanBeVisible(NotificationManager.IMPORTANCE_LOW)
+ && mDndVisualEffectsSuppressed));
+ setVisible(mVisibilityOverride, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN)
&& isLockScreenSecure());
}
}
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index 046c5e6..f3e4390 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -66,7 +66,6 @@
protected String mPkg;
protected PackageInfo mPkgInfo;
protected RestrictedSwitchPreference mBlock;
- protected RestrictedSwitchPreference mShow;
protected RestrictedSwitchPreference mBadge;
protected EnforcedAdmin mSuspendedAppsAdmin;
protected boolean mDndVisualEffectsSuppressed;
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
index 7006dfb..3ba4d02 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java
@@ -15,35 +15,69 @@
*/
package com.android.settings.accounts;
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorDescription;
+import android.content.Context;
import android.os.Bundle;
+import android.os.UserHandle;
+import android.support.v7.preference.Preference;
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.testutils.shadow.ShadowAccountManager;
+import com.android.settings.testutils.shadow.ShadowContentResolver;
import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.drawer.Tile;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Answers.RETURNS_DEEP_STUBS;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
-@RunWith(RobolectricTestRunner.class)
+@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class AccountDetailDashboardFragmentTest {
private static final String METADATA_CATEGORY = "com.android.settings.category";
private static final String METADATA_ACCOUNT_TYPE = "com.android.settings.ia.account";
+ private static final String METADATA_USER_HANDLE = "user_handle";
+ private static final String PREF_ACCOUNT_HEADER = "account_header";
+
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private AccountManager mAccountManager;
+ @Mock
+ private Preference mPreference;
private AccountDetailDashboardFragment mFragment;
+ private Context mContext;
@Before
public void setUp() {
- mFragment = new AccountDetailDashboardFragment();
+ MockitoAnnotations.initMocks(this);
+ ShadowApplication shadowContext = ShadowApplication.getInstance();
+ shadowContext.setSystemService(Context.ACCOUNT_SERVICE, mAccountManager);
+ mContext = spy(shadowContext.getApplicationContext());
+
+ mFragment = spy(new AccountDetailDashboardFragment());
final Bundle args = new Bundle();
- args.putString(METADATA_ACCOUNT_TYPE, "com.abc");
+ args.putParcelable(METADATA_USER_HANDLE, UserHandle.CURRENT);
+ mFragment.setArguments(args);
mFragment.mAccountType = "com.abc";
+ mFragment.mAccount = new Account("name1@abc.com", "com.abc");
}
@Test
@@ -83,4 +117,18 @@
assertThat(mFragment.displayTile(tile)).isFalse();
}
+ @Test
+ @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
+ public void updateAccountHeader_shouldShowAccountName() throws Exception {
+ when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(
+ new AuthenticatorDescription[0]);
+ when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
+ when(mFragment.getContext()).thenReturn(mContext);
+ doReturn(mPreference).when(mFragment).findPreference(PREF_ACCOUNT_HEADER);
+
+ mFragment.updateAccountHeader();
+
+ verify(mPreference).setTitle("name1@abc.com");
+ }
+
}
diff --git a/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java
new file mode 100644
index 0000000..50f3ac6
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2017 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.accounts;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AuthenticatorDescription;
+import android.app.Activity;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.Context;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v14.preference.PreferenceFragment;
+import android.widget.Button;
+
+import com.android.settings.AccessiblePreferenceCategory;
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.applications.LayoutPreference;
+import com.android.settings.search.SearchIndexableRaw;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.ShadowAccountManager;
+import com.android.settings.testutils.shadow.ShadowContentResolver;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Answers.RETURNS_DEEP_STUBS;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class RemoveAccountPreferenceControllerTest {
+
+ private static final String KEY_REMOVE_ACCOUNT = "remove_account";
+ private static final String TAG_REMOVE_ACCOUNT_DIALOG = "confirmRemoveAccount";
+
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private AccountManager mAccountManager;
+ @Mock(answer = RETURNS_DEEP_STUBS)
+ private PreferenceFragment mFragment;
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private FragmentManager mFragmentManager;
+ @Mock
+ private FragmentTransaction mFragmentTransaction;
+ @Mock
+ private LayoutPreference mPreference;
+
+ private Context mContext;
+ private RemoveAccountPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ ShadowApplication shadowContext = ShadowApplication.getInstance();
+ shadowContext.setSystemService(Context.ACCOUNT_SERVICE, mAccountManager);
+ mContext = spy(shadowContext.getApplicationContext());
+
+ when(mFragment.getPreferenceScreen()).thenReturn(mScreen);
+ when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
+ when(mFragment.getFragmentManager()).thenReturn(mFragmentManager);
+ when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction);
+ when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(
+ new AuthenticatorDescription[0]);
+ when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
+ mController = new RemoveAccountPreferenceController(mContext, mFragment);
+ }
+
+ @Test
+ public void displayPreference_shouldAddClickListener() {
+ when(mScreen.findPreference(KEY_REMOVE_ACCOUNT)).thenReturn(mPreference);
+ final Button button = mock(Button.class);
+ when(mPreference.findViewById(R.id.button)).thenReturn(button);
+
+ mController.displayPreference(mScreen);
+
+ verify(button).setOnClickListener(mController);
+ }
+
+ @Test
+ public void onClick_shouldStartConfirmDialog() {
+ when(mFragment.isAdded()).thenReturn(true);
+ mController.onClick(null);
+
+ verify(mFragmentTransaction).add(
+ any(RemoveAccountPreferenceController.ConfirmRemoveAccountDialog.class),
+ eq(TAG_REMOVE_ACCOUNT_DIALOG));
+ }
+
+ @Test
+ @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
+ public void confirmRemove_shouldRemoveAccount() {
+ when(mFragment.isAdded()).thenReturn(true);
+ Activity activity = mock(Activity.class);
+ when(activity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
+ when(mFragment.getActivity()).thenReturn(activity);
+
+ Account account = new Account("Account11", "com.acct1");
+ RemoveAccountPreferenceController.ConfirmRemoveAccountDialog dialog =
+ RemoveAccountPreferenceController.ConfirmRemoveAccountDialog.show(mFragment, account);
+
+ dialog.onClick(null, 0);
+ verify(mAccountManager).removeAccountAsUser(eq(account), any(Activity.class),
+ any(AccountManagerCallback.class), any(Handler.class), any(UserHandle.class));
+ }
+}
\ No newline at end of file