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