Home | History | Annotate | Download | only in ui
      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 
     18 package com.android.mail.ui;
     19 
     20 import android.app.AlertDialog;
     21 import android.app.LoaderManager;
     22 import android.content.Context;
     23 import android.content.CursorLoader;
     24 import android.content.DialogInterface;
     25 import android.content.Loader;
     26 import android.database.Cursor;
     27 import android.net.Uri;
     28 import android.os.Bundle;
     29 
     30 import com.android.mail.R;
     31 import com.android.mail.providers.Conversation;
     32 import com.android.mail.providers.Folder;
     33 import com.android.mail.providers.UIProvider;
     34 import com.android.mail.providers.UIProvider.FolderType;
     35 import com.android.mail.ui.FolderSelectorAdapter.FolderRow;
     36 import com.android.mail.utils.Utils;
     37 import com.google.common.collect.ImmutableSet;
     38 
     39 import java.util.Arrays;
     40 import java.util.HashMap;
     41 import java.util.HashSet;
     42 import java.util.List;
     43 import java.util.Map;
     44 import java.util.Set;
     45 
     46 /**
     47  * Displays a folder selection dialog for the conversation provided. It allows
     48  * the user to mark folders to assign that conversation to.
     49  */
     50 public class MultiFoldersSelectionDialog extends FolderSelectionDialog {
     51     private boolean mSingle;
     52     private final HashMap<Uri, FolderOperation> mOperations;
     53 
     54     public MultiFoldersSelectionDialog() {
     55         mOperations = new HashMap<Uri, FolderOperation>();
     56     }
     57 
     58     private static final int FOLDER_LOADER_ID = 0;
     59     private static final String FOLDER_QUERY_URI_TAG = "folderQueryUri";
     60 
     61     private static final String SAVESTATE_OPERATIONS_TAG = "operations";
     62 
     63     @Override
     64     public void onCreate(Bundle savedInstanceState) {
     65         super.onCreate(savedInstanceState);
     66 
     67         mSingle = !mAccount
     68                 .supportsCapability(UIProvider.AccountCapabilities.MULTIPLE_FOLDERS_PER_CONV);
     69         mTitleId = R.string.change_folders_selection_dialog_title;
     70 
     71         if (savedInstanceState != null) {
     72             final FolderOperation[] savedOps = (FolderOperation[])
     73                     savedInstanceState.getParcelableArray(SAVESTATE_OPERATIONS_TAG);
     74             for (final FolderOperation op : savedOps) {
     75                 mOperations.put(op.mFolder.folderUri.fullUri, op);
     76             }
     77         }
     78 
     79         final Bundle args = new Bundle(1);
     80         args.putParcelable(FOLDER_QUERY_URI_TAG, !Utils.isEmpty(mAccount.fullFolderListUri) ?
     81                 mAccount.fullFolderListUri : mAccount.folderListUri);
     82         final Context loaderContext = getActivity().getApplicationContext();
     83         getLoaderManager().initLoader(FOLDER_LOADER_ID, args,
     84                 new LoaderManager.LoaderCallbacks<Cursor>() {
     85                     @Override
     86                     public Loader<Cursor> onCreateLoader(int id, Bundle args) {
     87                         final Uri queryUri = args.getParcelable(FOLDER_QUERY_URI_TAG);
     88                         return new CursorLoader(loaderContext, queryUri,
     89                                 UIProvider.FOLDERS_PROJECTION, null, null, null);
     90                     }
     91 
     92                     @Override
     93                     public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
     94                         final Context context = getActivity();
     95                         if (data == null || context == null) {
     96                             return;
     97                         }
     98                         final AlertDialog dialog = (AlertDialog) getDialog();
     99                         if (dialog == null) {
    100                             // This could happen if the dialog is dismissed just before the
    101                             // load finishes.
    102                             return;
    103                         }
    104                         // The number of view types changes here, so we have to reset the listview's
    105                         // adapter.
    106                         dialog.getListView().setAdapter(null);
    107                         dialog.getListView().setDivider(null);
    108 
    109                         final HashSet<String> checked = new HashSet<String>();
    110                         for (final Conversation conversation : mTarget) {
    111                             final List<Folder> rawFolders = conversation.getRawFolders();
    112                             if (rawFolders != null && rawFolders.size() > 0) {
    113                                 // Parse the raw folders and get all the uris.
    114                                 checked.addAll(Arrays.asList(Folder.getUriArray(rawFolders)));
    115                             } else {
    116                                 // There are no folders for this conversation, so it must
    117                                 // belong to the folder we are currently looking at.
    118                                 checked.add(mCurrentFolder.folderUri.fullUri.toString());
    119                             }
    120                         }
    121                         final Set<String> originalChecked = ImmutableSet.copyOf(checked);
    122                         for (final Map.Entry<Uri, FolderOperation> entry : mOperations.entrySet()) {
    123                             if (entry.getValue().mAdd) {
    124                                 checked.add(entry.getKey().toString());
    125                             } else {
    126                                 checked.remove(entry.getKey().toString());
    127                             }
    128                         }
    129                         mAdapter.clearSections();
    130                         // TODO(mindyp) : bring this back in UR8 when Email providers
    131                         // will have divided folder sections.
    132                         /* final String[] headers = mContext.getResources()
    133                                 .getStringArray(R.array.moveto_folder_sections);
    134                          // Currently, the number of adapters are assumed to match the
    135                          // number of headers in the string array.
    136                          mAdapter.addSection(new SystemFolderSelectorAdapter(mContext,
    137                          foldersCursor, checked, R.layout.multi_folders_view, null));
    138 
    139                         // TODO(mindyp): we currently do not support frequently moved to
    140                         // folders, at headers[1]; need to define what that means.*/
    141 
    142                         Cursor c = AddableFolderSelectorAdapter.filterFolders(data,
    143                                 ImmutableSet.of(FolderType.INBOX_SECTION), originalChecked,
    144                                 true /* includeOnlyInitiallySelected */);
    145                         if (c.getCount() > 0) {
    146                             mAdapter.addSection(new AddableFolderSelectorAdapter(context, c,
    147                                     checked, R.layout.multi_folders_view));
    148                         }
    149 
    150                         c = AddableFolderSelectorAdapter.filterFolders(data,
    151                                 ImmutableSet.of(FolderType.INBOX_SECTION), originalChecked,
    152                                 false /* includeOnlyInitiallySelected */);
    153                         if (c.getCount() > 0) {
    154                             mAdapter.addSection(new AddableFolderSelectorAdapter(context, c,
    155                                     checked, R.layout.multi_folders_view));
    156                         }
    157 
    158                         dialog.getListView().setAdapter(mAdapter);
    159                     }
    160 
    161                     @Override
    162                     public void onLoaderReset(Loader<Cursor> loader) {
    163                         mAdapter.clearSections();
    164                     }
    165                 });
    166     }
    167 
    168     @Override
    169     public void onSaveInstanceState(Bundle outState) {
    170         super.onSaveInstanceState(outState);
    171         outState.putParcelableArray(SAVESTATE_OPERATIONS_TAG,
    172                 mOperations.values().toArray(new FolderOperation[mOperations.size()]));
    173     }
    174 
    175     @Override
    176     protected void onListItemClick(int position) {
    177         final Object item = mAdapter.getItem(position);
    178         if (item instanceof FolderRow) {
    179             update((FolderRow) item);
    180         }
    181     }
    182 
    183     /**
    184      * Call this to update the state of folders as a result of them being
    185      * selected / de-selected.
    186      *
    187      * @param row The item being updated.
    188      */
    189     private void update(FolderSelectorAdapter.FolderRow row) {
    190         final boolean add = !row.isSelected();
    191         if (mSingle) {
    192             if (!add) {
    193                 // This would remove the check on a single radio button, so just
    194                 // return.
    195                 return;
    196             }
    197             // Clear any other checked items.
    198             for (int i = 0, size = mAdapter.getCount(); i < size; i++) {
    199                 final Object item = mAdapter.getItem(i);
    200                 if (item instanceof FolderRow) {
    201                    ((FolderRow)item).setIsSelected(false);
    202                    final Folder folder = ((FolderRow)item).getFolder();
    203                    mOperations.put(folder.folderUri.fullUri,
    204                            new FolderOperation(folder, false));
    205                 }
    206             }
    207         }
    208         row.setIsSelected(add);
    209         mAdapter.notifyDataSetChanged();
    210         final Folder folder = row.getFolder();
    211         mOperations.put(folder.folderUri.fullUri, new FolderOperation(folder, add));
    212     }
    213 
    214     @Override
    215     public void onClick(DialogInterface dialog, int which) {
    216         switch (which) {
    217             case DialogInterface.BUTTON_POSITIVE:
    218                 getConversationUpdater().assignFolder(mOperations.values(), mTarget, mBatch,
    219                         true /* showUndo */, false /* isMoveTo */);
    220                 break;
    221             case DialogInterface.BUTTON_NEGATIVE:
    222                 break;
    223             default:
    224                 break;
    225         }
    226     }
    227 }
    228