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