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