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