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