Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2012 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 
     17 package com.android.mail.ui;
     18 
     19 import android.app.Fragment;
     20 import android.app.FragmentTransaction;
     21 import android.appwidget.AppWidgetManager;
     22 import android.content.ContentResolver;
     23 import android.content.Context;
     24 import android.content.DialogInterface;
     25 import android.content.Intent;
     26 import android.database.DataSetObservable;
     27 import android.database.DataSetObserver;
     28 import android.os.Bundle;
     29 import android.support.v7.app.ActionBarActivity;
     30 import android.view.DragEvent;
     31 import android.view.View;
     32 import android.view.View.OnClickListener;
     33 import android.widget.Button;
     34 import android.widget.ListView;
     35 
     36 import com.android.bitmap.BitmapCache;
     37 import com.android.mail.R;
     38 import com.android.mail.bitmap.ContactResolver;
     39 import com.android.mail.providers.Account;
     40 import com.android.mail.providers.Folder;
     41 import com.android.mail.providers.FolderWatcher;
     42 import com.android.mail.utils.LogTag;
     43 import com.android.mail.utils.LogUtils;
     44 import com.android.mail.utils.MailObservable;
     45 import com.android.mail.utils.Utils;
     46 import com.android.mail.utils.VeiledAddressMatcher;
     47 import com.android.mail.widget.WidgetProvider;
     48 
     49 import java.util.ArrayList;
     50 
     51 /**
     52  * This activity displays the list of available folders for the current account.
     53  */
     54 public class FolderSelectionActivity extends ActionBarActivity implements OnClickListener,
     55         DialogInterface.OnClickListener, FolderChangeListener, ControllableActivity,
     56         FolderSelector {
     57     public static final String EXTRA_ACCOUNT_SHORTCUT = "account-shortcut";
     58 
     59     private static final String LOG_TAG = LogTag.getLogTag();
     60 
     61     private static final int CONFIGURE = 0;
     62 
     63     private static final int VIEW = 1;
     64 
     65     private Account mAccount;
     66     private Folder mSelectedFolder;
     67     private boolean mConfigureShortcut;
     68     protected boolean mConfigureWidget;
     69     private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
     70     private int mMode = -1;
     71     /** Empty placeholder for communicating to the consumer of the drawer observer. */
     72     private final DataSetObservable mFolderOrAccountObservers =
     73             new MailObservable("FolderOrAccount");
     74 
     75     private final AccountController mAccountController = new AccountController() {
     76         @Override
     77         public void registerAccountObserver(DataSetObserver observer) {
     78             // Do nothing
     79         }
     80 
     81         @Override
     82         public void unregisterAccountObserver(DataSetObserver observer) {
     83             // Do nothing
     84         }
     85 
     86         @Override
     87         public Account getAccount() {
     88             return mAccount;
     89         }
     90 
     91         @Override
     92         public void registerAllAccountObserver(DataSetObserver observer) {
     93             // Do nothing
     94         }
     95 
     96         @Override
     97         public void unregisterAllAccountObserver(DataSetObserver observer) {
     98             // Do nothing
     99         }
    100 
    101         @Override
    102         public Account[] getAllAccounts() {
    103             return new Account[]{mAccount};
    104         }
    105 
    106         @Override
    107         public VeiledAddressMatcher getVeiledAddressMatcher() {
    108             return null;
    109         }
    110 
    111         @Override
    112         public void switchToDefaultInboxOrChangeAccount(Account account) {
    113             // Never gets called, so do nothing here.
    114             LogUtils.wtf(LOG_TAG,"FolderSelectionActivity.switchToDefaultInboxOrChangeAccount() " +
    115                     "called when NOT expected.");
    116         }
    117 
    118         @Override
    119         public void registerFolderOrAccountChangedObserver(final DataSetObserver observer) {
    120             mFolderOrAccountObservers.registerObserver(observer);
    121         }
    122 
    123         @Override
    124         public void unregisterFolderOrAccountChangedObserver(final DataSetObserver observer) {
    125             mFolderOrAccountObservers.unregisterObserver(observer);
    126         }
    127 
    128         /**
    129          * Since there is no drawer to wait for, notifyChanged to the observers.
    130          */
    131         @Override
    132         public void closeDrawer(final boolean hasNewFolderOrAccount,
    133                 Account account, Folder folder) {
    134             mFolderOrAccountObservers.notifyChanged();
    135         }
    136 
    137         @Override
    138         public void setFolderWatcher(FolderWatcher watcher) {
    139             // Unsupported.
    140         }
    141 
    142         @Override
    143         public boolean isDrawerPullEnabled() {
    144             // Unsupported
    145             return false;
    146         }
    147 
    148         @Override
    149         public int getFolderListViewChoiceMode() {
    150             return ListView.CHOICE_MODE_NONE;
    151         }
    152     };
    153 
    154     @Override
    155     public void onCreate(Bundle icicle) {
    156         super.onCreate(icicle);
    157 
    158         setContentView(R.layout.folders_activity);
    159 
    160         final Intent intent = getIntent();
    161         final String action = intent.getAction();
    162         mConfigureShortcut = Intent.ACTION_CREATE_SHORTCUT.equals(action);
    163         mConfigureWidget = AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action);
    164         if (!mConfigureShortcut && !mConfigureWidget) {
    165             LogUtils.wtf(LOG_TAG, "unexpected intent: %s", intent);
    166         }
    167         if (mConfigureShortcut || mConfigureWidget) {
    168             mMode = CONFIGURE;
    169         } else {
    170             mMode = VIEW;
    171         }
    172 
    173         if (mConfigureWidget) {
    174             mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
    175                     AppWidgetManager.INVALID_APPWIDGET_ID);
    176             if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
    177                 LogUtils.wtf(LOG_TAG, "invalid widgetId");
    178             }
    179         }
    180 
    181         mAccount = intent.getParcelableExtra(EXTRA_ACCOUNT_SHORTCUT);
    182         final Button firstButton = (Button) findViewById(R.id.first_button);
    183         firstButton.setVisibility(View.VISIBLE);
    184         // TODO(mindyp) disable the manage folders buttons until we have a manage folders screen.
    185         if (mMode == VIEW) {
    186             firstButton.setEnabled(false);
    187         }
    188         firstButton.setOnClickListener(this);
    189         createFolderListFragment(FolderListFragment.ofTopLevelTree(mAccount.folderListUri,
    190                 getExcludedFolderTypes()));
    191     }
    192 
    193     /**
    194      * Create a Fragment showing this folder and its children.
    195      */
    196     private void createFolderListFragment(Fragment fragment) {
    197         final FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
    198         fragmentTransaction.replace(R.id.content_pane, fragment);
    199         fragmentTransaction.commitAllowingStateLoss();
    200     }
    201 
    202     /**
    203      * Gets an {@link ArrayList} of canonical names of any folders to exclude from displaying.
    204      * By default, this list is empty.
    205      *
    206      * @return An {@link ArrayList} of folder canonical names
    207      */
    208     protected ArrayList<Integer> getExcludedFolderTypes() {
    209         return new ArrayList<Integer>();
    210     }
    211 
    212     @Override
    213     protected void onResume() {
    214         super.onResume();
    215 
    216         // TODO: (mindyp) Make sure we're operating on the same account as
    217         // before. If the user switched accounts, switch back.
    218     }
    219 
    220     @Override
    221     public void onClick(View v) {
    222         final int id = v.getId();
    223         if (id == R.id.first_button) {
    224             if (mMode == CONFIGURE) {
    225                 doCancel();
    226             } else {
    227                 // TODO (mindyp): open manage folders screen.
    228             }
    229         }
    230     }
    231 
    232     private void doCancel() {
    233         setResult(RESULT_CANCELED);
    234         finish();
    235     }
    236 
    237     /**
    238      * Create a widget for the specified account and folder
    239      */
    240     protected void createWidget(int id, Account account, Folder selectedFolder) {
    241         WidgetProvider.updateWidget(this, id, account, selectedFolder.type,
    242                 selectedFolder.capabilities, selectedFolder.folderUri.fullUri,
    243                 selectedFolder.conversationListUri, selectedFolder.name);
    244         final Intent result = new Intent();
    245         result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id);
    246         setResult(RESULT_OK, result);
    247         finish();
    248     }
    249 
    250     @Override
    251     public void onClick(DialogInterface dialog, int which) {
    252         if (which == DialogInterface.BUTTON_POSITIVE) {
    253             // The only dialog that is
    254             createWidget(mAppWidgetId, mAccount, mSelectedFolder);
    255         } else {
    256             doCancel();
    257         }
    258     }
    259 
    260     @Override
    261     public void onFolderChanged(Folder folder, final boolean force) {
    262         if (!folder.equals(mSelectedFolder)) {
    263             mSelectedFolder = folder;
    264             Intent resultIntent = new Intent();
    265 
    266             if (mConfigureShortcut) {
    267                 /*
    268                  * Create the shortcut Intent based on it with the additional
    269                  * information that we have in this activity: name of the
    270                  * account, calculate the human readable name of the folder and
    271                  * use it as the shortcut name, etc...
    272                  */
    273                 final Intent clickIntent = Utils.createViewFolderIntent(this,
    274                         mSelectedFolder.folderUri.fullUri, mAccount);
    275                 resultIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, clickIntent);
    276                 resultIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
    277                         Intent.ShortcutIconResource.fromContext(this,
    278                                 R.mipmap.ic_launcher_shortcut_folder));
    279                 /**
    280                  * Note: Email1 created shortcuts using R.mipmap#ic_launcher_email
    281                  * so don't delete that resource until we have an upgrade/migration solution
    282                  */
    283 
    284                 final CharSequence humanFolderName = mSelectedFolder.name;
    285 
    286                 resultIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, humanFolderName);
    287 
    288                 // Now ask the user what name they want for this shortcut. Pass
    289                 // the
    290                 // shortcut intent that we just created, the user can modify the
    291                 // folder in
    292                 // ShortcutNameActivity.
    293                 final Intent shortcutNameIntent = new Intent(this, ShortcutNameActivity.class);
    294                 shortcutNameIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY
    295                         | Intent.FLAG_ACTIVITY_FORWARD_RESULT);
    296                 shortcutNameIntent.putExtra(ShortcutNameActivity.EXTRA_FOLDER_CLICK_INTENT,
    297                         resultIntent);
    298                 shortcutNameIntent.putExtra(ShortcutNameActivity.EXTRA_SHORTCUT_NAME,
    299                         humanFolderName);
    300 
    301                 startActivity(shortcutNameIntent);
    302                 finish();
    303             } else if (mConfigureWidget) {
    304                 createWidget(mAppWidgetId, mAccount, mSelectedFolder);
    305             }
    306         }
    307     }
    308 
    309     @Override
    310     public Context getActivityContext() {
    311         return this;
    312     }
    313 
    314     @Override
    315     public ViewMode getViewMode() {
    316         return null;
    317     }
    318 
    319     @Override
    320     public ConversationListCallbacks getListHandler() {
    321         return null;
    322     }
    323 
    324     @Override
    325     public FolderChangeListener getFolderChangeListener() {
    326         return this;
    327     }
    328 
    329     @Override
    330     public ConversationSelectionSet getSelectedSet() {
    331         return null;
    332     }
    333 
    334     private Folder mNavigatedFolder;
    335     @Override
    336     public void onFolderSelected(Folder folder) {
    337         if (folder.hasChildren && !folder.equals(mNavigatedFolder)) {
    338             mNavigatedFolder = folder;
    339             // Replace this fragment with a new FolderListFragment
    340             // showing this folder's children if we are not already looking
    341             // at the child view for this folder.
    342             createFolderListFragment(FolderListFragment.ofTree(folder));
    343             return;
    344         }
    345         onFolderChanged(folder, false /* force */);
    346     }
    347 
    348     @Override
    349     public FolderSelector getFolderSelector() {
    350         return this;
    351     }
    352 
    353     @Override
    354     public boolean supportsDrag(DragEvent event, Folder folder) {
    355         return false;
    356     }
    357 
    358     @Override
    359     public void handleDrop(DragEvent event, Folder folder) {
    360         // Do nothing.
    361     }
    362 
    363     @Override
    364     public void onUndoAvailable(ToastBarOperation undoOp) {
    365         // Do nothing.
    366     }
    367 
    368     @Override
    369     public Folder getHierarchyFolder() {
    370         return null;
    371     }
    372 
    373     @Override
    374     public ConversationUpdater getConversationUpdater() {
    375         return null;
    376     }
    377 
    378     @Override
    379     public ErrorListener getErrorListener() {
    380         return null;
    381     }
    382 
    383     @Override
    384     public void setPendingToastOperation(ToastBarOperation op) {
    385         // Do nothing.
    386     }
    387 
    388     @Override
    389     public ToastBarOperation getPendingToastOperation() {
    390         return null;
    391     }
    392 
    393     @Override
    394     public FolderController getFolderController() {
    395         return null;
    396     }
    397 
    398     @Override
    399     public void onAnimationEnd(AnimatedAdapter animatedAdapter) {
    400     }
    401 
    402     @Override
    403     public AccountController getAccountController() {
    404         return mAccountController;
    405     }
    406 
    407     @Override
    408     public void onFooterViewErrorActionClick(Folder folder, int errorStatus) {
    409         // Unsupported
    410     }
    411 
    412     @Override
    413     public void onFooterViewLoadMoreClick(Folder folder) {
    414         // Unsupported
    415     }
    416 
    417     @Override
    418     public void startDragMode() {
    419         // Unsupported
    420     }
    421 
    422     @Override
    423     public void stopDragMode() {
    424         // Unsupported
    425     }
    426 
    427     @Override
    428     public RecentFolderController getRecentFolderController() {
    429         // Unsupported
    430         return null;
    431     }
    432 
    433     @Override
    434     public DrawerController getDrawerController() {
    435         // Unsupported
    436         return null;
    437     }
    438 
    439     @Override
    440     public KeyboardNavigationController getKeyboardNavigationController() {
    441         // Unsupported
    442         return null;
    443     }
    444 
    445     @Override
    446     public boolean isAccessibilityEnabled() {
    447         // Unsupported
    448         return true;
    449     }
    450 
    451     @Override
    452     public ConversationListHelper getConversationListHelper() {
    453         // Unsupported
    454         return null;
    455     }
    456 
    457     @Override
    458     public FragmentLauncher getFragmentLauncher() {
    459         // Unsupported
    460         return null;
    461     }
    462 
    463     @Override
    464     public ContactLoaderCallbacks getContactLoaderCallbacks() {
    465         // Unsupported
    466         return null;
    467     }
    468 
    469     @Override
    470     public ContactResolver getContactResolver(ContentResolver resolver, BitmapCache bitmapCache) {
    471         // Unsupported
    472         return null;
    473     }
    474 
    475     @Override
    476     public BitmapCache getSenderImageCache() {
    477         // Unsupported
    478         return null;
    479     }
    480 
    481     @Override
    482     public void resetSenderImageCache() {
    483         // Unsupported
    484     }
    485 
    486     @Override
    487     public void showHelp(Account account, int viewMode) {
    488         //Unsupported
    489     }
    490 }
    491