diff options
author | Danny Baumann <dannybaumann@web.de> | 2014-11-12 17:14:27 -0800 |
---|---|---|
committer | Steve Kondik <steve@cyngn.com> | 2015-11-13 09:01:09 +0100 |
commit | e2bdd4895c967771c6c31b4a037cbd85092e4abf (patch) | |
tree | 4c2e398eef74ce372d395570374315916d9f15ae | |
parent | 925bfff09a29db5d2f5ae1e852c71a82173b9414 (diff) | |
download | packages_apps_Settings-e2bdd4895c967771c6c31b4a037cbd85092e4abf.zip packages_apps_Settings-e2bdd4895c967771c6c31b4a037cbd85092e4abf.tar.gz packages_apps_Settings-e2bdd4895c967771c6c31b4a037cbd85092e4abf.tar.bz2 |
Add back blacklist settings.
Change-Id: Iae35717acfa9af4da75c07d24352acf981d19fc7
Improve translatability of summaries.
Change-Id: I362b335cbe219d6e371a458c9d50fcd66bdf19fe
Settings: Alert user when they attempt to add an invalid number to BL.
- BlacklistProvider will reject numbers that aren't valid, silently. So instead of
resuming to a blank screen, we should alert the user that the number they attempted to
add is invalid by utilizing BlacklistUtils#addOrUpdate method.
Change-Id: I1ca32427baad41c1c9379e18046e6ca7937b6d32
Add missing blacklist xxhdpi drawables.
Change-Id: I327f408ff344e9358c479cf5fe9dc341918511b2
Blacklist: Fix launching blacklist settings
Change-Id: I0043503e6ac0d3536941394ee5057001b72f9114
Settings : Launch only contacts picker for blacklist entry
Change-Id: I266d1ad7f1aab745728b33490268cb197188f2b3
37 files changed, 1312 insertions, 3 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e28c1d4..28489d6 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2161,12 +2161,12 @@ <category android:name="android.intent.category.VOICE_LAUNCH" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.SHORTCUT" /> - </intent-filter> + </intent-filter> <meta-data android:name="com.android.settings.FRAGMENT_CLASS" android:value="com.android.settings.profiles.ProfilesSettings" /> <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID" android:resource="@id/profiles_settings" /> - </activity> + </activity> <!-- Keep compatibility with old shortcuts. --> <activity-alias android:name="ProfileSettings" @@ -2219,10 +2219,28 @@ <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID" android:resource="@id/display_settings" /> </activity-alias> - <!-- CyanogenMod activities End --> + <activity android:name=".cyanogenmod.SpamList" /> + <!-- "Blacklist settings" UI, used only on voice-capable phone devices. --> + <activity android:name="Settings$BlacklistSettingsActivity" + android:theme="@style/Theme.SubSettingsDialogWhenLarge" + android:uiOptions="splitActionBarWhenNarrow" + android:label="@string/blacklist_title" + android:excludeFromRecents="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + <meta-data android:name="com.android.settings.FRAGMENT_CLASS" + android:value="com.android.settings.blacklist.BlacklistSettings" /> + <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID" + android:resource="@id/security_settings" /> + </activity> + + <!-- CyanogenMod activities End --> + <!-- Pseudo-activity used to provide an intent-filter entry point to encryption settings --> <activity android:name="Settings$CryptKeeperSettingsActivity" android:label="@string/crypt_keeper_encrypt_title"> diff --git a/res/drawable-hdpi/ic_blacklist_calls_off.png b/res/drawable-hdpi/ic_blacklist_calls_off.png Binary files differnew file mode 100644 index 0000000..22a05c2 --- /dev/null +++ b/res/drawable-hdpi/ic_blacklist_calls_off.png diff --git a/res/drawable-hdpi/ic_blacklist_calls_on.png b/res/drawable-hdpi/ic_blacklist_calls_on.png Binary files differnew file mode 100644 index 0000000..5073d63 --- /dev/null +++ b/res/drawable-hdpi/ic_blacklist_calls_on.png diff --git a/res/drawable-hdpi/ic_blacklist_messages_off.png b/res/drawable-hdpi/ic_blacklist_messages_off.png Binary files differnew file mode 100644 index 0000000..812aaa5 --- /dev/null +++ b/res/drawable-hdpi/ic_blacklist_messages_off.png diff --git a/res/drawable-hdpi/ic_blacklist_messages_on.png b/res/drawable-hdpi/ic_blacklist_messages_on.png Binary files differnew file mode 100644 index 0000000..4d7c809 --- /dev/null +++ b/res/drawable-hdpi/ic_blacklist_messages_on.png diff --git a/res/drawable-hdpi/ic_see_contacts_holo_dark.png b/res/drawable-hdpi/ic_see_contacts_holo_dark.png Binary files differnew file mode 100644 index 0000000..8e2182f --- /dev/null +++ b/res/drawable-hdpi/ic_see_contacts_holo_dark.png diff --git a/res/drawable-mdpi/ic_blacklist_calls_off.png b/res/drawable-mdpi/ic_blacklist_calls_off.png Binary files differnew file mode 100644 index 0000000..7917f46 --- /dev/null +++ b/res/drawable-mdpi/ic_blacklist_calls_off.png diff --git a/res/drawable-mdpi/ic_blacklist_calls_on.png b/res/drawable-mdpi/ic_blacklist_calls_on.png Binary files differnew file mode 100644 index 0000000..9ec572d --- /dev/null +++ b/res/drawable-mdpi/ic_blacklist_calls_on.png diff --git a/res/drawable-mdpi/ic_blacklist_messages_off.png b/res/drawable-mdpi/ic_blacklist_messages_off.png Binary files differnew file mode 100644 index 0000000..a2e53e3 --- /dev/null +++ b/res/drawable-mdpi/ic_blacklist_messages_off.png diff --git a/res/drawable-mdpi/ic_blacklist_messages_on.png b/res/drawable-mdpi/ic_blacklist_messages_on.png Binary files differnew file mode 100644 index 0000000..01b4747 --- /dev/null +++ b/res/drawable-mdpi/ic_blacklist_messages_on.png diff --git a/res/drawable-mdpi/ic_see_contacts_holo_dark.png b/res/drawable-mdpi/ic_see_contacts_holo_dark.png Binary files differnew file mode 100644 index 0000000..ef1d2df --- /dev/null +++ b/res/drawable-mdpi/ic_see_contacts_holo_dark.png diff --git a/res/drawable-xhdpi/ic_blacklist_calls_off.png b/res/drawable-xhdpi/ic_blacklist_calls_off.png Binary files differnew file mode 100644 index 0000000..6fd91de --- /dev/null +++ b/res/drawable-xhdpi/ic_blacklist_calls_off.png diff --git a/res/drawable-xhdpi/ic_blacklist_calls_on.png b/res/drawable-xhdpi/ic_blacklist_calls_on.png Binary files differnew file mode 100644 index 0000000..cb67ee0 --- /dev/null +++ b/res/drawable-xhdpi/ic_blacklist_calls_on.png diff --git a/res/drawable-xhdpi/ic_blacklist_messages_off.png b/res/drawable-xhdpi/ic_blacklist_messages_off.png Binary files differnew file mode 100644 index 0000000..f32eab6 --- /dev/null +++ b/res/drawable-xhdpi/ic_blacklist_messages_off.png diff --git a/res/drawable-xhdpi/ic_blacklist_messages_on.png b/res/drawable-xhdpi/ic_blacklist_messages_on.png Binary files differnew file mode 100644 index 0000000..c12e04c --- /dev/null +++ b/res/drawable-xhdpi/ic_blacklist_messages_on.png diff --git a/res/drawable-xhdpi/ic_see_contacts_holo_dark.png b/res/drawable-xhdpi/ic_see_contacts_holo_dark.png Binary files differnew file mode 100644 index 0000000..279fff9 --- /dev/null +++ b/res/drawable-xhdpi/ic_see_contacts_holo_dark.png diff --git a/res/drawable-xxhdpi/ic_blacklist_calls_off.png b/res/drawable-xxhdpi/ic_blacklist_calls_off.png Binary files differnew file mode 100644 index 0000000..0841442 --- /dev/null +++ b/res/drawable-xxhdpi/ic_blacklist_calls_off.png diff --git a/res/drawable-xxhdpi/ic_blacklist_calls_on.png b/res/drawable-xxhdpi/ic_blacklist_calls_on.png Binary files differnew file mode 100644 index 0000000..7f252d3 --- /dev/null +++ b/res/drawable-xxhdpi/ic_blacklist_calls_on.png diff --git a/res/drawable-xxhdpi/ic_blacklist_messages_off.png b/res/drawable-xxhdpi/ic_blacklist_messages_off.png Binary files differnew file mode 100644 index 0000000..10a07db --- /dev/null +++ b/res/drawable-xxhdpi/ic_blacklist_messages_off.png diff --git a/res/drawable-xxhdpi/ic_blacklist_messages_on.png b/res/drawable-xxhdpi/ic_blacklist_messages_on.png Binary files differnew file mode 100644 index 0000000..50dd562 --- /dev/null +++ b/res/drawable-xxhdpi/ic_blacklist_messages_on.png diff --git a/res/drawable/ic_blacklist_calls.xml b/res/drawable/ic_blacklist_calls.xml new file mode 100644 index 0000000..401fb4a --- /dev/null +++ b/res/drawable/ic_blacklist_calls.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The CyanogenMod 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_checked="true" android:drawable="@drawable/ic_blacklist_calls_on" /> + <item android:drawable="@drawable/ic_blacklist_calls_off" /> +</selector> + diff --git a/res/drawable/ic_blacklist_messages.xml b/res/drawable/ic_blacklist_messages.xml new file mode 100644 index 0000000..f0fafa1 --- /dev/null +++ b/res/drawable/ic_blacklist_messages.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The CyanogenMod 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_checked="true" android:drawable="@drawable/ic_blacklist_messages_on" /> + <item android:drawable="@drawable/ic_blacklist_messages_off" /> +</selector> + diff --git a/res/layout/blacklist_entry_row.xml b/res/layout/blacklist_entry_row.xml new file mode 100644 index 0000000..16dc1d2 --- /dev/null +++ b/res/layout/blacklist_entry_row.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The CyanogenMod 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="?android:attr/listPreferredItemHeight" + android:gravity="center_vertical" + android:padding="5dip" + android:orientation="horizontal" + android:descendantFocusability="blocksDescendants"> + + <LinearLayout + android:layout_width="0dip" + android:layout_height="match_parent" + android:layout_weight="1" + android:gravity="center_vertical" + android:orientation="vertical" + android:paddingStart="10dip" + android:paddingEnd="10dip"> + + <TextView android:id="@+id/number" + style="?android:attr/textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <TextView android:id="@+id/name" + style="?android:attr/textAppearanceSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + </LinearLayout> + + <com.android.settings.blacklist.ToggleImageView + android:id="@+id/block_calls" + android:layout_width="@android:dimen/app_icon_size" + android:layout_height="@android:dimen/app_icon_size" + android:src="@drawable/ic_blacklist_calls" + android:scaleType="centerInside" + android:clickable="true" + android:contentDescription="@null" /> + + <com.android.settings.blacklist.ToggleImageView + android:id="@+id/block_messages" + android:layout_width="@android:dimen/app_icon_size" + android:layout_height="@android:dimen/app_icon_size" + android:src="@drawable/ic_blacklist_messages" + android:scaleType="centerInside" + android:clickable="true" + android:contentDescription="@null" /> + +</LinearLayout> diff --git a/res/layout/dialog_blacklist_edit_entry.xml b/res/layout/dialog_blacklist_edit_entry.xml new file mode 100644 index 0000000..30b7c24 --- /dev/null +++ b/res/layout/dialog_blacklist_edit_entry.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2006 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="wrap_content" + android:layout_height="wrap_content" + android:padding="5dip" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/number_field" + android:layout_width="match_parent" + android:layout_height="0dip" + android:layout_weight="1.0" + android:addStatesFromChildren="true" + android:gravity="center_vertical" + android:baselineAligned="false" + android:paddingStart="10dip" + android:paddingEnd="10dip"> + + <EditText android:id="@+id/number_edit" + android:layout_width="0dip" + android:layout_weight="1" + android:orientation="horizontal" + android:layout_height="wrap_content"/> + + <ImageButton android:id="@+id/select_contact" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="10dip" + android:src="@drawable/ic_see_contacts_holo_dark" + android:contentDescription="@string/select_contact" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/options_field" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1.0" + android:orientation="vertical" + android:baselineAligned="false" + android:padding="10dip" > + + <CheckBox android:id="@+id/incoming_calls" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/blacklist_policy_block_calls" + android:textAppearance="?android:attr/textAppearanceSmall" /> + + <CheckBox android:id="@+id/incoming_messages" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/blacklist_policy_block_messages" + android:textAppearance="?android:attr/textAppearanceSmall" /> + + </LinearLayout> + +</LinearLayout> diff --git a/res/menu/blacklist.xml b/res/menu/blacklist.xml new file mode 100644 index 0000000..a3d294e --- /dev/null +++ b/res/menu/blacklist.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The CyanogenMod 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. +--> + +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/blacklist_add" + android:title="@string/add_blacklist_number" + android:icon="@drawable/ic_menu_add" + android:showAsAction="ifRoom|withText" /> + <item + android:id="@+id/blacklist_prefs" + android:title="@string/blacklist_prefs" + android:icon="@drawable/ic_sysbar_quicksettings" + android:showAsAction="ifRoom|withText" /> +</menu> diff --git a/res/values/cm_arrays.xml b/res/values/cm_arrays.xml index 8aee1ff..7990443 100644 --- a/res/values/cm_arrays.xml +++ b/res/values/cm_arrays.xml @@ -406,4 +406,23 @@ <item>100</item> <item>200</item> </string-array> + + <!-- Phone blacklist management --> + <string-array name="blacklist_policy_unknown_entries" translatable="false"> + <item>@string/blacklist_policy_block_calls</item> + <item>@string/blacklist_policy_block_messages</item> + </string-array> + + <string-array name="blacklist_policy_unknown_values" translatable="false"> + <item>1</item> + <item>16</item> + </string-array> + + <string-array name="blacklist_policy_private_entries" translatable="false"> + <item>@string/blacklist_policy_block_calls</item> + </string-array> + + <string-array name="blacklist_policy_private_values" translatable="false"> + <item>1</item> + </string-array> </resources> diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index 17ef49d..9bf77af 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -732,4 +732,35 @@ <string name="block_notifications_title">Filter notifications</string> <string name="no_filters_title">No filters set</string> + <!-- Blacklist preferences --> + <string name="blacklist_title">Blacklist</string> + <string name="blacklist_edit_dialog_title">Edit blacklist entry</string> + <string name="blacklist_prefs">Settings</string> + <string name="blacklist_button_delete">Delete</string> + <string name="blacklist_empty_text">You don\'t have any blacklisted numbers. Add an entry by touching the Add (+) button.</string> + <string name="blacklist_disabled_empty_text">To blacklist calls and/or messages from certain numbers, enable the blacklist.</string> + <string name="blacklist_summary_disabled">Disabled</string> + <string name="blacklist_summary">Incoming calls and messages from phone numbers in the blacklist will be blocked</string> + <string name="blacklist_notify">Show notification</string> + <string name="blacklist_private_numbers_title">Private numbers</string> + <string name="blacklist_private_numbers_summary_disabled">Don\'t block calls from private numbers</string> + <string name="blacklist_private_numbers_summary">Block incoming <xliff:g id="type">%2$s</xliff:g> from private numbers</string> + <string name="blacklist_unknown_numbers_title">Unknown numbers</string> + <string name="blacklist_unknown_numbers_summary_disabled">Don\'t block calls or messages from numbers not in the contact list</string> + <string name="blacklist_unknown_numbers_summary">Block incoming <xliff:g id="type">%2$s</xliff:g> from numbers not in the contact list</string> + <string name="blacklist_summary_type_calls_only">calls</string> + <string name="blacklist_summary_type_messages_only">messages</string> + <string name="blacklist_summary_type_calls_and_messages">calls and messages</string> + <string name="blacklist_regex_title">Use wildcards</string> + <string name="blacklist_regex_summary">Use . as a wildcard and * for repetition. E.g. 123.* blocks numbers starting with 123 and .*123.* blocks numbers containing 123</string> + <string name="blacklist_policy_block_calls">Block incoming calls</string> + <string name="blacklist_policy_block_messages">Block incoming messages</string> + <string name="blacklist_bad_number_add">Unable to add invalid number to blacklist</string> + + <!-- Blacklist management --> + <string name="add_blacklist_number">Add number</string> + <string name="remove_blacklist_number_title">Remove number</string> + <string name="remove_blacklist_entry">Do you want to remove this blacklist entry?</string> + <string name="select_contact">Select contact</string> + </resources> diff --git a/res/xml/blacklist_prefs.xml b/res/xml/blacklist_prefs.xml new file mode 100644 index 0000000..be63b7d --- /dev/null +++ b/res/xml/blacklist_prefs.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 The CyanogenMod Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" + android:title="@string/blacklist_title" > + + <com.android.settings.cyanogenmod.SystemSettingCheckBoxPreference + android:key="phone_blacklist_notify_enabled" + android:title="@string/blacklist_notify" + android:defaultValue="true" /> + + <MultiSelectListPreference + android:key="button_blacklist_private_numbers" + android:title="@string/blacklist_private_numbers_title" + android:dialogTitle="@string/blacklist_private_numbers_title" + android:entries="@array/blacklist_policy_private_entries" + android:entryValues="@array/blacklist_policy_private_values" + android:persistent="false" /> + + <MultiSelectListPreference + android:key="button_blacklist_unknown_numbers" + android:title="@string/blacklist_unknown_numbers_title" + android:dialogTitle="@string/blacklist_unknown_numbers_title" + android:entries="@array/blacklist_policy_unknown_entries" + android:entryValues="@array/blacklist_policy_unknown_values" + android:persistent="false" /> + + <com.android.settings.cyanogenmod.SystemSettingCheckBoxPreference + android:key="phone_blacklist_regex_enabled" + android:title="@string/blacklist_regex_title" + android:summary="@string/blacklist_regex_summary" /> + +</PreferenceScreen> diff --git a/res/xml/security_settings_app_cyanogenmod.xml b/res/xml/security_settings_app_cyanogenmod.xml new file mode 100644 index 0000000..a63fba6 --- /dev/null +++ b/res/xml/security_settings_app_cyanogenmod.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The CyanogenMod Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<PreferenceScreen + xmlns:android="http://schemas.android.com/apk/res/android"> + + <PreferenceCategory + android:key="app_security" + android:title="@string/app_security_title"> + + <PreferenceScreen + android:key="blacklist" + android:title="@string/blacklist_title" + android:fragment="com.android.settings.blacklist.BlacklistSettings" /> + + </PreferenceCategory> + +</PreferenceScreen> diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index 66af22b..fd785d3 100755 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -52,6 +52,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.logging.MetricsLogger; +import com.android.internal.telephony.util.BlacklistUtils; import com.android.internal.widget.LockPatternUtils; import com.android.settings.TrustAgentUtils.TrustAgentComponentInfo; import com.android.settings.fingerprint.FingerprintEnrollIntroduction; @@ -60,6 +61,7 @@ import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Index; import com.android.settings.search.Indexable; import com.android.settings.search.SearchIndexableRaw; +import com.android.settings.R; import java.util.ArrayList; import java.util.List; @@ -119,6 +121,11 @@ public class SecuritySettings extends SettingsPreferenceFragment private static final int MY_USER_ID = UserHandle.myUserId(); + // CyanogenMod Additions + private static final String KEY_APP_SECURITY_CATEGORY = "app_security"; + private static final String KEY_BLACKLIST = "blacklist"; + + private PackageManager mPM; private DevicePolicyManager mDPM; private SubscriptionManager mSubscriptionManager; @@ -142,6 +149,7 @@ public class SecuritySettings extends SettingsPreferenceFragment private boolean mIsPrimary; private Intent mTrustAgentClickIntent; + private Preference mOwnerInfoPref; @Override @@ -149,6 +157,9 @@ public class SecuritySettings extends SettingsPreferenceFragment return MetricsLogger.SECURITY; } + // CyanogenMod Additions + private PreferenceScreen mBlacklist; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -169,6 +180,7 @@ public class SecuritySettings extends SettingsPreferenceFragment private static int getResIdForLockUnlockScreen(Context context, LockPatternUtils lockPatternUtils) { + // Add options for lock/unlock screen int resid = 0; if (!lockPatternUtils.isSecure(MY_USER_ID)) { if (lockPatternUtils.isLockScreenDisabled(MY_USER_ID)) { @@ -208,6 +220,8 @@ public class SecuritySettings extends SettingsPreferenceFragment } addPreferencesFromResource(R.xml.security_settings); root = getPreferenceScreen(); + // Add package manager to check if features are available + PackageManager pm = getActivity().getPackageManager(); // Add package manager to check if features are available PackageManager pm = getPackageManager(); @@ -347,6 +361,18 @@ public class SecuritySettings extends SettingsPreferenceFragment } } + // App security settings + addPreferencesFromResource(R.xml.security_settings_app_cyanogenmod); + mBlacklist = (PreferenceScreen) root.findPreference(KEY_BLACKLIST); + + // Determine options based on device telephony support + if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { + // No telephony, remove dependent options + PreferenceGroup appCategory = (PreferenceGroup) + root.findPreference(KEY_APP_SECURITY_CATEGORY); + appCategory.removePreference(mBlacklist); + } + // The above preferences come and go based on security state, so we need to update // the index. This call is expected to be fairly cheap, but we may want to do something // smarter in the future. @@ -648,6 +674,7 @@ public class SecuritySettings extends SettingsPreferenceFragment } updateOwnerInfo(); + updateBlacklistSummary(); } public void updateOwnerInfo() { @@ -901,4 +928,13 @@ public class SecuritySettings extends SettingsPreferenceFragment } } + private void updateBlacklistSummary() { + if (mBlacklist != null) { + if (BlacklistUtils.isBlacklistEnabled(getActivity())) { + mBlacklist.setSummary(R.string.blacklist_summary); + } else { + mBlacklist.setSummary(R.string.blacklist_summary_disabled); + } + } + } } diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 101219b..06f0149 100644..100755 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -17,6 +17,7 @@ package com.android.settings; import com.android.settings.applications.AppOpsSummary; +import com.android.settings.blacklist.BlacklistSettings; /** * Top-level Settings activity @@ -118,4 +119,5 @@ public class Settings extends SettingsActivity { public static class AppDrawOverlaySettingsActivity extends SettingsActivity { /* empty */ } public static class AppWriteSettingsActivity extends SettingsActivity { /* empty */ } public static class LiveDisplayActivity extends SettingsActivity { /* empty */ } + public static class BlacklistSettingsActivity extends SettingsActivity { /* empty */ } } diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 70694c8..74b8ff9 100644..100755 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -79,6 +79,7 @@ import com.android.settings.applications.ProcessStatsSummary; import com.android.settings.applications.ProcessStatsUi; import com.android.settings.applications.UsageAccessDetails; import com.android.settings.applications.WriteSettingsDetails; +import com.android.settings.blacklist.BlacklistSettings; import com.android.settings.bluetooth.BluetoothSettings; import com.android.settings.dashboard.DashboardCategory; import com.android.settings.dashboard.DashboardSummary; @@ -364,6 +365,7 @@ public class SettingsActivity extends Activity WriteSettingsDetails.class.getName(), LiveDisplay.class.getName(), com.android.settings.cyanogenmod.PrivacySettings.class.getName() + BlacklistSettings.class.getName() }; diff --git a/src/com/android/settings/SubSettings.java b/src/com/android/settings/SubSettings.java index 13ead6e..13ead6e 100644..100755 --- a/src/com/android/settings/SubSettings.java +++ b/src/com/android/settings/SubSettings.java diff --git a/src/com/android/settings/blacklist/BlacklistSettings.java b/src/com/android/settings/blacklist/BlacklistSettings.java new file mode 100644 index 0000000..c30d410 --- /dev/null +++ b/src/com/android/settings/blacklist/BlacklistSettings.java @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.blacklist; + +import android.app.ActionBar; +import android.app.Activity; +import android.app.FragmentTransaction; +import android.app.ListFragment; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.location.CountryDetector; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Process; +import android.provider.ContactsContract.PhoneLookup; +import android.provider.Settings; +import android.provider.Telephony.Blacklist; +import android.telephony.PhoneNumberUtils; +import android.text.TextUtils; +import android.util.SparseArray; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CompoundButton; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.ResourceCursorAdapter; +import android.widget.Switch; +import android.widget.TextView; + +import com.android.internal.telephony.util.BlacklistUtils; +import com.android.settings.R; + +import java.util.HashMap; + +/** + * Blacklist settings UI for the Phone app. + */ +public class BlacklistSettings extends ListFragment + implements CompoundButton.OnCheckedChangeListener { + + private static final String[] BLACKLIST_PROJECTION = { + Blacklist._ID, + Blacklist.NUMBER, + Blacklist.PHONE_MODE, + Blacklist.MESSAGE_MODE + }; + private static final int COLUMN_ID = 0; + private static final int COLUMN_NUMBER = 1; + private static final int COLUMN_PHONE = 2; + private static final int COLUMN_MESSAGE = 3; + + private Switch mEnabledSwitch; + private boolean mLastEnabledState; + + private BlacklistAdapter mAdapter; + private Cursor mCursor; + private TextView mEmptyView; + + @Override + public View onCreateView(LayoutInflater inflater, + ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(com.android.internal.R.layout.preference_list_fragment, + container, false); + } + + @Override + public void onActivityCreated(Bundle icicle) { + super.onActivityCreated(icicle); + + setHasOptionsMenu(true); + + final Activity activity = getActivity(); + mEnabledSwitch = new Switch(activity); + + final int padding = activity.getResources().getDimensionPixelSize( + R.dimen.action_bar_switch_padding); + mEnabledSwitch.setPaddingRelative(0, 0, padding, 0); + mEnabledSwitch.setOnCheckedChangeListener(this); + + mCursor = getActivity().managedQuery(Blacklist.CONTENT_URI, + BLACKLIST_PROJECTION, null, null, null); + mAdapter = new BlacklistAdapter(getActivity(), null); + + mEmptyView = (TextView) getView().findViewById(android.R.id.empty); + + final ListView listView = getListView(); + listView.setAdapter(mAdapter); + listView.setEmptyView(mEmptyView); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.blacklist, menu); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + menu.findItem(R.id.blacklist_add).setEnabled(mLastEnabledState); + menu.findItem(R.id.blacklist_prefs).setEnabled(mLastEnabledState); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.blacklist_add: + showEntryEditDialog(-1); + return true; + case R.id.blacklist_prefs: + PreferenceFragment prefs = new PreferenceFragment(); + FragmentTransaction ft = getFragmentManager().beginTransaction(); + ft.replace(android.R.id.content, prefs); + ft.hide(this); + ft.addToBackStack(null); + ft.commitAllowingStateLoss(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + @Override + public void onStart() { + super.onStart(); + final Activity activity = getActivity(); + activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, + ActionBar.DISPLAY_SHOW_CUSTOM); + activity.getActionBar().setCustomView(mEnabledSwitch, new ActionBar.LayoutParams( + ActionBar.LayoutParams.WRAP_CONTENT, + ActionBar.LayoutParams.WRAP_CONTENT, + Gravity.CENTER_VERTICAL | Gravity.END)); + } + + @Override + public void onStop() { + super.onStop(); + final Activity activity = getActivity(); + activity.getActionBar().setDisplayOptions(0, ActionBar.DISPLAY_SHOW_CUSTOM); + activity.getActionBar().setCustomView(null); + } + + @Override + public void onResume() { + super.onResume(); + + final Context context = getActivity(); + mLastEnabledState = BlacklistUtils.isBlacklistEnabled(context); + mEnabledSwitch.setChecked(mLastEnabledState); + updateEnabledState(); + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + showEntryEditDialog(id); + } + + private void showEntryEditDialog(long id) { + EntryEditDialogFragment fragment = EntryEditDialogFragment.newInstance(id); + fragment.show(getFragmentManager(), "blacklist_edit"); + } + + private void updateEnabledState() { + getListView().setEnabled(mLastEnabledState); + getActivity().invalidateOptionsMenu(); + + mEmptyView.setText(mLastEnabledState + ? R.string.blacklist_empty_text + : R.string.blacklist_disabled_empty_text); + mAdapter.swapCursor(mLastEnabledState ? mCursor : null); + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (buttonView == mEnabledSwitch && isChecked != mLastEnabledState) { + Settings.System.putInt(getActivity().getContentResolver(), + Settings.System.PHONE_BLACKLIST_ENABLED, isChecked ? 1 : 0); + mLastEnabledState = isChecked; + updateEnabledState(); + } + } + + private static class BlacklistAdapter extends ResourceCursorAdapter + implements ToggleImageView.OnCheckedChangeListener { + private Object mLock = new Object(); + private ContentResolver mResolver; + private String mCurrentCountryIso; + private SparseArray<String> mRequestedLookups = new SparseArray<String>(); + private HashMap<String, String> mContactNameCache = new HashMap<String, String>(); + + private Handler mMainHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + int lookupIndex = msg.arg1; + String name = (String) msg.obj; + mContactNameCache.put(mRequestedLookups.get(lookupIndex), + name == null ? "" : name); + mRequestedLookups.delete(lookupIndex); + notifyDataSetChanged(); + } + }; + private Handler mQueryHandler; + + private class QueryHandler extends Handler { + public static final int MSG_LOOKUP = 1; + private static final int MSG_FINISH = 2; + + public QueryHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_LOOKUP: + String name = lookupNameForNumber((String) msg.obj); + mMainHandler.obtainMessage(0, msg.arg1, 0, name).sendToTarget(); + synchronized (mLock) { + if (mQueryHandler != null) { + Message finishMessage = mQueryHandler.obtainMessage(MSG_FINISH); + mQueryHandler.sendMessageDelayed(finishMessage, 3000); + } + } + break; + case MSG_FINISH: + synchronized (mLock) { + if (mQueryHandler != null) { + mQueryHandler.getLooper().quit(); + mQueryHandler = null; + } + } + break; + } + } + + private String lookupNameForNumber(String number) { + if (!TextUtils.isEmpty(mCurrentCountryIso)) { + // Normalise the number: this is needed because the PhoneLookup query + // below does not accept a country code as an input. + String numberE164 = PhoneNumberUtils.formatNumberToE164(number, + mCurrentCountryIso); + if (!TextUtils.isEmpty(numberE164)) { + // Only use it if the number could be formatted to E164. + number = numberE164; + } + } + + String result = null; + final String[] projection = new String[] { PhoneLookup.DISPLAY_NAME }; + Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); + Cursor cursor = mResolver.query(uri, projection, null, null, null); + if (cursor != null) { + if (cursor.moveToFirst()) { + result = cursor.getString(0); + } + cursor.close(); + } + + return result; + } + } + + public BlacklistAdapter(Context context, Cursor cursor) { + super(context, R.layout.blacklist_entry_row, cursor); + + final CountryDetector detector = + (CountryDetector) context.getSystemService(Context.COUNTRY_DETECTOR); + mCurrentCountryIso = detector.detectCountry().getCountryIso(); + mResolver = context.getContentResolver(); + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + View view = super.newView(context, cursor, parent); + + ViewHolder holder = new ViewHolder(); + holder.mainText = (TextView) view.findViewById(R.id.number); + holder.subText = (TextView) view.findViewById(R.id.name); + holder.callStatus = (ToggleImageView) view.findViewById(R.id.block_calls); + holder.messageStatus = (ToggleImageView) view.findViewById(R.id.block_messages); + + holder.callStatus.setTag(Blacklist.PHONE_MODE); + holder.callStatus.setOnCheckedChangeListener(this); + + holder.messageStatus.setTag(Blacklist.MESSAGE_MODE); + holder.messageStatus.setOnCheckedChangeListener(this); + + view.setTag(holder); + + return view; + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + ViewHolder holder = (ViewHolder) view.getTag(); + String number = cursor.getString(COLUMN_NUMBER); + String name = mContactNameCache.get(number); + String formattedNumber = PhoneNumberUtils.formatNumber(number, + null, mCurrentCountryIso); + + if (TextUtils.isEmpty(name)) { + holder.mainText.setText(formattedNumber); + holder.subText.setVisibility(View.GONE); + } else { + holder.mainText.setText(name); + holder.subText.setText(formattedNumber); + holder.subText.setVisibility(View.VISIBLE); + } + + if (name == null) { + int id = cursor.getInt(COLUMN_ID); + scheduleNameLookup(id, number); + } + + holder.callStatus.setCheckedInternal(cursor.getInt(COLUMN_PHONE) != 0, false); + holder.messageStatus.setCheckedInternal(cursor.getInt(COLUMN_MESSAGE) != 0, false); + holder.position = cursor.getPosition(); + } + + @Override + public void onCheckedChanged(ToggleImageView view, boolean isChecked) { + View parent = (View) view.getParent(); + ViewHolder holder = (ViewHolder) parent.getTag(); + String column = (String) view.getTag(); + long id = getItemId(holder.position); + Uri uri = ContentUris.withAppendedId(Blacklist.CONTENT_URI, id); + ContentValues cv = new ContentValues(); + + cv.put(column, view.isChecked() ? 1 : 0); + if (mResolver.update(uri, cv, null, null) <= 0) { + // something went wrong, force an update to the correct state + notifyDataSetChanged(); + } + } + + private void scheduleNameLookup(int id, String number) { + synchronized (mLock) { + if (mQueryHandler == null) { + HandlerThread thread = new HandlerThread("blacklist_contact_query", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + mQueryHandler = new QueryHandler(thread.getLooper()); + } + } + + mRequestedLookups.put(id, number); + Message msg = mQueryHandler.obtainMessage(QueryHandler.MSG_LOOKUP, id, 0, number); + msg.sendToTarget(); + } + + private static class ViewHolder { + TextView mainText; + TextView subText; + ToggleImageView callStatus; + ToggleImageView messageStatus; + int position; + } + } +} diff --git a/src/com/android/settings/blacklist/EntryEditDialogFragment.java b/src/com/android/settings/blacklist/EntryEditDialogFragment.java new file mode 100644 index 0000000..3e29279 --- /dev/null +++ b/src/com/android/settings/blacklist/EntryEditDialogFragment.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.blacklist; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.ContactsContract.CommonDataKinds; +import android.provider.Telephony.Blacklist; +import android.text.Editable; +import android.text.TextWatcher; +import android.text.method.ArrowKeyMovementMethod; +import android.text.method.DialerKeyListener; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ImageButton; + +import android.widget.Toast; +import com.android.internal.telephony.util.BlacklistUtils; +import com.android.settings.R; + +public class EntryEditDialogFragment extends DialogFragment + implements TextWatcher, DialogInterface.OnClickListener { + + private EditText mEditText; + private ImageButton mContactPickButton; + private CheckBox mBlockCalls; + private CheckBox mBlockMessages; + private Button mOkButton; + + private static final String[] BLACKLIST_PROJECTION = { + Blacklist.NUMBER, Blacklist.PHONE_MODE, Blacklist.MESSAGE_MODE + }; + private static final String[] NUMBER_PROJECTION = { + CommonDataKinds.Phone.NUMBER + }; + private static final int COLUMN_NUMBER = 0; + private static final int COLUMN_PHONE = 1; + private static final int COLUMN_MESSAGE = 2; + + private static final int REQUEST_CODE_PICKER = 1; + + private static final String DIALOG_STATE = "blacklist_edit_state"; + private static final String STATE_NUMBER = "number"; + private static final String STATE_PHONE = "phone"; + private static final String STATE_MESSAGE = "message"; + + public static EntryEditDialogFragment newInstance(long id) { + Bundle args = new Bundle(); + args.putLong("id", id); + + EntryEditDialogFragment fragment = new EntryEditDialogFragment(); + fragment.setArguments(args); + return fragment; + } + + public EntryEditDialogFragment() { + super(); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + long id = getEntryId(); + Bundle dialogState = savedInstanceState != null + ? savedInstanceState.getBundle(DIALOG_STATE) : null; + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) + .setTitle(R.string.blacklist_edit_dialog_title) + .setPositiveButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, null) + .setView(createDialogView(id, dialogState)); + + if (id >= 0) { + builder.setNeutralButton(R.string.blacklist_button_delete, this); + } + + return builder.create(); + } + + @Override + public void onStart() { + super.onStart(); + + AlertDialog dialog = (AlertDialog) getDialog(); + Button neutralButton = dialog.getButton(DialogInterface.BUTTON_NEUTRAL); + neutralButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + EntryEditDialogFragment parent = EntryEditDialogFragment.this; + DialogFragment confirm = DeleteConfirmationFragment.newInstance(parent); + confirm.show(getFragmentManager(), "delete_confirm"); + } + }); + + updateOkButtonState(); + } + + @Override + public void onClick(DialogInterface dialog, int which) { + if (which == DialogInterface.BUTTON_POSITIVE) { + updateBlacklistEntry(); + } + } + + private void onDeleteConfirmResult(boolean confirmed) { + if (confirmed) { + Uri uri = ContentUris.withAppendedId(Blacklist.CONTENT_URI, getEntryId()); + getActivity().getContentResolver().delete(uri, null, null); + dismiss(); + } + } + + private long getEntryId() { + return getArguments().getLong("id", -1); + } + + private View createDialogView(long id, Bundle savedState) { + final Activity activity = getActivity(); + final LayoutInflater inflater = (LayoutInflater) + activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + final View view = inflater.inflate(R.layout.dialog_blacklist_edit_entry, null); + + mEditText = (EditText) view.findViewById(R.id.number_edit); + mEditText.setMovementMethod(ArrowKeyMovementMethod.getInstance()); + mEditText.setKeyListener(DialerKeyListener.getInstance()); + mEditText.addTextChangedListener(this); + + mContactPickButton = (ImageButton) view.findViewById(R.id.select_contact); + mContactPickButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent contactListIntent = new Intent(Intent.ACTION_PICK); + contactListIntent.setType(CommonDataKinds.Phone.CONTENT_TYPE); + + startActivityForResult(contactListIntent, REQUEST_CODE_PICKER, null); + } + }); + + mBlockCalls = (CheckBox) view.findViewById(R.id.incoming_calls); + mBlockMessages = (CheckBox) view.findViewById(R.id.incoming_messages); + + if (savedState != null) { + mEditText.setText(savedState.getCharSequence(STATE_NUMBER)); + mBlockCalls.setChecked(savedState.getBoolean(STATE_PHONE)); + mBlockMessages.setChecked(savedState.getBoolean(STATE_MESSAGE)); + } else if (id >= 0) { + Uri uri = ContentUris.withAppendedId(Blacklist.CONTENT_URI, id); + Cursor cursor = activity.getContentResolver().query(uri, + BLACKLIST_PROJECTION, null, null, null); + if (cursor != null && cursor.moveToFirst()) { + mEditText.setText(cursor.getString(COLUMN_NUMBER)); + mBlockCalls.setChecked(cursor.getInt(COLUMN_PHONE) != 0); + mBlockMessages.setChecked(cursor.getInt(COLUMN_MESSAGE) != 0); + } else { + id = -1; + } + if (cursor != null) { + cursor.close(); + } + } + + if (id < 0) { + // defaults + mEditText.setText(""); + mBlockCalls.setChecked(true); + mBlockMessages.setChecked(true); + } + + return view; + } + + private void updateBlacklistEntry() { + String number = mEditText.getText().toString(); + int flags = 0; + if (mBlockCalls.isChecked()) { + flags = flags | BlacklistUtils.BLOCK_CALLS; + } + if (mBlockMessages.isChecked()) { + flags = flags | BlacklistUtils.BLOCK_MESSAGES; + } + // Since BlacklistProvider enforces validity for a number to be added + // we should alert the user if and when it gets rejected + if (!BlacklistUtils.addOrUpdate(getActivity(), number, flags, flags)) { + Toast.makeText(getActivity(), getString(R.string.blacklist_bad_number_add), + Toast.LENGTH_LONG).show(); + } + } + + private void updateOkButtonState() { + if (mOkButton == null) { + AlertDialog dialog = (AlertDialog) getDialog(); + if (dialog != null) { + mOkButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE); + } + } + + if (mOkButton != null) { + mOkButton.setEnabled(mEditText.getText().length() != 0); + } + } + + @Override + public void onSaveInstanceState(Bundle state) { + super.onSaveInstanceState(state); + + Bundle dialogState = new Bundle(); + dialogState.putCharSequence(STATE_NUMBER, mEditText.getText()); + dialogState.putBoolean(STATE_PHONE, mBlockCalls.isChecked()); + dialogState.putBoolean(STATE_MESSAGE, mBlockMessages.isChecked()); + state.putBundle(DIALOG_STATE, dialogState); + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void afterTextChanged(Editable s) { + updateOkButtonState(); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode != REQUEST_CODE_PICKER) { + super.onActivityResult(requestCode, resultCode, data); + return; + } + + if (resultCode == Activity.RESULT_OK) { + Cursor cursor = getActivity().getContentResolver().query(data.getData(), + NUMBER_PROJECTION, null, null, null); + if (cursor != null) { + if (cursor.moveToFirst()) { + mEditText.setText(cursor.getString(COLUMN_NUMBER)); + } + cursor.close(); + } + } + } + + private static class DeleteConfirmationFragment extends DialogFragment + implements DialogInterface.OnClickListener { + public static DialogFragment newInstance(EntryEditDialogFragment parent) { + DialogFragment fragment = new DeleteConfirmationFragment(); + fragment.setTargetFragment(parent, 0); + return fragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog dialog = new AlertDialog.Builder(getActivity()) + .setTitle(R.string.remove_blacklist_number_title) + .setMessage(R.string.remove_blacklist_entry) + .setPositiveButton(R.string.yes, this) + .setNegativeButton(R.string.no, this) + .create(); + + return dialog; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + EntryEditDialogFragment parent = (EntryEditDialogFragment) getTargetFragment(); + parent.onDeleteConfirmResult(which == DialogInterface.BUTTON_POSITIVE); + } + } +} diff --git a/src/com/android/settings/blacklist/PreferenceFragment.java b/src/com/android/settings/blacklist/PreferenceFragment.java new file mode 100644 index 0000000..b8ecddd --- /dev/null +++ b/src/com/android/settings/blacklist/PreferenceFragment.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.blacklist; + +import android.content.Context; +import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.MultiSelectListPreference; +import android.preference.Preference; +import android.preference.PreferenceScreen; +import android.provider.Settings; + +import com.android.internal.telephony.util.BlacklistUtils; +import com.android.settings.R; +import com.android.settings.SettingsPreferenceFragment; + +import java.util.HashSet; +import java.util.Set; + +public class PreferenceFragment extends SettingsPreferenceFragment implements + Preference.OnPreferenceChangeListener { + + private static final String BUTTON_BLACKLIST_PRIVATE = "button_blacklist_private_numbers"; + private static final String BUTTON_BLACKLIST_UNKNOWN = "button_blacklist_unknown_numbers"; + + private MultiSelectListPreference mBlacklistPrivate; + private MultiSelectListPreference mBlacklistUnknown; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + addPreferencesFromResource(R.xml.blacklist_prefs); + + PreferenceScreen prefSet = getPreferenceScreen(); + mBlacklistPrivate = + (MultiSelectListPreference) prefSet.findPreference(BUTTON_BLACKLIST_PRIVATE); + mBlacklistPrivate.setOnPreferenceChangeListener(this); + mBlacklistUnknown = + (MultiSelectListPreference) prefSet.findPreference(BUTTON_BLACKLIST_UNKNOWN); + mBlacklistUnknown.setOnPreferenceChangeListener(this); + } + + @Override + public void onResume() { + super.onResume(); + + final Context context = getActivity(); + updateSelectListFromPolicy(mBlacklistPrivate, + Settings.System.PHONE_BLACKLIST_PRIVATE_NUMBER_MODE); + updateSelectListSummary(mBlacklistPrivate, mBlacklistPrivate.getValues(), + R.string.blacklist_private_numbers_summary, + R.string.blacklist_private_numbers_summary_disabled); + updateSelectListFromPolicy(mBlacklistUnknown, + Settings.System.PHONE_BLACKLIST_UNKNOWN_NUMBER_MODE); + updateSelectListSummary(mBlacklistUnknown, mBlacklistUnknown.getValues(), + R.string.blacklist_unknown_numbers_summary, + R.string.blacklist_unknown_numbers_summary_disabled); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object objValue) { + if (preference == mBlacklistUnknown) { + Set<String> newValues = (Set<String>) objValue; + updatePolicyFromSelectList(newValues, + Settings.System.PHONE_BLACKLIST_UNKNOWN_NUMBER_MODE); + updateSelectListSummary(mBlacklistUnknown, newValues, + R.string.blacklist_unknown_numbers_summary, + R.string.blacklist_unknown_numbers_summary_disabled); + } else if (preference == mBlacklistPrivate) { + Set<String> newValues = (Set<String>) objValue; + updatePolicyFromSelectList(newValues, + Settings.System.PHONE_BLACKLIST_PRIVATE_NUMBER_MODE); + updateSelectListSummary(mBlacklistPrivate, newValues, + R.string.blacklist_private_numbers_summary, + R.string.blacklist_private_numbers_summary_disabled); + } + + return true; + } + + private void updateSelectListFromPolicy(MultiSelectListPreference pref, String setting) { + int mode = Settings.System.getInt(getContentResolver(), setting, 0); + Set<String> values = new HashSet<String>(); + + if ((mode & BlacklistUtils.BLOCK_CALLS) != 0) { + values.add(Integer.toString(BlacklistUtils.BLOCK_CALLS)); + } + if ((mode & BlacklistUtils.BLOCK_MESSAGES) != 0) { + values.add(Integer.toString(BlacklistUtils.BLOCK_MESSAGES)); + } + pref.setValues(values); + } + + private int getPolicyFromSelectList(Set<String> values) { + int mode = 0; + + for (String value : values) { + mode |= Integer.parseInt(value); + } + + return mode; + } + + private void updatePolicyFromSelectList(Set<String> values, String setting) { + int mode = getPolicyFromSelectList(values); + Settings.System.putInt(getContentResolver(), setting, mode); + } + + private void updateSelectListSummary(MultiSelectListPreference pref, + Set<String> values, int summaryResId, int disabledSummaryResId) { + int mode = getPolicyFromSelectList(values); + int typeResId; + + if (mode == 0) { + pref.setSummary(getString(disabledSummaryResId)); + return; + } + + if (mode == BlacklistUtils.BLOCK_CALLS) { + typeResId = R.string.blacklist_summary_type_calls_only; + } else if (mode == BlacklistUtils.BLOCK_MESSAGES) { + typeResId = R.string.blacklist_summary_type_messages_only; + } else { + typeResId = R.string.blacklist_summary_type_calls_and_messages; + } + + pref.setSummary(getString(summaryResId, getString(typeResId))); + } +} diff --git a/src/com/android/settings/blacklist/ToggleImageView.java b/src/com/android/settings/blacklist/ToggleImageView.java new file mode 100644 index 0000000..3091c52 --- /dev/null +++ b/src/com/android/settings/blacklist/ToggleImageView.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.blacklist; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.widget.Checkable; +import android.widget.CompoundButton; +import android.widget.ImageView; + +public class ToggleImageView extends ImageView implements Checkable { + public static interface OnCheckedChangeListener { + void onCheckedChanged(ToggleImageView view, boolean isChecked); + } + + private static final int[] CHECKED_STATE_SET = { + com.android.internal.R.attr.state_checked + }; + + private boolean mIsChecked = false; + private OnCheckedChangeListener mOnCheckedChangeListener; + + public ToggleImageView(Context context) { + super(context); + } + + public ToggleImageView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ToggleImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, + com.android.internal.R.styleable.CompoundButton, defStyle, 0); + boolean checked = a.getBoolean( + com.android.internal.R.styleable.CompoundButton_checked, false); + setChecked(checked); + a.recycle(); + } + + @Override + public boolean performClick() { + /* When clicked, toggle the state */ + toggle(); + return super.performClick(); + } + + @Override + public void setChecked(boolean checked) { + setCheckedInternal(checked, true); + } + + @Override + public boolean isChecked() { + return mIsChecked; + } + + @Override + public void toggle() { + setChecked(!mIsChecked); + } + + public void setOnCheckedChangeListener(OnCheckedChangeListener listener) { + mOnCheckedChangeListener = listener; + } + + /* package */ void setCheckedInternal(boolean checked, boolean callListener) { + if (mIsChecked != checked) { + mIsChecked = checked; + setImageState(checked ? CHECKED_STATE_SET : null, true); + if (callListener && mOnCheckedChangeListener != null) { + mOnCheckedChangeListener.onCheckedChanged(this, mIsChecked); + } + } + } +} |