SingleFolderSelectionDialog.java revision 9eb1c9a76a400f84c002b58c831119119ebf4870
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.AlertDialog;
21import android.app.AlertDialog.Builder;
22import android.content.Context;
23import android.content.DialogInterface;
24import android.content.DialogInterface.OnClickListener;
25import android.database.Cursor;
26import android.os.AsyncTask;
27import android.view.View;
28import android.widget.AdapterView;
29
30import com.android.mail.R;
31import com.android.mail.providers.Account;
32import com.android.mail.providers.Conversation;
33import com.android.mail.providers.Folder;
34import com.android.mail.providers.UIProvider;
35import com.android.mail.ui.FolderSelectorAdapter.FolderRow;
36import com.android.mail.utils.Utils;
37
38import java.util.ArrayList;
39import java.util.Collection;
40
41/**
42 * Displays a folder selection dialog for the conversation provided. It allows
43 * the user to switch a conversation from one folder to another.
44 */
45public class SingleFolderSelectionDialog extends FolderSelectionDialog implements OnClickListener {
46    private AlertDialog mDialog;
47    private ConversationUpdater mUpdater;
48    private SeparatedFolderListAdapter mAdapter;
49    private final Collection<Conversation> mTarget;
50    private boolean mBatch;
51    final QueryRunner mRunner;
52    private Folder mExcludeFolder;
53    private Builder mBuilder;
54    private Account mAccount;
55
56    public static SingleFolderSelectionDialog getInstance(final Context context, Account account,
57            final ConversationUpdater updater, Collection<Conversation> target, boolean isBatch,
58            Folder currentFolder) {
59        if (isShown()) {
60            return null;
61        }
62        return new SingleFolderSelectionDialog(
63                context, account, updater, target, isBatch, currentFolder);
64    }
65
66    /**
67     * Create a new {@link SingleFolderSelectionDialog}. It is displayed when
68     * the {@link #show()} method is called.
69     * @param context
70     * @param account the current account
71     * @param updater
72     * @param target conversations that are impacted
73     * @param isBatch whether the dialog is shown during Contextual Action Bar
74     *            (CAB) mode
75     * @param currentFolder the current folder that the
76     *            {@link FolderListFragment} is showing
77     */
78    private SingleFolderSelectionDialog(final Context context, Account account,
79            final ConversationUpdater updater, Collection<Conversation> target, boolean isBatch,
80            Folder currentFolder) {
81        mUpdater = updater;
82        mTarget = target;
83        mBatch = isBatch;
84        mExcludeFolder = currentFolder;
85        mBuilder = new AlertDialog.Builder(context);
86        mBuilder.setTitle(R.string.folder_selection_dialog_title);
87        mBuilder.setNegativeButton(R.string.cancel, this);
88        mAccount = account;
89        mAdapter = new SeparatedFolderListAdapter(context);
90        mRunner = new QueryRunner(context);
91    }
92
93    /**
94     * Class to query the Folder list database in the background and update the adapter with an
95     * open cursor.
96     */
97    private final class QueryRunner extends AsyncTask<Void, Void, Void> {
98        private final Context mContext;
99
100        private QueryRunner(final Context context){
101            mContext = context;
102        }
103
104        @Override
105        protected Void doInBackground(Void... v) {
106            Cursor foldersCursor = null;
107            try {
108                foldersCursor = mContext.getContentResolver().query(
109                        !Utils.isEmpty(mAccount.fullFolderListUri) ? mAccount.fullFolderListUri
110                                : mAccount.folderListUri, UIProvider.FOLDERS_PROJECTION, null,
111                        null, null);
112                // TODO(mindyp) : bring this back in UR8 when Email providers
113                // will have divided folder sections.
114                final String[] headers = mContext.getResources().getStringArray(
115                        R.array.moveto_folder_sections);
116                // Currently, the number of adapters are assumed to match the
117                // number of headers in the string array.
118                mAdapter.addSection(new SystemFolderSelectorAdapter(mContext, foldersCursor,
119                        R.layout.single_folders_view, null, mExcludeFolder));
120
121                // TODO(mindyp): we currently do not support frequently moved to
122                // folders, at headers[1]; need to define what that means.*/
123                mAdapter.addSection(new HierarchicalFolderSelectorAdapter(mContext,
124                        AddableFolderSelectorAdapter.filterFolders(foldersCursor),
125                        R.layout.single_folders_view, headers[2], mExcludeFolder));
126                mBuilder.setAdapter(mAdapter, SingleFolderSelectionDialog.this);
127            } finally {
128                if (foldersCursor != null) {
129                    foldersCursor.close();
130                }
131            }
132            return null;
133        }
134
135        @Override
136        protected void onPostExecute(Void v) {
137            mDialog = mBuilder.create();
138            showInternal();
139        }
140    }
141
142    /**
143     * Shows the {@link SingleFolderSelectionDialog} dialog.
144     */
145    @Override
146    public void show() {
147        super.show();
148        mRunner.execute();
149    }
150
151    /**
152     * Shows the dialog after a database query has occurred.
153     */
154    private final void showInternal() {
155        mDialog.show();
156        mDialog.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
157            @Override
158            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
159                final Object item = mAdapter.getItem(position);
160                if (item instanceof FolderRow) {
161                    final Folder folder = ((FolderRow) item).getFolder();
162                    ArrayList<FolderOperation> ops = new ArrayList<FolderOperation>();
163                    // Remove the current folder and add the new folder.
164                    ops.add(new FolderOperation(mExcludeFolder, false));
165                    ops.add(new FolderOperation(folder, true));
166                    mUpdater.assignFolder(ops, mTarget, mBatch, true);
167                    mDialog.dismiss();
168                }
169            }
170        });
171        mDialog.setOnDismissListener(this);
172    }
173
174    @Override
175    public void onClick(DialogInterface dialog, int which) {
176        // Do nothing.
177    }
178}
179