Merge branch 'LA.BF64.1.2.2_rb4.6' of git://codeaurora.org/platform/packages/services/Telecomm into cm-13.0
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f4ae711..43e5ab4 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -195,6 +195,10 @@
                 <action android:name="com.android.server.telecom.ACTION_CLEAR_MISSED_CALLS" />
                 <action android:name="com.android.server.telecom.ACTION_CALL_BACK_FROM_NOTIFICATION" />
                 <action android:name="com.android.server.telecom.ACTION_SEND_SMS_FROM_NOTIFICATION" />
+                <action android:name="com.android.phone.intent.CLEAR_BLACKLISTED_CALLS" />
+                <action android:name="com.android.phone.intent.CLEAR_BLACKLISTED_MESSAGES" />
+                <action android:name="com.android.phone.REMOVE_BLACKLIST" />
+                <action android:name="android.provider.Telephony.SMS_REJECTED" />
             </intent-filter>
         </receiver>
 
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/mipmap-hdpi/ic_launcher_phone.png b/res/mipmap-hdpi/ic_launcher_phone.png
index 47d7894..aa3f099 100644
--- a/res/mipmap-hdpi/ic_launcher_phone.png
+++ b/res/mipmap-hdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_launcher_phone.png b/res/mipmap-mdpi/ic_launcher_phone.png
index 3b333cf..b554b7c 100644
--- a/res/mipmap-mdpi/ic_launcher_phone.png
+++ b/res/mipmap-mdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher_phone.png b/res/mipmap-xhdpi/ic_launcher_phone.png
index 020c2fa..5b9aff0 100644
--- a/res/mipmap-xhdpi/ic_launcher_phone.png
+++ b/res/mipmap-xhdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/mipmap-xxhdpi/ic_launcher_phone.png b/res/mipmap-xxhdpi/ic_launcher_phone.png
index 1594e4e..4e204d4 100644
--- a/res/mipmap-xxhdpi/ic_launcher_phone.png
+++ b/res/mipmap-xxhdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/mipmap-xxxhdpi/ic_launcher_phone.png b/res/mipmap-xxxhdpi/ic_launcher_phone.png
index 8c92ac1..3efbee9 100644
--- a/res/mipmap-xxxhdpi/ic_launcher_phone.png
+++ b/res/mipmap-xxxhdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
new file mode 100644
index 0000000..5766bae
--- /dev/null
+++ b/res/values/cm_strings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2013-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.
+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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- 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/src/com/android/server/telecom/Blacklist.java b/src/com/android/server/telecom/Blacklist.java
new file mode 100644
index 0000000..5584e6d
--- /dev/null
+++ b/src/com/android/server/telecom/Blacklist.java
@@ -0,0 +1,88 @@
+package com.android.server.telecom;
+
+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/server/telecom/BlacklistCallNotifier.java b/src/com/android/server/telecom/BlacklistCallNotifier.java
new file mode 100644
index 0000000..6e6a527
--- /dev/null
+++ b/src/com/android/server/telecom/BlacklistCallNotifier.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2014, 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.server.telecom;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.TaskStackBuilder;
+import android.content.*;
+import android.net.Uri;
+import android.provider.CallLog.Calls;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.text.style.RelativeSizeSpan;
+import com.android.internal.telephony.util.BlacklistUtils;
+import com.android.server.telecom.components.TelecomBroadcastReceiver;
+
+import java.util.ArrayList;
+
+// TODO: Needed for move to system service: import com.android.internal.R;
+
+/**
+ * Handles notifying the user of any blacklisted calls or messages.
+ */
+class BlacklistCallNotifier extends CallsManagerListenerBase {
+
+    private static final boolean DEBUG = false;
+
+    private static final RelativeSizeSpan TIME_SPAN = new RelativeSizeSpan(0.7f);
+
+    private final Context mContext;
+    private final NotificationManager mNotificationManager;
+
+    static final int BLACKLISTED_CALL_NOTIFICATION = 7;
+    static final int BLACKLISTED_MESSAGE_NOTIFICATION = 8;
+
+    // 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>();
+
+    BlacklistCallNotifier(Context context) {
+        mContext = context;
+        mNotificationManager =
+                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void onCallStateChanged(Call call, int oldState, int newState) {
+
+    }
+
+    /* 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 (DEBUG) Log.d(this, "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.blacklist.BlacklistSettings");
+        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 = 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, TelecomBroadcastReceiver.class);
+        intent.setAction(TelecomBroadcastIntentProcessor.ACTION_CLEAR_BLACKLISTED_CALLS);
+        return PendingIntent.getService(mContext, 0, intent, 0);
+    }
+
+    private PendingIntent createClearBlacklistedMessagesIntent() {
+        Intent intent = new Intent(mContext, TelecomBroadcastReceiver.class);
+        intent.setAction(TelecomBroadcastIntentProcessor.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);
+        }
+    }
+
+    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 */ static PendingIntent getUnblockNumberFromNotificationPendingIntent(
+            Context context, String number, int type) {
+        Intent intent = new Intent(TelecomBroadcastIntentProcessor.REMOVE_BLACKLIST);
+        intent.putExtra(TelecomBroadcastIntentProcessor.EXTRA_NUMBER, number);
+        intent.putExtra(TelecomBroadcastIntentProcessor.EXTRA_FROM_NOTIFICATION, true);
+        intent.putExtra(TelecomBroadcastIntentProcessor.EXTRA_TYPE, type);
+        return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+    }
+
+}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 7f3b359..82a20b6 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -41,8 +41,11 @@
 import android.text.TextUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.CallStateException;
+import com.android.internal.telephony.CallerInfo;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.telephony.util.BlacklistUtils;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.util.Collection;
@@ -138,6 +141,7 @@
     private final CallerInfoAsyncQueryFactory mCallerInfoAsyncQueryFactory;
     private final PhoneAccountRegistrar mPhoneAccountRegistrar;
     private final MissedCallNotifier mMissedCallNotifier;
+    private final BlacklistCallNotifier mBlacklistCallNotifier;
     private final Set<Call> mLocallyDisconnectingCalls = new HashSet<>();
     private final Set<Call> mPendingCallsToDisconnect = new HashSet<>();
     /* Handler tied to thread in which CallManager was initialized. */
@@ -180,13 +184,15 @@
             PhoneAccountRegistrar phoneAccountRegistrar,
             HeadsetMediaButtonFactory headsetMediaButtonFactory,
             ProximitySensorManagerFactory proximitySensorManagerFactory,
-            InCallWakeLockControllerFactory inCallWakeLockControllerFactory) {
+            InCallWakeLockControllerFactory inCallWakeLockControllerFactory,
+            BlacklistCallNotifier blacklistCallNotifier) {
         mContext = context;
         mLock = lock;
         mContactsAsyncHelper = contactsAsyncHelper;
         mCallerInfoAsyncQueryFactory = callerInfoAsyncQueryFactory;
         mPhoneAccountRegistrar = phoneAccountRegistrar;
         mMissedCallNotifier = missedCallNotifier;
+        mBlacklistCallNotifier = blacklistCallNotifier;
         StatusBarNotifier statusBarNotifier = new StatusBarNotifier(context, this);
         mWiredHeadsetManager = new WiredHeadsetManager(context);
         mDockManager = new DockManager(context);
@@ -264,21 +270,27 @@
     @Override
     public void onSuccessfulIncomingCall(Call incomingCall) {
         Log.d(this, "onSuccessfulIncomingCall");
-        setCallState(incomingCall, CallState.RINGING, "successful incoming call");
 
-        if (hasMaximumRingingCalls(incomingCall.getTargetPhoneAccount().getId())) {
-            incomingCall.reject(false, null);
-            // since the call was not added to the list of calls, we have to call the missed
-            // call notifier and the call logger manually.
-            mMissedCallNotifier.showMissedCallNotification(incomingCall);
-            mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE);
+        if (isCallBlacklisted(incomingCall)) {
+            mCallLogManager.logCall(incomingCall, Calls.BLACKLIST_TYPE);
+            incomingCall.setDisconnectCause(
+                    new DisconnectCause(android.telephony.DisconnectCause.CALL_BLACKLISTED));
         } else {
-            if (TelephonyManager.getDefault().getMultiSimConfiguration()
-                == TelephonyManager.MultiSimVariants.DSDA) {
-                incomingCall.mIsActiveSub = true;
+            setCallState(incomingCall, CallState.RINGING, "ringing set explicitly");
+            if (hasMaximumRingingCalls(incomingCall.getTargetPhoneAccount().getId())) {
+                incomingCall.reject(false, null);
+                // since the call was not added to the list of calls, we have to call the missed
+                // call notifier and the call logger manually.
+                mMissedCallNotifier.showMissedCallNotification(incomingCall);
+                mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE);
+            } else {
+                if (TelephonyManager.getDefault().getMultiSimConfiguration()
+                    == TelephonyManager.MultiSimVariants.DSDA) {
+                    incomingCall.mIsActiveSub = true;
+                }
+                addCall(incomingCall);
+                setActiveSubscription(incomingCall.getTargetPhoneAccount().getId());
             }
-            addCall(incomingCall);
-            setActiveSubscription(incomingCall.getTargetPhoneAccount().getId());
         }
     }
 
@@ -1448,6 +1460,14 @@
     }
 
     /**
+     * Retrieves the {@link MissedCallNotifier}
+     * @return The {@link MissedCallNotifier}.
+     */
+    BlacklistCallNotifier getBlacklistCallNotifier() {
+        return mBlacklistCallNotifier;
+    }
+
+    /**
      * Adds the specified call to the main list of live calls.
      *
      * @param call The call to add.
@@ -2307,4 +2327,19 @@
             }
         }
     }
+
+    protected boolean isCallBlacklisted(Call c) {
+        final String number = c.getCallerInfo().phoneNumber;
+        // See if the number is in the blacklist
+        // Result is one of: MATCH_NONE, MATCH_LIST or MATCH_REGEX
+        int listType = BlacklistUtils.isListed(mContext, number, BlacklistUtils.BLOCK_CALLS);
+        if (listType != BlacklistUtils.MATCH_NONE) {
+            // We have a match, set the user and hang up the call and notify
+            Log.d(this, "Incoming call from " + number + " blocked.");
+            mBlacklistCallNotifier.notifyBlacklistedCall(number,
+                    c.getCreationTimeMillis(), listType);
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
index 89aa2aa..a6a5796 100644
--- a/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
+++ b/src/com/android/server/telecom/TelecomBroadcastIntentProcessor.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.UserHandle;
+import com.android.internal.telephony.util.BlacklistUtils;
 
 public final class TelecomBroadcastIntentProcessor {
     /** The action used to send SMS response for the missed call notification. */
@@ -41,6 +42,22 @@
         mCallsManager = callsManager;
     }
 
+    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";
+
+    public static final String ACTION_REJECTED_SMS =
+            "android.provider.Telephony.SMS_REJECTED";
+
+    // For adding to Blacklist from call log
+    static final String REMOVE_BLACKLIST = "com.android.phone.REMOVE_BLACKLIST";
+    static final String EXTRA_NUMBER = "number";
+    static final String EXTRA_TYPE = "type";
+    static final String EXTRA_FROM_NOTIFICATION = "fromNotification";
+
+
     public void processIntent(Intent intent) {
         String action = intent.getAction();
 
@@ -72,6 +89,32 @@
         // Clear the missed call notification and call log entries.
         } else if (ACTION_CLEAR_MISSED_CALLS.equals(action)) {
             missedCallNotifier.clearMissedCalls();
+        }  else if (ACTION_CLEAR_BLACKLISTED_CALLS.equals(action)) {
+            BlacklistCallNotifier bcn = mCallsManager.getBlacklistCallNotifier();
+            bcn.cancelBlacklistedNotification(BlacklistUtils.BLOCK_CALLS);
+        } else if (ACTION_CLEAR_BLACKLISTED_MESSAGES.equals(action)) {
+            BlacklistCallNotifier bcn = mCallsManager.getBlacklistCallNotifier();
+            bcn.cancelBlacklistedNotification(BlacklistUtils.BLOCK_MESSAGES);
+        } else if (intent.getAction().equals(REMOVE_BLACKLIST)) {
+            if (intent.getBooleanExtra(EXTRA_FROM_NOTIFICATION, false)) {
+                // Dismiss the notification that brought us here
+                int blacklistType = intent.getIntExtra(EXTRA_TYPE, 0);
+                BlacklistCallNotifier bcn = mCallsManager.getBlacklistCallNotifier();
+                bcn.cancelBlacklistedNotification(blacklistType);
+                BlacklistUtils.addOrUpdate(mContext, intent.getStringExtra(EXTRA_NUMBER),
+                        0, blacklistType);
+            }
+        } else if (ACTION_REJECTED_SMS.equals(action)) {
+            if (!intent.getBooleanExtra("blacklisted", false)) {
+                return;
+            }
+
+            String sender = intent.getStringExtra("sender");
+            long timestamp = intent.getLongExtra("timestamp", 0);
+            int matchType = intent.getIntExtra("blacklistMatchType", -1);
+
+            BlacklistCallNotifier bcn = mCallsManager.getBlacklistCallNotifier();
+            bcn.notifyBlacklistedMessage(sender, timestamp, matchType);
         }
     }
 
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index c3ab0dc..cddf784 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -68,6 +68,12 @@
     private final TelecomServiceImpl mTelecomServiceImpl;
     private final ContactsAsyncHelper mContactsAsyncHelper;
 
+    /**
+     * Blacklist call notifier. Exists here so that the instance can be shared with
+     * {@link TelecomBroadcastReceiver}.
+     */
+    private BlacklistCallNotifier mBlacklistCallNotifier;
+
     private final BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -101,6 +107,7 @@
         mMissedCallNotifier = missedCallNotifier;
         mPhoneAccountRegistrar = new PhoneAccountRegistrar(mContext);
         mContactsAsyncHelper = new ContactsAsyncHelper(mLock);
+        mBlacklistCallNotifier = new BlacklistCallNotifier(mContext);
 
         mCallsManager = new CallsManager(
                 mContext,
@@ -111,7 +118,8 @@
                 mPhoneAccountRegistrar,
                 headsetMediaButtonFactory,
                 proximitySensorManagerFactory,
-                inCallWakeLockControllerFactory);
+                inCallWakeLockControllerFactory,
+                mBlacklistCallNotifier);
 
         mRespondViaSmsManager = new RespondViaSmsManager(mCallsManager, mLock);
         mCallsManager.setRespondViaSmsManager(mRespondViaSmsManager);