Skip to content
Snippets Groups Projects
Select Git revision
  • 450458a7d233fc79d7de9ba632b5325b3e6ee53b
  • master default protected
  • release/202005
  • release/202001
  • release/201912
  • release/windows-test/201910
  • release/201908
  • release/201906
  • release/201905
  • release/201904
  • release/201903
  • release/201902
  • release/201901
  • release/201812
  • release/201811
  • release/201808
  • wip/patches_poly_2017/cedryk_doucet/abderahmane_bouziane
  • releases/beta1
  • android/release_463
  • android/release_462
  • android/release_461
  • android/release_460
  • android/release_459
  • android/release_458
  • android/release_457
  • android/release_456
  • android/release_455
  • android/release_454
  • android/release_453
  • android/release_452
  • android/release_451
  • android/release_450
  • android/release_449
  • android/release_448
  • android/release_447
  • android/release_446
  • android/release_445
  • android/release_444
38 results

ContactListFragment.java

Blame
  • user avatar
    Alexandre Lision authored
    450458a7
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    ContactListFragment.java 16.69 KiB
    /*
     *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
     *
     *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
     *          Alexandre Lision <alexandre.lision@savoirfairelinux.com>
     *
     *  This program is free software; you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License as published by
     *  the Free Software Foundation; either version 3 of the License, or
     *  (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *  GNU General Public License for more details.
     *
     *  You should have received a copy of the GNU General Public License
     *  along with this program; if not, write to the Free Software
     *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     *
     *  Additional permission under GNU GPL version 3 section 7:
     *
     *  If you modify this program, or any covered work, by linking or
     *  combining it with the OpenSSL project's OpenSSL library (or a
     *  modified version of that library), containing parts covered by the
     *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
     *  grants you additional permission to convey the resulting work.
     *  Corresponding Source for a non-source form of such a combination
     *  shall include the source code for the parts of OpenSSL used as well
     *  as that of the covered work.
     */
    package org.sflphone.fragments;
    
    import java.util.ArrayList;
    
    import org.sflphone.R;
    import org.sflphone.adapters.ContactsAdapter;
    import org.sflphone.adapters.StarredContactsAdapter;
    import org.sflphone.loaders.ContactsLoader;
    import org.sflphone.loaders.LoaderConstants;
    import org.sflphone.model.CallContact;
    import org.sflphone.service.ISipService;
    import org.sflphone.views.SwipeListViewTouchListener;
    import org.sflphone.views.stickylistheaders.StickyListHeadersListView;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.app.Fragment;
    import android.app.LoaderManager;
    import android.content.Loader;
    import android.net.Uri;
    import android.os.Bundle;
    import android.provider.ContactsContract.Contacts;
    import android.util.Log;
    import android.view.DragEvent;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.View.DragShadowBuilder;
    import android.view.View.MeasureSpec;
    import android.view.View.OnClickListener;
    import android.view.View.OnDragListener;
    import android.view.ViewGroup;
    import android.widget.AbsListView;
    import android.widget.AbsListView.OnScrollListener;
    import android.widget.AdapterView;
    import android.widget.AdapterView.OnItemClickListener;
    import android.widget.AdapterView.OnItemLongClickListener;
    import android.widget.GridView;
    import android.widget.ImageButton;
    import android.widget.LinearLayout;
    import android.widget.ListAdapter;
    import android.widget.ListView;
    import android.widget.RelativeLayout;
    import android.widget.SearchView;
    import android.widget.SearchView.OnQueryTextListener;
    
    public class ContactListFragment extends Fragment implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Bundle> {
        private static final String TAG = "ContactListFragment";
        ContactsAdapter mListAdapter;
        StarredContactsAdapter mGridAdapter;
        SearchView mQuickReturnSearchView;
        String mCurFilter;
        StickyListHeadersListView mContactList;
        private GridView mStarredGrid;
    
        private int mCachedVerticalScrollRange;
        private int mQuickReturnHeight;
    
        private static final int STATE_ONSCREEN = 0;
        private static final int STATE_OFFSCREEN = 1;
        private static final int STATE_RETURNING = 2;
        private int mState = STATE_ONSCREEN;
        private int mScrollY;
        private int mMinRawY = 0;
    
        @Override
        public void onCreate(Bundle savedInBundle) {
            super.onCreate(savedInBundle);
            mGridAdapter = new StarredContactsAdapter(getActivity());
            mListAdapter = new ContactsAdapter(this);
        }
    
        public Callbacks mCallbacks = sDummyCallbacks;
        private LinearLayout llMain;
        /**
         * A dummy implementation of the {@link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity.
         */
        private static Callbacks sDummyCallbacks = new Callbacks() {
            @Override
            public void onCallContact(CallContact c) {
            }
    
            @Override
            public void onTextContact(CallContact c) {
            }
    
            @Override
            public void onEditContact(CallContact c) {
            }
    
            @Override
            public ISipService getService() {
                Log.i(TAG, "Dummy");
                return null;
            }
    
            @Override
            public void onContactDragged() {
            }
    
            @Override
            public void openDrawer() {
            }
        };
    
        public interface Callbacks {
            void onCallContact(CallContact c);
    
            void onTextContact(CallContact c);
    
            public ISipService getService();
    
            void onContactDragged();
    
            void openDrawer();
    
            void onEditContact(CallContact item);
    
        }
    
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            if (!(activity instanceof Callbacks)) {
                throw new IllegalStateException("Activity must implement fragment's callbacks.");
            }
    
            mCallbacks = (Callbacks) activity;
        }
    
        @Override
        public void onDetach() {
            super.onDetach();
            mCallbacks = sDummyCallbacks;
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View inflatedView = inflater.inflate(R.layout.frag_contact_list, container, false);
            mHeader = (LinearLayout) inflater.inflate(R.layout.frag_contact_list_header, null);
            mContactList = (StickyListHeadersListView) inflatedView.findViewById(R.id.contacts_list);
            
            ((ImageButton) inflatedView.findViewById(R.id.contact_search_button)).setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    mContactList.smoothScrollToPosition(0);
                    mQuickReturnSearchView.setOnQueryTextListener(ContactListFragment.this);
                    mQuickReturnSearchView.setIconified(false);
                    mQuickReturnSearchView.setFocusable(true);
                    mCallbacks.openDrawer();
                }
            });
            
            mQuickReturnSearchView = (SearchView) mHeader.findViewById(R.id.contact_search);
            mStarredGrid = (GridView) mHeader.findViewById(R.id.favorites_grid);
            llMain = (LinearLayout) mHeader.findViewById(R.id.llMain);
            return inflatedView;
        }
    
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
    
            mContactList.addHeaderView(mHeader, null, false);
            mContactList.setAdapter(mListAdapter);
    
            mStarredGrid.setAdapter(mGridAdapter);
            mQuickReturnSearchView.setIconifiedByDefault(false);
    
            mQuickReturnSearchView.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    mQuickReturnSearchView.setOnQueryTextListener(ContactListFragment.this);
                    mQuickReturnSearchView.setIconified(false);
                    mQuickReturnSearchView.setFocusable(true);
                }
            });
    
            getLoaderManager().initLoader(LoaderConstants.CONTACT_LOADER, null, this);
    
        }
    
        private OnItemLongClickListener mItemLongClickListener = new OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> av, View view, int pos, long id) {
                DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view.findViewById(R.id.photo));
                view.startDrag(null, shadowBuilder, view, 0);
                mCallbacks.onContactDragged();
                return true;
            }
    
        };
        private SwipeListViewTouchListener mSwipeLvTouchListener;
        private View mPlaceHolder;
        private LinearLayout mHeader;
    
        private void setGridViewListeners() {
            mStarredGrid.setOnDragListener(dragListener);
            mStarredGrid.setOnItemClickListener(new OnItemClickListener() {
    
                @Override
                public void onItemClick(AdapterView<?> arg0, View v, int pos, long arg3) {
                    mCallbacks.onCallContact(mGridAdapter.getItem(pos));
                }
            });
            mStarredGrid.setOnItemLongClickListener(mItemLongClickListener);
        }
    
        private void setListViewListeners() {
            mSwipeLvTouchListener = new SwipeListViewTouchListener(mContactList.getWrappedList(), new SwipeListViewTouchListener.OnSwipeCallback() {
                @Override
                public void onSwipeLeft(ListView listView, int[] reverseSortedPositions) {
                }
    
                @Override
                public void onSwipeRight(ListView listView, View down) {
                    down.findViewById(R.id.quick_edit).setClickable(true);
                    down.findViewById(R.id.quick_discard).setClickable(true);
                    down.findViewById(R.id.quick_starred).setClickable(true);
    
                }
            }, true, false);
    
            mContactList.getWrappedList().setOnDragListener(dragListener);
            mContactList.getWrappedList().setOnTouchListener(mSwipeLvTouchListener);
            mContactList.getWrappedList().setOnItemLongClickListener(mItemLongClickListener);
            mContactList.getWrappedList().setOnItemClickListener(new OnItemClickListener() {
    
                @Override
                public void onItemClick(AdapterView<?> arg0, View view, int pos, long id) {
    
                    mSwipeLvTouchListener.openItem(view, pos, id);
                }
            });
    
            // mContactList.getWrappedList().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            // @Override
            // public void onGlobalLayout() {
            // if (!mContactList.scrollYIsComputed()) {
            // mQuickReturnHeight = mQuickReturnSearchView.getHeight();
            // mContactList.computeScrollY();
            // mCachedVerticalScrollRange = mContactList.getListHeight();
            // }
            // }
            // });
            // mContactList.setOnScrollListener(mScrollListener);
        }
    
        OnDragListener dragListener = new OnDragListener() {
    
            @Override
            public boolean onDrag(View v, DragEvent event) {
                switch (event.getAction()) {
                case DragEvent.ACTION_DRAG_STARTED:
                    // Do nothing
                    break;
                case DragEvent.ACTION_DRAG_ENTERED:
                    break;
                case DragEvent.ACTION_DRAG_EXITED:
                    // v.setBackgroundDrawable(null);
                    break;
                case DragEvent.ACTION_DROP:
                    break;
                case DragEvent.ACTION_DRAG_ENDED:
                    View view1 = (View) event.getLocalState();
                    view1.setVisibility(View.VISIBLE);
                default:
                    break;
                }
                return true;
            }
    
        };
    
        @Override
        public boolean onQueryTextChange(String newText) {
    
            // Called when the action bar search text has changed. Update
            // the search filter, and restart the loader to do a new query
            // with this filter.
            // String newFilter = !TextUtils.isEmpty(newText) ? newText : null;
            // Don't do anything if the filter hasn't actually changed.
            // Prefents restarting the loader when restoring state.
            // if (mCurFilter == null && newFilter == null) {
            // return true;
            // }
            // if (mCurFilter != null && mCurFilter.equals(newText)) {
            // return true;
            // }
            if (newText.isEmpty()) {
                getLoaderManager().restartLoader(LoaderConstants.CONTACT_LOADER, null, this);
                return true;
            }
            mCurFilter = newText;
            Bundle b = new Bundle();
            b.putString("filter", mCurFilter);
            getLoaderManager().restartLoader(LoaderConstants.CONTACT_LOADER, b, this);
            return true;
        }
    
        @Override
        public boolean onQueryTextSubmit(String query) {
            // Return false to let the SearchView perform the default action
            return false;
        }
    
        @Override
        public Loader<Bundle> onCreateLoader(int id, Bundle args) {
            Uri baseUri;
    
            Log.i(TAG, "createLoader");
    
            if (args != null) {
                baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(args.getString("filter")));
            } else {
                baseUri = Contacts.CONTENT_URI;
            }
            ContactsLoader l = new ContactsLoader(getActivity(), baseUri);
            l.forceLoad();
            return l;
        }
    
        @Override
        public void onLoadFinished(Loader<Bundle> loader, Bundle data) {
    
            mGridAdapter.removeAll();
            mListAdapter.clear();
            ArrayList<CallContact> tmp = data.getParcelableArrayList("Contacts");
            ArrayList<CallContact> tmp2 = data.getParcelableArrayList("Starred");
            mListAdapter.addAll(tmp);
            mGridAdapter.addAll(tmp2);
    
            setListViewListeners();
            setGridViewListeners();
    
            mStarredGrid.post(new Runnable() {
    
                @Override
                public void run() {
                    setGridViewHeight(mStarredGrid, llMain);
                }
            });
    
        }
    
        // Sets the GridView holder's height to fully expand it
        public void setGridViewHeight(GridView gridView, LinearLayout llMain) {
            ListAdapter listAdapter = gridView.getAdapter();
            if (listAdapter == null) {
                return;
            }
    
            int totalHeight = 0;
            int firstHeight = 0;
            int desiredWidth = MeasureSpec.makeMeasureSpec(gridView.getWidth(), MeasureSpec.AT_MOST);
    
            int rows = (listAdapter.getCount() + gridView.getNumColumns() - 1) / gridView.getNumColumns();
    
            for (int i = 0; i < rows; i++) {
    
                if (i == 0) {
                    View listItem = listAdapter.getView(i, null, gridView);
                    listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
                    firstHeight = listItem.getMeasuredHeight();
                }
                totalHeight += firstHeight;
            }
    
            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) llMain.getLayoutParams();
    
            params.height = (int) (totalHeight + (getResources().getDimension(R.dimen.contact_vertical_spacing) * (rows - 1)));
            ;
            llMain.setLayoutParams(params);
            mHeader.requestLayout();
        }
    
        private OnScrollListener mScrollListener = new OnScrollListener() {
            @SuppressLint("NewApi")
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    
                mScrollY = 0;
                int translationY = 0;
    
                if (mContactList.scrollYIsComputed()) {
                    mScrollY = mContactList.getComputedScrollY();
                }
    
                int rawY = mPlaceHolder.getTop() - Math.min(mCachedVerticalScrollRange - mContactList.getHeight(), mScrollY);
    
                switch (mState) {
                case STATE_OFFSCREEN:
                    if (rawY <= mMinRawY) {
                        mMinRawY = rawY;
                    } else {
                        mState = STATE_RETURNING;
                    }
                    translationY = rawY;
                    break;
    
                case STATE_ONSCREEN:
                    if (rawY < -mQuickReturnHeight) {
                        mState = STATE_OFFSCREEN;
                        mMinRawY = rawY;
                    }
                    translationY = rawY;
                    break;
    
                case STATE_RETURNING:
                    translationY = (rawY - mMinRawY) - mQuickReturnHeight;
                    if (translationY > 0) {
                        translationY = 0;
                        mMinRawY = rawY - mQuickReturnHeight;
                    }
    
                    if (rawY > 0) {
                        mState = STATE_ONSCREEN;
                        translationY = rawY;
                    }
    
                    if (translationY < -mQuickReturnHeight) {
                        mState = STATE_OFFSCREEN;
                        mMinRawY = rawY;
                    }
                    break;
                }
    
                mQuickReturnSearchView.setTranslationY(translationY);
    
            }
    
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
            }
        };
    
        @Override
        public void onLoaderReset(Loader<Bundle> loader) {
        }
    
        public void setHandleView(RelativeLayout handle) {
    
            ((ImageButton) handle.findViewById(R.id.contact_search_button)).setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    mContactList.smoothScrollToPosition(0);
                    mQuickReturnSearchView.setOnQueryTextListener(ContactListFragment.this);
                    mQuickReturnSearchView.setIconified(false);
                    mQuickReturnSearchView.setFocusable(true);
                    mCallbacks.openDrawer();
                }
            });
    
        }
    
    }