Blacklist (6/9)
Add back call blacklist backend.
Change-Id: I065f1c206cbb86b790e698b396cc611c9a434279
Conflicts:
src/com/android/phone/CallFeaturesSetting.java
src/com/android/phone/CallNotifier.java
Move message blacklist to framework (2/3).
Change-Id: Ie1bea95513b985e79da2e28c86b15a2042c98754
Telephony: fix Blacklist support for L (2/3)
Change-Id: I9cd9c7007fc1016bf2872b01b18334bd8c2601ba
Signed-off-by: Roman Birg <roman@cyngn.com>
Conflicts:
src/com/android/phone/CallNotifier.java
Fix blacklist for SlimLP
Change-Id: If52d357bdd5c3992ba78fe1195e9a76b07b527d6
Signed-off-by: RobbieL811 <RobbieLancaster811@gmail.com>
Fix blacklist for SlimLP
Revert "Telephony: fix Blacklist support for L (2/3)"
This reverts commit 640561592e4ebf6c7cb1675ca47c5bf567b565a3.
Change-Id: I6b1f5dfd4f2bc6a81df31cdeb5ac46e7ebd7bcec
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7d6aad6..0f1ff89 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -65,6 +65,7 @@
<uses-permission android:name="android.permission.STATUS_BAR" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE" />
<uses-permission android:name="android.permission.SET_TIME" />
@@ -520,6 +521,9 @@
<service android:name="EmergencyCallbackModeService">
</service>
+ <!-- Blacklist notification intent service -->
+ <service android:name="ClarBlacklistService" />
+
<!-- service to dump telephony information -->
<service android:name="TelephonyDebugService" />
@@ -617,6 +621,12 @@
android:theme="@style/DialerSettingsLight">
</activity>
+ <receiver android:name="RejectedSmsReceiver">
+ <intent-filter>
+ <action android:name="android.provider.Telephony.SMS_REJECTED" />
+ </intent-filter>
+ </receiver>
+
<!-- BroadcastReceiver for receiving Intents from Notification mechanism. -->
<receiver android:name="PhoneGlobals$NotificationBroadcastReceiver" android:exported="false">
<intent-filter>
diff --git a/res/drawable-hdpi/ic_block_contact_holo_dark.png b/res/drawable-hdpi/ic_block_contact_holo_dark.png
new file mode 100644
index 0000000..4c05fbe
--- /dev/null
+++ b/res/drawable-hdpi/ic_block_contact_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_block_message_holo_dark.png b/res/drawable-hdpi/ic_block_message_holo_dark.png
new file mode 100644
index 0000000..739559f
--- /dev/null
+++ b/res/drawable-hdpi/ic_block_message_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_unblock_contact_holo_dark.png b/res/drawable-hdpi/ic_unblock_contact_holo_dark.png
new file mode 100644
index 0000000..682800c
--- /dev/null
+++ b/res/drawable-hdpi/ic_unblock_contact_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_unblock_message_holo_dark.png b/res/drawable-hdpi/ic_unblock_message_holo_dark.png
new file mode 100644
index 0000000..498d246
--- /dev/null
+++ b/res/drawable-hdpi/ic_unblock_message_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_block_contact_holo_dark.png b/res/drawable-mdpi/ic_block_contact_holo_dark.png
new file mode 100644
index 0000000..1daf088
--- /dev/null
+++ b/res/drawable-mdpi/ic_block_contact_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_block_message_holo_dark.png b/res/drawable-mdpi/ic_block_message_holo_dark.png
new file mode 100644
index 0000000..08aee62
--- /dev/null
+++ b/res/drawable-mdpi/ic_block_message_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_unblock_contact_holo_dark.png b/res/drawable-mdpi/ic_unblock_contact_holo_dark.png
new file mode 100644
index 0000000..f60ee16
--- /dev/null
+++ b/res/drawable-mdpi/ic_unblock_contact_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_unblock_message_holo_dark.png b/res/drawable-mdpi/ic_unblock_message_holo_dark.png
new file mode 100644
index 0000000..d9526d0
--- /dev/null
+++ b/res/drawable-mdpi/ic_unblock_message_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_block_contact_holo_dark.png b/res/drawable-xhdpi/ic_block_contact_holo_dark.png
new file mode 100644
index 0000000..afea00f
--- /dev/null
+++ b/res/drawable-xhdpi/ic_block_contact_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_block_message_holo_dark.png b/res/drawable-xhdpi/ic_block_message_holo_dark.png
new file mode 100644
index 0000000..0d78f36
--- /dev/null
+++ b/res/drawable-xhdpi/ic_block_message_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_unblock_contact_holo_dark.png b/res/drawable-xhdpi/ic_unblock_contact_holo_dark.png
new file mode 100644
index 0000000..659a9a2
--- /dev/null
+++ b/res/drawable-xhdpi/ic_unblock_contact_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_unblock_message_holo_dark.png b/res/drawable-xhdpi/ic_unblock_message_holo_dark.png
new file mode 100644
index 0000000..3cd13c1
--- /dev/null
+++ b/res/drawable-xhdpi/ic_unblock_message_holo_dark.png
Binary files differ
diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml
index 573ba23..430dbcf 100644
--- a/res/values/custom_strings.xml
+++ b/res/values/custom_strings.xml
@@ -25,4 +25,24 @@
<string name="prox_auto_speaker_incall_only_summary_on">On outgoing calls, listener will only become active after the receiving party answers</string>
<string name="prox_auto_speaker_incall_only_summary_off">Listener will be active during all offhook call states (default)</string>
-</resources>
+ <!-- Advanced Settings -->
+ <string name="advanced_setting">Advanced Settings</string>
+
+ <!-- Blacklist preferences -->
+ <string name="blacklist_title">Blacklist</string>
+ <string name="blacklist_summary_disabled">Disabled</string>
+ <string name="blacklist_summary">Incoming calls from phone numbers in the blacklist will be blocked</string>
+
+ <!-- Blacklist notifications -->
+ <string name="blacklist_call_notification">Blocked a call from %s</string>
+ <string name="blacklist_call_notification_private_number">Blocked a call from a private number</string>
+ <string name="blacklist_call_notification_unknown_number">Blocked a call from unknown number %s</string>
+ <string name="blacklist_call_notification_multiple"><xliff:g id="count">%d</xliff:g> calls were blocked</string>
+ <string name="blacklist_message_notification">Blocked a message from %s</string>
+ <string name="blacklist_message_notification_private_number">Blocked a message from a private number</string>
+ <string name="blacklist_message_notification_unknown_number">Blocked a message from unknown number %s</string>
+ <string name="blacklist_message_notification_multiple"><xliff:g id="count">%d</xliff:g> messages were blocked</string>
+ <string name="blacklist_notification_list_private">Private</string>
+ <string name="unblock_number">Unblock</string>
+
+</resources>
\ No newline at end of file
diff --git a/res/xml/call_feature_setting.xml b/res/xml/call_feature_setting.xml
index 9bf9079..7def545 100644
--- a/res/xml/call_feature_setting.xml
+++ b/res/xml/call_feature_setting.xml
@@ -179,4 +179,17 @@
</PreferenceCategory>
+ <PreferenceCategory
+ android:key="pref_advanced_settings"
+ android:title="@string/advanced_settings">
+
+ <PreferenceScreen
+ android:key="button_blacklist"
+ android:title="@string/blacklist_title"
+ android:persistent="false">
+ <intent android:action="android.intent.action.MAIN"
+ android:targetPackage="com.android.settings"
+ android:targetClass="com.android.settings.Settings$BlacklistSettingsActivity" />
+ </PreferenceScreen>
+ </PreferenceCategory>
</PreferenceScreen>
diff --git a/src/com/android/phone/Blacklist.java b/src/com/android/phone/Blacklist.java
new file mode 100644
index 0000000..80c5f06
--- /dev/null
+++ b/src/com/android/phone/Blacklist.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 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.phone;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.provider.Telephony;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.util.HashSet;
+
+/**
+ * This class used to handle the blacklist data. Its
+ * only remaining purpose is legacy data migration
+ */
+class Blacklist {
+ private static class PhoneNumber implements Externalizable {
+ static final long serialVersionUID = 32847013274L;
+ String phone;
+
+ public PhoneNumber() {
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ phone = (String) in.readObject();
+ }
+
+ @Override
+ public int hashCode() {
+ return phone != null ? phone.hashCode() : 0;
+ }
+ }
+
+ private static final String BLFILE = "blacklist.dat";
+ private static final int BLFILE_VER = 1;
+
+ public static void migrateOldDataIfPresent(Context context) {
+ ObjectInputStream ois = null;
+ HashSet<PhoneNumber> data = null;
+
+ try {
+ ois = new ObjectInputStream(context.openFileInput(BLFILE));
+ Object o = ois.readObject();
+ if (o != null && o instanceof Integer) {
+ // check the version
+ Integer version = (Integer) o;
+ if (version == BLFILE_VER) {
+ Object numbers = ois.readObject();
+ if (numbers instanceof HashSet) {
+ data = (HashSet<PhoneNumber>) numbers;
+ }
+ }
+ }
+ } catch (IOException e) {
+ // Do nothing
+ } catch (ClassNotFoundException e) {
+ // Do nothing
+ } finally {
+ if (ois != null) {
+ try {
+ ois.close();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ context.deleteFile(BLFILE);
+ }
+ }
+ if (data != null) {
+ ContentResolver cr = context.getContentResolver();
+ ContentValues cv = new ContentValues();
+ cv.put(Telephony.Blacklist.PHONE_MODE, 1);
+
+ for (PhoneNumber number : data) {
+ Uri uri = Uri.withAppendedPath(
+ Telephony.Blacklist.CONTENT_FILTER_BYNUMBER_URI, number.phone);
+ cv.put(Telephony.Blacklist.NUMBER, number.phone);
+ cr.update(uri, cv, null, null);
+ }
+ }
+ }
+}
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 6438175..50a71f4 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -68,6 +69,7 @@
import com.android.phone.common.util.SettingsUtil;
import com.android.phone.settings.AccountSelectionPreference;
import com.android.services.telephony.sip.SipUtil;
+import com.android.internal.telephony.util.BlacklistUtils;
import java.lang.String;
import java.util.Collection;
@@ -245,6 +247,9 @@
private static final String VOICEMAIL_VIBRATION_ALWAYS = "always";
private static final String VOICEMAIL_VIBRATION_NEVER = "never";
+ // Blacklist support
+ private static final String BUTTON_BLACKLIST = "button_blacklist";
+
private EditPhoneNumberPreference mSubMenuVoicemailSettings;
private Runnable mVoicemailRingtoneLookupRunnable;
@@ -271,6 +276,8 @@
private Preference mVoicemailNotificationRingtone;
private CheckBoxPreference mVoicemailNotificationVibrate;
private AccountSelectionPreference mDefaultOutgoingAccount;
+ private boolean isSpeedDialListStarted = false;
+ private PreferenceScreen mButtonBlacklist;
private class VoiceMailProvider {
public VoiceMailProvider(String name, Intent intent) {
@@ -1768,6 +1775,9 @@
updateVoiceNumberField();
mVMProviderSettingsForced = false;
+ // Blacklist screen - Needed for setting summary
+ mButtonBlacklist = (PreferenceScreen) prefSet.findPreference(BUTTON_BLACKLIST);
+
PreferenceScreen selectSub = (PreferenceScreen) findPreference(BUTTON_SELECT_SUB_KEY);
if (selectSub != null) {
Intent intent = selectSub.getIntent();
@@ -1820,6 +1830,17 @@
// Look up the voicemail ringtone name asynchronously and update its preference.
new Thread(mVoicemailRingtoneLookupRunnable).start();
+ updateBlacklistSummary();
+ }
+
+ private void updateBlacklistSummary() {
+ if (mButtonBlacklist != null) {
+ if (BlacklistUtils.isBlacklistEnabled(this)) {
+ mButtonBlacklist.setSummary(R.string.blacklist_summary);
+ } else {
+ mButtonBlacklist.setSummary(R.string.blacklist_summary_disabled);
+ }
+ }
}
// Migrate settings from BUTTON_VOICEMAIL_NOTIFICATION_VIBRATE_WHEN_KEY to
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 8ffda6f..367e52e 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -20,6 +21,7 @@
import com.android.internal.telephony.CallManager;
import com.android.internal.telephony.CallerInfo;
import com.android.internal.telephony.CallerInfoAsyncQuery;
+import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
@@ -29,6 +31,7 @@
import com.android.internal.telephony.cdma.CdmaInformationRecords.CdmaDisplayInfoRec;
import com.android.internal.telephony.cdma.CdmaInformationRecords.CdmaSignalInfoRec;
import com.android.internal.telephony.cdma.SignalToneUtil;
+import com.android.internal.telephony.util.BlacklistUtils;
import android.app.ActivityManagerNative;
import android.bluetooth.BluetoothAdapter;
@@ -38,6 +41,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.Cursor;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.ToneGenerator;
@@ -49,6 +53,7 @@
import android.os.SystemVibrator;
import android.os.Vibrator;
import android.provider.CallLog.Calls;
+import android.provider.ContactsContract;
import android.provider.Settings;
import android.telecom.TelecomManager;
import android.telephony.DisconnectCause;
@@ -117,6 +122,10 @@
private PhoneStateListener[] mPhoneStateListener;
+ // Blacklist handling
+ private static final String BLACKLIST = "Blacklist";
+ private boolean mSilentRingerRequested;
+
/**
* Initialize the singleton CallNotifier instance.
* This is only done once, at startup, from PhoneApp.onCreate().
@@ -343,6 +352,11 @@
return;
}
+ // Blacklist handling
+ if (isConnectionBlacklisted(c)) {
+ return;
+ }
+
// Stop any signalInfo tone being played on receiving a Call
stopSignalInfoTone();
@@ -393,6 +407,81 @@
if (VDBG) log("- onNewRingingConnection() done.");
}
+ private static final String[] FAVORITE_PROJECTION = new String[] {
+ ContactsContract.PhoneLookup.STARRED
+ };
+ private static final String[] CONTACT_PROJECTION = new String[] {
+ ContactsContract.PhoneLookup.NUMBER
+ };
+
+ protected boolean isConnectionBlacklisted(Connection c) {
+ final String number = c.getAddress();
+ if (DBG) log("Incoming number is: " + number);
+ // See if the number is in the blacklist
+ // Result is one of: MATCH_NONE, MATCH_LIST or MATCH_REGEX
+ int listType = BlacklistUtils.isListed(mApplication, number, BlacklistUtils.BLOCK_CALLS);
+ if (listType != BlacklistUtils.MATCH_NONE) {
+ // We have a match, set the user and hang up the call and notify
+ if (DBG) log("Incoming call from " + number + " blocked.");
+ c.setUserData(new CallerInfo().markAsBlacklist());
+ try {
+ mSilentRingerRequested = true;
+ c.hangup();
+ mApplication.notificationMgr.notifyBlacklistedCall(number,
+ c.getCreateTime(), listType);
+ } catch (CallStateException e) {
+ e.printStackTrace();
+ Log.w(LOG_TAG, "Invalid call state", e);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Helper function used to determine if calling number is from person in the Contacts
+ * Optionally, it can also check if the contact is a 'Starred'or favourite contact
+ */
+ private boolean isContact(String number, boolean checkFavorite) {
+ if (DBG) log("isContact(): checking if " + number + " is in the contact list.");
+
+ Uri lookupUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
+ Uri.encode(number));
+ Cursor cursor = mApplication.getContentResolver().query(lookupUri,
+ checkFavorite ? FAVORITE_PROJECTION : CONTACT_PROJECTION,
+ ContactsContract.PhoneLookup.NUMBER + "=?",
+ new String[] { number }, null);
+
+ if (cursor == null) {
+ if (DBG) log("Couldn't query contacts provider");
+ return false;
+ }
+
+ try {
+ if (cursor.moveToFirst() && !checkFavorite) {
+ // All we care about is that the number is in the Contacts list
+ if (DBG) log("Number belongs to a contact");
+ return true;
+ }
+
+ // Either no result or we should check for favorite.
+ // In the former case the loop won't be entered.
+ while (!cursor.isAfterLast()) {
+ if (cursor.getInt(cursor.getColumnIndex(
+ ContactsContract.PhoneLookup.STARRED)) == 1) {
+ if (DBG) log("Number belongs to a favorite");
+ return true;
+ }
+ cursor.moveToNext();
+ }
+ } finally {
+ cursor.close();
+ }
+
+ if (DBG) log("A match for the number wasn't found");
+ return false;
+ }
+
/**
* Determines whether or not we're allowed to present incoming calls to the
* user, based on the capabilities and/or current state of the device.
@@ -542,6 +631,11 @@
Log.w(LOG_TAG, "onDisconnect: null connection");
}
+ boolean disconnectedDueToBlacklist = false;
+ if (c != null) {
+ disconnectedDueToBlacklist = isDisconnectedDueToBlacklist(c);
+ }
+
int autoretrySetting = 0;
if ((c != null) &&
(c.getCall().getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA)) {
@@ -580,7 +674,8 @@
// TODO: We may eventually want to disable this via a preference.
if ((toneToPlay == InCallTonePlayer.TONE_NONE)
&& (mCM.getState() == PhoneConstants.State.IDLE)
- && (c != null)) {
+ && (c != null)
+ && !mSilentRingerRequested) {
int cause = c.getDisconnectCause();
if ((cause == DisconnectCause.NORMAL) // remote hangup
|| (cause == DisconnectCause.LOCAL)) { // local hangup
@@ -600,7 +695,11 @@
}
if (c != null) {
- mCallLogger.logCall(c);
+ if (disconnectedDueToBlacklist) {
+ mCallLogger.logCall(c, Calls.BLACKLIST_TYPE);
+ } else {
+ mCallLogger.logCall(c);
+ }
final String number = c.getAddress();
final Phone phone = c.getCall().getPhone();
@@ -629,6 +728,7 @@
if (((mPreviousCdmaCallState == Call.State.DIALING)
|| (mPreviousCdmaCallState == Call.State.ALERTING))
&& (!isEmergencyNumber)
+ && !disconnectedDueToBlacklist
&& (cause != DisconnectCause.INCOMING_MISSED )
&& (cause != DisconnectCause.NORMAL)
&& (cause != DisconnectCause.LOCAL)
@@ -1157,4 +1257,11 @@
private void log(String msg) {
Log.d(LOG_TAG, msg);
}
+
+ protected boolean isDisconnectedDueToBlacklist(Connection c) {
+ if (c == null) {
+ return false;
+ }
+ return ((CallerInfo) c.getUserData()).isBlacklistedNumber();
+ }
}
diff --git a/src/com/android/phone/ClearBlacklistService.java b/src/com/android/phone/ClearBlacklistService.java
new file mode 100644
index 0000000..d969945
--- /dev/null
+++ b/src/com/android/phone/ClearBlacklistService.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 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.phone;
+
+import com.android.internal.telephony.util.BlacklistUtils;
+
+import android.app.IntentService;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.provider.CallLog.Calls;
+
+/**
+ * Handles the intent to clear the missed calls that is triggered when a notification is dismissed.
+ */
+public class ClearBlacklistService extends IntentService {
+ /** This action is used to clear blacklisted calls. */
+ public static final String ACTION_CLEAR_BLACKLISTED_CALLS =
+ "com.android.phone.intent.CLEAR_BLACKLISTED_CALLS";
+ /** This action is used to clear blacklisted messages. */
+ public static final String ACTION_CLEAR_BLACKLISTED_MESSAGES =
+ "com.android.phone.intent.CLEAR_BLACKLISTED_MESSAGES";
+
+ private PhoneGlobals mApp;
+
+ public ClearBlacklistService() {
+ super(ClearBlacklistService.class.getSimpleName());
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mApp = PhoneGlobals.getInstance();
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ final String action = intent.getAction();
+ if (ACTION_CLEAR_BLACKLISTED_CALLS.equals(action)) {
+ mApp.notificationMgr.cancelBlacklistedNotification(BlacklistUtils.BLOCK_CALLS);
+ } else if (ACTION_CLEAR_BLACKLISTED_MESSAGES.equals(action)) {
+ mApp.notificationMgr.cancelBlacklistedNotification(BlacklistUtils.BLOCK_MESSAGES);
+ }
+ }
+}
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index a027fd2..42a5f75 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -16,6 +16,8 @@
package com.android.phone;
+import java.util.ArrayList;
+
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -38,6 +40,9 @@
import android.telecom.PhoneAccount;
import android.telephony.PhoneNumberUtils;
import android.telephony.ServiceState;
+import android.text.SpannableStringBuilder;
+import android.text.format.DateUtils;
+import android.text.style.RelativeSizeSpan;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
@@ -47,6 +52,7 @@
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.PhoneBase;
import com.android.internal.telephony.TelephonyCapabilities;
+import com.android.internal.telephony.util.BlacklistUtils;
import java.util.List;
@@ -75,6 +81,8 @@
static final int CALL_FORWARD_NOTIFICATION = 4;
static final int DATA_DISCONNECTED_ROAMING_NOTIFICATION = 5;
static final int SELECTED_OPERATOR_FAIL_NOTIFICATION = 6;
+ static final int BLACKLISTED_CALL_NOTIFICATION = 7;
+ static final int BLACKLISTED_MESSAGE_NOTIFICATION = 8;
static final int NOTIFICATION_ID_OFFSET = 50;
@@ -91,6 +99,23 @@
public StatusBarHelper statusBarHelper;
+ // used to track blacklisted calls and messages
+ private static class BlacklistedItemInfo {
+ String number;
+ long date;
+ int matchType;
+
+ BlacklistedItemInfo(String number, long date, int matchType) {
+ this.number = number;
+ this.date = date;
+ this.matchType = matchType;
+ }
+ };
+ private ArrayList<BlacklistedItemInfo> mBlacklistedCalls =
+ new ArrayList<BlacklistedItemInfo>();
+ private ArrayList<BlacklistedItemInfo> mBlacklistedMessages =
+ new ArrayList<BlacklistedItemInfo>();
+
// used to track the notification of selected network unavailable
private boolean mSelectedUnavailableNotify = false;
@@ -235,6 +260,167 @@
PhoneLookup._ID
};
+ private static final RelativeSizeSpan TIME_SPAN = new RelativeSizeSpan(0.7f);
+
+ private CharSequence formatSingleCallLine(String caller, long date) {
+ int flags = DateUtils.FORMAT_SHOW_TIME;
+ if (!DateUtils.isToday(date)) {
+ flags |= DateUtils.FORMAT_SHOW_WEEKDAY;
+ }
+
+ SpannableStringBuilder lineBuilder = new SpannableStringBuilder();
+ lineBuilder.append(caller);
+ lineBuilder.append(" ");
+
+ int timeIndex = lineBuilder.length();
+ lineBuilder.append(DateUtils.formatDateTime(mContext, date, flags));
+ lineBuilder.setSpan(TIME_SPAN, timeIndex, lineBuilder.length(), 0);
+
+ return lineBuilder;
+ }
+
+ /* package */ void notifyBlacklistedCall(String number, long date, int matchType) {
+ notifyBlacklistedItem(number, date, matchType, BLACKLISTED_CALL_NOTIFICATION);
+ }
+
+ /* package */ void notifyBlacklistedMessage(String number, long date, int matchType) {
+ notifyBlacklistedItem(number, date, matchType, BLACKLISTED_MESSAGE_NOTIFICATION);
+ }
+
+ private void notifyBlacklistedItem(String number, long date,
+ int matchType, int notificationId) {
+ if (!BlacklistUtils.isBlacklistNotifyEnabled(mContext)) {
+ return;
+ }
+
+ if (VDBG) {
+ log("notifyBlacklistedItem(). number: " + number
+ + ", match type: " + matchType + ", date: " + date + ", type: " + notificationId);
+ }
+
+ ArrayList<BlacklistedItemInfo> items = notificationId == BLACKLISTED_CALL_NOTIFICATION
+ ? mBlacklistedCalls : mBlacklistedMessages;
+ PendingIntent clearIntent = notificationId == BLACKLISTED_CALL_NOTIFICATION
+ ? createClearBlacklistedCallsIntent() : createClearBlacklistedMessagesIntent();
+ int iconDrawableResId = notificationId == BLACKLISTED_CALL_NOTIFICATION
+ ? R.drawable.ic_block_contact_holo_dark : R.drawable.ic_block_message_holo_dark;
+
+ // Keep track of the call/message, keeping list sorted from newest to oldest
+ items.add(0, new BlacklistedItemInfo(number, date, matchType));
+
+ // Get the intent to open Blacklist settings if user taps on content ready
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClassName("com.android.settings",
+ "com.android.settings.Settings$BlacklistSettingsActivity");
+ PendingIntent blSettingsIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+
+ // Start building the notification
+ Notification.Builder builder = new Notification.Builder(mContext);
+ builder.setSmallIcon(iconDrawableResId)
+ .setContentIntent(blSettingsIntent)
+ .setAutoCancel(true)
+ .setContentTitle(mContext.getString(R.string.blacklist_title))
+ .setWhen(date)
+ .setDeleteIntent(clearIntent);
+
+ // Add the 'Remove block' notification action only for MATCH_LIST items since
+ // MATCH_REGEX and MATCH_PRIVATE items does not have an associated specific number
+ // to unblock, and MATCH_UNKNOWN unblock for a single number does not make sense.
+ boolean addUnblockAction = true;
+
+ if (items.size() == 1) {
+ int messageResId;
+
+ switch (matchType) {
+ case BlacklistUtils.MATCH_PRIVATE:
+ messageResId = notificationId == BLACKLISTED_CALL_NOTIFICATION
+ ? R.string.blacklist_call_notification_private_number
+ : R.string.blacklist_message_notification_private_number;
+ break;
+ case BlacklistUtils.MATCH_UNKNOWN:
+ messageResId = notificationId == BLACKLISTED_CALL_NOTIFICATION
+ ? R.string.blacklist_call_notification_unknown_number
+ : R.string.blacklist_message_notification_unknown_number;
+ break;
+ default:
+ messageResId = notificationId == BLACKLISTED_CALL_NOTIFICATION
+ ? R.string.blacklist_call_notification
+ : R.string.blacklist_message_notification;
+ break;
+ }
+ builder.setContentText(mContext.getString(messageResId, number));
+
+ if (matchType != BlacklistUtils.MATCH_LIST) {
+ addUnblockAction = false;
+ }
+ } else {
+ int messageResId = notificationId == BLACKLISTED_CALL_NOTIFICATION
+ ? R.string.blacklist_call_notification_multiple
+ : R.string.blacklist_message_notification_multiple;
+ String message = mContext.getString(messageResId, items.size());
+
+ builder.setContentText(message);
+ builder.setNumber(items.size());
+
+ Notification.InboxStyle style = new Notification.InboxStyle(builder);
+
+ for (BlacklistedItemInfo info : items) {
+ // Takes care of displaying "Private" instead of an empty string
+ String numberString = TextUtils.isEmpty(info.number)
+ ? mContext.getString(R.string.blacklist_notification_list_private)
+ : info.number;
+ style.addLine(formatSingleCallLine(numberString, info.date));
+
+ if (!TextUtils.equals(number, info.number)) {
+ addUnblockAction = false;
+ } else if (info.matchType != BlacklistUtils.MATCH_LIST) {
+ addUnblockAction = false;
+ }
+ }
+ style.setBigContentTitle(message);
+ style.setSummaryText(" ");
+ builder.setStyle(style);
+ }
+
+ if (addUnblockAction) {
+ int actionDrawableResId = notificationId == BLACKLISTED_CALL_NOTIFICATION
+ ? R.drawable.ic_unblock_contact_holo_dark
+ : R.drawable.ic_unblock_message_holo_dark;
+ int unblockType = notificationId == BLACKLISTED_CALL_NOTIFICATION
+ ? BlacklistUtils.BLOCK_CALLS : BlacklistUtils.BLOCK_MESSAGES;
+ PendingIntent action = PhoneGlobals.getUnblockNumberFromNotificationPendingIntent(
+ mContext, number, unblockType);
+
+ builder.addAction(actionDrawableResId,
+ mContext.getString(R.string.unblock_number), action);
+ }
+
+ mNotificationManager.notify(notificationId, builder.getNotification());
+ }
+
+ private PendingIntent createClearBlacklistedCallsIntent() {
+ Intent intent = new Intent(mContext, ClearBlacklistService.class);
+ intent.setAction(ClearBlacklistService.ACTION_CLEAR_BLACKLISTED_CALLS);
+ return PendingIntent.getService(mContext, 0, intent, 0);
+ }
+
+ private PendingIntent createClearBlacklistedMessagesIntent() {
+ Intent intent = new Intent(mContext, ClearBlacklistService.class);
+ intent.setAction(ClearBlacklistService.ACTION_CLEAR_BLACKLISTED_MESSAGES);
+ return PendingIntent.getService(mContext, 0, intent, 0);
+ }
+
+ void cancelBlacklistedNotification(int type) {
+ if ((type & BlacklistUtils.BLOCK_CALLS) != 0) {
+ mBlacklistedCalls.clear();
+ mNotificationManager.cancel(BLACKLISTED_CALL_NOTIFICATION);
+ }
+ if ((type & BlacklistUtils.BLOCK_MESSAGES) != 0) {
+ mBlacklistedMessages.clear();
+ mNotificationManager.cancel(BLACKLISTED_MESSAGE_NOTIFICATION);
+ }
+ }
+
/**
* Updates the message waiting indicator (voicemail) notification.
*
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 4982217..2180047 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -64,6 +64,7 @@
import com.android.internal.telephony.PhoneProxy;
import com.android.internal.telephony.TelephonyCapabilities;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.util.BlacklistUtils;
import com.android.phone.common.CallLogAsync;
import com.android.server.sip.SipService;
@@ -213,6 +214,12 @@
public OtaUtils.CdmaOtaScreenState cdmaOtaScreenState;
public OtaUtils.CdmaOtaInCallScreenUiState cdmaOtaInCallScreenUiState;
+ // For adding to Blacklist from call log
+ private static final String REMOVE_BLACKLIST = "com.android.phone.REMOVE_BLACKLIST";
+ private static final String EXTRA_NUMBER = "number";
+ private static final String EXTRA_TYPE = "type";
+ private static final String EXTRA_FROM_NOTIFICATION = "fromNotification";
+
/**
* Set the restore mute state flag. Used when we are setting the mute state
* OUTSIDE of user interaction {@link PhoneUtils#startNewCall(Phone)}
@@ -414,6 +421,9 @@
phoneMgr = PhoneInterfaceManager.init(this, phone);
+ // Convert old blacklist to new format
+ Blacklist.migrateOldDataIfPresent(this);
+
// Create the CallNotifer singleton, which handles
// asynchronous events from the telephony layer (like
// launching the incoming-call UI when an incoming call comes
@@ -444,6 +454,7 @@
intentFilter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
intentFilter.addAction(TelephonyIntents.ACTION_MANAGED_ROAMING_IND);
+ intentFilter.addAction(REMOVE_BLACKLIST);
registerReceiver(mReceiver, intentFilter);
//set the default values for the preferences in the phone.
@@ -549,6 +560,15 @@
return PendingIntent.getBroadcast(context, 0, intent, 0);
}
+ /* package */ static PendingIntent getUnblockNumberFromNotificationPendingIntent(
+ Context context, String number, int type) {
+ Intent intent = new Intent(REMOVE_BLACKLIST);
+ intent.putExtra(EXTRA_NUMBER, number);
+ intent.putExtra(EXTRA_FROM_NOTIFICATION, true);
+ intent.putExtra(EXTRA_TYPE, type);
+ return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
boolean isSimPinEnabled() {
return mIsSimPinEnabled;
}
@@ -901,6 +921,14 @@
createIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
createIntent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subscription);
context.startActivity(createIntent);
+ } else if (action.equals(REMOVE_BLACKLIST)) {
+ if (intent.getBooleanExtra(EXTRA_FROM_NOTIFICATION, false)) {
+ // Dismiss the notification that brought us here
+ int blacklistType = intent.getIntExtra(EXTRA_TYPE, 0);
+ notificationMgr.cancelBlacklistedNotification(blacklistType);
+ BlacklistUtils.addOrUpdate(context, intent.getStringExtra(EXTRA_NUMBER),
+ 0, blacklistType);
+ }
}
}
}
diff --git a/src/com/android/phone/RejectedSmsReceiver.java b/src/com/android/phone/RejectedSmsReceiver.java
new file mode 100644
index 0000000..076f095
--- /dev/null
+++ b/src/com/android/phone/RejectedSmsReceiver.java
@@ -0,0 +1,37 @@
+/*
+ * 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.phone;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class RejectedSmsReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!intent.getBooleanExtra("blacklisted", false)) {
+ return;
+ }
+
+ String sender = intent.getStringExtra("sender");
+ long timestamp = intent.getLongExtra("timestamp", 0);
+ int matchType = intent.getIntExtra("blacklistMatchType", -1);
+
+ PhoneGlobals.getInstance().notificationMgr.notifyBlacklistedMessage(
+ sender, timestamp, matchType);
+ }
+}