Add UI to manage blocked numbers.

TESTING/Functionality=
 - Adding empty not allowed.
 - Rotation: dialogs/general UI.
 - Adding same number ignored.
 - Non-primary users not allowed to manage blocked numbers.
 - Material ripple for delete button.
 - Action bar back button exit activity.
 - Prevent EditText from stealing focus so talk-back starts
   from the beginning.
 - Talk back allow user to read row by row in list view.

There are two things left that I will do in a follow-up:
 - Alert Dialog Theme.
 - Add some validation for the user input

Screenshots: https://drive.google.com/a/google.com/folderview?id=0ByV4lfyID02GTGV1QWRTOGlKWTQ&usp=sharing
Bug: 26917087
Change-Id: If390d863f40162e12b0bd5d06b8bfccaa7fad5b2
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 6fb5b20..86f6cdc 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -85,6 +85,13 @@
              3) CALL_EMERGENCY - Expected from the emergency dialer app and requires CALL_PRIVILEGED
              permission. Through this intent, an app can call *only* emergency numbers. -->
 
+        <!-- Activity that displays UI for managing blocked numbers. -->
+        <activity android:name=".settings.BlockedNumbersActivity"
+                  android:label="@string/blocked_numbers"
+                  android:configChanges="orientation|screenSize|keyboardHidden"
+                  android:theme="@style/Theme.Telecom.BlockedNumbers"
+                  android:process=":ui"
+                  android:exported="false" />
         <!-- Activity that starts the outgoing call process by listening to CALL intent which
              contain contact information in the intent's data. CallActivity handles any data
              URL with the schemes "tel", "sip", and "voicemail". It also handles URLs linked to
diff --git a/res/drawable-hdpi/ic_close_grey_24dp.png b/res/drawable-hdpi/ic_close_grey_24dp.png
new file mode 100644
index 0000000..9efc2b6
--- /dev/null
+++ b/res/drawable-hdpi/ic_close_grey_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_close_grey_24dp.png b/res/drawable-mdpi/ic_close_grey_24dp.png
new file mode 100644
index 0000000..6fef704
--- /dev/null
+++ b/res/drawable-mdpi/ic_close_grey_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_close_grey_24dp.png b/res/drawable-xhdpi/ic_close_grey_24dp.png
new file mode 100644
index 0000000..cb03036
--- /dev/null
+++ b/res/drawable-xhdpi/ic_close_grey_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_close_grey_24dp.png b/res/drawable-xxhdpi/ic_close_grey_24dp.png
new file mode 100644
index 0000000..8912da1
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_close_grey_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_close_grey_24dp.png b/res/drawable-xxxhdpi/ic_close_grey_24dp.png
new file mode 100644
index 0000000..0a48d99
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_close_grey_24dp.png
Binary files differ
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index f7ad003..f2b1f5f 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -20,4 +20,11 @@
     <dimen name="notification_icon_size">64dp</dimen>
 
     <dimen name="dialer_settings_actionbar_elevation">2dp</dimen>
+
+    <dimen name="blocked_numbers_large_padding">16dp</dimen>
+    <dimen name="blocked_numbers_extra_large_padding">32dp</dimen>
+    <dimen name="blocked_numbers_delete_icon_size">24dp</dimen>
+    <dimen name="blocked_numbers_progress_bar_padding">100dp</dimen>
+    <dimen name="blocked_numbers_font_size">16sp</dimen>
+    <dimen name="blocked_numbers_line_spacing">8sp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 16b1752..42fb5b4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -116,6 +116,28 @@
     <string name="change_default_dialer_no_previous_app_set_text">Use <xliff:g id="new_app">%s</xliff:g> as your default dialer app?</string>
 
 
+    <!-- Blocked numbers -->
+    <string name="blocked_numbers">Blocked numbers</string>
+    <!-- Text shown at the beginning of the blocked numbers screen to explain what the screen is about. -->
+    <string name="blocked_numbers_msg">Calls and texts from numbers on this list are blocked.</string>
+    <!-- Button to add a blocked number. -->
+    <string name="block_number">Add a number</string>
+    <!-- Body of dialog to confirm unblocking a number. -->
+    <string name="unblock_dialog_body">Unblock <xliff:g id="number_to_block">%1$s</xliff:g>?</string>
+    <!-- Button to unblock a number. -->
+    <string name="unblock_button">Unblock</string>
+    <!-- Body of dialog to block a number.  -->
+    <string name="add_blocked_dialog_body">Block calls and texts from</string>
+    <!-- Hint shown in the edit text box for adding a blocked number -->
+    <string name="add_blocked_number_hint">Number or email</string>
+    <!-- Button to block a number. -->
+    <string name="block_button">Block</string>
+    <!-- String shown to users unable to manage blocked numbers because they are not owners of the
+        device. -->
+    <string name="non_primary_user">Only the device owner can view and manage blocked numbers.</string>
+    <!-- Description of icon to delete blocked number. -->
+    <string name="delete_icon_description">Tab to unblock</string>
+
     <!-- DO NOT TRANSLATE. Label for test Subscription 0. -->
     <string name="test_account_0_label">Q Mobile</string>
     <!-- DO NOT TRANSLATE. Label for test Subscription 1. -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index d846cda..a7eb2fd 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -33,6 +33,13 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
+    <style name="Theme.Telecom.BlockedNumbers" parent="@android:style/Theme.Material.Light">
+        <item name="android:actionBarStyle">@style/TelecomDialerSettingsActionBarStyle</item>
+        <item name="android:colorPrimaryDark">@color/dialer_settings_color_dark</item>
+        <item name="android:homeAsUpIndicator">@drawable/ic_back_arrow</item>
+        <item name="android:windowContentOverlay">@null</item>
+    </style>
+
     <style name="TelecomDialerSettingsActionBarStyle" parent="android:Widget.Material.ActionBar">
         <item name="android:background">@color/dialer_settings_actionbar_background_color</item>
         <item name="android:titleTextStyle">@style/TelecomDialerSettingsActionBarTitleText</item>
@@ -50,4 +57,15 @@
             parent="@android:style/Widget.Material.Light.ActionButton.Overflow">
         <item name="android:src">@drawable/ic_more_vert_24dp</item>
     </style>
+
+    <style name="BlockedNumbersAddButton">
+        <item name="android:textColor">@color/theme_color</item>
+        <item name="android:textSize">@dimen/blocked_numbers_font_size</item>
+        <item name="android:textAllCaps">true</item>
+    </style>
+
+    <style name="BlockedNumbersText">
+        <item name="android:textSize">@dimen/blocked_numbers_font_size</item>
+        <item name="android:lineSpacingExtra">@dimen/blocked_numbers_line_spacing</item>
+    </style>
 </resources>
diff --git a/res/xml/activity_blocked_numbers.xml b/res/xml/activity_blocked_numbers.xml
new file mode 100644
index 0000000..a79078b
--- /dev/null
+++ b/res/xml/activity_blocked_numbers.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<FrameLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingLeft="@dimen/blocked_numbers_large_padding"
+        android:paddingRight="@dimen/blocked_numbers_large_padding">
+
+    <TextView
+            android:id="@+id/non_primary_user"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/non_primary_user"
+            android:paddingTop="@dimen/blocked_numbers_large_padding"
+            style="@style/BlockedNumbersText"
+            android:visibility="gone" />
+
+    <LinearLayout
+            android:id="@+id/manage_blocked_ui"
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="@dimen/blocked_numbers_large_padding">
+
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/blocked_numbers_msg"
+                android:paddingBottom="@dimen/blocked_numbers_extra_large_padding"
+                style="@style/BlockedNumbersText" />
+
+        <TextView
+                android:id="@+id/add_blocked"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/block_number"
+                android:paddingBottom="@dimen/blocked_numbers_extra_large_padding"
+                style="@style/BlockedNumbersAddButton" />
+
+        <ProgressBar
+                android:id="@+id/progress_bar"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:indeterminate="true"
+                android:layout_marginTop="@dimen/blocked_numbers_progress_bar_padding"
+                style="@android:style/Widget.ProgressBar.Large" />
+
+        <ListView
+                android:id="@android:id/list"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+    </LinearLayout>
+</FrameLayout>
diff --git a/res/xml/add_blocked_number_dialog.xml b/res/xml/add_blocked_number_dialog.xml
new file mode 100644
index 0000000..b71f78f
--- /dev/null
+++ b/res/xml/add_blocked_number_dialog.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:paddingLeft="@dimen/blocked_numbers_extra_large_padding"
+        android:paddingRight="@dimen/blocked_numbers_extra_large_padding"
+        android:focusable="true"
+        android:focusableInTouchMode="true">
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/add_blocked_dialog_body"
+            android:paddingTop="@dimen/blocked_numbers_large_padding"
+            android:paddingBottom="@dimen/blocked_numbers_large_padding"
+            style="@style/BlockedNumbersText" />
+    <EditText
+            android:id="@+id/add_blocked_number"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="@dimen/blocked_numbers_large_padding"
+            android:paddingBottom="@dimen/blocked_numbers_large_padding"
+            android:hint="@string/add_blocked_number_hint"
+            android:inputType="text" />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/xml/layout_blocked_number.xml b/res/xml/layout_blocked_number.xml
new file mode 100644
index 0000000..e6475a4
--- /dev/null
+++ b/res/xml/layout_blocked_number.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:focusable="true"
+    style="@style/BlockedNumbersText" >
+
+    <TextView
+        android:id="@+id/blocked_number"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:paddingBottom="@dimen/blocked_numbers_extra_large_padding"
+        android:layout_toLeftOf="@+id/delete" />
+
+    <ImageButton
+        android:id="@+id/delete_blocked_number"
+        android:layout_width="@dimen/blocked_numbers_delete_icon_size"
+        android:layout_height="@dimen/blocked_numbers_delete_icon_size"
+        android:src="@drawable/ic_close_grey_24dp"
+        android:layout_alignParentRight="true"
+        android:contentDescription="@string/delete_icon_description"
+        android:background="?android:attr/selectableItemBackgroundBorderless" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index a269085..cfe6ebc 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -51,6 +51,7 @@
 import com.android.internal.telecom.ITelecomService;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.telecom.components.UserCallIntentProcessorFactory;
+import com.android.server.telecom.settings.BlockedNumbersActivity;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -1176,10 +1177,12 @@
             Log.dumpCallEvents(pw);
         }
 
-        // TODO: Add javadoc which points to TelecomManager
+        /**
+         * @see android.telecom.TelecomManager#launchManageBlockedNumbersActivity
+         */
         @Override
         public void launchManageBlockedNumbersActivity(String callingPackageName) {
-            // TODO: Add implementation
+            BlockedNumbersActivity.start(mContext);
         }
     };
 
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersActivity.java b/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
new file mode 100644
index 0000000..a347590
--- /dev/null
+++ b/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom.settings;
+
+import android.annotation.Nullable;
+import android.app.ActionBar;
+import android.app.AlertDialog;
+import android.app.ListActivity;
+import android.app.LoaderManager;
+import android.content.*;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserManager;
+import android.provider.BlockedNumberContract;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.*;
+import com.android.server.telecom.R;
+
+/**
+ * Activity to manage blocked numbers using {@link BlockedNumberContract}.
+ */
+public class BlockedNumbersActivity extends ListActivity
+        implements LoaderManager.LoaderCallbacks<Cursor>, View.OnClickListener, TextWatcher {
+    private static final String[] PROJECTION = new String[] {
+            BlockedNumberContract.BlockedNumbers.COLUMN_ID,
+            BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER
+    };
+
+    private static final String SELECTION = "((" +
+            BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER + " NOTNULL) AND (" +
+            BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER + " != '' ))";
+
+    private BlockedNumbersAdapter mAdapter;
+    private TextView mAddButton;
+    private ProgressBar mProgressBar;
+    @Nullable private Button mBlockButton;
+
+    public static void start(Context context) {
+        Intent intent = new Intent(context, BlockedNumbersActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.xml.activity_blocked_numbers);
+
+        ActionBar actionBar = getActionBar();
+        if (actionBar != null) {
+            actionBar.setDisplayHomeAsUpEnabled(true);
+        }
+
+        UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
+        if (userManager.isPrimaryUser()) {
+            TextView nonPrimaryUserText = (TextView) findViewById(R.id.non_primary_user);
+            nonPrimaryUserText.setVisibility(View.VISIBLE);
+
+            LinearLayout manageBlockedNumbersUi =
+                    (LinearLayout) findViewById(R.id.manage_blocked_ui);
+            manageBlockedNumbersUi.setVisibility(View.GONE);
+            return;
+        }
+        mAddButton = (TextView) findViewById(R.id.add_blocked);
+        mAddButton.setOnClickListener(this);
+
+        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
+
+        String[] fromColumns = {BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER};
+        int[] toViews = {R.id.blocked_number};
+        mAdapter = new BlockedNumbersAdapter(this, R.xml.layout_blocked_number, null, fromColumns,
+                toViews, 0);
+
+        ListView listView = getListView();
+        listView.setAdapter(mAdapter);
+        listView.setDivider(null);
+        listView.setDividerHeight(0);
+
+        getLoaderManager().initLoader(0, null, this);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                this.finish();
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
+    }
+
+    @Override
+    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+        return new CursorLoader(this, BlockedNumberContract.BlockedNumbers.CONTENT_URI,
+                PROJECTION, SELECTION, null, null);
+    }
+
+    @Override
+    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+        mAdapter.swapCursor(data);
+        mProgressBar.setVisibility(View.GONE);
+    }
+
+    @Override
+    public void onLoaderReset(Loader<Cursor> loader) {
+        mAdapter.swapCursor(null);
+        mProgressBar.setVisibility(View.VISIBLE);
+    }
+
+    @Override
+    public void onClick(View view) {
+        if (view == mAddButton) {
+            showAddBlockedNumberDialog();
+        }
+    }
+
+    private void showAddBlockedNumberDialog() {
+        LayoutInflater inflater = this.getLayoutInflater();
+        View dialogView = inflater.inflate(R.xml.add_blocked_number_dialog, null);
+        final EditText editText = (EditText) dialogView.findViewById(R.id.add_blocked_number);
+        editText.addTextChangedListener(this);
+        AlertDialog dialog = new AlertDialog.Builder(this)
+                .setView(dialogView)
+                .setPositiveButton(R.string.block_button, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int id) {
+                        addBlockedNumber(editText.getText().toString());
+                    }
+                })
+                .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int id) {
+                        dialog.dismiss();
+                    }
+                })
+                .create();
+        dialog.setOnShowListener(new AlertDialog.OnShowListener() {
+                    @Override
+                    public void onShow(DialogInterface dialog) {
+                        mBlockButton = ((AlertDialog) dialog)
+                                .getButton(AlertDialog.BUTTON_POSITIVE);
+                        mBlockButton.setEnabled(false);
+                    }
+                });
+        dialog.show();
+    }
+
+    /**
+     * Add blocked number if it does not exist.
+     */
+    private void addBlockedNumber(String number) {
+        ContentResolver contentResolver = getContentResolver();
+        Cursor cursor = contentResolver.query(
+                BlockedNumberContract.BlockedNumbers.CONTENT_URI,
+                PROJECTION,
+                BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER + "=?",
+                new String[] {number},
+                null);
+        if (cursor == null || cursor.getCount() == 0) {
+            ContentValues newValues = new ContentValues();
+            newValues.put(BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER, number);
+            contentResolver.insert(BlockedNumberContract.BlockedNumbers.CONTENT_URI, newValues);
+        }
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+        // no-op
+    }
+
+    @Override
+    public void onTextChanged(CharSequence text, int start, int before, int count) {
+        if (mBlockButton != null) {
+            mBlockButton.setEnabled(!TextUtils.isEmpty(text.toString().trim()));
+        }
+    }
+
+    @Override
+    public void afterTextChanged(Editable s) {
+        // no-op
+    }
+}
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java b/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
new file mode 100644
index 0000000..3d56459
--- /dev/null
+++ b/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom.settings;
+
+import android.app.AlertDialog;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.database.Cursor;
+import android.provider.BlockedNumberContract;
+import android.telephony.PhoneNumberUtils;
+import android.view.View;
+import android.widget.SimpleCursorAdapter;
+import android.widget.TextView;
+import com.android.server.telecom.R;
+
+import java.util.Locale;
+
+public class BlockedNumbersAdapter extends SimpleCursorAdapter {
+    public BlockedNumbersAdapter(Context context, int layout, Cursor c, String[] from, int[] to,
+            int flags) {
+        super(context, layout, c, from, to, flags);
+    }
+
+    @Override
+    public void bindView(View view, final Context context, final Cursor cursor) {
+        super.bindView(view, context, cursor);
+        final String rawNumber = cursor.getString(cursor.getColumnIndex(
+                BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER));
+        String formattedNumber = PhoneNumberUtils.formatNumber(rawNumber,
+                getLocaleDefaultToUS());
+        final String finalFormattedNumber = formattedNumber == null ? rawNumber : formattedNumber;
+
+        TextView numberView = (TextView) view.findViewById(R.id.blocked_number);
+        numberView.setText(finalFormattedNumber);
+
+        View deleteButton = view.findViewById(R.id.delete_blocked_number);
+        deleteButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+               showDeleteBlockedNumberDialog(context, rawNumber, finalFormattedNumber);
+            }
+        });
+    }
+
+    private String getLocaleDefaultToUS() {
+        String countryIso = Locale.getDefault().getCountry();
+        if (countryIso == null || countryIso.length() != 2) {
+            countryIso = "US";
+        }
+        return countryIso;
+    }
+
+    private void showDeleteBlockedNumberDialog(final Context context, final String rawNumber,
+            final String formattedNumber) {
+        new AlertDialog.Builder(context)
+                .setMessage(context.getString(R.string.unblock_dialog_body, formattedNumber))
+                .setPositiveButton(R.string.unblock_button,
+                        new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int id) {
+                                deleteBlockedNumber(context, rawNumber);
+                            }
+                        }
+                )
+                .setNegativeButton(android.R.string.cancel,
+                        new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int id) {
+                                dialog.dismiss();
+                            }
+                        }
+                )
+                .create()
+                .show();
+    }
+
+    private void deleteBlockedNumber(Context context, String number) {
+        ContentResolver contentResolver = context.getContentResolver();
+        contentResolver.delete(BlockedNumberContract.BlockedNumbers.CONTENT_URI,
+                BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER + "=?",
+                new String[] {number});
+    }
+}