blob: f6f57a4a3867f03ea34304933a1e844c4e3811a2 [file] [log] [blame]
Alexandre Savarda04c5202012-09-18 17:19:53 -04001/*
alisiond295ec22013-05-17 10:12:13 -04002 * Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
Alexandre Savarda04c5202012-09-18 17:19:53 -04003 *
Alexandre Savard23240c12012-09-19 18:23:44 -04004 * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
alisiond295ec22013-05-17 10:12:13 -04005 * Alexandre Lision <alexandre.lision@savoirfairelinux.com>
Alexandre Savarda04c5202012-09-18 17:19:53 -04006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * Additional permission under GNU GPL version 3 section 7:
22 *
23 * If you modify this program, or any covered work, by linking or
24 * combining it with the OpenSSL project's OpenSSL library (or a
25 * modified version of that library), containing parts covered by the
26 * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
27 * grants you additional permission to convey the resulting work.
28 * Corresponding Source for a non-source form of such a combination
29 * shall include the source code for the parts of OpenSSL used as well
30 * as that of the covered work.
31 */
Alexandre Lision064e1e02013-10-01 16:18:42 -040032package org.sflphone.fragments;
alisionf76de3b2013-04-16 15:35:22 -040033
alisionf76de3b2013-04-16 15:35:22 -040034import java.util.ArrayList;
Alexandre Savarda04c5202012-09-18 17:19:53 -040035
Alexandre Lision064e1e02013-10-01 16:18:42 -040036import org.sflphone.R;
37import org.sflphone.adapters.ContactsAdapter;
38import org.sflphone.adapters.StarredContactsAdapter;
39import org.sflphone.loaders.ContactsLoader;
40import org.sflphone.loaders.LoaderConstants;
41import org.sflphone.model.CallContact;
42import org.sflphone.service.ISipService;
Alexandre Lisione1c96db2013-10-04 14:34:21 -040043import org.sflphone.views.SwipeListViewTouchListener;
Alexandre Lision691a1d62013-11-12 10:06:27 -050044import org.sflphone.views.stickylistheaders.StickyListHeadersListView;
Alexandre Lision064e1e02013-10-01 16:18:42 -040045
Emeric Vigier1f1ced32012-11-02 16:56:32 -040046import android.app.Activity;
alisiond295ec22013-05-17 10:12:13 -040047import android.app.Fragment;
Alexandre Savard6668cf82012-09-19 10:59:21 -040048import android.app.LoaderManager;
Alexandre Savard6668cf82012-09-19 10:59:21 -040049import android.content.Loader;
Alexandre Savard6668cf82012-09-19 10:59:21 -040050import android.net.Uri;
Alexandre Savarda04c5202012-09-18 17:19:53 -040051import android.os.Bundle;
Alexandre Savard6668cf82012-09-19 10:59:21 -040052import android.provider.ContactsContract.Contacts;
alisionf76de3b2013-04-16 15:35:22 -040053import android.util.Log;
alisiond295ec22013-05-17 10:12:13 -040054import android.view.DragEvent;
Alexandre Savarda04c5202012-09-18 17:19:53 -040055import android.view.LayoutInflater;
Alexandre Lision0936ba62013-11-25 10:04:56 -050056import android.view.MotionEvent;
Alexandre Savarda04c5202012-09-18 17:19:53 -040057import android.view.View;
alisiond295ec22013-05-17 10:12:13 -040058import android.view.View.DragShadowBuilder;
Alexandre Lision691a1d62013-11-12 10:06:27 -050059import android.view.View.MeasureSpec;
alision84813a12013-05-27 17:40:39 -040060import android.view.View.OnClickListener;
alisiond295ec22013-05-17 10:12:13 -040061import android.view.View.OnDragListener;
Alexandre Lision0936ba62013-11-25 10:04:56 -050062import android.view.View.OnTouchListener;
Alexandre Savarda04c5202012-09-18 17:19:53 -040063import android.view.ViewGroup;
Alexandre Savard31433992012-09-20 15:19:49 -040064import android.widget.AdapterView;
alisiond295ec22013-05-17 10:12:13 -040065import android.widget.AdapterView.OnItemClickListener;
Alexandre Savard31433992012-09-20 15:19:49 -040066import android.widget.AdapterView.OnItemLongClickListener;
Alexandre Lision691a1d62013-11-12 10:06:27 -050067import android.widget.GridView;
alision84813a12013-05-27 17:40:39 -040068import android.widget.ImageButton;
Alexandre Lision691a1d62013-11-12 10:06:27 -050069import android.widget.LinearLayout;
70import android.widget.ListAdapter;
alisionf76de3b2013-04-16 15:35:22 -040071import android.widget.ListView;
alision84813a12013-05-27 17:40:39 -040072import android.widget.RelativeLayout;
alisionf76de3b2013-04-16 15:35:22 -040073import android.widget.SearchView;
Alexandre Savard6668cf82012-09-19 10:59:21 -040074import android.widget.SearchView.OnQueryTextListener;
Alexandre Savarda04c5202012-09-18 17:19:53 -040075
alisiond295ec22013-05-17 10:12:13 -040076public class ContactListFragment extends Fragment implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Bundle> {
alision84813a12013-05-27 17:40:39 -040077 private static final String TAG = "ContactListFragment";
alisiond8c83882013-05-17 17:00:42 -040078 ContactsAdapter mListAdapter;
79 StarredContactsAdapter mGridAdapter;
Alexandre Lision691a1d62013-11-12 10:06:27 -050080 SearchView mQuickReturnSearchView;
alisiond8c83882013-05-17 17:00:42 -040081 String mCurFilter;
Alexandre Lision691a1d62013-11-12 10:06:27 -050082 StickyListHeadersListView mContactList;
83 private GridView mStarredGrid;
Alexandre Lision0936ba62013-11-25 10:04:56 -050084 private SwipeListViewTouchListener mSwipeLvTouchListener;
85 private LinearLayout mHeader;
Alexandre Savard6668cf82012-09-19 10:59:21 -040086
alisiond8c83882013-05-17 17:00:42 -040087 @Override
88 public void onCreate(Bundle savedInBundle) {
89 super.onCreate(savedInBundle);
alisiond8c83882013-05-17 17:00:42 -040090 mGridAdapter = new StarredContactsAdapter(getActivity());
Alexandre Lision691a1d62013-11-12 10:06:27 -050091 mListAdapter = new ContactsAdapter(this);
alisiond8c83882013-05-17 17:00:42 -040092 }
Alexandre Savarda04c5202012-09-18 17:19:53 -040093
Alexandre Lisione1c96db2013-10-04 14:34:21 -040094 public Callbacks mCallbacks = sDummyCallbacks;
Alexandre Lision691a1d62013-11-12 10:06:27 -050095 private LinearLayout llMain;
alision84813a12013-05-27 17:40:39 -040096 /**
97 * A dummy implementation of the {@link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity.
98 */
99 private static Callbacks sDummyCallbacks = new Callbacks() {
100 @Override
Alexandre Lisione1c96db2013-10-04 14:34:21 -0400101 public void onCallContact(CallContact c) {
102 }
103
104 @Override
105 public void onTextContact(CallContact c) {
alision84813a12013-05-27 17:40:39 -0400106 }
Alexandre Lisionbecb8032013-10-28 13:48:15 -0400107
Alexandre Lisionc59685a2013-10-04 16:36:36 -0400108 @Override
109 public void onEditContact(CallContact c) {
110 }
alision84813a12013-05-27 17:40:39 -0400111
112 @Override
113 public ISipService getService() {
114 Log.i(TAG, "Dummy");
115 return null;
116 }
117
alisiond45da712013-05-30 09:18:49 -0400118 @Override
119 public void onContactDragged() {
120 }
121
alision58356b72013-06-03 17:13:36 -0400122 @Override
Alexandre Lision0936ba62013-11-25 10:04:56 -0500123 public void toggleDrawer() {
124 }
125
126 @Override
127 public void setDragView(RelativeLayout relativeLayout) {
128
alision58356b72013-06-03 17:13:36 -0400129 }
alision84813a12013-05-27 17:40:39 -0400130 };
131
132 public interface Callbacks {
Alexandre Lisione1c96db2013-10-04 14:34:21 -0400133 void onCallContact(CallContact c);
134
135 void onTextContact(CallContact c);
alision84813a12013-05-27 17:40:39 -0400136
137 public ISipService getService();
138
alisiond45da712013-05-30 09:18:49 -0400139 void onContactDragged();
140
Alexandre Lision0936ba62013-11-25 10:04:56 -0500141 void toggleDrawer();
alision58356b72013-06-03 17:13:36 -0400142
Alexandre Lisionc59685a2013-10-04 16:36:36 -0400143 void onEditContact(CallContact item);
144
Alexandre Lision0936ba62013-11-25 10:04:56 -0500145 void setDragView(RelativeLayout relativeLayout);
146
alision84813a12013-05-27 17:40:39 -0400147 }
148
alisiond8c83882013-05-17 17:00:42 -0400149 @Override
150 public void onAttach(Activity activity) {
151 super.onAttach(activity);
alision84813a12013-05-27 17:40:39 -0400152 if (!(activity instanceof Callbacks)) {
153 throw new IllegalStateException("Activity must implement fragment's callbacks.");
154 }
155
156 mCallbacks = (Callbacks) activity;
Alexandre Lision0936ba62013-11-25 10:04:56 -0500157
alisiond8c83882013-05-17 17:00:42 -0400158 }
alision55c36cb2013-06-14 14:57:38 -0400159
alisionfde875f2013-05-28 17:01:54 -0400160 @Override
161 public void onDetach() {
162 super.onDetach();
163 mCallbacks = sDummyCallbacks;
164 }
Emeric Vigier1f1ced32012-11-02 16:56:32 -0400165
alisiond8c83882013-05-17 17:00:42 -0400166 @Override
Alexandre Lision691a1d62013-11-12 10:06:27 -0500167 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
168 View inflatedView = inflater.inflate(R.layout.frag_contact_list, container, false);
169 mHeader = (LinearLayout) inflater.inflate(R.layout.frag_contact_list_header, null);
Alexandre Lision691a1d62013-11-12 10:06:27 -0500170 mContactList = (StickyListHeadersListView) inflatedView.findViewById(R.id.contacts_list);
Alexandre Lision0936ba62013-11-25 10:04:56 -0500171
172 ((LinearLayout) inflatedView.findViewById(R.id.drag_view)).setOnTouchListener(new OnTouchListener() {
173
174 @Override
175 public boolean onTouch(View v, MotionEvent event) {
176 return true;
177 }
178 });
179
Alexandre Lision450458a2013-11-22 11:33:12 -0500180 ((ImageButton) inflatedView.findViewById(R.id.contact_search_button)).setOnClickListener(new OnClickListener() {
181
182 @Override
183 public void onClick(View v) {
184 mContactList.smoothScrollToPosition(0);
185 mQuickReturnSearchView.setOnQueryTextListener(ContactListFragment.this);
186 mQuickReturnSearchView.setIconified(false);
187 mQuickReturnSearchView.setFocusable(true);
Alexandre Lision0936ba62013-11-25 10:04:56 -0500188 mCallbacks.toggleDrawer();
189 }
190 });
191
192 ((RelativeLayout) inflatedView.findViewById(R.id.slider_button)).setOnClickListener(new OnClickListener() {
193
194 @Override
195 public void onClick(View v) {
196 mCallbacks.toggleDrawer();
Alexandre Lision450458a2013-11-22 11:33:12 -0500197 }
198 });
199
Alexandre Lision0936ba62013-11-25 10:04:56 -0500200 mCallbacks.setDragView(((RelativeLayout) inflatedView.findViewById(R.id.slider_button)));
201
Alexandre Lision691a1d62013-11-12 10:06:27 -0500202 mQuickReturnSearchView = (SearchView) mHeader.findViewById(R.id.contact_search);
203 mStarredGrid = (GridView) mHeader.findViewById(R.id.favorites_grid);
204 llMain = (LinearLayout) mHeader.findViewById(R.id.llMain);
205 return inflatedView;
206 }
207
208 @Override
alisiond8c83882013-05-17 17:00:42 -0400209 public void onActivityCreated(Bundle savedInstanceState) {
210 super.onActivityCreated(savedInstanceState);
Alexandre Savarda04c5202012-09-18 17:19:53 -0400211
Alexandre Lision691a1d62013-11-12 10:06:27 -0500212 mContactList.addHeaderView(mHeader, null, false);
213 mContactList.setAdapter(mListAdapter);
214
215 mStarredGrid.setAdapter(mGridAdapter);
216 mQuickReturnSearchView.setIconifiedByDefault(false);
217
218 mQuickReturnSearchView.setOnClickListener(new OnClickListener() {
219
220 @Override
221 public void onClick(View v) {
222 mQuickReturnSearchView.setOnQueryTextListener(ContactListFragment.this);
223 mQuickReturnSearchView.setIconified(false);
224 mQuickReturnSearchView.setFocusable(true);
225 }
226 });
227
alision2ec64f92013-06-17 17:28:58 -0400228 getLoaderManager().initLoader(LoaderConstants.CONTACT_LOADER, null, this);
Alexandre Savarda04c5202012-09-18 17:19:53 -0400229
alisiond8c83882013-05-17 17:00:42 -0400230 }
Alexandre Savard23240c12012-09-19 18:23:44 -0400231
alisiond8c83882013-05-17 17:00:42 -0400232 private OnItemLongClickListener mItemLongClickListener = new OnItemLongClickListener() {
233 @Override
234 public boolean onItemLongClick(AdapterView<?> av, View view, int pos, long id) {
235 DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view.findViewById(R.id.photo));
236 view.startDrag(null, shadowBuilder, view, 0);
alisiond45da712013-05-30 09:18:49 -0400237 mCallbacks.onContactDragged();
alisiond8c83882013-05-17 17:00:42 -0400238 return true;
239 }
alisiond295ec22013-05-17 10:12:13 -0400240
alisiond8c83882013-05-17 17:00:42 -0400241 };
Alexandre Lisionbecb8032013-10-28 13:48:15 -0400242
243 private void setGridViewListeners() {
Alexandre Lision691a1d62013-11-12 10:06:27 -0500244 mStarredGrid.setOnDragListener(dragListener);
245 mStarredGrid.setOnItemClickListener(new OnItemClickListener() {
Alexandre Savard0014d232012-09-24 10:31:23 -0400246
alisiond8c83882013-05-17 17:00:42 -0400247 @Override
248 public void onItemClick(AdapterView<?> arg0, View v, int pos, long arg3) {
Alexandre Lisione1c96db2013-10-04 14:34:21 -0400249 mCallbacks.onCallContact(mGridAdapter.getItem(pos));
alisiond8c83882013-05-17 17:00:42 -0400250 }
251 });
Alexandre Lision691a1d62013-11-12 10:06:27 -0500252 mStarredGrid.setOnItemLongClickListener(mItemLongClickListener);
Alexandre Lisionbecb8032013-10-28 13:48:15 -0400253 }
alisiond295ec22013-05-17 10:12:13 -0400254
Alexandre Lision691a1d62013-11-12 10:06:27 -0500255 private void setListViewListeners() {
256 mSwipeLvTouchListener = new SwipeListViewTouchListener(mContactList.getWrappedList(), new SwipeListViewTouchListener.OnSwipeCallback() {
Alexandre Lisionbecb8032013-10-28 13:48:15 -0400257 @Override
258 public void onSwipeLeft(ListView listView, int[] reverseSortedPositions) {
259 }
260
261 @Override
262 public void onSwipeRight(ListView listView, View down) {
263 down.findViewById(R.id.quick_edit).setClickable(true);
264 down.findViewById(R.id.quick_discard).setClickable(true);
265 down.findViewById(R.id.quick_starred).setClickable(true);
266
267 }
268 }, true, false);
269
Alexandre Lision691a1d62013-11-12 10:06:27 -0500270 mContactList.getWrappedList().setOnDragListener(dragListener);
271 mContactList.getWrappedList().setOnTouchListener(mSwipeLvTouchListener);
272 mContactList.getWrappedList().setOnItemLongClickListener(mItemLongClickListener);
273 mContactList.getWrappedList().setOnItemClickListener(new OnItemClickListener() {
Alexandre Lisionbecb8032013-10-28 13:48:15 -0400274
275 @Override
276 public void onItemClick(AdapterView<?> arg0, View view, int pos, long id) {
Alexandre Lision4e458dc2013-11-12 10:07:40 -0500277
Alexandre Lisionbecb8032013-10-28 13:48:15 -0400278 mSwipeLvTouchListener.openItem(view, pos, id);
279 }
280 });
alisiond8c83882013-05-17 17:00:42 -0400281 }
alisiond295ec22013-05-17 10:12:13 -0400282
alisiond8c83882013-05-17 17:00:42 -0400283 OnDragListener dragListener = new OnDragListener() {
Alexandre Savard0014d232012-09-24 10:31:23 -0400284
alisiond8c83882013-05-17 17:00:42 -0400285 @Override
286 public boolean onDrag(View v, DragEvent event) {
287 switch (event.getAction()) {
288 case DragEvent.ACTION_DRAG_STARTED:
289 // Do nothing
290 break;
291 case DragEvent.ACTION_DRAG_ENTERED:
292 break;
293 case DragEvent.ACTION_DRAG_EXITED:
alision55c36cb2013-06-14 14:57:38 -0400294 // v.setBackgroundDrawable(null);
alisiond8c83882013-05-17 17:00:42 -0400295 break;
296 case DragEvent.ACTION_DROP:
alisiond8c83882013-05-17 17:00:42 -0400297 break;
298 case DragEvent.ACTION_DRAG_ENDED:
299 View view1 = (View) event.getLocalState();
300 view1.setVisibility(View.VISIBLE);
301 default:
302 break;
303 }
304 return true;
305 }
Alexandre Savarda04c5202012-09-18 17:19:53 -0400306
alisiond8c83882013-05-17 17:00:42 -0400307 };
Alexandre Savarda04c5202012-09-18 17:19:53 -0400308
alisiond8c83882013-05-17 17:00:42 -0400309 @Override
310 public boolean onQueryTextChange(String newText) {
Alexandre Lisione2839d52013-10-01 09:37:37 -0400311 if (newText.isEmpty()) {
Alexandre Lision22db86b2013-09-24 13:33:28 -0400312 getLoaderManager().restartLoader(LoaderConstants.CONTACT_LOADER, null, this);
alisiond8c83882013-05-17 17:00:42 -0400313 return true;
314 }
Alexandre Lision22db86b2013-09-24 13:33:28 -0400315 mCurFilter = newText;
alision2ec64f92013-06-17 17:28:58 -0400316 Bundle b = new Bundle();
317 b.putString("filter", mCurFilter);
318 getLoaderManager().restartLoader(LoaderConstants.CONTACT_LOADER, b, this);
alisiond8c83882013-05-17 17:00:42 -0400319 return true;
320 }
alisiond295ec22013-05-17 10:12:13 -0400321
alisiond8c83882013-05-17 17:00:42 -0400322 @Override
323 public boolean onQueryTextSubmit(String query) {
324 // Return false to let the SearchView perform the default action
325 return false;
326 }
alisiond295ec22013-05-17 10:12:13 -0400327
alisiond8c83882013-05-17 17:00:42 -0400328 @Override
329 public Loader<Bundle> onCreateLoader(int id, Bundle args) {
330 Uri baseUri;
alision17052d42013-04-22 10:39:38 -0400331
Alexandre Lision4e458dc2013-11-12 10:07:40 -0500332 Log.i(TAG, "createLoader");
Alexandre Lisionbecb8032013-10-28 13:48:15 -0400333
alision2ec64f92013-06-17 17:28:58 -0400334 if (args != null) {
335 baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(args.getString("filter")));
alisiond8c83882013-05-17 17:00:42 -0400336 } else {
337 baseUri = Contacts.CONTENT_URI;
338 }
339 ContactsLoader l = new ContactsLoader(getActivity(), baseUri);
340 l.forceLoad();
341 return l;
342 }
Alexandre Savard6668cf82012-09-19 10:59:21 -0400343
alisiond8c83882013-05-17 17:00:42 -0400344 @Override
345 public void onLoadFinished(Loader<Bundle> loader, Bundle data) {
Alexandre Savard6668cf82012-09-19 10:59:21 -0400346
alisiond8c83882013-05-17 17:00:42 -0400347 mGridAdapter.removeAll();
Alexandre Lision4e458dc2013-11-12 10:07:40 -0500348 mListAdapter.clear();
alisiond8c83882013-05-17 17:00:42 -0400349 ArrayList<CallContact> tmp = data.getParcelableArrayList("Contacts");
350 ArrayList<CallContact> tmp2 = data.getParcelableArrayList("Starred");
alisiond8c83882013-05-17 17:00:42 -0400351 mListAdapter.addAll(tmp);
352 mGridAdapter.addAll(tmp2);
Alexandre Savard6668cf82012-09-19 10:59:21 -0400353
Alexandre Lision4e458dc2013-11-12 10:07:40 -0500354 setListViewListeners();
355 setGridViewListeners();
356
357 mStarredGrid.post(new Runnable() {
358
359 @Override
360 public void run() {
361 setGridViewHeight(mStarredGrid, llMain);
362 }
363 });
364
alisiond8c83882013-05-17 17:00:42 -0400365 }
Alexandre Savard6668cf82012-09-19 10:59:21 -0400366
Alexandre Lision4e458dc2013-11-12 10:07:40 -0500367 // Sets the GridView holder's height to fully expand it
368 public void setGridViewHeight(GridView gridView, LinearLayout llMain) {
369 ListAdapter listAdapter = gridView.getAdapter();
370 if (listAdapter == null) {
371 return;
372 }
373
374 int totalHeight = 0;
375 int firstHeight = 0;
376 int desiredWidth = MeasureSpec.makeMeasureSpec(gridView.getWidth(), MeasureSpec.AT_MOST);
377
378 int rows = (listAdapter.getCount() + gridView.getNumColumns() - 1) / gridView.getNumColumns();
379
380 for (int i = 0; i < rows; i++) {
381
382 if (i == 0) {
383 View listItem = listAdapter.getView(i, null, gridView);
384 listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
385 firstHeight = listItem.getMeasuredHeight();
386 }
387 totalHeight += firstHeight;
388 }
389
390 LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) llMain.getLayoutParams();
391
392 params.height = (int) (totalHeight + (getResources().getDimension(R.dimen.contact_vertical_spacing) * (rows - 1)));
Alexandre Lision4e458dc2013-11-12 10:07:40 -0500393 llMain.setLayoutParams(params);
394 mHeader.requestLayout();
395 }
396
alisiond8c83882013-05-17 17:00:42 -0400397 @Override
398 public void onLoaderReset(Loader<Bundle> loader) {
alisiond8c83882013-05-17 17:00:42 -0400399 }
Alexandre Savarda04c5202012-09-18 17:19:53 -0400400}