1 /*
2  * Copyright (C) 2010 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.contacts.common.list;
17 
18 import android.content.Intent;
19 import android.content.Loader;
20 import android.database.Cursor;
21 import android.net.Uri;
22 import android.os.Bundle;
23 import android.text.TextUtils;
24 import android.util.Log;
25 import android.view.LayoutInflater;
26 import android.view.MenuItem;
27 import android.view.View;
28 import android.view.View.OnClickListener;
29 import android.view.ViewGroup;
30 
31 import com.android.contacts.common.R;
32 import com.android.contacts.common.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener;
33 import com.android.contacts.common.util.AccountFilterUtil;
34 
35 /**
36  * Fragment containing a phone number list for picking.
37  */
38 public class PhoneNumberPickerFragment extends ContactEntryListFragment<ContactEntryListAdapter>
39         implements OnShortcutIntentCreatedListener {
40     private static final String TAG = PhoneNumberPickerFragment.class.getSimpleName();
41 
42     private static final int REQUEST_CODE_ACCOUNT_FILTER = 1;
43 
44     private static final String KEY_SHORTCUT_ACTION = "shortcutAction";
45 
46     private OnPhoneNumberPickerActionListener mListener;
47     private String mShortcutAction;
48 
49     private ContactListFilter mFilter;
50 
51     private View mAccountFilterHeader;
52     /**
53      * Lives as ListView's header and is shown when {@link #mAccountFilterHeader} is set
54      * to View.GONE.
55      */
56     private View mPaddingView;
57 
58     private static final String KEY_FILTER = "filter";
59 
60     /** true if the loader has started at least once. */
61     private boolean mLoaderStarted;
62 
63     private boolean mUseCallableUri;
64 
65     private ContactListItemView.PhotoPosition mPhotoPosition =
66             ContactListItemView.getDefaultPhotoPosition(false /* normal/non opposite */);
67 
68     private class FilterHeaderClickListener implements OnClickListener {
69         @Override
onClick(View view)70         public void onClick(View view) {
71             AccountFilterUtil.startAccountFilterActivityForResult(
72                     PhoneNumberPickerFragment.this,
73                     REQUEST_CODE_ACCOUNT_FILTER,
74                     mFilter);
75         }
76     }
77     private OnClickListener mFilterHeaderClickListener = new FilterHeaderClickListener();
78 
PhoneNumberPickerFragment()79     public PhoneNumberPickerFragment() {
80         setQuickContactEnabled(false);
81         setPhotoLoaderEnabled(true);
82         setSectionHeaderDisplayEnabled(true);
83         setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_NONE);
84 
85         // Show nothing instead of letting caller Activity show something.
86         setHasOptionsMenu(true);
87     }
88 
setDirectorySearchEnabled(boolean flag)89     public void setDirectorySearchEnabled(boolean flag) {
90         setDirectorySearchMode(flag ? DirectoryListLoader.SEARCH_MODE_DEFAULT
91                 : DirectoryListLoader.SEARCH_MODE_NONE);
92     }
93 
setOnPhoneNumberPickerActionListener(OnPhoneNumberPickerActionListener listener)94     public void setOnPhoneNumberPickerActionListener(OnPhoneNumberPickerActionListener listener) {
95         this.mListener = listener;
96     }
97 
getOnPhoneNumberPickerListener()98     public OnPhoneNumberPickerActionListener getOnPhoneNumberPickerListener() {
99         return mListener;
100     }
101 
102     @Override
onCreateView(LayoutInflater inflater, ViewGroup container)103     protected void onCreateView(LayoutInflater inflater, ViewGroup container) {
104         super.onCreateView(inflater, container);
105 
106         View paddingView = inflater.inflate(R.layout.contact_detail_list_padding, null, false);
107         mPaddingView = paddingView.findViewById(R.id.contact_detail_list_padding);
108         getListView().addHeaderView(paddingView);
109 
110         mAccountFilterHeader = getView().findViewById(R.id.account_filter_header_container);
111         mAccountFilterHeader.setOnClickListener(mFilterHeaderClickListener);
112         updateFilterHeaderView();
113 
114         setVisibleScrollbarEnabled(getVisibleScrollbarEnabled());
115     }
116 
getVisibleScrollbarEnabled()117     protected boolean getVisibleScrollbarEnabled() {
118         return true;
119     }
120 
121     @Override
setSearchMode(boolean flag)122     protected void setSearchMode(boolean flag) {
123         super.setSearchMode(flag);
124         updateFilterHeaderView();
125     }
126 
updateFilterHeaderView()127     private void updateFilterHeaderView() {
128         final ContactListFilter filter = getFilter();
129         if (mAccountFilterHeader == null || filter == null) {
130             return;
131         }
132         final boolean shouldShowHeader =
133                 !isSearchMode() &&
134                 AccountFilterUtil.updateAccountFilterTitleForPhone(
135                         mAccountFilterHeader, filter, false);
136         if (shouldShowHeader) {
137             mPaddingView.setVisibility(View.GONE);
138             mAccountFilterHeader.setVisibility(View.VISIBLE);
139         } else {
140             mPaddingView.setVisibility(View.VISIBLE);
141             mAccountFilterHeader.setVisibility(View.GONE);
142         }
143     }
144 
145     @Override
restoreSavedState(Bundle savedState)146     public void restoreSavedState(Bundle savedState) {
147         super.restoreSavedState(savedState);
148 
149         if (savedState == null) {
150             return;
151         }
152 
153         mFilter = savedState.getParcelable(KEY_FILTER);
154         mShortcutAction = savedState.getString(KEY_SHORTCUT_ACTION);
155     }
156 
157     @Override
onSaveInstanceState(Bundle outState)158     public void onSaveInstanceState(Bundle outState) {
159         super.onSaveInstanceState(outState);
160         outState.putParcelable(KEY_FILTER, mFilter);
161         outState.putString(KEY_SHORTCUT_ACTION, mShortcutAction);
162     }
163 
164     @Override
onOptionsItemSelected(MenuItem item)165     public boolean onOptionsItemSelected(MenuItem item) {
166         final int itemId = item.getItemId();
167         if (itemId == android.R.id.home) {  // See ActionBar#setDisplayHomeAsUpEnabled()
168             if (mListener != null) {
169                 mListener.onHomeInActionBarSelected();
170             }
171             return true;
172         }
173         return super.onOptionsItemSelected(item);
174     }
175 
176     /**
177      * @param shortcutAction either {@link Intent#ACTION_CALL} or
178      *            {@link Intent#ACTION_SENDTO} or null.
179      */
setShortcutAction(String shortcutAction)180     public void setShortcutAction(String shortcutAction) {
181         this.mShortcutAction = shortcutAction;
182     }
183 
184     @Override
onItemClick(int position, long id)185     protected void onItemClick(int position, long id) {
186         final Uri phoneUri = getPhoneUri(position);
187 
188         if (phoneUri != null) {
189             pickPhoneNumber(phoneUri);
190         } else {
191             final String number = getPhoneNumber(position);
192             if (!TextUtils.isEmpty(number)) {
193                 cacheContactInfo(position);
194                 mListener.onCallNumberDirectly(number);
195             } else {
196                 Log.w(TAG, "Item at " + position + " was clicked before"
197                         + " adapter is ready. Ignoring");
198             }
199         }
200     }
201 
cacheContactInfo(int position)202     protected void cacheContactInfo(int position) {
203         // Not implemented. Hook for child classes
204     }
205 
getPhoneNumber(int position)206     protected String getPhoneNumber(int position) {
207         final PhoneNumberListAdapter adapter = (PhoneNumberListAdapter) getAdapter();
208         return adapter.getPhoneNumber(position);
209     }
210 
getPhoneUri(int position)211     protected Uri getPhoneUri(int position) {
212         final PhoneNumberListAdapter adapter = (PhoneNumberListAdapter) getAdapter();
213         return adapter.getDataUri(position);
214     }
215 
216     @Override
startLoading()217     protected void startLoading() {
218         mLoaderStarted = true;
219         super.startLoading();
220     }
221 
222     @Override
onLoadFinished(Loader<Cursor> loader, Cursor data)223     public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
224         super.onLoadFinished(loader, data);
225 
226         // disable scroll bar if there is no data
227         setVisibleScrollbarEnabled(data != null && data.getCount() > 0);
228     }
229 
setUseCallableUri(boolean useCallableUri)230     public void setUseCallableUri(boolean useCallableUri) {
231         mUseCallableUri = useCallableUri;
232     }
233 
usesCallableUri()234     public boolean usesCallableUri() {
235         return mUseCallableUri;
236     }
237 
238     @Override
createListAdapter()239     protected ContactEntryListAdapter createListAdapter() {
240         PhoneNumberListAdapter adapter = new PhoneNumberListAdapter(getActivity());
241         adapter.setDisplayPhotos(true);
242         adapter.setUseCallableUri(mUseCallableUri);
243         return adapter;
244     }
245 
246     @Override
configureAdapter()247     protected void configureAdapter() {
248         super.configureAdapter();
249 
250         final ContactEntryListAdapter adapter = getAdapter();
251         if (adapter == null) {
252             return;
253         }
254 
255         if (!isSearchMode() && mFilter != null) {
256             adapter.setFilter(mFilter);
257         }
258 
259         setPhotoPosition(adapter);
260     }
261 
setPhotoPosition(ContactEntryListAdapter adapter)262     protected void setPhotoPosition(ContactEntryListAdapter adapter) {
263         ((PhoneNumberListAdapter) adapter).setPhotoPosition(mPhotoPosition);
264     }
265 
266     @Override
inflateView(LayoutInflater inflater, ViewGroup container)267     protected View inflateView(LayoutInflater inflater, ViewGroup container) {
268         return inflater.inflate(R.layout.contact_list_content, null);
269     }
270 
pickPhoneNumber(Uri uri)271     public void pickPhoneNumber(Uri uri) {
272         if (mShortcutAction == null) {
273             mListener.onPickPhoneNumberAction(uri);
274         } else {
275             startPhoneNumberShortcutIntent(uri);
276         }
277     }
278 
startPhoneNumberShortcutIntent(Uri uri)279     protected void startPhoneNumberShortcutIntent(Uri uri) {
280         ShortcutIntentBuilder builder = new ShortcutIntentBuilder(getActivity(), this);
281         builder.createPhoneNumberShortcutIntent(uri, mShortcutAction);
282     }
283 
onShortcutIntentCreated(Uri uri, Intent shortcutIntent)284     public void onShortcutIntentCreated(Uri uri, Intent shortcutIntent) {
285         mListener.onShortcutIntentCreated(shortcutIntent);
286     }
287 
288     @Override
onPickerResult(Intent data)289     public void onPickerResult(Intent data) {
290         mListener.onPickPhoneNumberAction(data.getData());
291     }
292 
293     @Override
onActivityResult(int requestCode, int resultCode, Intent data)294     public void onActivityResult(int requestCode, int resultCode, Intent data) {
295         if (requestCode == REQUEST_CODE_ACCOUNT_FILTER) {
296             if (getActivity() != null) {
297                 AccountFilterUtil.handleAccountFilterResult(
298                         ContactListFilterController.getInstance(getActivity()), resultCode, data);
299             } else {
300                 Log.e(TAG, "getActivity() returns null during Fragment#onActivityResult()");
301             }
302         }
303     }
304 
getFilter()305     public ContactListFilter getFilter() {
306         return mFilter;
307     }
308 
setFilter(ContactListFilter filter)309     public void setFilter(ContactListFilter filter) {
310         if ((mFilter == null && filter == null) ||
311                 (mFilter != null && mFilter.equals(filter))) {
312             return;
313         }
314 
315         mFilter = filter;
316         if (mLoaderStarted) {
317             reloadData();
318         }
319         updateFilterHeaderView();
320     }
321 
setPhotoPosition(ContactListItemView.PhotoPosition photoPosition)322     public void setPhotoPosition(ContactListItemView.PhotoPosition photoPosition) {
323         mPhotoPosition = photoPosition;
324 
325         final PhoneNumberListAdapter adapter = (PhoneNumberListAdapter) getAdapter();
326         if (adapter != null) {
327             adapter.setPhotoPosition(photoPosition);
328         }
329     }
330 }
331