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}