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 */
16package com.android.dialer.list;
17
18import android.app.Activity;
19import android.os.Bundle;
20import android.support.v7.app.ActionBar;
21import android.support.v7.app.AppCompatActivity;
22import android.telephony.PhoneNumberUtils;
23import android.text.Editable;
24import android.text.TextUtils;
25import android.text.TextWatcher;
26import android.util.Log;
27import android.util.TypedValue;
28import android.view.View;
29import android.widget.AdapterView;
30import android.widget.EditText;
31import android.widget.Toast;
32
33import com.android.contacts.common.GeoUtil;
34import com.android.contacts.common.list.ContactEntryListAdapter;
35import com.android.contacts.common.util.ContactDisplayUtils;
36import com.android.dialer.R;
37import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
38import com.android.dialer.database.FilteredNumberAsyncQueryHandler.OnCheckBlockedListener;
39import com.android.dialer.filterednumber.BlockNumberDialogFragment;
40import com.android.dialer.logging.InteractionEvent;
41import com.android.dialer.logging.Logger;
42import com.android.dialer.widget.SearchEditTextLayout;
43
44public 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
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
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
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
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
166    protected void onItemClick(int position, long id) {
167        // Prevent SearchFragment.onItemClicked from being called.
168    }
169
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
203    public void onFilterNumberSuccess() {
204        Logger.logInteraction(InteractionEvent.BLOCK_NUMBER_MANAGEMENT_SCREEN);
205        goBack();
206    }
207
208    @Override
209    public void onUnfilterNumberSuccess() {
210        Log.wtf(TAG, "Unblocked a number from the BlockedListSearchFragment");
211        goBack();
212    }
213
214    private void goBack() {
215        Activity activity = getActivity();
216        if (activity == null) {
217            return;
218        }
219        activity.onBackPressed();
220    }
221
222    @Override
223    public void onChangeFilteredNumberUndo() {
224        getAdapter().notifyDataSetChanged();
225    }
226
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