FolderListFragment.java revision 30fd47bf1947da5ad813cb957b6cbe569dce563a
1/* 2 * Copyright (C) 2012 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package com.android.mail.ui; 19 20import android.app.Activity; 21import android.app.Fragment; 22import android.app.FragmentTransaction; 23import android.app.ListFragment; 24import android.app.LoaderManager; 25import android.content.Context; 26import android.content.CursorLoader; 27import android.content.Loader; 28import android.database.Cursor; 29import android.net.Uri; 30import android.os.Bundle; 31import android.text.TextUtils; 32import android.view.LayoutInflater; 33import android.view.View; 34import android.view.ViewGroup; 35import android.widget.ListView; 36import android.widget.SimpleCursorAdapter; 37 38import com.android.mail.R; 39import com.android.mail.providers.Folder; 40import com.android.mail.providers.UIProvider; 41import com.android.mail.utils.LogUtils; 42 43/** 44 * The folder list UI component. 45 */ 46public final class FolderListFragment extends ListFragment implements 47 LoaderManager.LoaderCallbacks<Cursor>, ViewMode.ModeChangeListener { 48 private static final String LOG_TAG = new LogUtils().getLogTag(); 49 50 private ControllableActivity mActivity; 51 52 // Control state. 53 private Cursor mFolderListCursor; 54 55 // The internal view objects. 56 private ListView mListView; 57 58 private Uri mFolderListUri; 59 60 private FolderChangeListener mListener; 61 62 private Folder mSelectedFolder; 63 64 private static final int FOLDER_LOADER_ID = 0; 65 public static final int MODE_DEFAULT = 0; 66 public static final int MODE_PICK = 1; 67 private static final String ARG_FOLDER_URI = "arg-folder-list-uri"; 68 69 /** 70 * Constructor needs to be public to handle orientation changes and activity lifecycle events. 71 */ 72 public FolderListFragment() { 73 super(); 74 } 75 76 /** 77 * Creates a new instance of {@link ConversationListFragment}, initialized 78 * to display conversation list context. 79 */ 80 public static FolderListFragment newInstance(FolderChangeListener listener, Uri uri) { 81 FolderListFragment fragment = new FolderListFragment(); 82 Bundle args = new Bundle(); 83 args.putString(ARG_FOLDER_URI, uri.toString()); 84 fragment.setArguments(args); 85 return fragment; 86 } 87 88 @Override 89 public void onActivityCreated(Bundle savedState) { 90 super.onActivityCreated(savedState); 91 // Strictly speaking, we get back an android.app.Activity from getActivity. However, the 92 // only activity creating a ConversationListContext is a MailActivity which is of type 93 // ControllableActivity, so this cast should be safe. If this cast fails, some other 94 // activity is creating ConversationListFragments. This activity must be of type 95 // ControllableActivity. 96 final Activity activity = getActivity(); 97 if (! (activity instanceof ControllableActivity)){ 98 LogUtils.wtf(LOG_TAG, "FolderListFragment expects only a ControllableActivity to" + 99 "create it. Cannot proceed."); 100 } 101 mActivity = (ControllableActivity) activity; 102 mActivity.attachFolderList(this); 103 104 if (mActivity.isFinishing()) { 105 // Activity is finishing, just bail. 106 return; 107 } 108 mListener = mActivity.getFolderChangeListener(); 109 final Bundle args = getArguments(); 110 mFolderListUri = Uri.parse(args.getString(ARG_FOLDER_URI)); 111 mListView.setEmptyView(null); 112 getLoaderManager().initLoader(FOLDER_LOADER_ID, Bundle.EMPTY, this); 113 } 114 115 @Override 116 public void onCreate(Bundle savedState) { 117 super.onCreate(savedState); 118 } 119 120 @Override 121 public View onCreateView(LayoutInflater inflater, 122 ViewGroup container, Bundle savedInstanceState) { 123 View rootView = inflater.inflate(R.layout.folder_list, null); 124 mListView = (ListView) rootView.findViewById(android.R.id.list); 125 mListView.setHeaderDividersEnabled(false); 126 mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 127 128 // Note - we manually save/restore the listview state. 129 mListView.setSaveEnabled(false); 130 131 return rootView; 132 } 133 134 @Override 135 public void onDestroyView() { 136 // Clear the adapter. 137 setListAdapter(null); 138 139 mActivity.attachFolderList(null); 140 141 super.onDestroyView(); 142 } 143 144 @Override 145 public void onListItemClick(ListView l, View v, int position, long id) { 146 viewFolder(position); 147 } 148 149 private void viewFolder(int position) { 150 mFolderListCursor.moveToPosition(position); 151 mSelectedFolder = new Folder(mFolderListCursor); 152 if (mSelectedFolder.hasChildren) { 153 // Replace this fragment with a new FolderListFragment 154 // showing this folder's children. 155 FragmentTransaction fragmentTransaction = mActivity.getFragmentManager() 156 .beginTransaction(); 157 fragmentTransaction.addToBackStack(null); 158 final boolean accountChanged = false; 159 // TODO(viki): This account transition looks strange in two pane 160 // mode. Revisit as the app 161 // is coming together and improve the look and feel. 162 final int transition = accountChanged ? FragmentTransaction.TRANSIT_FRAGMENT_FADE 163 : FragmentTransaction.TRANSIT_FRAGMENT_OPEN; 164 fragmentTransaction.setTransition(transition); 165 166 Fragment folderListFragment = FolderListFragment 167 .newInstance(mListener, mSelectedFolder.childFoldersListUri); 168 fragmentTransaction.replace(R.id.content_pane, folderListFragment); 169 170 fragmentTransaction.commitAllowingStateLoss(); 171 172 } else { 173 // Go to the conversation list for this folder. 174 mListener.onFolderChanged(mSelectedFolder); 175 } 176 } 177 178 @Override 179 public void onPause() { 180 super.onPause(); 181 } 182 183 @Override 184 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 185 return new CursorLoader(mActivity.getActivityContext(), mFolderListUri, 186 UIProvider.FOLDERS_PROJECTION, null, null, null); 187 } 188 189 @Override 190 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 191 mFolderListCursor = data; 192 setListAdapter(new FolderListAdapter(mActivity.getActivityContext(), 193 R.layout.folder_item, mFolderListCursor, null, null)); 194 } 195 196 @Override 197 public void onLoaderReset(Loader<Cursor> loader) { 198 // Do nothing. 199 } 200 201 private class FolderListAdapter extends SimpleCursorAdapter { 202 203 public FolderListAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { 204 super(context, layout, c, new String[0], new int[0], 0); 205 } 206 207 @Override 208 public View getView(int position, View convertView, ViewGroup parent) { 209 FolderItemView folderItemView; 210 if (convertView != null) { 211 folderItemView = (FolderItemView) convertView; 212 } else { 213 folderItemView = (FolderItemView) LayoutInflater.from( 214 mActivity.getActivityContext()).inflate(R.layout.folder_item, null); 215 } 216 getCursor().moveToPosition(position); 217 Folder folder = new Folder(getCursor()); 218 folderItemView.bind(folder, null); 219 if (mSelectedFolder != null && TextUtils.equals(folder.id, mSelectedFolder.id)) { 220 getListView().setItemChecked(position, true); 221 } 222 Folder.setFolderBlockColor(folder, folderItemView.findViewById(R.id.folder_box)); 223 return folderItemView; 224 } 225 } 226 227 @Override 228 public void onViewModeChanged(int newMode) { 229 // Listen on mode changes, when we move to Folder list mode, change accordingly. 230 } 231 232 public void selectFolder(Folder folder) { 233 mSelectedFolder = folder; 234 } 235}