1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.dialer.list; 17 18 import android.app.Activity; 19 import android.os.Bundle; 20 import android.support.v7.app.ActionBar; 21 import android.support.v7.app.AppCompatActivity; 22 import android.telephony.PhoneNumberUtils; 23 import android.text.Editable; 24 import android.text.TextUtils; 25 import android.text.TextWatcher; 26 import android.util.Log; 27 import android.util.TypedValue; 28 import android.view.View; 29 import android.widget.AdapterView; 30 import android.widget.EditText; 31 import android.widget.Toast; 32 33 import com.android.contacts.common.GeoUtil; 34 import com.android.contacts.common.list.ContactEntryListAdapter; 35 import com.android.contacts.common.util.ContactDisplayUtils; 36 import com.android.dialer.R; 37 import com.android.dialer.database.FilteredNumberAsyncQueryHandler; 38 import com.android.dialer.database.FilteredNumberAsyncQueryHandler.OnCheckBlockedListener; 39 import com.android.dialer.filterednumber.BlockNumberDialogFragment; 40 import com.android.dialer.logging.InteractionEvent; 41 import com.android.dialer.logging.Logger; 42 import com.android.dialer.widget.SearchEditTextLayout; 43 44 public class BlockedListSearchFragment extends RegularSearchFragment 45 implements BlockNumberDialogFragment.Callback { 46 private static final String TAG = BlockedListSearchFragment.class.getSimpleName(); 47 48 private static final String KEY_SEARCH_QUERY = "search_query"; 49 50 private FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler; 51 52 private EditText mSearchView; 53 54 private final TextWatcher mPhoneSearchQueryTextListener = new TextWatcher() { 55 @Override 56 public void beforeTextChanged(CharSequence s, int start, int count, int after) {} 57 58 @Override 59 public void onTextChanged(CharSequence s, int start, int before, int count) { 60 setQueryString(s.toString(), false); 61 } 62 63 @Override 64 public void afterTextChanged(Editable s) {} 65 }; 66 67 private final SearchEditTextLayout.Callback mSearchLayoutCallback = 68 new SearchEditTextLayout.Callback() { 69 @Override 70 public void onBackButtonClicked() { 71 getActivity().onBackPressed(); 72 } 73 74 @Override 75 public void onSearchViewClicked() { 76 } 77 }; 78 79 @Override onCreate(Bundle savedInstanceState)80 public void onCreate(Bundle savedInstanceState) { 81 super.onCreate(savedInstanceState); 82 83 setShowEmptyListForNullQuery(true); 84 /* 85 * Pass in the empty string here so ContactEntryListFragment#setQueryString interprets it as 86 * an empty search query, rather than as an uninitalized value. In the latter case, the 87 * adapter returned by #createListAdapter is used, which populates the view with contacts. 88 * Passing in the empty string forces ContactEntryListFragment to interpret it as an empty 89 * query, which results in showing an empty view 90 */ 91 setQueryString(getQueryString() == null ? "" : getQueryString(), false); 92 mFilteredNumberAsyncQueryHandler = new FilteredNumberAsyncQueryHandler( 93 getContext().getContentResolver()); 94 } 95 96 @Override onResume()97 public void onResume() { 98 super.onResume(); 99 100 ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar(); 101 actionBar.setCustomView(R.layout.search_edittext); 102 actionBar.setDisplayShowCustomEnabled(true); 103 actionBar.setDisplayHomeAsUpEnabled(false); 104 actionBar.setDisplayShowHomeEnabled(false); 105 106 final SearchEditTextLayout searchEditTextLayout = (SearchEditTextLayout) actionBar 107 .getCustomView().findViewById(R.id.search_view_container); 108 searchEditTextLayout.expand(false, true); 109 searchEditTextLayout.setCallback(mSearchLayoutCallback); 110 searchEditTextLayout.setBackgroundDrawable(null); 111 112 mSearchView = (EditText) searchEditTextLayout.findViewById(R.id.search_view); 113 mSearchView.addTextChangedListener(mPhoneSearchQueryTextListener); 114 mSearchView.setHint(R.string.block_number_search_hint); 115 116 searchEditTextLayout.findViewById(R.id.search_box_expanded) 117 .setBackgroundColor(getContext().getResources().getColor(android.R.color.white)); 118 119 if (!TextUtils.isEmpty(getQueryString())) { 120 mSearchView.setText(getQueryString()); 121 } 122 123 // TODO: Don't set custom text size; use default search text size. 124 mSearchView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 125 getResources().getDimension(R.dimen.blocked_number_search_text_size)); 126 } 127 128 @Override createListAdapter()129 protected ContactEntryListAdapter createListAdapter() { 130 BlockedListSearchAdapter adapter = new BlockedListSearchAdapter(getActivity()); 131 adapter.setDisplayPhotos(true); 132 // Don't show SIP addresses. 133 adapter.setUseCallableUri(false); 134 // Keep in sync with the queryString set in #onCreate 135 adapter.setQueryString(getQueryString() == null ? "" : getQueryString()); 136 return adapter; 137 } 138 139 140 @Override onItemClick(AdapterView<?> parent, View view, int position, long id)141 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 142 super.onItemClick(parent, view, position, id); 143 final int adapterPosition = position - getListView().getHeaderViewsCount(); 144 final BlockedListSearchAdapter adapter = (BlockedListSearchAdapter) getAdapter(); 145 final int shortcutType = adapter.getShortcutTypeFromPosition(adapterPosition); 146 final Integer blockId = (Integer) view.getTag(R.id.block_id); 147 final String number; 148 switch (shortcutType) { 149 case DialerPhoneNumberListAdapter.SHORTCUT_INVALID: 150 // Handles click on a search result, either contact or nearby places result. 151 number = adapter.getPhoneNumber(adapterPosition); 152 blockContactNumber(number, blockId); 153 break; 154 case DialerPhoneNumberListAdapter.SHORTCUT_BLOCK_NUMBER: 155 // Handles click on 'Block number' shortcut to add the user query as a number. 156 number = adapter.getQueryString(); 157 blockNumber(number); 158 break; 159 default: 160 Log.w(TAG, "Ignoring unsupported shortcut type: " + shortcutType); 161 break; 162 } 163 } 164 165 @Override onItemClick(int position, long id)166 protected void onItemClick(int position, long id) { 167 // Prevent SearchFragment.onItemClicked from being called. 168 } 169 blockNumber(final String number)170 private void blockNumber(final String number) { 171 final String countryIso = GeoUtil.getCurrentCountryIso(getContext()); 172 final OnCheckBlockedListener onCheckListener = new OnCheckBlockedListener() { 173 @Override 174 public void onCheckComplete(Integer id) { 175 if (id == null) { 176 BlockNumberDialogFragment.show( 177 id, 178 number, 179 countryIso, 180 PhoneNumberUtils.formatNumber(number, countryIso), 181 R.id.blocked_numbers_activity_container, 182 getFragmentManager(), 183 BlockedListSearchFragment.this); 184 } else { 185 Toast.makeText(getContext(), 186 ContactDisplayUtils.getTtsSpannedPhoneNumber(getResources(), 187 R.string.alreadyBlocked, number), 188 Toast.LENGTH_SHORT).show(); 189 } 190 } 191 }; 192 final boolean success = mFilteredNumberAsyncQueryHandler.isBlockedNumber( 193 onCheckListener, number, countryIso); 194 if (!success) { 195 Toast.makeText(getContext(), 196 ContactDisplayUtils.getTtsSpannedPhoneNumber( 197 getResources(), R.string.invalidNumber, number), 198 Toast.LENGTH_SHORT).show(); 199 } 200 } 201 202 @Override onFilterNumberSuccess()203 public void onFilterNumberSuccess() { 204 Logger.logInteraction(InteractionEvent.BLOCK_NUMBER_MANAGEMENT_SCREEN); 205 goBack(); 206 } 207 208 @Override onUnfilterNumberSuccess()209 public void onUnfilterNumberSuccess() { 210 Log.wtf(TAG, "Unblocked a number from the BlockedListSearchFragment"); 211 goBack(); 212 } 213 goBack()214 private void goBack() { 215 Activity activity = getActivity(); 216 if (activity == null) { 217 return; 218 } 219 activity.onBackPressed(); 220 } 221 222 @Override onChangeFilteredNumberUndo()223 public void onChangeFilteredNumberUndo() { 224 getAdapter().notifyDataSetChanged(); 225 } 226 blockContactNumber(final String number, final Integer blockId)227 private void blockContactNumber(final String number, final Integer blockId) { 228 if (blockId != null) { 229 Toast.makeText(getContext(), ContactDisplayUtils.getTtsSpannedPhoneNumber( 230 getResources(), R.string.alreadyBlocked, number), 231 Toast.LENGTH_SHORT).show(); 232 return; 233 } 234 235 BlockNumberDialogFragment.show( 236 blockId, 237 number, 238 GeoUtil.getCurrentCountryIso(getContext()), 239 number, 240 R.id.blocked_numbers_activity_container, 241 getFragmentManager(), 242 this); 243 } 244 } 245