GroupDetailFragment.java revision 7979ea27c046dfc2d9305b3282233046acef6ec4
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 17package com.android.contacts.group; 18 19import com.android.contacts.ContactPhotoManager; 20import com.android.contacts.GroupMemberLoader; 21import com.android.contacts.GroupMetaDataLoader; 22import com.android.contacts.R; 23import com.android.contacts.interactions.GroupDeletionDialogFragment; 24import com.android.contacts.list.ContactTileAdapter; 25import com.android.contacts.list.ContactTileAdapter.DisplayType; 26import com.android.contacts.model.AccountType; 27import com.android.contacts.model.AccountTypeManager; 28 29import android.app.Activity; 30import android.app.Fragment; 31import android.app.LoaderManager; 32import android.app.LoaderManager.LoaderCallbacks; 33import android.content.Context; 34import android.content.CursorLoader; 35import android.content.Loader; 36import android.content.res.Resources; 37import android.database.Cursor; 38import android.net.Uri; 39import android.os.Bundle; 40import android.util.Log; 41import android.view.LayoutInflater; 42import android.view.Menu; 43import android.view.MenuInflater; 44import android.view.MenuItem; 45import android.view.View; 46import android.view.ViewGroup; 47import android.widget.AbsListView; 48import android.widget.AbsListView.OnScrollListener; 49import android.widget.ListView; 50import android.widget.TextView; 51 52/** 53 * Displays the details of a group and shows a list of actions possible for the group. 54 */ 55public class GroupDetailFragment extends Fragment implements OnScrollListener { 56 57 public static interface Listener { 58 /** 59 * The group title has been loaded 60 */ 61 public void onGroupTitleUpdated(String title); 62 63 /** 64 * The number of group members has been determined 65 */ 66 public void onGroupSizeUpdated(String size); 67 68 /** 69 * User decided to go to Edit-Mode 70 */ 71 public void onEditRequested(Uri groupUri); 72 73 /** 74 * Contact is selected and should launch details page 75 */ 76 public void onContactSelected(Uri contactUri); 77 } 78 79 private static final String TAG = "GroupDetailFragment"; 80 81 private static final int LOADER_METADATA = 0; 82 private static final int LOADER_MEMBERS = 1; 83 84 private Context mContext; 85 86 private View mRootView; 87 private TextView mGroupTitle; 88 private TextView mGroupSize; 89 private ListView mMemberListView; 90 91 private Listener mListener; 92 93 private ContactTileAdapter mAdapter; 94 private ContactPhotoManager mPhotoManager; 95 private AccountTypeManager mAccountTypeManager; 96 97 private Uri mGroupUri; 98 private long mGroupId; 99 private String mGroupName; 100 private String mAccountTypeString; 101 102 private boolean mOptionsMenuEditable; 103 private boolean mCloseActivityAfterDelete; 104 105 public GroupDetailFragment() { 106 } 107 108 @Override 109 public void onAttach(Activity activity) { 110 super.onAttach(activity); 111 mContext = activity; 112 mAccountTypeManager = AccountTypeManager.getInstance(mContext); 113 114 Resources res = getResources(); 115 int columnCount = res.getInteger(R.integer.contact_tile_column_count); 116 117 mAdapter = new ContactTileAdapter(activity, mContactTileListener, columnCount, 118 DisplayType.GROUP_MEMBERS); 119 120 configurePhotoLoader(); 121 } 122 123 @Override 124 public void onDetach() { 125 super.onDetach(); 126 mContext = null; 127 } 128 129 @Override 130 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { 131 setHasOptionsMenu(true); 132 mRootView = inflater.inflate(R.layout.group_detail_fragment, container, false); 133 mGroupTitle = (TextView) mRootView.findViewById(R.id.group_title); 134 mGroupSize = (TextView) mRootView.findViewById(R.id.group_size); 135 mMemberListView = (ListView) mRootView.findViewById(android.R.id.list); 136 137 return mRootView; 138 } 139 140 public void loadGroup(Uri groupUri) { 141 mGroupUri= groupUri; 142 startGroupMetadataLoader(); 143 } 144 145 public void setQuickContact(boolean enableQuickContact) { 146 mAdapter.enableQuickContact(enableQuickContact); 147 } 148 149 private void configureAdapter(long groupId) { 150 mGroupId = groupId; 151 mMemberListView.setAdapter(mAdapter); 152 } 153 154 private void configurePhotoLoader() { 155 if (mContext != null) { 156 if (mPhotoManager == null) { 157 mPhotoManager = ContactPhotoManager.getInstance(mContext); 158 } 159 if (mMemberListView != null) { 160 mMemberListView.setOnScrollListener(this); 161 } 162 if (mAdapter != null) { 163 mAdapter.setPhotoLoader(mPhotoManager); 164 } 165 } 166 } 167 168 public void setListener(Listener value) { 169 mListener = value; 170 } 171 172 /** 173 * Start the loader to retrieve the metadata for this group. 174 */ 175 private void startGroupMetadataLoader() { 176 getLoaderManager().destroyLoader(LOADER_METADATA); 177 getLoaderManager().restartLoader(LOADER_METADATA, null, mGroupMetadataLoaderListener); 178 } 179 180 /** 181 * Start the loader to retrieve the list of group members. 182 */ 183 private void startGroupMembersLoader() { 184 getLoaderManager().destroyLoader(LOADER_MEMBERS); 185 getLoaderManager().restartLoader(LOADER_MEMBERS, null, mGroupMemberListLoaderListener); 186 } 187 188 private final ContactTileAdapter.Listener mContactTileListener = 189 new ContactTileAdapter.Listener() { 190 191 @Override 192 public void onContactSelected(Uri contactUri) { 193 mListener.onContactSelected(contactUri); 194 } 195 }; 196 197 /** 198 * The listener for the group metadata loader. 199 */ 200 private final LoaderManager.LoaderCallbacks<Cursor> mGroupMetadataLoaderListener = 201 new LoaderCallbacks<Cursor>() { 202 203 @Override 204 public CursorLoader onCreateLoader(int id, Bundle args) { 205 return new GroupMetaDataLoader(mContext, mGroupUri); 206 } 207 208 @Override 209 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 210 data.moveToPosition(-1); 211 if (data.moveToNext()) { 212 boolean deleted = data.getInt(GroupMetaDataLoader.DELETED) == 1; 213 if (!deleted) { 214 bindGroupMetaData(data); 215 216 // Retrieve the list of members 217 configureAdapter(mGroupId); 218 startGroupMembersLoader(); 219 return; 220 } 221 } 222 updateSize(-1); 223 updateTitle(null); 224 } 225 226 @Override 227 public void onLoaderReset(Loader<Cursor> loader) {} 228 }; 229 230 /** 231 * The listener for the group members list loader 232 */ 233 private final LoaderManager.LoaderCallbacks<Cursor> mGroupMemberListLoaderListener = 234 new LoaderCallbacks<Cursor>() { 235 236 @Override 237 public CursorLoader onCreateLoader(int id, Bundle args) { 238 return new GroupMemberLoader(mContext, mGroupId); 239 } 240 241 @Override 242 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 243 updateSize(data.getCount()); 244 mAdapter.setContactCursor(data); 245 } 246 247 @Override 248 public void onLoaderReset(Loader<Cursor> loader) {} 249 }; 250 251 private void bindGroupMetaData(Cursor cursor) { 252 cursor.moveToPosition(-1); 253 if (cursor.moveToNext()) { 254 mAccountTypeString = cursor.getString(GroupMetaDataLoader.ACCOUNT_TYPE); 255 mGroupId = cursor.getLong(GroupMetaDataLoader.GROUP_ID); 256 mGroupName = cursor.getString(GroupMetaDataLoader.TITLE); 257 updateTitle(mGroupName); 258 259 // TODO: Replace by real button 260 final String action = cursor.getString(GroupMetaDataLoader.ACTION); 261 final String actionUri = cursor.getString(GroupMetaDataLoader.ACTION_URI); 262 Log.d(TAG, "Group open action: " + action + ", uri: " + actionUri); 263 } 264 } 265 266 private void updateTitle(String title) { 267 if (mGroupTitle != null) { 268 mGroupTitle.setText(title); 269 } else { 270 mListener.onGroupTitleUpdated(title); 271 } 272 } 273 274 /** 275 * Display the count of the number of group members. 276 * @param size of the group (can be -1 if no size could be determined) 277 */ 278 private void updateSize(int size) { 279 String groupSizeString; 280 if (size == -1) { 281 groupSizeString = null; 282 } else { 283 String groupSizeTemplateString = getResources().getQuantityString( 284 R.plurals.num_contacts_in_group, size); 285 AccountType accountType = mAccountTypeManager.getAccountType(mAccountTypeString); 286 groupSizeString = String.format(groupSizeTemplateString, size, 287 accountType.getDisplayLabel(mContext)); 288 } 289 290 if (mGroupSize != null) { 291 mGroupSize.setText(groupSizeString); 292 } else { 293 mListener.onGroupSizeUpdated(groupSizeString); 294 } 295 } 296 297 @Override 298 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 299 int totalItemCount) { 300 } 301 302 @Override 303 public void onScrollStateChanged(AbsListView view, int scrollState) { 304 if (scrollState == OnScrollListener.SCROLL_STATE_FLING) { 305 mPhotoManager.pause(); 306 } else { 307 mPhotoManager.resume(); 308 } 309 } 310 311 @Override 312 public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) { 313 inflater.inflate(R.menu.view_group, menu); 314 } 315 316 public boolean isOptionsMenuChanged() { 317 return mOptionsMenuEditable != isGroupEditable(); 318 } 319 320 public boolean isGroupEditable() { 321 // TODO: This should check the group_is_read_only flag. Modify GroupMetaDataLoader. 322 // Bug: 4601729. 323 return mGroupUri != null; 324 } 325 326 @Override 327 public void onPrepareOptionsMenu(Menu menu) { 328 mOptionsMenuEditable = isGroupEditable(); 329 330 final MenuItem editMenu = menu.findItem(R.id.menu_edit_group); 331 editMenu.setVisible(mOptionsMenuEditable); 332 333 final MenuItem deleteMenu = menu.findItem(R.id.menu_delete_group); 334 deleteMenu.setVisible(mOptionsMenuEditable); 335 } 336 337 @Override 338 public boolean onOptionsItemSelected(MenuItem item) { 339 switch (item.getItemId()) { 340 case R.id.menu_edit_group: { 341 if (mListener != null) mListener.onEditRequested(mGroupUri); 342 break; 343 } 344 case R.id.menu_delete_group: { 345 GroupDeletionDialogFragment.show(getFragmentManager(), mGroupId, mGroupName, 346 mCloseActivityAfterDelete); 347 return true; 348 } 349 } 350 return false; 351 } 352 353 public void closeActivityAfterDelete(boolean closeActivity) { 354 mCloseActivityAfterDelete = closeActivity; 355 } 356} 357