UIControllerOnePane.java revision bfac9f2e8a13f6c719608a6948203bbef921c99f
1/* 2 * Copyright (C) 2011 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.email.activity; 18 19import com.android.email.Email; 20import com.android.email.R; 21import com.android.emailcommon.Logging; 22import com.android.emailcommon.provider.EmailContent.Mailbox; 23import com.android.emailcommon.utility.Utility; 24 25import android.app.FragmentManager; 26import android.app.FragmentTransaction; 27import android.os.Bundle; 28import android.util.Log; 29 30import java.util.Set; 31 32 33/** 34 * UI Controller for non x-large devices. Supports a single-pane layout. 35 * 36 * STOPSHIP Everything in this class is 100% temporary at this point 37 * - Navigation model is different from what it should be (whatever it'll be). 38 * e.g. when the app is launched, we should show Inbox, not mailbox list. 39 * 40 * - It uses the two-pane action bar only so that we can change accounts 41 * 42 * Major TODOs 43 * - TODO Proper Navigation model, including retaining fragments to keep state such as the scroll 44 * position and batch selection. 45 * - TODO Nested folders 46 * - TODO Newer/Older for message view 47 * - TODO Implement callbacks 48 */ 49class UIControllerOnePane extends UIControllerBase { 50 private ActionBarController mActionBarController; 51 52 /** 53 * Current account/mailbox/message IDs. 54 * Don't use them directly; use the accessors instead, as we might want to get them from the 55 * topmost fragment in the future. 56 */ 57 private long mCurrentAccountId = NO_ACCOUNT; 58 private long mCurrentMailboxId = NO_MAILBOX; 59 private long mCurrentMessageId = NO_MESSAGE; 60 61 private MessageCommandButtonView mMessageCommandButtons; 62 63 private final MailboxListFragment.Callback mMailboxListFragmentCallback = 64 new MailboxListFragment.Callback() { 65 @Override 66 public void onAccountSelected(long accountId) { 67 openAccount(accountId); 68 } 69 70 @Override 71 public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount) { 72 } 73 74 @Override 75 public void onMailboxSelected( 76 long accountId, long mailboxId, boolean navigate, boolean dragDrop) { 77 open(accountId, mailboxId, NO_MESSAGE); 78 } 79 }; 80 81 private final MessageListFragment.Callback mMessageListFragmentCallback = 82 new MessageListFragment.Callback() { 83 @Override 84 public void onAdvancingOpAccepted(Set<Long> affectedMessages) { 85 // Nothing to do on 1 pane. 86 } 87 88 @Override 89 public void onEnterSelectionMode(boolean enter) { 90 // TODO Auto-generated method stub 91 92 } 93 94 @Override 95 public void onListLoaded() { 96 // TODO Auto-generated method stub 97 98 } 99 100 @Override 101 public void onMailboxNotFound() { 102 open(getUIAccountId(), NO_MAILBOX, NO_MESSAGE); 103 } 104 105 @Override 106 public void onMessageOpen( 107 long messageId, long messageMailboxId, long listMailboxId, int type) { 108 if (type == MessageListFragment.Callback.TYPE_DRAFT) { 109 MessageCompose.actionEditDraft(mActivity, messageId); 110 } else { 111 open(getUIAccountId(), getMailboxId(), messageId); 112 } 113 } 114 }; 115 116 private final MessageViewFragment.Callback mMessageViewFragmentCallback = 117 new MessageViewFragment.Callback() { 118 @Override 119 public void onForward() { 120 MessageCompose.actionForward(mActivity, getMessageId()); 121 } 122 123 @Override 124 public void onReply() { 125 MessageCompose.actionReply(mActivity, getMessageId(), false); 126 } 127 128 @Override 129 public void onReplyAll() { 130 MessageCompose.actionReply(mActivity, getMessageId(), true); 131 } 132 133 @Override 134 public void onCalendarLinkClicked(long epochEventStartTime) { 135 ActivityHelper.openCalendar(mActivity, epochEventStartTime); 136 } 137 138 @Override 139 public boolean onUrlInMessageClicked(String url) { 140 return ActivityHelper.openUrlInMessage(mActivity, url, getActualAccountId()); 141 } 142 143 @Override 144 public void onBeforeMessageGone() { 145 // TODO Auto-generated method stub 146 147 } 148 149 @Override 150 public void onMessageSetUnread() { 151 // TODO Auto-generated method stub 152 153 } 154 155 @Override 156 public void onRespondedToInvite(int response) { 157 // TODO Auto-generated method stub 158 159 } 160 161 @Override 162 public void onLoadMessageError(String errorMessage) { 163 // TODO Auto-generated method stub 164 165 } 166 167 @Override 168 public void onLoadMessageFinished() { 169 // TODO Auto-generated method stub 170 171 } 172 173 @Override 174 public void onLoadMessageStarted() { 175 // TODO Auto-generated method stub 176 177 } 178 179 @Override 180 public void onMessageNotExists() { 181 // TODO Auto-generated method stub 182 183 } 184 185 @Override 186 public void onMessageViewGone() { 187 // TODO Auto-generated method stub 188 189 } 190 191 @Override 192 public void onMessageViewShown(int mailboxType) { 193 // TODO Auto-generated method stub 194 195 } 196 }; 197 198 199 // This is all temporary as we'll have a different action bar controller for 1-pane. 200 private final ActionBarController.Callback mActionBarControllerCallback 201 = new ActionBarController.Callback() { 202 @Override 203 public boolean shouldShowMailboxName() { 204 return false; // no mailbox name/unread count. 205 } 206 207 @Override 208 public String getCurrentMailboxName() { 209 return null; // no mailbox name/unread count. 210 } 211 212 @Override 213 public int getCurrentMailboxUnreadCount() { 214 return 0; // no mailbox name/unread count. 215 } 216 217 @Override 218 public boolean shouldShowUp() { 219 // Always show the UP arrow. 220 return true; 221 } 222 223 @Override 224 public long getUIAccountId() { 225 return UIControllerOnePane.this.getUIAccountId(); 226 } 227 228 @Override 229 public boolean isAccountSelected() { 230 return UIControllerOnePane.this.isAccountSelected(); 231 } 232 233 @Override 234 public void onAccountSelected(long accountId) { 235 openAccount(accountId); 236 } 237 238 @Override 239 public void onNoAccountsFound() { 240 Welcome.actionStart(mActivity); 241 mActivity.finish(); 242 } 243 }; 244 245 public UIControllerOnePane(EmailActivity activity) { 246 super(activity); 247 } 248 249 @Override 250 public void onSaveInstanceState(Bundle outState) { 251 super.onSaveInstanceState(outState); 252 outState.putLong(BUNDLE_KEY_ACCOUNT_ID, mCurrentAccountId); 253 outState.putLong(BUNDLE_KEY_MAILBOX_ID, mCurrentMailboxId); 254 outState.putLong(BUNDLE_KEY_MESSAGE_ID, mCurrentMessageId); 255 } 256 257 @Override 258 public void restoreInstanceState(Bundle savedInstanceState) { 259 super.restoreInstanceState(savedInstanceState); 260 mCurrentAccountId = savedInstanceState.getLong(BUNDLE_KEY_ACCOUNT_ID, NO_ACCOUNT); 261 mCurrentMailboxId = savedInstanceState.getLong(BUNDLE_KEY_MAILBOX_ID, NO_MAILBOX); 262 mCurrentMessageId = savedInstanceState.getLong(BUNDLE_KEY_MESSAGE_ID, NO_MESSAGE); 263 } 264 265 @Override 266 public int getLayoutId() { 267 return R.layout.email_activity_one_pane; 268 } 269 270 @Override 271 public void onActivityViewReady() { 272 super.onActivityViewReady(); 273 mActionBarController = new ActionBarController(mActivity, mActivity.getLoaderManager(), 274 mActivity.getActionBar(), mActionBarControllerCallback); 275 276 mMessageCommandButtons = UiUtilities.getView(mActivity, R.id.message_command_buttons); 277 mMessageCommandButtons.setCallback(new CommandButtonCallback()); 278 } 279 280 @Override 281 public void onActivityCreated() { 282 super.onActivityCreated(); 283 mActionBarController.onActivityCreated(); 284 } 285 286 @Override 287 public void onActivityResume() { 288 super.onActivityResume(); 289 refreshActionBar(); 290 } 291 292 @Override 293 public long getUIAccountId() { 294 return mCurrentAccountId; 295 } 296 297 private long getMailboxId() { 298 return mCurrentMailboxId; 299 } 300 301 private long getMessageId() { 302 return mCurrentMessageId; 303 } 304 305 private void refreshActionBar() { 306 if (mActionBarController != null) { 307 mActionBarController.refresh(); 308 } 309 mActivity.invalidateOptionsMenu(); 310 } 311 312 private boolean isMailboxListVisible() { 313 return (getMailboxId() == NO_MAILBOX); 314 } 315 316 private boolean isMessageListVisible() { 317 return (getMailboxId() != NO_MAILBOX) && (getMessageId() == NO_MESSAGE); 318 } 319 320 private boolean isMessageViewVisible() { 321 return (getMailboxId() != NO_MAILBOX) && (getMessageId() != NO_MESSAGE); 322 } 323 324 @Override 325 public boolean onBackPressed(boolean isSystemBackKey) { 326 if (isMessageViewVisible()) { 327 open(getUIAccountId(), getMailboxId(), NO_MESSAGE); 328 return true; 329 } else if (isMessageListVisible()) { 330 open(getUIAccountId(), NO_MAILBOX, NO_MESSAGE); 331 return true; 332 } else { 333 // STOPSHIP Remove this and return false. This is so that the app can be closed 334 // with the UP press. (usuful when the device doesn't have a HW back key.) 335 mActivity.finish(); 336 return true; 337// return false; 338 } 339 } 340 341 @Override 342 protected void installMailboxListFragment(MailboxListFragment fragment) { 343 fragment.setCallback(mMailboxListFragmentCallback); 344 } 345 346 @Override 347 protected void installMessageListFragment(MessageListFragment fragment) { 348 fragment.setCallback(mMessageListFragmentCallback); 349 } 350 351 @Override 352 protected void installMessageViewFragment(MessageViewFragment fragment) { 353 fragment.setCallback(mMessageViewFragmentCallback); 354 } 355 356 @Override 357 public void openAccount(long accountId) { 358 open(accountId, NO_MAILBOX, NO_MESSAGE); 359 } 360 361 @Override 362 public void open(final long accountId, final long mailboxId, final long messageId) { 363 if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 364 Log.d(Logging.LOG_TAG, this + " open accountId=" + accountId 365 + " mailboxId=" + mailboxId + " messageId=" + messageId); 366 } 367 if (accountId == NO_ACCOUNT) { 368 throw new IllegalArgumentException(); 369 } 370 371 // !!! It's all temporary to make 1 pane UI (barely) usable !!! 372 // 373 // - Nested folders still doesn't work 374 // - When opening a child view (e.g. message list -> message view), we should retain 375 // the current fragment so that all the state (selection, scroll position, etc) will be 376 // restored when back. 377 378 if ((getUIAccountId() == accountId) && (getMailboxId() == mailboxId) 379 && (getMessageId() == messageId)) { 380 return; 381 } 382 383 final FragmentManager fm = mActivity.getFragmentManager(); 384 final FragmentTransaction ft = fm.beginTransaction(); 385 386 if (messageId != NO_MESSAGE) { 387 ft.replace(R.id.fragment_placeholder, MessageViewFragment.newInstance(messageId)); 388 389 } else if (mailboxId != NO_MAILBOX) { 390 ft.replace(R.id.fragment_placeholder, MessageListFragment.newInstance(mailboxId)); 391 392 } else { 393 ft.replace(R.id.fragment_placeholder, 394 MailboxListFragment.newInstance(accountId, Mailbox.PARENT_KEY_NONE)); 395 } 396 397 mCurrentAccountId = accountId; 398 mCurrentMailboxId = mailboxId; 399 mCurrentMessageId = messageId; 400 401 commitFragmentTransaction(ft); 402 403 refreshActionBar(); 404 } 405 406 /* 407 * STOPSHIP Remove this -- see the base class method. 408 */ 409 @Override 410 public long getMailboxSettingsMailboxId() { 411 // Mailbox settings is still experimental, and doesn't have to work on the phone. 412 Utility.showToast(mActivity, "STOPSHIP: Mailbox settings not supported on 1 pane"); 413 return -1; 414 } 415 416 /* 417 * STOPSHIP Remove this -- see the base class method. 418 */ 419 @Override 420 public long getSearchMailboxId() { 421 // Search is still experimental, and doesn't have to work on the phone. 422 Utility.showToast(mActivity, "STOPSHIP: Search not supported on 1 pane"); 423 return -1; 424 } 425 426 private class CommandButtonCallback implements MessageCommandButtonView.Callback { 427 @Override 428 public void onMoveToNewer() { 429 // TODO 430 } 431 432 @Override 433 public void onMoveToOlder() { 434 // TODO 435 } 436 } 437 438 @Override 439 protected boolean isRefreshEnabled() { 440 // Refreshable only when an actual account is selected, and message view isn't shown. 441 // (i.e. only available on the mailbox list or the message view, but not on the combined 442 // one) 443 return isActualAccountSelected() && !isMessageViewVisible(); 444 } 445 446 @Override 447 public void onRefresh() { 448 if (!isRefreshEnabled()) { 449 return; 450 } 451 if (isMessageListVisible()) { 452 mRefreshManager.refreshMessageList(getActualAccountId(), getMailboxId(), true); 453 } else { 454 mRefreshManager.refreshMailboxList(getActualAccountId()); 455 } 456 } 457 458 @Override 459 protected boolean isRefreshInProgress() { 460 if (!isRefreshEnabled()) { 461 return false; 462 } 463 if (isMessageListVisible()) { 464 return mRefreshManager.isMessageListRefreshing(getMailboxId()); 465 } else { 466 return mRefreshManager.isMailboxListRefreshing(getActualAccountId()); 467 } 468 } 469} 470