• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 
17 package com.android.contacts.group;
18 
19 import com.android.contacts.ContactsUtils;
20 import com.android.contacts.GroupListLoader;
21 import com.android.contacts.R;
22 import com.android.contacts.group.GroupBrowseListAdapter.GroupListItemViewCache;
23 import com.android.contacts.widget.AutoScrollListView;
24 
25 import android.app.Activity;
26 import android.app.Fragment;
27 import android.app.LoaderManager;
28 import android.app.LoaderManager.LoaderCallbacks;
29 import android.content.Context;
30 import android.content.CursorLoader;
31 import android.content.Intent;
32 import android.content.Loader;
33 import android.database.Cursor;
34 import android.net.Uri;
35 import android.os.Bundle;
36 import android.os.Parcelable;
37 import android.provider.ContactsContract;
38 import android.provider.Settings;
39 import android.text.TextUtils;
40 import android.view.LayoutInflater;
41 import android.view.MotionEvent;
42 import android.view.View;
43 import android.view.View.OnClickListener;
44 import android.view.View.OnFocusChangeListener;
45 import android.view.View.OnTouchListener;
46 import android.view.ViewGroup;
47 import android.view.inputmethod.InputMethodManager;
48 import android.widget.AdapterView;
49 import android.widget.AdapterView.OnItemClickListener;
50 import android.widget.ListView;
51 import android.widget.TextView;
52 
53 /**
54  * Fragment to display the list of groups.
55  */
56 public class GroupBrowseListFragment extends Fragment
57         implements OnFocusChangeListener, OnTouchListener {
58 
59     /**
60      * Action callbacks that can be sent by a group list.
61      */
62     public interface OnGroupBrowserActionListener  {
63 
64         /**
65          * Opens the specified group for viewing.
66          *
67          * @param groupUri for the group that the user wishes to view.
68          */
onViewGroupAction(Uri groupUri)69         void onViewGroupAction(Uri groupUri);
70 
71     }
72 
73     private static final String TAG = "GroupBrowseListFragment";
74 
75     private static final int LOADER_GROUPS = 1;
76 
77     private Context mContext;
78     private Cursor mGroupListCursor;
79 
80     private boolean mSelectionToScreenRequested;
81 
82     private static final String EXTRA_KEY_GROUP_URI = "groups.groupUri";
83 
84     private View mRootView;
85     private AutoScrollListView mListView;
86     private TextView mEmptyView;
87     private View mAddAccountsView;
88     private View mAddAccountButton;
89 
90     private GroupBrowseListAdapter mAdapter;
91     private boolean mSelectionVisible;
92     private Uri mSelectedGroupUri;
93 
94     private int mVerticalScrollbarPosition = View.SCROLLBAR_POSITION_RIGHT;
95 
96     private OnGroupBrowserActionListener mListener;
97 
GroupBrowseListFragment()98     public GroupBrowseListFragment() {
99     }
100 
101     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)102     public View onCreateView(LayoutInflater inflater, ViewGroup container,
103             Bundle savedInstanceState) {
104         if (savedInstanceState != null) {
105             mSelectedGroupUri = savedInstanceState.getParcelable(EXTRA_KEY_GROUP_URI);
106             if (mSelectedGroupUri != null) {
107                 // The selection may be out of screen, if rotated from portrait to landscape,
108                 // so ensure it's visible.
109                 mSelectionToScreenRequested = true;
110             }
111         }
112 
113         mRootView = inflater.inflate(R.layout.group_browse_list_fragment, null);
114         mEmptyView = (TextView)mRootView.findViewById(R.id.empty);
115 
116         mAdapter = new GroupBrowseListAdapter(mContext);
117         mAdapter.setSelectionVisible(mSelectionVisible);
118         mAdapter.setSelectedGroup(mSelectedGroupUri);
119 
120         mListView = (AutoScrollListView) mRootView.findViewById(R.id.list);
121         mListView.setOnFocusChangeListener(this);
122         mListView.setOnTouchListener(this);
123         mListView.setAdapter(mAdapter);
124         mListView.setOnItemClickListener(new OnItemClickListener() {
125             @Override
126             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
127                 GroupListItemViewCache groupListItem = (GroupListItemViewCache) view.getTag();
128                 if (groupListItem != null) {
129                     viewGroup(groupListItem.getUri());
130                 }
131             }
132         });
133 
134         mListView.setEmptyView(mEmptyView);
135         mAddAccountsView = mRootView.findViewById(R.id.add_accounts);
136         mAddAccountButton = mRootView.findViewById(R.id.add_account_button);
137         mAddAccountButton.setOnClickListener(new OnClickListener() {
138             @Override
139             public void onClick(View v) {
140                 Intent intent = new Intent(Settings.ACTION_ADD_ACCOUNT);
141                 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
142                 intent.putExtra(Settings.EXTRA_AUTHORITIES,
143                         new String[] { ContactsContract.AUTHORITY });
144                 startActivity(intent);
145             }
146         });
147         setAddAccountsVisibility(!ContactsUtils.areGroupWritableAccountsAvailable(mContext));
148 
149         return mRootView;
150     }
151 
setVerticalScrollbarPosition(int position)152     public void setVerticalScrollbarPosition(int position) {
153         if (mVerticalScrollbarPosition != position) {
154             mVerticalScrollbarPosition = position;
155             configureVerticalScrollbar();
156         }
157     }
158 
configureVerticalScrollbar()159     private void configureVerticalScrollbar() {
160         mListView.setVerticalScrollbarPosition(mVerticalScrollbarPosition);
161         mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
162         int leftPadding = 0;
163         int rightPadding = 0;
164         if (mVerticalScrollbarPosition == View.SCROLLBAR_POSITION_LEFT) {
165             leftPadding = mContext.getResources().getDimensionPixelOffset(
166                     R.dimen.list_visible_scrollbar_padding);
167         } else {
168             rightPadding = mContext.getResources().getDimensionPixelOffset(
169                     R.dimen.list_visible_scrollbar_padding);
170         }
171         mListView.setPadding(leftPadding, mListView.getPaddingTop(),
172                 rightPadding, mListView.getPaddingBottom());
173     }
174 
175     @Override
onAttach(Activity activity)176     public void onAttach(Activity activity) {
177         super.onAttach(activity);
178         mContext = activity;
179     }
180 
181     @Override
onDetach()182     public void onDetach() {
183         super.onDetach();
184         mContext = null;
185     }
186 
187     @Override
onStart()188     public void onStart() {
189         getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener);
190         super.onStart();
191     }
192 
193     /**
194      * The listener for the group meta data loader for all groups.
195      */
196     private final LoaderManager.LoaderCallbacks<Cursor> mGroupLoaderListener =
197             new LoaderCallbacks<Cursor>() {
198 
199         @Override
200         public CursorLoader onCreateLoader(int id, Bundle args) {
201             mEmptyView.setText(null);
202             return new GroupListLoader(mContext);
203         }
204 
205         @Override
206         public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
207             mGroupListCursor = data;
208             bindGroupList();
209         }
210 
211         public void onLoaderReset(Loader<Cursor> loader) {
212         }
213     };
214 
bindGroupList()215     private void bindGroupList() {
216         mEmptyView.setText(R.string.noGroups);
217         setAddAccountsVisibility(!ContactsUtils.areGroupWritableAccountsAvailable(mContext));
218         if (mGroupListCursor == null) {
219             return;
220         }
221         mAdapter.setCursor(mGroupListCursor);
222 
223         if (mSelectionToScreenRequested) {
224             mSelectionToScreenRequested = false;
225             requestSelectionToScreen();
226         }
227 
228         mSelectedGroupUri = mAdapter.getSelectedGroup();
229         if (mSelectionVisible && mSelectedGroupUri != null) {
230             viewGroup(mSelectedGroupUri);
231         }
232     }
233 
setListener(OnGroupBrowserActionListener listener)234     public void setListener(OnGroupBrowserActionListener listener) {
235         mListener = listener;
236     }
237 
setSelectionVisible(boolean flag)238     public void setSelectionVisible(boolean flag) {
239         mSelectionVisible = flag;
240         if (mAdapter != null) {
241             mAdapter.setSelectionVisible(mSelectionVisible);
242         }
243     }
244 
setSelectedGroup(Uri groupUri)245     private void setSelectedGroup(Uri groupUri) {
246         mSelectedGroupUri = groupUri;
247         mAdapter.setSelectedGroup(groupUri);
248         mListView.invalidateViews();
249     }
250 
viewGroup(Uri groupUri)251     private void viewGroup(Uri groupUri) {
252         setSelectedGroup(groupUri);
253         if (mListener != null) mListener.onViewGroupAction(groupUri);
254     }
255 
setSelectedUri(Uri groupUri)256     public void setSelectedUri(Uri groupUri) {
257         viewGroup(groupUri);
258         mSelectionToScreenRequested = true;
259     }
260 
requestSelectionToScreen()261     protected void requestSelectionToScreen() {
262         if (!mSelectionVisible) {
263             return; // If selection isn't visible we don't care.
264         }
265         int selectedPosition = mAdapter.getSelectedGroupPosition();
266         if (selectedPosition != -1) {
267             mListView.requestPositionToScreen(selectedPosition,
268                     true /* smooth scroll requested */);
269         }
270     }
271 
hideSoftKeyboard()272     private void hideSoftKeyboard() {
273         if (mContext == null) {
274             return;
275         }
276         // Hide soft keyboard, if visible
277         InputMethodManager inputMethodManager = (InputMethodManager)
278                 mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
279         inputMethodManager.hideSoftInputFromWindow(mListView.getWindowToken(), 0);
280     }
281 
282     /**
283      * Dismisses the soft keyboard when the list takes focus.
284      */
285     @Override
onFocusChange(View view, boolean hasFocus)286     public void onFocusChange(View view, boolean hasFocus) {
287         if (view == mListView && hasFocus) {
288             hideSoftKeyboard();
289         }
290     }
291 
292     /**
293      * Dismisses the soft keyboard when the list is touched.
294      */
295     @Override
onTouch(View view, MotionEvent event)296     public boolean onTouch(View view, MotionEvent event) {
297         if (view == mListView) {
298             hideSoftKeyboard();
299         }
300         return false;
301     }
302 
303     @Override
onSaveInstanceState(Bundle outState)304     public void onSaveInstanceState(Bundle outState) {
305         super.onSaveInstanceState(outState);
306         outState.putParcelable(EXTRA_KEY_GROUP_URI, mSelectedGroupUri);
307     }
308 
setAddAccountsVisibility(boolean visible)309     public void setAddAccountsVisibility(boolean visible) {
310         if (mAddAccountsView != null) {
311             mAddAccountsView.setVisibility(visible ? View.VISIBLE : View.GONE);
312         }
313     }
314 }
315