summaryrefslogtreecommitdiff
path: root/java/com/android/dialer
diff options
context:
space:
mode:
authorcalderwoodra <calderwoodra@google.com>2017-09-05 18:49:07 -0700
committerEric Erfanian <erfanian@google.com>2017-09-11 10:59:49 -0700
commit21e24b6d9355e5e64a594b3b32cb4c8301e3330b (patch)
treef0b6004c5f2d035f0f4c177455bea79c5047d1a4 /java/com/android/dialer
parented4e11ddafece1d308b87955880f4f153dbfc8e2 (diff)
Automated g4 rollback of changelist 167310802.
*** Reason for rollback *** Turns out blocked number activity is actually used for devices on M. *** Original change description *** Removes the unused dialer/app/filterednumber package. *** Test: n/a PiperOrigin-RevId: 167663280 Change-Id: I6af1fc7d6eb61f946d4fba255fe7374bcdee0e72
Diffstat (limited to 'java/com/android/dialer')
-rw-r--r--java/com/android/dialer/app/AndroidManifest.xml12
-rw-r--r--java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java96
-rw-r--r--java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java272
-rw-r--r--java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java142
-rw-r--r--java/com/android/dialer/app/filterednumber/NumbersAdapter.java140
-rw-r--r--java/com/android/dialer/app/filterednumber/ViewNumbersToImportAdapter.java57
-rw-r--r--java/com/android/dialer/app/filterednumber/ViewNumbersToImportFragment.java131
-rw-r--r--java/com/android/dialer/app/list/BlockedListSearchFragment.java248
8 files changed, 1098 insertions, 0 deletions
diff --git a/java/com/android/dialer/app/AndroidManifest.xml b/java/com/android/dialer/app/AndroidManifest.xml
index 1c04b764c..4200082a6 100644
--- a/java/com/android/dialer/app/AndroidManifest.xml
+++ b/java/com/android/dialer/app/AndroidManifest.xml
@@ -61,6 +61,18 @@
<application android:theme="@style/Theme.AppCompat">
<activity
+ android:exported="false"
+ android:label="@string/manage_blocked_numbers_label"
+ android:name="com.android.dialer.app.filterednumber.BlockedNumbersSettingsActivity"
+ android:parentActivityName="com.android.dialer.app.settings.DialerSettingsActivity"
+ android:theme="@style/ManageBlockedNumbersStyle">
+ <intent-filter>
+ <action android:name="com.android.dialer.action.BLOCKED_NUMBERS_SETTINGS"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+
+ <activity
android:label="@string/call_log_activity_title"
android:name="com.android.dialer.app.calllog.CallLogActivity"
android:theme="@style/DialtactsThemeWithoutActionBarOverlay">
diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java
new file mode 100644
index 000000000..4f8bc66a9
--- /dev/null
+++ b/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2015 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.dialer.app.filterednumber;
+
+import android.app.FragmentManager;
+import android.content.Context;
+import android.database.Cursor;
+import android.telephony.PhoneNumberUtils;
+import android.view.View;
+import com.android.dialer.app.R;
+import com.android.dialer.blocking.BlockNumberDialogFragment;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.database.FilteredNumberContract.FilteredNumberColumns;
+import com.android.dialer.location.GeoUtil;
+import com.android.dialer.logging.InteractionEvent;
+import com.android.dialer.logging.Logger;
+import com.android.dialer.phonenumbercache.ContactInfoHelper;
+
+/** TODO(calderwoodra): documentation */
+public class BlockedNumbersAdapter extends NumbersAdapter {
+
+ private BlockedNumbersAdapter(
+ Context context,
+ FragmentManager fragmentManager,
+ ContactInfoHelper contactInfoHelper,
+ ContactPhotoManager contactPhotoManager) {
+ super(context, fragmentManager, contactInfoHelper, contactPhotoManager);
+ }
+
+ public static BlockedNumbersAdapter newBlockedNumbersAdapter(
+ Context context, FragmentManager fragmentManager) {
+ return new BlockedNumbersAdapter(
+ context,
+ fragmentManager,
+ new ContactInfoHelper(context, GeoUtil.getCurrentCountryIso(context)),
+ ContactPhotoManager.getInstance(context));
+ }
+
+ @Override
+ public void bindView(View view, final Context context, Cursor cursor) {
+ super.bindView(view, context, cursor);
+ final Integer id = cursor.getInt(cursor.getColumnIndex(FilteredNumberColumns._ID));
+ final String countryIso =
+ cursor.getString(cursor.getColumnIndex(FilteredNumberColumns.COUNTRY_ISO));
+ final String number = cursor.getString(cursor.getColumnIndex(FilteredNumberColumns.NUMBER));
+
+ final View deleteButton = view.findViewById(R.id.delete_button);
+ deleteButton.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ BlockNumberDialogFragment.show(
+ id,
+ number,
+ countryIso,
+ PhoneNumberUtils.formatNumber(number, countryIso),
+ R.id.blocked_numbers_activity_container,
+ getFragmentManager(),
+ new BlockNumberDialogFragment.Callback() {
+ @Override
+ public void onFilterNumberSuccess() {}
+
+ @Override
+ public void onUnfilterNumberSuccess() {
+ Logger.get(context)
+ .logInteraction(InteractionEvent.Type.UNBLOCK_NUMBER_MANAGEMENT_SCREEN);
+ }
+
+ @Override
+ public void onChangeFilteredNumberUndo() {}
+ });
+ }
+ });
+
+ updateView(view, number, countryIso);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ // Always return false, so that the header with blocking-related options always shows.
+ return false;
+ }
+}
diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java
new file mode 100644
index 000000000..36afe5429
--- /dev/null
+++ b/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2015 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.dialer.app.filterednumber;
+
+import android.app.ListFragment;
+import android.app.LoaderManager;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Loader;
+import android.database.Cursor;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.support.v4.app.ActivityCompat;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.android.dialer.app.R;
+import com.android.dialer.blocking.BlockedNumbersMigrator;
+import com.android.dialer.blocking.BlockedNumbersMigrator.Listener;
+import com.android.dialer.blocking.FilteredNumberCompat;
+import com.android.dialer.blocking.FilteredNumbersUtil;
+import com.android.dialer.blocking.FilteredNumbersUtil.CheckForSendToVoicemailContactListener;
+import com.android.dialer.blocking.FilteredNumbersUtil.ImportSendToVoicemailContactsListener;
+import com.android.dialer.database.FilteredNumberContract;
+import com.android.dialer.lettertile.LetterTileDrawable;
+import com.android.dialer.voicemailstatus.VisualVoicemailEnabledChecker;
+
+/** TODO(calderwoodra): documentation */
+public class BlockedNumbersFragment extends ListFragment
+ implements LoaderManager.LoaderCallbacks<Cursor>,
+ View.OnClickListener,
+ VisualVoicemailEnabledChecker.Callback {
+
+ private static final char ADD_BLOCKED_NUMBER_ICON_LETTER = '+';
+ protected View migratePromoView;
+ private BlockedNumbersMigrator blockedNumbersMigratorForTest;
+ private TextView blockedNumbersText;
+ private TextView footerText;
+ private BlockedNumbersAdapter mAdapter;
+ private VisualVoicemailEnabledChecker mVoicemailEnabledChecker;
+ private View mImportSettings;
+ private View mBlockedNumbersDisabledForEmergency;
+ private View mBlockedNumberListDivider;
+
+ @Override
+ public Context getContext() {
+ return getActivity();
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ LayoutInflater inflater =
+ (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ getListView().addHeaderView(inflater.inflate(R.layout.blocked_number_header, null));
+ getListView().addFooterView(inflater.inflate(R.layout.blocked_number_footer, null));
+ //replace the icon for add number with LetterTileDrawable(), so it will have identical style
+ ImageView addNumberIcon = (ImageView) getActivity().findViewById(R.id.add_number_icon);
+ LetterTileDrawable drawable = new LetterTileDrawable(getResources());
+ drawable.setLetter(ADD_BLOCKED_NUMBER_ICON_LETTER);
+ drawable.setColor(
+ ActivityCompat.getColor(getActivity(), R.color.add_blocked_number_icon_color));
+ drawable.setIsCircular(true);
+ addNumberIcon.setImageDrawable(drawable);
+
+ if (mAdapter == null) {
+ mAdapter =
+ BlockedNumbersAdapter.newBlockedNumbersAdapter(
+ getContext(), getActivity().getFragmentManager());
+ }
+ setListAdapter(mAdapter);
+
+ blockedNumbersText = (TextView) getListView().findViewById(R.id.blocked_number_text_view);
+ migratePromoView = getListView().findViewById(R.id.migrate_promo);
+ getListView().findViewById(R.id.migrate_promo_allow_button).setOnClickListener(this);
+ mImportSettings = getListView().findViewById(R.id.import_settings);
+ mBlockedNumbersDisabledForEmergency =
+ getListView().findViewById(R.id.blocked_numbers_disabled_for_emergency);
+ mBlockedNumberListDivider = getActivity().findViewById(R.id.blocked_number_list_divider);
+ getListView().findViewById(R.id.import_button).setOnClickListener(this);
+ getListView().findViewById(R.id.view_numbers_button).setOnClickListener(this);
+ getListView().findViewById(R.id.add_number_linear_layout).setOnClickListener(this);
+
+ footerText = (TextView) getActivity().findViewById(R.id.blocked_number_footer_textview);
+ mVoicemailEnabledChecker = new VisualVoicemailEnabledChecker(getContext(), this);
+ mVoicemailEnabledChecker.asyncUpdate();
+ updateActiveVoicemailProvider();
+ }
+
+ @Override
+ public void onDestroy() {
+ setListAdapter(null);
+ super.onDestroy();
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getLoaderManager().initLoader(0, null, this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+ ColorDrawable backgroundDrawable =
+ new ColorDrawable(ActivityCompat.getColor(getActivity(), R.color.dialer_theme_color));
+ actionBar.setBackgroundDrawable(backgroundDrawable);
+ actionBar.setDisplayShowCustomEnabled(false);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowHomeEnabled(true);
+ actionBar.setDisplayShowTitleEnabled(true);
+ actionBar.setTitle(R.string.manage_blocked_numbers_label);
+
+ // If the device can use the framework blocking solution, users should not be able to add
+ // new blocked numbers from the Blocked Management UI. They will be shown a promo card
+ // asking them to migrate to new blocking instead.
+ if (FilteredNumberCompat.canUseNewFiltering()) {
+ migratePromoView.setVisibility(View.VISIBLE);
+ blockedNumbersText.setVisibility(View.GONE);
+ getListView().findViewById(R.id.add_number_linear_layout).setVisibility(View.GONE);
+ getListView().findViewById(R.id.add_number_linear_layout).setOnClickListener(null);
+ mBlockedNumberListDivider.setVisibility(View.GONE);
+ mImportSettings.setVisibility(View.GONE);
+ getListView().findViewById(R.id.import_button).setOnClickListener(null);
+ getListView().findViewById(R.id.view_numbers_button).setOnClickListener(null);
+ mBlockedNumbersDisabledForEmergency.setVisibility(View.GONE);
+ footerText.setVisibility(View.GONE);
+ } else {
+ FilteredNumbersUtil.checkForSendToVoicemailContact(
+ getActivity(),
+ new CheckForSendToVoicemailContactListener() {
+ @Override
+ public void onComplete(boolean hasSendToVoicemailContact) {
+ final int visibility = hasSendToVoicemailContact ? View.VISIBLE : View.GONE;
+ mImportSettings.setVisibility(visibility);
+ }
+ });
+ }
+
+ // All views except migrate and the block list are hidden when new filtering is available
+ if (!FilteredNumberCompat.canUseNewFiltering()
+ && FilteredNumbersUtil.hasRecentEmergencyCall(getContext())) {
+ mBlockedNumbersDisabledForEmergency.setVisibility(View.VISIBLE);
+ } else {
+ mBlockedNumbersDisabledForEmergency.setVisibility(View.GONE);
+ }
+
+ mVoicemailEnabledChecker.asyncUpdate();
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.blocked_number_fragment, container, false);
+ }
+
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ final String[] projection = {
+ FilteredNumberContract.FilteredNumberColumns._ID,
+ FilteredNumberContract.FilteredNumberColumns.COUNTRY_ISO,
+ FilteredNumberContract.FilteredNumberColumns.NUMBER,
+ FilteredNumberContract.FilteredNumberColumns.NORMALIZED_NUMBER
+ };
+ final String selection =
+ FilteredNumberContract.FilteredNumberColumns.TYPE
+ + "="
+ + FilteredNumberContract.FilteredNumberTypes.BLOCKED_NUMBER;
+ return new CursorLoader(
+ getContext(),
+ FilteredNumberContract.FilteredNumber.CONTENT_URI,
+ projection,
+ selection,
+ null,
+ null);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ mAdapter.swapCursor(data);
+ if (FilteredNumberCompat.canUseNewFiltering() || data.getCount() == 0) {
+ mBlockedNumberListDivider.setVisibility(View.INVISIBLE);
+ } else {
+ mBlockedNumberListDivider.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ mAdapter.swapCursor(null);
+ }
+
+ @Override
+ public void onClick(final View view) {
+ final BlockedNumbersSettingsActivity activity = (BlockedNumbersSettingsActivity) getActivity();
+ if (activity == null) {
+ return;
+ }
+
+ int resId = view.getId();
+ if (resId == R.id.add_number_linear_layout) {
+ activity.showSearchUi();
+ } else if (resId == R.id.view_numbers_button) {
+ activity.showNumbersToImportPreviewUi();
+ } else if (resId == R.id.import_button) {
+ FilteredNumbersUtil.importSendToVoicemailContacts(
+ activity,
+ new ImportSendToVoicemailContactsListener() {
+ @Override
+ public void onImportComplete() {
+ mImportSettings.setVisibility(View.GONE);
+ }
+ });
+ } else if (resId == R.id.migrate_promo_allow_button) {
+ view.setEnabled(false);
+ (blockedNumbersMigratorForTest != null
+ ? blockedNumbersMigratorForTest
+ : new BlockedNumbersMigrator(getContext()))
+ .migrate(
+ new Listener() {
+ @Override
+ public void onComplete() {
+ getContext()
+ .startActivity(
+ FilteredNumberCompat.createManageBlockedNumbersIntent(getContext()));
+ // Remove this activity from the backstack
+ activity.finish();
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onVisualVoicemailEnabledStatusChanged(boolean newStatus) {
+ updateActiveVoicemailProvider();
+ }
+
+ private void updateActiveVoicemailProvider() {
+ if (getActivity() == null || getActivity().isFinishing()) {
+ return;
+ }
+ if (mVoicemailEnabledChecker.isVisualVoicemailEnabled()) {
+ footerText.setText(R.string.block_number_footer_message_vvm);
+ } else {
+ footerText.setText(R.string.block_number_footer_message_no_vvm);
+ }
+ }
+
+ void setBlockedNumbersMigratorForTest(BlockedNumbersMigrator blockedNumbersMigrator) {
+ blockedNumbersMigratorForTest = blockedNumbersMigrator;
+ }
+}
diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java
new file mode 100644
index 000000000..858d28355
--- /dev/null
+++ b/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015 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.dialer.app.filterednumber;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.MenuItem;
+import com.android.dialer.app.R;
+import com.android.dialer.app.list.BlockedListSearchFragment;
+import com.android.dialer.app.list.SearchFragment;
+import com.android.dialer.logging.Logger;
+import com.android.dialer.logging.ScreenEvent;
+
+/** TODO(calderwoodra): documentation */
+public class BlockedNumbersSettingsActivity extends AppCompatActivity
+ implements SearchFragment.HostInterface {
+
+ private static final String TAG_BLOCKED_MANAGEMENT_FRAGMENT = "blocked_management";
+ private static final String TAG_BLOCKED_SEARCH_FRAGMENT = "blocked_search";
+ private static final String TAG_VIEW_NUMBERS_TO_IMPORT_FRAGMENT = "view_numbers_to_import";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.blocked_numbers_activity);
+
+ // If savedInstanceState != null, the Activity will automatically restore the last fragment.
+ if (savedInstanceState == null) {
+ showManagementUi();
+ }
+ }
+
+ /** Shows fragment with the list of currently blocked numbers and settings related to blocking. */
+ public void showManagementUi() {
+ BlockedNumbersFragment fragment =
+ (BlockedNumbersFragment)
+ getFragmentManager().findFragmentByTag(TAG_BLOCKED_MANAGEMENT_FRAGMENT);
+ if (fragment == null) {
+ fragment = new BlockedNumbersFragment();
+ }
+
+ getFragmentManager()
+ .beginTransaction()
+ .replace(R.id.blocked_numbers_activity_container, fragment, TAG_BLOCKED_MANAGEMENT_FRAGMENT)
+ .commit();
+
+ Logger.get(this).logScreenView(ScreenEvent.Type.BLOCKED_NUMBER_MANAGEMENT, this);
+ }
+
+ /** Shows fragment with search UI for browsing/finding numbers to block. */
+ public void showSearchUi() {
+ BlockedListSearchFragment fragment =
+ (BlockedListSearchFragment)
+ getFragmentManager().findFragmentByTag(TAG_BLOCKED_SEARCH_FRAGMENT);
+ if (fragment == null) {
+ fragment = new BlockedListSearchFragment();
+ fragment.setHasOptionsMenu(false);
+ fragment.setShowEmptyListForNullQuery(true);
+ fragment.setDirectorySearchEnabled(false);
+ }
+
+ getFragmentManager()
+ .beginTransaction()
+ .replace(R.id.blocked_numbers_activity_container, fragment, TAG_BLOCKED_SEARCH_FRAGMENT)
+ .addToBackStack(null)
+ .commit();
+
+ Logger.get(this).logScreenView(ScreenEvent.Type.BLOCKED_NUMBER_ADD_NUMBER, this);
+ }
+
+ /**
+ * Shows fragment with UI to preview the numbers of contacts currently marked as send-to-voicemail
+ * in Contacts. These numbers can be imported into Dialer's blocked number list.
+ */
+ public void showNumbersToImportPreviewUi() {
+ ViewNumbersToImportFragment fragment =
+ (ViewNumbersToImportFragment)
+ getFragmentManager().findFragmentByTag(TAG_VIEW_NUMBERS_TO_IMPORT_FRAGMENT);
+ if (fragment == null) {
+ fragment = new ViewNumbersToImportFragment();
+ }
+
+ getFragmentManager()
+ .beginTransaction()
+ .replace(
+ R.id.blocked_numbers_activity_container, fragment, TAG_VIEW_NUMBERS_TO_IMPORT_FRAGMENT)
+ .addToBackStack(null)
+ .commit();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onBackPressed() {
+ // TODO: Achieve back navigation without overriding onBackPressed.
+ if (getFragmentManager().getBackStackEntryCount() > 0) {
+ getFragmentManager().popBackStack();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ @Override
+ public boolean isActionBarShowing() {
+ return false;
+ }
+
+ @Override
+ public boolean isDialpadShown() {
+ return false;
+ }
+
+ @Override
+ public int getDialpadHeight() {
+ return 0;
+ }
+
+ @Override
+ public int getActionBarHeight() {
+ return 0;
+ }
+}
diff --git a/java/com/android/dialer/app/filterednumber/NumbersAdapter.java b/java/com/android/dialer/app/filterednumber/NumbersAdapter.java
new file mode 100644
index 000000000..938a78479
--- /dev/null
+++ b/java/com/android/dialer/app/filterednumber/NumbersAdapter.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 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.dialer.app.filterednumber;
+
+import android.app.FragmentManager;
+import android.content.Context;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.text.BidiFormatter;
+import android.text.TextDirectionHeuristics;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.QuickContactBadge;
+import android.widget.SimpleCursorAdapter;
+import android.widget.TextView;
+import com.android.dialer.app.R;
+import com.android.dialer.compat.CompatUtils;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest;
+import com.android.dialer.lettertile.LetterTileDrawable;
+import com.android.dialer.phonenumbercache.ContactInfo;
+import com.android.dialer.phonenumbercache.ContactInfoHelper;
+import com.android.dialer.phonenumberutil.PhoneNumberHelper;
+import com.android.dialer.util.UriUtils;
+
+/** TODO(calderwoodra): documentation */
+public class NumbersAdapter extends SimpleCursorAdapter {
+
+ private final Context mContext;
+ private final FragmentManager mFragmentManager;
+ private final ContactInfoHelper mContactInfoHelper;
+ private final BidiFormatter mBidiFormatter = BidiFormatter.getInstance();
+ private final ContactPhotoManager mContactPhotoManager;
+
+ public NumbersAdapter(
+ Context context,
+ FragmentManager fragmentManager,
+ ContactInfoHelper contactInfoHelper,
+ ContactPhotoManager contactPhotoManager) {
+ super(context, R.layout.blocked_number_item, null, new String[] {}, new int[] {}, 0);
+ mContext = context;
+ mFragmentManager = fragmentManager;
+ mContactInfoHelper = contactInfoHelper;
+ mContactPhotoManager = contactPhotoManager;
+ }
+
+ public void updateView(View view, String number, String countryIso) {
+ final TextView callerName = (TextView) view.findViewById(R.id.caller_name);
+ final TextView callerNumber = (TextView) view.findViewById(R.id.caller_number);
+ final QuickContactBadge quickContactBadge =
+ (QuickContactBadge) view.findViewById(R.id.quick_contact_photo);
+ quickContactBadge.setOverlay(null);
+ if (CompatUtils.hasPrioritizedMimeType()) {
+ quickContactBadge.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);
+ }
+
+ ContactInfo info = mContactInfoHelper.lookupNumber(number, countryIso);
+ if (info == null) {
+ info = new ContactInfo();
+ info.number = number;
+ }
+ final CharSequence locationOrType = getNumberTypeOrLocation(info);
+ final String displayNumber = getDisplayNumber(info);
+ final String displayNumberStr =
+ mBidiFormatter.unicodeWrap(displayNumber, TextDirectionHeuristics.LTR);
+
+ String nameForDefaultImage;
+ if (!TextUtils.isEmpty(info.name)) {
+ nameForDefaultImage = info.name;
+ callerName.setText(info.name);
+ callerNumber.setText(locationOrType + " " + displayNumberStr);
+ } else {
+ nameForDefaultImage = displayNumber;
+ callerName.setText(displayNumberStr);
+ if (!TextUtils.isEmpty(locationOrType)) {
+ callerNumber.setText(locationOrType);
+ callerNumber.setVisibility(View.VISIBLE);
+ } else {
+ callerNumber.setVisibility(View.GONE);
+ }
+ }
+ loadContactPhoto(info, nameForDefaultImage, quickContactBadge);
+ }
+
+ private void loadContactPhoto(ContactInfo info, String displayName, QuickContactBadge badge) {
+ final String lookupKey =
+ info.lookupUri == null ? null : UriUtils.getLookupKeyFromUri(info.lookupUri);
+ final int contactType =
+ mContactInfoHelper.isBusiness(info.sourceType)
+ ? LetterTileDrawable.TYPE_BUSINESS
+ : LetterTileDrawable.TYPE_DEFAULT;
+ final DefaultImageRequest request =
+ new DefaultImageRequest(displayName, lookupKey, contactType, true /* isCircular */);
+ badge.assignContactUri(info.lookupUri);
+ badge.setContentDescription(
+ mContext.getResources().getString(R.string.description_contact_details, displayName));
+ mContactPhotoManager.loadDirectoryPhoto(
+ badge, info.photoUri, false /* darkTheme */, true /* isCircular */, request);
+ }
+
+ private String getDisplayNumber(ContactInfo info) {
+ if (!TextUtils.isEmpty(info.formattedNumber)) {
+ return info.formattedNumber;
+ } else if (!TextUtils.isEmpty(info.number)) {
+ return info.number;
+ } else {
+ return "";
+ }
+ }
+
+ private CharSequence getNumberTypeOrLocation(ContactInfo info) {
+ if (!TextUtils.isEmpty(info.name)) {
+ return ContactsContract.CommonDataKinds.Phone.getTypeLabel(
+ mContext.getResources(), info.type, info.label);
+ } else {
+ return PhoneNumberHelper.getGeoDescription(mContext, info.number);
+ }
+ }
+
+ protected Context getContext() {
+ return mContext;
+ }
+
+ protected FragmentManager getFragmentManager() {
+ return mFragmentManager;
+ }
+}
diff --git a/java/com/android/dialer/app/filterednumber/ViewNumbersToImportAdapter.java b/java/com/android/dialer/app/filterednumber/ViewNumbersToImportAdapter.java
new file mode 100644
index 000000000..106c4fb71
--- /dev/null
+++ b/java/com/android/dialer/app/filterednumber/ViewNumbersToImportAdapter.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 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.dialer.app.filterednumber;
+
+import android.app.FragmentManager;
+import android.content.Context;
+import android.database.Cursor;
+import android.view.View;
+import com.android.dialer.app.R;
+import com.android.dialer.blocking.FilteredNumbersUtil;
+import com.android.dialer.contactphoto.ContactPhotoManager;
+import com.android.dialer.location.GeoUtil;
+import com.android.dialer.phonenumbercache.ContactInfoHelper;
+
+/** TODO(calderwoodra): documentation */
+public class ViewNumbersToImportAdapter extends NumbersAdapter {
+
+ private ViewNumbersToImportAdapter(
+ Context context,
+ FragmentManager fragmentManager,
+ ContactInfoHelper contactInfoHelper,
+ ContactPhotoManager contactPhotoManager) {
+ super(context, fragmentManager, contactInfoHelper, contactPhotoManager);
+ }
+
+ public static ViewNumbersToImportAdapter newViewNumbersToImportAdapter(
+ Context context, FragmentManager fragmentManager) {
+ return new ViewNumbersToImportAdapter(
+ context,
+ fragmentManager,
+ new ContactInfoHelper(context, GeoUtil.getCurrentCountryIso(context)),
+ ContactPhotoManager.getInstance(context));
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ super.bindView(view, context, cursor);
+
+ final String number = cursor.getString(FilteredNumbersUtil.PhoneQuery.NUMBER_COLUMN_INDEX);
+
+ view.findViewById(R.id.delete_button).setVisibility(View.GONE);
+ updateView(view, number, null /* countryIso */);
+ }
+}
diff --git a/java/com/android/dialer/app/filterednumber/ViewNumbersToImportFragment.java b/java/com/android/dialer/app/filterednumber/ViewNumbersToImportFragment.java
new file mode 100644
index 000000000..1de768219
--- /dev/null
+++ b/java/com/android/dialer/app/filterednumber/ViewNumbersToImportFragment.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2015 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.dialer.app.filterednumber;
+
+import android.app.ListFragment;
+import android.app.LoaderManager;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Loader;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.dialer.app.R;
+import com.android.dialer.blocking.FilteredNumbersUtil;
+import com.android.dialer.blocking.FilteredNumbersUtil.ImportSendToVoicemailContactsListener;
+
+/** TODO(calderwoodra): documentation */
+public class ViewNumbersToImportFragment extends ListFragment
+ implements LoaderManager.LoaderCallbacks<Cursor>, View.OnClickListener {
+
+ private ViewNumbersToImportAdapter mAdapter;
+
+ @Override
+ public Context getContext() {
+ return getActivity();
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ if (mAdapter == null) {
+ mAdapter =
+ ViewNumbersToImportAdapter.newViewNumbersToImportAdapter(
+ getContext(), getActivity().getFragmentManager());
+ }
+ setListAdapter(mAdapter);
+ }
+
+ @Override
+ public void onDestroy() {
+ setListAdapter(null);
+ super.onDestroy();
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getLoaderManager().initLoader(0, null, this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+ actionBar.setTitle(R.string.import_send_to_voicemail_numbers_label);
+ actionBar.setDisplayShowCustomEnabled(false);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowHomeEnabled(true);
+ actionBar.setDisplayShowTitleEnabled(true);
+
+ getActivity().findViewById(R.id.cancel_button).setOnClickListener(this);
+ getActivity().findViewById(R.id.import_button).setOnClickListener(this);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.view_numbers_to_import_fragment, container, false);
+ }
+
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ final CursorLoader cursorLoader =
+ new CursorLoader(
+ getContext(),
+ Phone.CONTENT_URI,
+ FilteredNumbersUtil.PhoneQuery.PROJECTION,
+ FilteredNumbersUtil.PhoneQuery.SELECT_SEND_TO_VOICEMAIL_TRUE,
+ null,
+ null);
+ return cursorLoader;
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ mAdapter.swapCursor(data);
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ mAdapter.swapCursor(null);
+ }
+
+ @Override
+ public void onClick(final View view) {
+ if (view.getId() == R.id.import_button) {
+ FilteredNumbersUtil.importSendToVoicemailContacts(
+ getContext(),
+ new ImportSendToVoicemailContactsListener() {
+ @Override
+ public void onImportComplete() {
+ if (getActivity() != null) {
+ getActivity().onBackPressed();
+ }
+ }
+ });
+ } else if (view.getId() == R.id.cancel_button) {
+ getActivity().onBackPressed();
+ }
+ }
+}
diff --git a/java/com/android/dialer/app/list/BlockedListSearchFragment.java b/java/com/android/dialer/app/list/BlockedListSearchFragment.java
new file mode 100644
index 000000000..bef5af713
--- /dev/null
+++ b/java/com/android/dialer/app/list/BlockedListSearchFragment.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2015 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.dialer.app.list;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.telephony.PhoneNumberUtils;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.EditText;
+import android.widget.Toast;
+import com.android.contacts.common.list.ContactEntryListAdapter;
+import com.android.contacts.common.util.ContactDisplayUtils;
+import com.android.dialer.app.R;
+import com.android.dialer.app.widget.SearchEditTextLayout;
+import com.android.dialer.blocking.BlockNumberDialogFragment;
+import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
+import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler.OnCheckBlockedListener;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.location.GeoUtil;
+import com.android.dialer.logging.InteractionEvent;
+import com.android.dialer.logging.Logger;
+
+/** TODO(calderwoodra): documentation */
+public class BlockedListSearchFragment extends RegularSearchFragment
+ implements BlockNumberDialogFragment.Callback {
+
+ private final TextWatcher mPhoneSearchQueryTextListener =
+ new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ setQueryString(s.toString());
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {}
+ };
+ private final SearchEditTextLayout.Callback mSearchLayoutCallback =
+ new SearchEditTextLayout.Callback() {
+ @Override
+ public void onBackButtonClicked() {
+ getActivity().onBackPressed();
+ }
+
+ @Override
+ public void onSearchViewClicked() {}
+ };
+ private FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler;
+ private EditText mSearchView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setShowEmptyListForNullQuery(true);
+ /*
+ * Pass in the empty string here so ContactEntryListFragment#setQueryString interprets it as
+ * an empty search query, rather than as an uninitalized value. In the latter case, the
+ * adapter returned by #createListAdapter is used, which populates the view with contacts.
+ * Passing in the empty string forces ContactEntryListFragment to interpret it as an empty
+ * query, which results in showing an empty view
+ */
+ setQueryString(getQueryString() == null ? "" : getQueryString());
+ mFilteredNumberAsyncQueryHandler = new FilteredNumberAsyncQueryHandler(getContext());
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+ actionBar.setCustomView(R.layout.search_edittext);
+ actionBar.setDisplayShowCustomEnabled(true);
+ actionBar.setDisplayHomeAsUpEnabled(false);
+ actionBar.setDisplayShowHomeEnabled(false);
+
+ final SearchEditTextLayout searchEditTextLayout =
+ (SearchEditTextLayout) actionBar.getCustomView().findViewById(R.id.search_view_container);
+ searchEditTextLayout.expand(false, true);
+ searchEditTextLayout.setCallback(mSearchLayoutCallback);
+ searchEditTextLayout.setBackgroundDrawable(null);
+
+ mSearchView = (EditText) searchEditTextLayout.findViewById(R.id.search_view);
+ mSearchView.addTextChangedListener(mPhoneSearchQueryTextListener);
+ mSearchView.setHint(R.string.block_number_search_hint);
+
+ searchEditTextLayout
+ .findViewById(R.id.search_box_expanded)
+ .setBackgroundColor(getContext().getResources().getColor(android.R.color.white));
+
+ if (!TextUtils.isEmpty(getQueryString())) {
+ mSearchView.setText(getQueryString());
+ }
+
+ // TODO: Don't set custom text size; use default search text size.
+ mSearchView.setTextSize(
+ TypedValue.COMPLEX_UNIT_PX,
+ getResources().getDimension(R.dimen.blocked_number_search_text_size));
+ }
+
+ @Override
+ protected ContactEntryListAdapter createListAdapter() {
+ BlockedListSearchAdapter adapter = new BlockedListSearchAdapter(getActivity());
+ adapter.setDisplayPhotos(true);
+ // Don't show SIP addresses.
+ adapter.setUseCallableUri(false);
+ // Keep in sync with the queryString set in #onCreate
+ adapter.setQueryString(getQueryString() == null ? "" : getQueryString());
+ return adapter;
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ super.onItemClick(parent, view, position, id);
+ final int adapterPosition = position - getListView().getHeaderViewsCount();
+ final BlockedListSearchAdapter adapter = (BlockedListSearchAdapter) getAdapter();
+ final int shortcutType = adapter.getShortcutTypeFromPosition(adapterPosition);
+ final Integer blockId = (Integer) view.getTag(R.id.block_id);
+ final String number;
+ switch (shortcutType) {
+ case DialerPhoneNumberListAdapter.SHORTCUT_INVALID:
+ // Handles click on a search result, either contact or nearby places result.
+ number = adapter.getPhoneNumber(adapterPosition);
+ blockContactNumber(number, blockId);
+ break;
+ case DialerPhoneNumberListAdapter.SHORTCUT_BLOCK_NUMBER:
+ // Handles click on 'Block number' shortcut to add the user query as a number.
+ number = adapter.getQueryString();
+ blockNumber(number);
+ break;
+ default:
+ LogUtil.w(
+ "BlockedListSearchFragment.onItemClick",
+ "ignoring unsupported shortcut type: " + shortcutType);
+ break;
+ }
+ }
+
+ @Override
+ protected void onItemClick(int position, long id) {
+ // Prevent SearchFragment.onItemClicked from being called.
+ }
+
+ private void blockNumber(final String number) {
+ final String countryIso = GeoUtil.getCurrentCountryIso(getContext());
+ final OnCheckBlockedListener onCheckListener =
+ new OnCheckBlockedListener() {
+ @Override
+ public void onCheckComplete(Integer id) {
+ if (id == null) {
+ BlockNumberDialogFragment.show(
+ id,
+ number,
+ countryIso,
+ PhoneNumberUtils.formatNumber(number, countryIso),
+ R.id.blocked_numbers_activity_container,
+ getFragmentManager(),
+ BlockedListSearchFragment.this);
+ } else if (id == FilteredNumberAsyncQueryHandler.INVALID_ID) {
+ Toast.makeText(
+ getContext(),
+ ContactDisplayUtils.getTtsSpannedPhoneNumber(
+ getResources(), R.string.invalidNumber, number),
+ Toast.LENGTH_SHORT)
+ .show();
+ } else {
+ Toast.makeText(
+ getContext(),
+ ContactDisplayUtils.getTtsSpannedPhoneNumber(
+ getResources(), R.string.alreadyBlocked, number),
+ Toast.LENGTH_SHORT)
+ .show();
+ }
+ }
+ };
+ mFilteredNumberAsyncQueryHandler.isBlockedNumber(onCheckListener, number, countryIso);
+ }
+
+ @Override
+ public void onFilterNumberSuccess() {
+ Logger.get(getContext()).logInteraction(InteractionEvent.Type.BLOCK_NUMBER_MANAGEMENT_SCREEN);
+ goBack();
+ }
+
+ @Override
+ public void onUnfilterNumberSuccess() {
+ LogUtil.e(
+ "BlockedListSearchFragment.onUnfilterNumberSuccess",
+ "unblocked a number from the BlockedListSearchFragment");
+ goBack();
+ }
+
+ private void goBack() {
+ Activity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+ activity.onBackPressed();
+ }
+
+ @Override
+ public void onChangeFilteredNumberUndo() {
+ getAdapter().notifyDataSetChanged();
+ }
+
+ private void blockContactNumber(final String number, final Integer blockId) {
+ if (blockId != null) {
+ Toast.makeText(
+ getContext(),
+ ContactDisplayUtils.getTtsSpannedPhoneNumber(
+ getResources(), R.string.alreadyBlocked, number),
+ Toast.LENGTH_SHORT)
+ .show();
+ return;
+ }
+
+ BlockNumberDialogFragment.show(
+ blockId,
+ number,
+ GeoUtil.getCurrentCountryIso(getContext()),
+ number,
+ R.id.blocked_numbers_activity_container,
+ getFragmentManager(),
+ this);
+ }
+}