Implement 1-pane navigation.

- Now that fragment useage is simplified (e.g. no new fragment
creation for nested mailbox navigation), most of the fragment
operation code for 2-pane is reuseable for 1-pane as well,
so moeved it to the base class.

- Temporarily added "Show all folders" as a menu option on 1-pane.

- Added "opener account id/mailbox id" to the message view fragment.
They are not used by the fragment itself, but they're used
by the UI controller for the back navigation.  (And now the UI
controller doesn't maintain the current IDs by itself; rather
it gets them from the currently-active fragment.)

- Use async fragment transaction on 1-pane too, now that it always
gets the current state from the active fragment.

- Changed the timing when we install fragments from onAttachFragment
to fragments' onActivityCreated.  So now all installed fragments are
created.

TODO Now that all installed fragments are guaranteed to be created,
remove all special trealment for the fragment argument accessor.
(They were meant be safe to call before onCreate, but it's not
necessary any more.)

Change-Id: I0ed100c3f0b460835b164c0dc908ea483a4e46ee
This commit is contained in:
Makoto Onuki 2011-06-02 16:44:13 -07:00
parent 5dc07ad26c
commit 3d9b8e76f0
12 changed files with 574 additions and 440 deletions

View File

@ -39,6 +39,17 @@
android:icon="@drawable/ic_menu_refresh_holo_light"
android:showAsAction="ifRoom"
/>
<!--
STOPSHIP "Show all folders" should be in the account spinner, not here.
It's temporary UI until we get the ICS style account spinner.
-->
<item
android:id="@+id/show_all_folders"
android:orderInCategory="400"
android:title="@string/mailbox_list_account_selector_show_all_folders"
android:showAsAction="ifRoom"
android:visible="false"
/>
<item
android:id="@+id/account_settings"
android:orderInCategory="2000"

View File

@ -265,6 +265,9 @@
<!-- Label shown in the account selector to select "Combined view", which contains
Combined Inbox, Combined Outbox, etc. [CHAR LIMIT=30] -->
<string name="mailbox_list_account_selector_combined_view">Combined view</string>
<!-- Label shown in the account/mailbox selector to switch to the show all the top-level
mailboxes. [CHAR LIMIT=30] -->
<string name="mailbox_list_account_selector_show_all_folders">Show all folders</string>
<!-- Appears at the bottom of list of messages; user selects to load more messages from that folder. -->
<string name="message_list_load_more_messages_action">Load more messages</string>

View File

@ -58,7 +58,7 @@ import java.util.ArrayList;
* Because this activity is device agnostic, so most of the UI aren't owned by this, but by
* the UIController.
*/
public class EmailActivity extends Activity implements View.OnClickListener {
public class EmailActivity extends Activity implements View.OnClickListener, FragmentInstallable {
private static final String EXTRA_ACCOUNT_ID = "ACCOUNT_ID";
private static final String EXTRA_MAILBOX_ID = "MAILBOX_ID";
private static final String EXTRA_MESSAGE_ID = "MESSAGE_ID";
@ -196,9 +196,6 @@ public class EmailActivity extends Activity implements View.OnClickListener {
int errorBannerHeight = getResources().getDimensionPixelSize(R.dimen.error_message_height);
mErrorBanner = new BannerController(this, errorMessage, errorBannerHeight);
// Install restored fragments.
mUIController.installRestoredFragments();
if (savedInstanceState != null) {
mUIController.restoreInstanceState(savedInstanceState);
} else {
@ -233,12 +230,11 @@ public class EmailActivity extends Activity implements View.OnClickListener {
}
@Override
public void onAttachFragment(Fragment fragment) {
public void onInstallFragment(Fragment fragment) {
if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " onAttachFragment fragment=" + fragment);
Log.d(Logging.LOG_TAG, this + " onInstallFragment fragment=" + fragment);
}
super.onAttachFragment(fragment);
mUIController.onAttachFragment(fragment);
mUIController.onInstallFragment(fragment);
}
@Override

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.email.activity;
import android.app.Activity;
import android.app.Fragment;
/**
* Interface for {@link Activity} that can "install" fragments.
*/
public interface FragmentInstallable {
/**
* Called when a {@link Fragment} wants to be installed to the host activity.
*
* Fragments which use this MUST call this from {@link Fragment#onActivityCreated} using
* {@link UiUtilities#installFragment}.
*
* This means a host {@link Activity} can safely assume a passed {@link Fragment} is already
* created.
*/
public void onInstallFragment(Fragment fragment);
}

View File

@ -463,6 +463,8 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
lv.setOnDragListener(this);
startLoading(mParentMailboxId, mHighlightedMailboxId);
UiUtilities.installFragment(this);
}
public void setCallback(Callback callback) {

View File

@ -394,6 +394,8 @@ public class MessageListFragment extends ListFragment
}
startLoading();
UiUtilities.installFragment(this);
}
@Override

View File

@ -47,6 +47,8 @@ import android.widget.ImageView;
public class MessageViewFragment extends MessageViewFragmentBase
implements CheckBox.OnCheckedChangeListener, MoveMessageToDialog.Callback {
/** Argument name(s) */
private static final String ARG_OPENER_ACCOUNT_ID = "accountId";
private static final String ARG_OPENER_MAILBOX_ID = "mailboxId";
private static final String ARG_MESSAGE_ID = "messageId";
private ImageView mFavoriteIcon;
@ -125,13 +127,33 @@ public class MessageViewFragment extends MessageViewFragmentBase
* Create a new instance with initialization parameters.
*
* This fragment should be created only with this method. (Arguments should always be set.)
*
* @param openerAccountId account ID that's used in the UI that opened this fragment.
* The primary use is for the back navigation to determine which mailbox to show.
*
* Note this is not necessarily the same ID as the actual account ID for the message.
* If a message is opened on the combined view, the caller probably want to pass
* {@link Account#ACCOUNT_ID_COMBINED_VIEW} so that back will navigate to the
* combined view.
*
* @param openerMailboxId mailbox ID that's used in the UI that opened this fragment.
* The primary use is for the back navigation to determine which mailbox to show.
*
* Note this is not necessarily the same ID as the actual mailbox ID for the message.
* If a message is opened on the combined view, the caller probably want to pass
* a combined mailbox ID so that back will navigate to it.
*
* @param messageId ID of the message to open
*/
public static MessageViewFragment newInstance(long messageId) {
if (messageId == -1) {
public static MessageViewFragment newInstance(long openerAccountId, long openerMailboxId,
long messageId) {
if (messageId == Message.NO_MESSAGE) {
throw new IllegalArgumentException();
}
final MessageViewFragment instance = new MessageViewFragment();
final Bundle args = new Bundle();
args.putLong(ARG_OPENER_ACCOUNT_ID, openerAccountId);
args.putLong(ARG_OPENER_MAILBOX_ID, openerMailboxId);
args.putLong(ARG_MESSAGE_ID, messageId);
instance.setArguments(args);
return instance;
@ -144,10 +166,14 @@ public class MessageViewFragment extends MessageViewFragmentBase
* constructs, this <em>must</em> be considered immutable.
*/
private Long mImmutableMessageId;
private Long mImmutableOpenerAccountId;
private Long mImmutableOpenerMailboxId;
private void initializeArgCache() {
if (mImmutableMessageId != null) return;
mImmutableMessageId = getArguments().getLong(ARG_MESSAGE_ID);
mImmutableOpenerAccountId = getArguments().getLong(ARG_OPENER_ACCOUNT_ID);
mImmutableOpenerMailboxId = getArguments().getLong(ARG_OPENER_MAILBOX_ID);
}
/**
@ -158,6 +184,22 @@ public class MessageViewFragment extends MessageViewFragmentBase
return mImmutableMessageId;
}
/**
* @return the account ID passed to {@link #newInstance}. Safe to call even before onCreate.
*/
public long getOpenerAccountId() {
initializeArgCache();
return mImmutableOpenerAccountId;
}
/**
* @return the mailbox ID passed to {@link #newInstance}. Safe to call even before onCreate.
*/
public long getOpenerMailboxId() {
initializeArgCache();
return mImmutableOpenerMailboxId;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

View File

@ -341,6 +341,8 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
resetView();
new LoadMessageTask(true).executeParallel();
UiUtilities.installFragment(this);
}
@Override

View File

@ -26,28 +26,24 @@ import com.android.emailcommon.provider.EmailContent.Message;
import com.android.emailcommon.provider.Mailbox;
import com.android.emailcommon.utility.EmailAsyncTask;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import java.util.ArrayList;
/**
* Base class for the UI controller.
*
* Note: Always use {@link #commitFragmentTransaction} to operate fragment transactions,
* so that we can easily switch between synchronous and asynchronous transactions.
*/
abstract class UIControllerBase {
protected static final String BUNDLE_KEY_ACCOUNT_ID = "UIController.state.account_id";
protected static final String BUNDLE_KEY_MAILBOX_ID = "UIController.state.mailbox_id";
protected static final String BUNDLE_KEY_MESSAGE_ID = "UIController.state.message_id";
abstract class UIControllerBase implements MailboxListFragment.Callback,
MessageListFragment.Callback, MessageViewFragment.Callback {
protected static final String BUNDLE_KEY_RESUME_INBOX_LOOKUP
= "UIController.state.resumeInboxLookup";
protected static final String BUNDLE_KEY_INBOX_LOOKUP_ACCOUNT_ID
@ -56,26 +52,15 @@ abstract class UIControllerBase {
/** The owner activity */
final EmailActivity mActivity;
private final ActionBarController mActionBarController;
final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker();
final RefreshManager mRefreshManager;
/**
* List of fragments that are restored by the framework while the activity is being re-created
* for configuration changes (e.g. screen rotation). We'll install them later when the activity
* is created in {@link #installRestoredFragments()}.
*/
private final ArrayList<Fragment> mRestoredFragments = new ArrayList<Fragment>();
/** {@code true} if the activity is resumed. */
private boolean mResumed;
/**
* Whether fragment installation should be hold.
* We hold installing fragments until {@link #installRestoredFragments()} is called.
*/
private boolean mHoldFragmentInstallation = true;
/**
* Use to find Inbox. This should only run while the activity is resumed, because otherwise
* we may not be able to perform fragment transactions when we get a callback.
@ -96,34 +81,47 @@ abstract class UIControllerBase {
*/
private boolean mResumeInboxLookup;
/**
* Fragments that are installed.
*
* A fragment is installed when:
* - it is attached to the activity
* - the parent activity is created
* - and it is not scheduled to be removed.
*
* We set callbacks to fragments only when they are installed.
*/
private MailboxListFragment mMailboxListFragment;
private MessageListFragment mMessageListFragment;
private MessageViewFragment mMessageViewFragment;
private final RefreshManager.Listener mRefreshListener
= new RefreshManager.Listener() {
@Override
public void onMessagingError(final long accountId, long mailboxId, final String message) {
updateRefreshProgress();
refreshActionBar();
}
@Override
public void onRefreshStatusChanged(long accountId, long mailboxId) {
updateRefreshProgress();
refreshActionBar();
}
};
public UIControllerBase(EmailActivity activity) {
mActivity = activity;
mRefreshManager = RefreshManager.getInstance(mActivity);
mActionBarController = createActionBarController(activity);
}
/**
* Called by the base class to let a subclass create an {@link ActionBarController}.
*/
protected abstract ActionBarController createActionBarController(Activity activity);
/** @return the layout ID for the activity. */
public abstract int getLayoutId();
/**
* @return true if the UI controller currently can install fragments.
*/
protected final boolean isFragmentInstallable() {
return !mHoldFragmentInstallation;
}
/**
* Must be called just after the activity sets up the content view. Used to initialize views.
*
@ -144,6 +142,7 @@ abstract class UIControllerBase {
Log.d(Logging.LOG_TAG, this + " onActivityCreated");
}
mRefreshManager.registerListener(mRefreshListener);
mActionBarController.onActivityCreated();
}
/**
@ -197,30 +196,10 @@ abstract class UIControllerBase {
if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " onActivityDestroy");
}
mHoldFragmentInstallation = true; // No more fragment installation.
mRefreshManager.unregisterListener(mRefreshListener);
mTaskTracker.cancellAllInterrupt();
}
/**
* Install all the fragments kept in {@link #mRestoredFragments}.
*
* Must be called at the end of {@link EmailActivity#onCreate}.
*/
public final void installRestoredFragments() {
if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " installRestoredFragments");
}
mHoldFragmentInstallation = false;
// Install all the fragments restored by the framework.
for (Fragment fragment : mRestoredFragments) {
installFragment(fragment);
}
mRestoredFragments.clear();
}
/**
* Handles the {@link android.app.Activity#onSaveInstanceState} callback.
*/
@ -244,24 +223,12 @@ abstract class UIControllerBase {
}
/**
* Handles the {@link android.app.Activity#onAttachFragment} callback.
*
* If the activity has already been created, we initialize the fragment here. Otherwise we
* keep the fragment in {@link #mRestoredFragments} and initialize it after the activity's
* onCreate.
* Install a fragment. Must be caleld from the host activity's
* {@link FragmentInstallable#onInstallFragment}.
*/
public final void onAttachFragment(Fragment fragment) {
if (mHoldFragmentInstallation) {
// Fragment being restored by the framework during the activity recreation.
mRestoredFragments.add(fragment);
return;
}
installFragment(fragment);
}
private void installFragment(Fragment fragment) {
public final void onInstallFragment(Fragment fragment) {
if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " installFragment fragment=" + fragment);
Log.d(Logging.LOG_TAG, this + " onInstallFragment fragment=" + fragment);
}
if (fragment instanceof MailboxListFragment) {
installMailboxListFragment((MailboxListFragment) fragment);
@ -270,15 +237,114 @@ abstract class UIControllerBase {
} else if (fragment instanceof MessageViewFragment) {
installMessageViewFragment((MessageViewFragment) fragment);
} else {
// Ignore -- uninteresting fragments such as dialogs.
throw new IllegalArgumentException("Tried to install unknown fragment");
}
}
protected abstract void installMailboxListFragment(MailboxListFragment fragment);
/** Install fragment */
protected void installMailboxListFragment(MailboxListFragment fragment) {
mMailboxListFragment = fragment;
mMailboxListFragment.setCallback(this);
refreshActionBar();
}
protected abstract void installMessageListFragment(MessageListFragment fragment);
/** Install fragment */
protected void installMessageListFragment(MessageListFragment fragment) {
mMessageListFragment = fragment;
mMessageListFragment.setCallback(this);
refreshActionBar();
}
protected abstract void installMessageViewFragment(MessageViewFragment fragment);
/** Install fragment */
protected void installMessageViewFragment(MessageViewFragment fragment) {
mMessageViewFragment = fragment;
mMessageViewFragment.setCallback(this);
refreshActionBar();
}
/**
* Uninstall - If the fragment is installed, remove it from the given
* {@link FragmentTransaction} and also clears the callabck.
*/
protected FragmentTransaction uninstallMailboxListFragment(FragmentTransaction ft) {
if (isMailboxListInstalled()) {
onMailboxListFragmentUninstalled(mMailboxListFragment);
ft.remove(mMailboxListFragment);
mMailboxListFragment.setCallback(null);
mMailboxListFragment = null;
}
return ft;
}
/** Called when a {@link MailboxListFragment} is about to be uninstalled */
protected void onMailboxListFragmentUninstalled(MailboxListFragment fragment) {
}
/**
* Uninstall - If the fragment is installed, remove it from the given
* {@link FragmentTransaction} and also clears the callabck.
*/
protected FragmentTransaction uninstallMessageListFragment(FragmentTransaction ft) {
if (isMessageListInstalled()) {
onMessageListFragmentUninstalled(mMessageListFragment);
ft.remove(mMessageListFragment);
mMessageListFragment.setCallback(null);
mMessageListFragment = null;
}
return ft;
}
/** Called when a {@link MessageListFragment} is about to be uninstalled */
protected void onMessageListFragmentUninstalled(MessageListFragment fragment) {
}
/**
* Uninstall - If the fragment is installed, remove it from the given
* {@link FragmentTransaction} and also clears the callabck.
*/
protected FragmentTransaction uninstallMessageViewFragment(FragmentTransaction ft) {
if (isMessageViewInstalled()) {
onMessageViewFragmentUninstalled(mMessageViewFragment);
ft.remove(mMessageViewFragment);
mMessageViewFragment.setCallback(null);
mMessageViewFragment = null;
}
return ft;
}
/** Called when a {@link MessageViewFragment} is about to be uninstalled */
protected void onMessageViewFragmentUninstalled(MessageViewFragment fragment) {
}
/** @return true if a {@link MailboxListFragment} is installed. */
protected final boolean isMailboxListInstalled() {
return mMailboxListFragment != null;
}
/** @return true if a {@link MessageListFragment} is installed. */
protected final boolean isMessageListInstalled() {
return mMessageListFragment != null;
}
/** @return true if a {@link MessageViewFragment} is installed. */
protected final boolean isMessageViewInstalled() {
return mMessageViewFragment != null;
}
/** @return the installed {@link MailboxListFragment} or null. */
protected final MailboxListFragment getMailboxListFragment() {
return mMailboxListFragment;
}
/** @return the installed {@link MessageListFragment} or null. */
protected final MessageListFragment getMessageListFragment() {
return mMessageListFragment;
}
/** @return the installed {@link MessageViewFragment} or null. */
protected final MessageViewFragment getMessageViewFragment() {
return mMessageViewFragment;
}
/**
* Commit a {@link FragmentTransaction}.
@ -535,14 +601,13 @@ abstract class UIControllerBase {
*/
protected abstract boolean isRefreshEnabled();
/**
* Start/stop the "refresh" animation on the action bar according to the current refresh state.
*
* (We start the animation if {@link #isRefreshInProgress} returns true,
* and stop otherwise.)
* Refresh the action bar and menu items, including the "refreshing" icon.
*/
protected void updateRefreshProgress() {
protected void refreshActionBar() {
if (mActionBarController != null) {
mActionBarController.refresh();
}
mActivity.invalidateOptionsMenu();
}
}

View File

@ -19,16 +19,21 @@ package com.android.email.activity;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.activity.MailboxFinder.Callback;
import com.android.email.activity.setup.AccountSecurity;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.EmailContent.Message;
import com.android.emailcommon.provider.Mailbox;
import com.android.emailcommon.utility.Utility;
import android.app.FragmentManager;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import java.util.Set;
@ -36,183 +41,179 @@ import java.util.Set;
/**
* UI Controller for non x-large devices. Supports a single-pane layout.
*
* STOPSHIP Everything in this class is 100% temporary at this point
* - Navigation model is different from what it should be (whatever it'll be).
* e.g. when the app is launched, we should show Inbox, not mailbox list.
* One one-pane, multiple fragments can be installed at the same time, but only one of them
* can be "visible" at a time. Others are in the back stack. Use {@link #isMailboxListVisible()},
* {@link #isMessageListVisible()} and {@link #isMessageViewVisible()} to determine which is
* visible.
*
* - It uses the two-pane action bar only so that we can change accounts
* Note due to the asynchronous nature of the fragment transaction, there is a window when
* there is no installed or visible fragments.
*
* TODO Use the back stack for the message list -> message view navigation, so that the list
* position/selection will be restored on back.
*
* Major TODOs
* - TODO Proper Navigation model, including retaining fragments to keep state such as the scroll
* position and batch selection.
* - TODO Nested folders
* - TODO Newer/Older for message view with swipe!
* - TODO Implement callbacks
*/
class UIControllerOnePane extends UIControllerBase {
private ActionBarController mActionBarController;
/**
* Current account/mailbox/message IDs.
* Don't use them directly; use the accessors instead, as we might want to get them from the
* topmost fragment in the future.
*/
private long mCurrentAccountId = Account.NO_ACCOUNT;
private long mCurrentMailboxId = Mailbox.NO_MAILBOX;
private long mCurrentMessageId = Message.NO_MESSAGE;
// TODO Newer/Older buttons not needed. Remove this.
private MessageCommandButtonView mMessageCommandButtons;
private final MailboxListFragment.Callback mMailboxListFragmentCallback =
new MailboxListFragment.Callback() {
@Override
public void onAccountSelected(long accountId) {
switchAccount(accountId);
// MailboxListFragment.Callback
@Override
public void onAccountSelected(long accountId) {
switchAccount(accountId);
}
// MailboxListFragment.Callback
@Override
public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount) {
}
// MailboxListFragment.Callback
@Override
public void onMailboxSelected(long accountId, long mailboxId, boolean nestedNavigation) {
if (nestedNavigation) {
return; // Nothing to do on 1-pane.
}
openMailbox(accountId, mailboxId);
}
@Override
public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount) {
// MailboxListFragment.Callback
@Override
public void onParentMailboxChanged() {
refreshActionBar();
}
// MessageListFragment.Callback
@Override
public void onAdvancingOpAccepted(Set<Long> affectedMessages) {
// Nothing to do on 1 pane.
}
// MessageListFragment.Callback
@Override
public void onEnterSelectionMode(boolean enter) {
// TODO Auto-generated method stub
}
// MessageListFragment.Callback
@Override
public void onListLoaded() {
// TODO Auto-generated method stub
}
// MessageListFragment.Callback
@Override
public void onMailboxNotFound() {
open(getUIAccountId(), Mailbox.NO_MAILBOX, Message.NO_MESSAGE);
}
// MessageListFragment.Callback
@Override
public void onMessageOpen(
long messageId, long messageMailboxId, long listMailboxId, int type) {
if (type == MessageListFragment.Callback.TYPE_DRAFT) {
MessageCompose.actionEditDraft(mActivity, messageId);
} else {
open(getUIAccountId(), getMailboxId(), messageId);
}
}
@Override
public void onMailboxSelected(long accountId, long mailboxId, boolean nestedNavigation) {
if (nestedNavigation) {
return; // Nothing to do on 1-pane.
}
openMailbox(accountId, mailboxId);
}
// MessageListFragment.Callback
@Override
public boolean onDragStarted() {
// No drag&drop on 1-pane
return false;
}
@Override
public void onParentMailboxChanged() {
refreshActionBar();
}
};
// MessageListFragment.Callback
@Override
public void onDragEnded() {
// No drag&drop on 1-pane
}
private final MessageListFragment.Callback mMessageListFragmentCallback =
new MessageListFragment.Callback() {
@Override
public void onAdvancingOpAccepted(Set<Long> affectedMessages) {
// Nothing to do on 1 pane.
}
// MessageViewFragment.Callback
@Override
public void onForward() {
MessageCompose.actionForward(mActivity, getMessageId());
}
@Override
public void onEnterSelectionMode(boolean enter) {
// TODO Auto-generated method stub
}
// MessageViewFragment.Callback
@Override
public void onReply() {
MessageCompose.actionReply(mActivity, getMessageId(), false);
}
@Override
public void onListLoaded() {
// TODO Auto-generated method stub
// MessageViewFragment.Callback
@Override
public void onReplyAll() {
MessageCompose.actionReply(mActivity, getMessageId(), true);
}
}
// MessageViewFragment.Callback
@Override
public void onCalendarLinkClicked(long epochEventStartTime) {
ActivityHelper.openCalendar(mActivity, epochEventStartTime);
}
@Override
public void onMailboxNotFound() {
open(getUIAccountId(), Mailbox.NO_MAILBOX, Message.NO_MESSAGE);
}
// MessageViewFragment.Callback
@Override
public boolean onUrlInMessageClicked(String url) {
return ActivityHelper.openUrlInMessage(mActivity, url, getActualAccountId());
}
@Override
public void onMessageOpen(
long messageId, long messageMailboxId, long listMailboxId, int type) {
if (type == MessageListFragment.Callback.TYPE_DRAFT) {
MessageCompose.actionEditDraft(mActivity, messageId);
} else {
open(getUIAccountId(), getMailboxId(), messageId);
}
}
// MessageViewFragment.Callback
@Override
public void onBeforeMessageGone() {
// TODO Auto-generated method stub
}
@Override
public boolean onDragStarted() {
// No drag&drop on 1-pane
return false;
}
// MessageViewFragment.Callback
@Override
public void onMessageSetUnread() {
// TODO Auto-generated method stub
}
@Override
public void onDragEnded() {
// No drag&drop on 1-pane
}
};
// MessageViewFragment.Callback
@Override
public void onRespondedToInvite(int response) {
// TODO Auto-generated method stub
}
private final MessageViewFragment.Callback mMessageViewFragmentCallback =
new MessageViewFragment.Callback() {
@Override
public void onForward() {
MessageCompose.actionForward(mActivity, getMessageId());
}
// MessageViewFragment.Callback
@Override
public void onLoadMessageError(String errorMessage) {
// TODO Auto-generated method stub
}
@Override
public void onReply() {
MessageCompose.actionReply(mActivity, getMessageId(), false);
}
// MessageViewFragment.Callback
@Override
public void onLoadMessageFinished() {
// TODO Auto-generated method stub
}
@Override
public void onReplyAll() {
MessageCompose.actionReply(mActivity, getMessageId(), true);
}
// MessageViewFragment.Callback
@Override
public void onLoadMessageStarted() {
// TODO Auto-generated method stub
}
@Override
public void onCalendarLinkClicked(long epochEventStartTime) {
ActivityHelper.openCalendar(mActivity, epochEventStartTime);
}
// MessageViewFragment.Callback
@Override
public void onMessageNotExists() {
// TODO Auto-generated method stub
}
@Override
public boolean onUrlInMessageClicked(String url) {
return ActivityHelper.openUrlInMessage(mActivity, url, getActualAccountId());
}
@Override
public void onBeforeMessageGone() {
// TODO Auto-generated method stub
}
@Override
public void onMessageSetUnread() {
// TODO Auto-generated method stub
}
@Override
public void onRespondedToInvite(int response) {
// TODO Auto-generated method stub
}
@Override
public void onLoadMessageError(String errorMessage) {
// TODO Auto-generated method stub
}
@Override
public void onLoadMessageFinished() {
// TODO Auto-generated method stub
}
@Override
public void onLoadMessageStarted() {
// TODO Auto-generated method stub
}
@Override
public void onMessageNotExists() {
// TODO Auto-generated method stub
}
@Override
public void onMessageShown() {
// TODO Auto-generated method stub
}
};
// MessageViewFragment.Callback
@Override
public void onMessageShown() {
// TODO Auto-generated method stub
}
// This is all temporary as we'll have a different action bar controller for 1-pane.
private final ActionBarController.Callback mActionBarControllerCallback
= new ActionBarController.Callback() {
private class ActionBarControllerCallback implements ActionBarController.Callback {
@Override
public boolean shouldShowMailboxName() {
return false; // no mailbox name/unread count.
@ -230,8 +231,8 @@ class UIControllerOnePane extends UIControllerBase {
@Override
public boolean shouldShowUp() {
// Always show the UP arrow.
return true;
return isMessageViewVisible()
|| (isMailboxListVisible() && !getMailboxListFragment().isRoot());
}
@Override
@ -254,37 +255,30 @@ class UIControllerOnePane extends UIControllerBase {
Welcome.actionStart(mActivity);
mActivity.finish();
}
};
}
public UIControllerOnePane(EmailActivity activity) {
super(activity);
}
/**
* {@inheritDoc}
*
* At this point we use synchronous transactions.
*/
@Override
protected void commitFragmentTransaction(FragmentTransaction ft) {
super.commitFragmentTransaction(ft);
mActivity.getFragmentManager().executePendingTransactions();
protected ActionBarController createActionBarController(Activity activity) {
// For now, we just reuse the same action bar controller used for 2-pane.
// We may change it later.
return new ActionBarController(activity, activity.getLoaderManager(),
activity.getActionBar(), new ActionBarControllerCallback());
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putLong(BUNDLE_KEY_ACCOUNT_ID, mCurrentAccountId);
outState.putLong(BUNDLE_KEY_MAILBOX_ID, mCurrentMailboxId);
outState.putLong(BUNDLE_KEY_MESSAGE_ID, mCurrentMessageId);
}
@Override
public void restoreInstanceState(Bundle savedInstanceState) {
super.restoreInstanceState(savedInstanceState);
mCurrentAccountId = savedInstanceState.getLong(BUNDLE_KEY_ACCOUNT_ID, Account.NO_ACCOUNT);
mCurrentMailboxId = savedInstanceState.getLong(BUNDLE_KEY_MAILBOX_ID, Mailbox.NO_MAILBOX);
mCurrentMessageId = savedInstanceState.getLong(BUNDLE_KEY_MESSAGE_ID, Message.NO_MESSAGE);
}
@Override
@ -295,8 +289,6 @@ class UIControllerOnePane extends UIControllerBase {
@Override
public void onActivityViewReady() {
super.onActivityViewReady();
mActionBarController = new ActionBarController(mActivity, mActivity.getLoaderManager(),
mActivity.getActionBar(), mActionBarControllerCallback);
mMessageCommandButtons = UiUtilities.getView(mActivity, R.id.message_command_buttons);
mMessageCommandButtons.setCallback(new CommandButtonCallback());
@ -305,7 +297,6 @@ class UIControllerOnePane extends UIControllerBase {
@Override
public void onActivityCreated() {
super.onActivityCreated();
mActionBarController.onActivityCreated();
}
@Override
@ -314,76 +305,96 @@ class UIControllerOnePane extends UIControllerBase {
refreshActionBar();
}
/** @return true if a {@link MailboxListFragment} is installed and visible. */
private final boolean isMailboxListVisible() {
return isMailboxListInstalled();
}
/** @return true if a {@link MessageListFragment} is installed and visible. */
private final boolean isMessageListVisible() {
return isMessageListInstalled();
}
/** @return true if a {@link MessageViewFragment} is installed and visible. */
private final boolean isMessageViewVisible() {
return isMessageViewInstalled();
}
@Override
public long getUIAccountId() {
return mCurrentAccountId;
// Get it from the visible fragment.
if (isMailboxListVisible()) {
return getMailboxListFragment().getAccountId();
}
if (isMessageListVisible()) {
return getMessageListFragment().getAccountId();
}
if (isMessageViewVisible()) {
return getMessageViewFragment().getOpenerAccountId();
}
return Account.NO_ACCOUNT;
}
private long getMailboxId() {
return mCurrentMailboxId;
// Get it from the visible fragment.
if (isMessageListVisible()) {
return getMessageListFragment().getMailboxId();
}
if (isMessageViewVisible()) {
return getMessageViewFragment().getOpenerMailboxId();
}
return Mailbox.NO_MAILBOX;
}
private long getMessageId() {
return mCurrentMessageId;
// Get it from the visible fragment.
if (isMessageViewVisible()) {
return getMessageViewFragment().getMessageId();
}
return Message.NO_MESSAGE;
}
private final MailboxFinder.Callback mInboxLookupCallback = new MailboxFinder.Callback() {
@Override
public void onMailboxFound(long accountId, long mailboxId) {
// Inbox found.
openMailbox(accountId, mailboxId);
}
@Override
public void onAccountNotFound() {
// Account removed?
Welcome.actionStart(mActivity);
}
@Override
public void onMailboxNotFound(long accountId) {
// Inbox not found??
Welcome.actionStart(mActivity);
}
@Override
public void onAccountSecurityHold(long accountId) {
mActivity.startActivity(AccountSecurity.actionUpdateSecurityIntent(mActivity, accountId,
true));
}
};
@Override
protected Callback getInboxLookupCallback() {
// We don't call startInboxLookup in UIControllerOnePane, so shouldn't be called.
throw new RuntimeException("SHOULD NOT BE CALLED"); // STOPSHIP
}
private void refreshActionBar() {
if (mActionBarController != null) {
mActionBarController.refresh();
}
mActivity.invalidateOptionsMenu();
}
private boolean isMailboxListVisible() {
return (getMailboxId() == Mailbox.NO_MAILBOX);
}
private boolean isMessageListVisible() {
return (getMailboxId() != Mailbox.NO_MAILBOX) && (getMessageId() == Message.NO_MESSAGE);
}
private boolean isMessageViewVisible() {
return (getMailboxId() != Mailbox.NO_MAILBOX) && (getMessageId() != Message.NO_MESSAGE);
return mInboxLookupCallback;
}
@Override
public boolean onBackPressed(boolean isSystemBackKey) {
if (isMessageViewVisible()) {
open(getUIAccountId(), getMailboxId(), Message.NO_MESSAGE);
openMailbox(getMessageViewFragment().getOpenerAccountId(),
getMessageViewFragment().getOpenerMailboxId());
return true;
} else if (isMessageListVisible()) {
open(getUIAccountId(), Mailbox.NO_MAILBOX, Message.NO_MESSAGE);
} else if (isMailboxListVisible() && getMailboxListFragment().navigateUp()) {
return true;
} else {
// TODO Call MailboxListFragment.navigateUp().
// STOPSHIP Remove this and return false. This is so that the app can be closed
// with the UP press. (usuful when the device doesn't have a HW back key.)
mActivity.finish();
return true;
// return false;
}
}
@Override
protected void installMailboxListFragment(MailboxListFragment fragment) {
fragment.setCallback(mMailboxListFragmentCallback);
}
@Override
protected void installMessageListFragment(MessageListFragment fragment) {
fragment.setCallback(mMessageListFragmentCallback);
}
@Override
protected void installMessageViewFragment(MessageViewFragment fragment) {
fragment.setCallback(mMessageViewFragmentCallback);
return false;
}
@Override
@ -396,40 +407,63 @@ class UIControllerOnePane extends UIControllerBase {
throw new IllegalArgumentException();
}
// !!! It's all temporary to make 1 pane UI (barely) usable !!!
//
// - Nested folders still doesn't work
// - When opening a child view (e.g. message list -> message view), we should retain
// the current fragment so that all the state (selection, scroll position, etc) will be
// restored when back.
if ((getUIAccountId() == accountId) && (getMailboxId() == mailboxId)
&& (getMessageId() == messageId)) {
return;
}
final FragmentManager fm = mActivity.getFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
if (messageId != Message.NO_MESSAGE) {
ft.replace(R.id.fragment_placeholder, MessageViewFragment.newInstance(messageId));
showMessageView(accountId, mailboxId, messageId);
} else if (mailboxId != Mailbox.NO_MAILBOX) {
ft.replace(R.id.fragment_placeholder, MessageListFragment.newInstance(
accountId, mailboxId));
showMessageList(accountId, mailboxId);
} else {
ft.replace(R.id.fragment_placeholder,
MailboxListFragment.newInstance(accountId, Mailbox.NO_MAILBOX, false));
// Mailbox not specified. Open Inbox or Combined Inbox.
if (accountId == Account.ACCOUNT_ID_COMBINED_VIEW) {
showMessageList(accountId, Mailbox.QUERY_ALL_INBOXES);
} else {
startInboxLookup(accountId);
}
}
}
mCurrentAccountId = accountId;
mCurrentMailboxId = mailboxId;
mCurrentMessageId = messageId;
private void uninstallAllFragments(FragmentTransaction ft) {
if (isMailboxListInstalled()) {
uninstallMailboxListFragment(ft);
}
if (isMessageListInstalled()) {
uninstallMessageListFragment(ft);
}
if (isMessageViewInstalled()) {
uninstallMessageViewFragment(ft);
}
}
private void showMailboxList(long accountId, long mailboxId) {
showFragment(MailboxListFragment.newInstance(accountId, mailboxId, false));
}
private void showMessageList(long accountId, long mailboxId) {
showFragment(MessageListFragment.newInstance(accountId, mailboxId));
}
private void showMessageView(long accountId, long mailboxId, long messageId) {
showFragment(MessageViewFragment.newInstance(accountId, mailboxId, messageId));
}
private void showFragment(Fragment fragment) {
final FragmentTransaction ft = mActivity.getFragmentManager().beginTransaction();
uninstallAllFragments(ft);
ft.add(R.id.fragment_placeholder, fragment);
commitFragmentTransaction(ft);
}
refreshActionBar();
private void showAllMailboxes() {
if (!isAccountSelected()) {
return; // Can happen because of asyncronous fragment transactions.
}
// Don't use open(account, NO_MAILBOX, NO_MESSAGE). This is used to open the default
// view, which is Inbox on the message list.
showMailboxList(getUIAccountId(), Mailbox.NO_MAILBOX);
}
/*
@ -495,4 +529,21 @@ class UIControllerOnePane extends UIControllerBase {
return mRefreshManager.isMailboxListRefreshing(getActualAccountId());
}
}
@Override
public boolean onPrepareOptionsMenu(MenuInflater inflater, Menu menu) {
// STOPSHIP For temporary menu item which should be visible only on 1-pane.
menu.findItem(R.id.show_all_folders).setVisible(true);
return super.onPrepareOptionsMenu(inflater, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.show_all_folders: // STOPSHIP For temporary menu item
showAllMailboxes();
return true;
}
return super.onOptionsItemSelected(item);
}
}

View File

@ -54,27 +54,9 @@ class UIControllerTwoPane extends UIControllerBase implements
@VisibleForTesting
static final int INBOX_AUTO_REFRESH_MIN_INTERVAL = 10 * 1000; // in milliseconds
private ActionBarController mActionBarController;
private final ActionBarControllerCallback mActionBarControllerCallback =
new ActionBarControllerCallback();
// Other UI elements
private ThreePaneLayout mThreePane;
/**
* Fragments that are installed.
*
* A fragment is installed when:
* - it is attached to the activity
* - the parent activity is created
* - and it is not scheduled to be removed.
*
* We set callbacks to fragments only when they are installed.
*/
private MailboxListFragment mMailboxListFragment;
private MessageListFragment mMessageListFragment;
private MessageViewFragment mMessageViewFragment;
private MessageCommandButtonView mMessageCommandButtons;
private MessageOrderManager mOrderManager;
@ -100,12 +82,6 @@ class UIControllerTwoPane extends UIControllerBase implements
FragmentManager.enableDebugLogging(true);
}
private void refreshActionBar() {
if (mActionBarController != null) {
mActionBarController.refresh();
}
}
@Override
public int getLayoutId() {
return R.layout.email_activity_two_pane;
@ -163,7 +139,7 @@ class UIControllerTwoPane extends UIControllerBase implements
}
// Disable CAB when the message list is not visible.
if (isMessageListInstalled()) {
mMessageListFragment.onHidden((visiblePanes & ThreePaneLayout.PANE_MIDDLE) == 0);
getMessageListFragment().onHidden((visiblePanes & ThreePaneLayout.PANE_MIDDLE) == 0);
}
}
@ -377,8 +353,6 @@ class UIControllerTwoPane extends UIControllerBase implements
@Override
public void onActivityViewReady() {
super.onActivityViewReady();
mActionBarController = new ActionBarController(mActivity, mActivity.getLoaderManager(),
mActivity.getActionBar(), mActionBarControllerCallback);
// Set up content
mThreePane = (ThreePaneLayout) mActivity.findViewById(R.id.three_pane);
@ -388,6 +362,12 @@ class UIControllerTwoPane extends UIControllerBase implements
mMessageCommandButtons.setCallback(new CommandButtonCallback());
}
@Override
protected ActionBarController createActionBarController(Activity activity) {
return new ActionBarController(activity, activity.getLoaderManager(),
activity.getActionBar(), new ActionBarControllerCallback());
}
/**
* @return the currently selected account ID, *or* {@link Account#ACCOUNT_ID_COMBINED_VIEW}.
*
@ -395,7 +375,7 @@ class UIControllerTwoPane extends UIControllerBase implements
*/
@Override
public long getUIAccountId() {
return isMailboxListInstalled() ? mMailboxListFragment.getAccountId()
return isMailboxListInstalled() ? getMailboxListFragment().getAccountId()
:Account.NO_ACCOUNT;
}
@ -406,7 +386,7 @@ class UIControllerTwoPane extends UIControllerBase implements
* {@link #getMessageListMailboxId()}
*/
private long getMailboxListMailboxId() {
return isMailboxListInstalled() ? mMailboxListFragment.getSelectedMailboxId()
return isMailboxListInstalled() ? getMailboxListFragment().getSelectedMailboxId()
: Mailbox.NO_MAILBOX;
}
@ -417,7 +397,7 @@ class UIControllerTwoPane extends UIControllerBase implements
* {@link #getMessageListMailboxId()}
*/
private long getMessageListMailboxId() {
return isMessageListInstalled() ? mMessageListFragment.getMailboxId()
return isMessageListInstalled() ? getMessageListFragment().getMailboxId()
: Message.NO_MESSAGE;
}
@ -438,23 +418,10 @@ class UIControllerTwoPane extends UIControllerBase implements
}
private long getMessageId() {
return isMessageViewInstalled() ? mMessageViewFragment.getMessageId()
return isMessageViewInstalled() ? getMessageViewFragment().getMessageId()
: Message.NO_MESSAGE;
}
private boolean isMailboxListInstalled() {
return mMailboxListFragment != null;
}
private boolean isMessageListInstalled() {
return mMessageListFragment != null;
}
private boolean isMessageViewInstalled() {
return mMessageViewFragment != null;
}
/**
* @return true if refresh is in progress for the current mailbox.
*/
@ -481,7 +448,6 @@ class UIControllerTwoPane extends UIControllerBase implements
@Override
public void onActivityCreated() {
super.onActivityCreated();
mActionBarController.onActivityCreated();
}
/** {@inheritDoc} */
@ -536,67 +502,28 @@ class UIControllerTwoPane extends UIControllerBase implements
return this;
}
@Override
protected void installMailboxListFragment(MailboxListFragment fragment) {
mMailboxListFragment = fragment;
mMailboxListFragment.setCallback(this);
// Update action bar / menu
updateRefreshProgress();
refreshActionBar();
}
@Override
protected void installMessageListFragment(MessageListFragment fragment) {
mMessageListFragment = fragment;
mMessageListFragment.setCallback(this);
super.installMessageListFragment(fragment);
if (isMailboxListInstalled()) {
mMailboxListFragment.setHighlightedMailbox(mMessageListFragment.getMailboxId());
getMailboxListFragment().setHighlightedMailbox(fragment.getMailboxId());
}
// Update action bar / menu
updateRefreshProgress();
refreshActionBar();
}
@Override
protected void installMessageViewFragment(MessageViewFragment fragment) {
mMessageViewFragment = fragment;
mMessageViewFragment.setCallback(this);
super.installMessageViewFragment(fragment);
if (isMessageListInstalled()) {
mMessageListFragment.setSelectedMessage(mMessageViewFragment.getMessageId());
getMessageListFragment().setSelectedMessage(fragment.getMessageId());
}
}
private FragmentTransaction uninstallMailboxListFragment(FragmentTransaction ft) {
if (isMailboxListInstalled()) {
ft.remove(mMailboxListFragment);
mMailboxListFragment.setCallback(null);
mMailboxListFragment = null;
}
return ft;
}
private FragmentTransaction uninstallMessageListFragment(FragmentTransaction ft) {
if (isMessageListInstalled()) {
ft.remove(mMessageListFragment);
mMessageListFragment.setCallback(null);
mMessageListFragment = null;
}
return ft;
}
private FragmentTransaction uninstallMessageViewFragment(FragmentTransaction ft) {
if (isMessageViewInstalled()) {
ft.remove(mMessageViewFragment);
mMessageViewFragment.setCallback(null);
mMessageViewFragment = null;
// Don't need it when there's no message view.
stopMessageOrderManager();
}
return ft;
@Override
protected void onMessageViewFragmentUninstalled(MessageViewFragment fragment) {
// Don't need it when there's no message view.
stopMessageOrderManager();
}
/**
@ -638,20 +565,6 @@ class UIControllerTwoPane extends UIControllerBase implements
commitFragmentTransaction(ft);
}
/**
* Pre-fragment transaction check.
*
* @throw IllegalStateException if updateXxx methods can't be called in the current state.
*/
private void preFragmentTransactionCheck() {
if (!isFragmentInstallable()) {
// Code assumes mMailboxListFragment/etc are set right within the
// commitFragmentTransaction() call (because we use synchronous transaction),
// so updateXxx() can't be called if fragments are not installable yet.
throw new IllegalStateException();
}
}
/**
* Loads the given account and optionally selects the given mailbox and message. If the
* specified account is already selected, no actions will be performed unless
@ -669,12 +582,10 @@ class UIControllerTwoPane extends UIControllerBase implements
Log.d(Logging.LOG_TAG, this + " updateMailboxList accountId=" + accountId
+ " mailboxId=" + mailboxId);
}
preFragmentTransactionCheck();
if (accountId == Account.NO_ACCOUNT) {
throw new IllegalArgumentException();
}
if ((getUIAccountId() != accountId) || (getMailboxListMailboxId() != mailboxId)) {
uninstallMailboxListFragment(ft);
ft.add(mThreePane.getLeftPaneId(),
@ -721,7 +632,6 @@ class UIControllerTwoPane extends UIControllerBase implements
if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " updateMessageList mMailboxId=" + mailboxId);
}
preFragmentTransactionCheck();
if (mailboxId == Mailbox.NO_MAILBOX) {
throw new IllegalArgumentException();
}
@ -758,7 +668,6 @@ class UIControllerTwoPane extends UIControllerBase implements
if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, this + " updateMessageView messageId=" + messageId);
}
preFragmentTransactionCheck();
if (messageId == Message.NO_MESSAGE) {
throw new IllegalArgumentException();
}
@ -768,7 +677,9 @@ class UIControllerTwoPane extends UIControllerBase implements
}
uninstallMessageViewFragment(ft);
ft.add(mThreePane.getRightPaneId(), MessageViewFragment.newInstance(messageId));
ft.add(mThreePane.getRightPaneId(), MessageViewFragment.newInstance(
getUIAccountId(), getMessageListMailboxId(), messageId));
}
/**
@ -786,8 +697,8 @@ class UIControllerTwoPane extends UIControllerBase implements
private void unselectMessage() {
commitFragmentTransaction(uninstallMessageViewFragment(
mActivity.getFragmentManager().beginTransaction()));
if (mMessageListFragment != null) {
mMessageListFragment.setSelectedMessage(Message.NO_MESSAGE);
if (isMessageListInstalled()) {
getMessageListFragment().setSelectedMessage(Message.NO_MESSAGE);
}
}
@ -891,7 +802,7 @@ class UIControllerTwoPane extends UIControllerBase implements
public boolean onBackPressed(boolean isSystemBackKey) {
if (mThreePane.onBackPressed(isSystemBackKey)) {
return true;
} else if (isMailboxListInstalled() && mMailboxListFragment.navigateUp()) {
} else if (isMailboxListInstalled() && getMailboxListFragment().navigateUp()) {
return true;
}
return false;
@ -1061,7 +972,7 @@ class UIControllerTwoPane extends UIControllerBase implements
final int visiblePanes = mThreePane.getVisiblePanes();
final boolean leftPaneHidden = ((visiblePanes & ThreePaneLayout.PANE_LEFT) == 0);
return leftPaneHidden
|| (isMailboxListInstalled() && !mMailboxListFragment.isRoot());
|| (isMailboxListInstalled() && !getMailboxListFragment().isRoot());
}
}
}

View File

@ -19,6 +19,7 @@ package com.android.email.activity;
import com.android.email.R;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.res.Resources;
import android.view.View;
@ -123,4 +124,16 @@ public class UiUtilities {
public static void setVisibilitySafe(View parent, int viewId, int visibility) {
setVisibilitySafe(parent.findViewById(viewId), visibility);
}
/**
* Used by an {@link Fragment} to install itself to the host activity.
*
* @see FragmentInstallable
*/
public static void installFragment(Fragment fragment) {
final Activity a = fragment.getActivity();
if (a instanceof FragmentInstallable) {
((FragmentInstallable) a).onInstallFragment(fragment);
}
}
}