AI 144525: Add structural support for Exchange transport.  The idea is that
  the shipping client will include the necessary generic pieces for
  configuring an Exchange client (e.g. account setup) but will not
  include actual Exchange client code (e.g. transport / protocol).
  Also added a "sample code" implementation of Exchange for use
  as a starting point for implementors.  (Note, this will not ship
  in Donut, it's a placeholder for working on the "framework"
  aspects.)
  BUG=1740621,1740626

Automated import of CL 144525
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 025d495..b1fc4fd 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -59,6 +59,11 @@
             >
         </activity>
         <activity
+            android:name=".activity.setup.AccountSetupExchange"
+            android:label="@string/account_setup_exchange_title"
+            >
+        </activity>
+        <activity
             android:name=".activity.setup.AccountSetupOptions"
             android:label="@string/account_setup_options_title"
             >
diff --git a/res/layout/account_setup_account_type.xml b/res/layout/account_setup_account_type.xml
index fbbcf74..3c30e25 100644
--- a/res/layout/account_setup_account_type.xml
+++ b/res/layout/account_setup_account_type.xml
@@ -42,4 +42,13 @@
         android:minWidth="@dimen/button_minWidth"
         android:layout_gravity="center_horizontal"
         />
+    <Button
+        android:id="@+id/exchange"
+        android:text="@string/account_setup_account_type_exchange_action"
+        android:layout_height="wrap_content"
+        android:layout_width="150sp"
+        android:minWidth="@dimen/button_minWidth"
+        android:layout_gravity="center_horizontal"
+        android:visibility="gone"
+        />
 </LinearLayout>
diff --git a/res/layout/account_setup_exchange.xml b/res/layout/account_setup_exchange.xml
new file mode 100644
index 0000000..2a6c651
--- /dev/null
+++ b/res/layout/account_setup_exchange.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:scrollbarStyle="outsideInset">
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:orientation="vertical">
+        <TextView
+            android:text="@string/account_setup_incoming_username_label"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorPrimary" />
+        <EditText
+            android:id="@+id/account_username"
+            android:inputType="textEmailAddress"
+            android:imeOptions="actionDone"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent" />
+        <TextView
+            android:text="@string/account_setup_incoming_password_label"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorPrimary" />
+        <EditText
+            android:id="@+id/account_password"
+            android:inputType="textPassword"
+            android:imeOptions="actionDone"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent" />
+        <!-- This text may be changed in code if the server is IMAP, etc. -->
+        <TextView
+            android:text="@string/account_setup_exchange_server_label"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorPrimary" />
+        <!-- Note: we use inputType=textUri as the closest approximation to a server name -->
+        <EditText
+            android:id="@+id/account_server"
+            android:inputType="textUri"
+            android:imeOptions="actionDone"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent" />
+        <TextView
+            android:text="@string/account_setup_exchange_domain_label"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorPrimary" />
+        <EditText
+            android:id="@+id/account_domain"
+            android:hint="@string/account_setup_exchange_domain_hint"
+            inputType="text"
+            android:imeOptions="actionDone"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent" />
+        <CheckBox
+            android:id="@+id/account_ssl"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent"
+            android:text="@string/account_setup_exchange_ssl_label" />
+
+        <View
+            android:layout_width="fill_parent"
+            android:layout_height="0px"
+            android:layout_weight="1" />
+        <RelativeLayout
+            android:layout_width="fill_parent"
+            android:layout_height="54dip"
+            android:background="@android:drawable/bottom_bar">
+            <Button
+                android:id="@+id/next"
+                android:text="@string/next_action"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:minWidth="@dimen/button_minWidth"
+                android:drawableRight="@drawable/button_indicator_next"
+                android:layout_alignParentRight="true"
+                android:layout_centerVertical="true" />
+        </RelativeLayout>
+    </LinearLayout>
+</ScrollView>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 509fb6d..47dffdc 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -238,6 +238,8 @@
     <string name="account_setup_account_type_pop_action">POP3 account</string>
     <!-- "Add new email account" screen, button name in response to what type of account this is -->
     <string name="account_setup_account_type_imap_action">IMAP account</string>
+    <!-- "Add new email account" screen, button name in response to what type of account this is -->
+    <string name="account_setup_account_type_exchange_action">Exchange/ActiveSync</string>
     <!-- "Incoming server settings" screen, label for text field -->
     <string name="account_setup_incoming_title">Incoming server settings</string>
     <!-- "Incoming server settings" screen, label for text field -->
@@ -290,6 +292,17 @@
     <string name="account_setup_outgoing_username_label">Username</string>
     <!-- On "Outgoing server settings" screen, label for text field -->
     <string name="account_setup_outgoing_password_label">Password</string>
+    
+    <!-- Title of "Exchange server settings" screen -->
+    <string name="account_setup_exchange_title">Exchange server settings</string>
+    <!-- On "Exchange" setup screen, the name of the server -->
+    <string name="account_setup_exchange_server_label">Exchange Server</string>
+    <!-- On "Exchange" setup screen, the domain name label -->
+    <string name="account_setup_exchange_domain_label">Domain:</string>
+    <!-- On "Exchange" setup screen, the domain name hint -->
+    <string name="account_setup_exchange_domain_hint">Enter domain here</string>
+    <!-- On "Exchange" setup screen, the use-SSL checkbox label -->
+    <string name="account_setup_exchange_ssl_label">Use secure connection (SSL)</string>
 
     <!-- In Account setup options screen, Activity title -->
     <string name="account_setup_options_title">Account options</string>
diff --git a/res/xml/senders.xml b/res/xml/senders.xml
index 138bcd8..3a1aff8 100644
--- a/res/xml/senders.xml
+++ b/res/xml/senders.xml
@@ -31,4 +31,7 @@
 
 <senders>
     <sender scheme="smtp" class="com.android.email.mail.transport.SmtpSender" />
+    
+    <!-- This is here for temporary demo purposes only.  Do not ship with this. -->
+    <!-- sender scheme="eas" class="com.android.email.mail.exchange.ExchangeSenderExample" / -->
 </senders>
diff --git a/res/xml/stores.xml b/res/xml/stores.xml
index d0f2d8c..efe4ac2 100644
--- a/res/xml/stores.xml
+++ b/res/xml/stores.xml
@@ -33,4 +33,7 @@
     <store scheme="local" class="com.android.email.mail.store.LocalStore" />
     <store scheme="pop3" class="com.android.email.mail.store.Pop3Store" />
     <store scheme="imap" class="com.android.email.mail.store.ImapStore" />
+    
+    <!-- This is here for temporary demo purposes only.  Do not ship with this. -->
+    <!-- store scheme="eas" class="com.android.email.mail.exchange.ExchangeStoreExample" / -->
 </stores>
diff --git a/src/com/android/email/activity/setup/AccountSetupAccountType.java b/src/com/android/email/activity/setup/AccountSetupAccountType.java
index f62e420..0211754 100644
--- a/src/com/android/email/activity/setup/AccountSetupAccountType.java
+++ b/src/com/android/email/activity/setup/AccountSetupAccountType.java
@@ -18,6 +18,8 @@
 
 import com.android.email.Account;
 import com.android.email.R;
+import com.android.email.mail.MessagingException;
+import com.android.email.mail.Store;
 
 import android.app.Activity;
 import android.content.Intent;
@@ -57,9 +59,15 @@
         setContentView(R.layout.account_setup_account_type);
         ((Button)findViewById(R.id.pop)).setOnClickListener(this);
         ((Button)findViewById(R.id.imap)).setOnClickListener(this);
-
+        ((Button)findViewById(R.id.exchange)).setOnClickListener(this);
+        
         mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT);
         mMakeDefault = (boolean)getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false);
+
+        if (isExchangeAvailable()) {
+            findViewById(R.id.exchange).setVisibility(View.VISIBLE);
+        }
+        // TODO: Dynamic creation of buttons, instead of just hiding things we don't need
     }
 
     private void onPop() {
@@ -98,6 +106,47 @@
         AccountSetupIncoming.actionIncomingSettings(this, mAccount, mMakeDefault);
         finish();
     }
+    
+    /**
+     * The user has selected an exchange account type.  Try to put together a URI using the entered
+     * email address.  Also set the mail delete policy here, because there is no UI (for exchange).
+     */
+    private void onExchange() {
+        try {
+            URI uri = new URI(mAccount.getStoreUri());
+            uri = new URI("eas", uri.getUserInfo(), uri.getHost(), uri.getPort(), null, null, null);
+            mAccount.setStoreUri(uri.toString());
+            mAccount.setSenderUri(uri.toString());
+        } catch (URISyntaxException use) {
+            /*
+             * This should not happen.
+             */
+            throw new Error(use);
+        }
+        // TODO: Confirm correct delete policy for exchange
+        mAccount.setDeletePolicy(Account.DELETE_POLICY_ON_DELETE);
+        AccountSetupExchange.actionIncomingSettings(this, mAccount, mMakeDefault);
+        finish();
+    }
+    
+    /**
+     * Determine if we can show the "exchange" option
+     * 
+     * TODO: This should be dynamic and data-driven for all account types, not just hardcoded
+     * like this.
+     */
+    private boolean isExchangeAvailable() {
+        try {
+            URI uri = new URI(mAccount.getStoreUri());
+            uri = new URI("eas", uri.getUserInfo(), uri.getHost(), uri.getPort(), null, null, null);
+            Store store = Store.getInstance(uri.toString(), this);
+            return (store != null);
+        } catch (URISyntaxException e) {
+            return false;
+        } catch (MessagingException e) {
+            return false;
+        }
+    }
 
     public void onClick(View v) {
         switch (v.getId()) {
@@ -107,6 +156,9 @@
             case R.id.imap:
                 onImap();
                 break;
+            case R.id.exchange:
+                onExchange();
+                break;
         }
     }
 }
diff --git a/src/com/android/email/activity/setup/AccountSetupExchange.java b/src/com/android/email/activity/setup/AccountSetupExchange.java
new file mode 100644
index 0000000..1367121
--- /dev/null
+++ b/src/com/android/email/activity/setup/AccountSetupExchange.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2009 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.setup;
+
+import com.android.email.Account;
+import com.android.email.Preferences;
+import com.android.email.R;
+import com.android.email.Utility;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * Provides generic setup for Exchange accounts.  The following fields are supported:
+ *
+ *  Email Address   (from previous setup screen)
+ *  Server
+ *  Domain
+ *  Requires SSL?
+ *  User (login)
+ *  Password
+ */
+public class AccountSetupExchange extends Activity implements OnClickListener {
+    private static final String EXTRA_ACCOUNT = "account";
+    private static final String EXTRA_MAKE_DEFAULT = "makeDefault";
+
+    private EditText mUsernameView;
+    private EditText mPasswordView;
+    private EditText mServerView;
+    private EditText mDomainView;
+    private CheckBox mSslSecurityView;
+
+    private Button mNextButton;
+    private Account mAccount;
+    private boolean mMakeDefault;
+
+    public static void actionIncomingSettings(Activity fromActivity, Account account, 
+            boolean makeDefault) {
+        Intent i = new Intent(fromActivity, AccountSetupExchange.class);
+        i.putExtra(EXTRA_ACCOUNT, account);
+        i.putExtra(EXTRA_MAKE_DEFAULT, makeDefault);
+        fromActivity.startActivity(i);
+    }
+
+    public static void actionEditIncomingSettings(Activity fromActivity, Account account) {
+        Intent i = new Intent(fromActivity, AccountSetupExchange.class);
+        i.setAction(Intent.ACTION_EDIT);
+        i.putExtra(EXTRA_ACCOUNT, account);
+        fromActivity.startActivity(i);
+    }
+
+    /**
+     * For now, we'll simply replicate outgoing, for the purpose of satisfying the 
+     * account settings flow.
+     */
+    public static void actionEditOutgoingSettings(Activity fromActivity, Account account) {
+        Intent i = new Intent(fromActivity, AccountSetupExchange.class);
+        i.setAction(Intent.ACTION_EDIT);
+        i.putExtra(EXTRA_ACCOUNT, account);
+        fromActivity.startActivity(i);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.account_setup_exchange);
+
+        mUsernameView = (EditText) findViewById(R.id.account_username);
+        mPasswordView = (EditText) findViewById(R.id.account_password);
+        mServerView = (EditText) findViewById(R.id.account_server);
+        mDomainView = (EditText) findViewById(R.id.account_domain);
+        mSslSecurityView = (CheckBox) findViewById(R.id.account_ssl);
+
+        mNextButton = (Button)findViewById(R.id.next);
+        mNextButton.setOnClickListener(this);
+
+        /*
+         * Calls validateFields() which enables or disables the Next button
+         * based on the fields' validity.
+         */
+        TextWatcher validationTextWatcher = new TextWatcher() {
+            public void afterTextChanged(Editable s) {
+                validateFields();
+            }
+
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+            }
+
+            public void onTextChanged(CharSequence s, int start, int before, int count) {
+            }
+        };
+        mUsernameView.addTextChangedListener(validationTextWatcher);
+        mPasswordView.addTextChangedListener(validationTextWatcher);
+        mServerView.addTextChangedListener(validationTextWatcher);
+        mDomainView.addTextChangedListener(validationTextWatcher);
+
+        mAccount = (Account)getIntent().getSerializableExtra(EXTRA_ACCOUNT);
+        mMakeDefault = getIntent().getBooleanExtra(EXTRA_MAKE_DEFAULT, false);
+
+        /*
+         * If we're being reloaded we override the original account with the one
+         * we saved
+         */
+        if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_ACCOUNT)) {
+            mAccount = (Account)savedInstanceState.getSerializable(EXTRA_ACCOUNT);
+        }
+
+        try {
+            URI uri = new URI(mAccount.getStoreUri());
+            String username = null;
+            String password = null;
+            if (uri.getUserInfo() != null) {
+                String[] userInfoParts = uri.getUserInfo().split(":", 2);
+                username = userInfoParts[0];
+                if (userInfoParts.length > 1) {
+                    password = userInfoParts[1];
+                }
+            }
+
+            if (username != null) {
+                mUsernameView.setText(username);
+            }
+
+            if (password != null) {
+                mPasswordView.setText(password);
+            }
+
+            if (uri.getScheme().startsWith("eas")) {
+                // any other setup from mAccount can go here
+            } else {
+                throw new Error("Unknown account type: " + mAccount.getStoreUri());
+            }
+
+            if (uri.getHost() != null) {
+                mServerView.setText(uri.getHost());
+            }
+            
+            String domain = uri.getPath();
+            if (!TextUtils.isEmpty(domain)) {
+                mDomainView.setText(domain.substring(1));
+            }
+            
+            mSslSecurityView.setChecked(uri.getScheme().contains("ssl"));
+
+        } catch (URISyntaxException use) {
+            /*
+             * We should always be able to parse our own settings.
+             */
+            throw new Error(use);
+        }
+
+        validateFields();
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putSerializable(EXTRA_ACCOUNT, mAccount);
+    }
+
+    /**
+     * Check the values in the fields and decide if it makes sense to enable the "next" button
+     * NOTE:  Does it make sense to extract & combine with similar code in AccountSetupIncoming? 
+     */
+    private void validateFields() {
+        boolean enabled = Utility.requiredFieldValid(mUsernameView)
+                && Utility.requiredFieldValid(mPasswordView)
+                && Utility.requiredFieldValid(mServerView)
+                && Utility.requiredFieldValid(mDomainView);
+        if (enabled) {
+            try {
+                URI uri = getUri();
+            } catch (URISyntaxException use) {
+                enabled = false;
+            }
+        }
+        mNextButton.setEnabled(enabled);
+        Utility.setCompoundDrawablesAlpha(mNextButton, enabled ? 255 : 128);
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (resultCode == RESULT_OK) {
+            if (Intent.ACTION_EDIT.equals(getIntent().getAction())) {
+                mAccount.save(Preferences.getPreferences(this));
+                finish();
+            } else {
+                // Go directly to end - there is no 2nd screen for incoming settings
+                AccountSetupOptions.actionOptions(this, mAccount, mMakeDefault);
+                finish();
+            }
+        }
+    }
+    
+    /**
+     * Attempt to create a URI from the fields provided.  Throws URISyntaxException if there's 
+     * a problem with the user input.
+     * @return a URI built from the account setup fields
+     */
+    private URI getUri() throws URISyntaxException {
+        boolean sslRequired = mSslSecurityView.isChecked();
+        String scheme = sslRequired ? "eas+ssl+" : "eas";
+        String userInfo = mUsernameView.getText().toString().trim() + ":" + 
+                mPasswordView.getText().toString().trim();
+        String host = mServerView.getText().toString().trim();
+        String path = "/" + mDomainView.getText().toString().trim();
+
+        URI uri = new URI(
+                scheme,
+                userInfo,
+                host,
+                0,
+                path,
+                null,
+                null);
+
+        return uri;
+    }
+
+    private void onNext() {
+        try {
+            URI uri = getUri();
+            mAccount.setStoreUri(uri.toString());
+        } catch (URISyntaxException use) {
+            /*
+             * It's unrecoverable if we cannot create a URI from components that
+             * we validated to be safe.
+             */
+            throw new Error(use);
+        }
+
+        AccountSetupCheckSettings.actionCheckSettings(this, mAccount, true, false);
+    }
+
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.next:
+                onNext();
+                break;
+        }
+    }
+}
diff --git a/src/com/android/email/mail/exchange/ExchangeFolderExample.java b/src/com/android/email/mail/exchange/ExchangeFolderExample.java
new file mode 100644
index 0000000..77b3e17
--- /dev/null
+++ b/src/com/android/email/mail/exchange/ExchangeFolderExample.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2009 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.mail.exchange;
+
+import com.android.email.mail.FetchProfile;
+import com.android.email.mail.Flag;
+import com.android.email.mail.Folder;
+import com.android.email.mail.Message;
+import com.android.email.mail.MessageRetrievalListener;
+import com.android.email.mail.MessagingException;
+
+/**
+ * Sample code for implementing a new server folder.  See also ExchangeStoreExample,
+ * ExchangeSenderExample, and ExchangeTransportExample.
+ */
+public class ExchangeFolderExample extends Folder {
+
+    private final ExchangeTransportExample mTransport;
+    private final ExchangeStoreExample mStore;
+    private final String mName;
+
+    public ExchangeFolderExample(ExchangeStoreExample store, String name) 
+            throws MessagingException {
+        mStore = store;
+        mTransport = store.getTransport();
+        mName = name;
+        if (!mTransport.isFolderAvailable(name)) {
+            throw new MessagingException("folder not supported: " + name);
+        }
+    }
+
+    @Override
+    public void appendMessages(Message[] messages) throws MessagingException {
+        // TODO Implement this function
+    }
+
+    @Override
+    public void close(boolean expunge) throws MessagingException {
+        // TODO Implement this function
+    }
+
+    @Override
+    public void copyMessages(Message[] msgs, Folder folder) throws MessagingException {
+        // TODO Implement this function
+    }
+
+    @Override
+    public boolean create(FolderType type) throws MessagingException {
+        // TODO Implement this function
+        return false;
+    }
+
+    @Override
+    public void delete(boolean recurse) throws MessagingException {
+        // TODO Implement this function
+    }
+
+    @Override
+    public boolean exists() throws MessagingException {
+        // TODO Implement this function
+        return false;
+    }
+
+    @Override
+    public Message[] expunge() throws MessagingException {
+        // TODO Implement this function
+        return null;
+    }
+
+    @Override
+    public void fetch(Message[] messages, FetchProfile fp, MessageRetrievalListener listener)
+            throws MessagingException {
+        // TODO Implement this function
+    }
+
+    @Override
+    public Message getMessage(String uid) throws MessagingException {
+        // TODO Implement this function
+        return null;
+    }
+
+    @Override
+    public int getMessageCount() throws MessagingException {
+        // TODO Implement this function
+        return 0;
+    }
+
+    @Override
+    public Message[] getMessages(int start, int end, MessageRetrievalListener listener)
+            throws MessagingException {
+        // TODO Implement this function
+        return null;
+    }
+
+    @Override
+    public Message[] getMessages(MessageRetrievalListener listener) throws MessagingException {
+        // TODO Implement this function
+        return null;
+    }
+
+    @Override
+    public Message[] getMessages(String[] uids, MessageRetrievalListener listener)
+            throws MessagingException {
+        // TODO Implement this function
+        return null;
+    }
+
+    @Override
+    public OpenMode getMode() throws MessagingException {
+        // TODO Implement this function
+        return null;
+    }
+
+    @Override
+    public String getName() {
+        // TODO Implement this function
+        return null;
+    }
+
+    @Override
+    public Flag[] getPermanentFlags() throws MessagingException {
+        // TODO Implement this function
+        return null;
+    }
+
+    @Override
+    public int getUnreadMessageCount() throws MessagingException {
+        // TODO Implement this function
+        return 0;
+    }
+
+    @Override
+    public boolean isOpen() {
+        // TODO Implement this function
+        return false;
+    }
+
+    @Override
+    public void open(OpenMode mode) throws MessagingException {
+        // TODO Implement this function
+    }
+
+    @Override
+    public void setFlags(Message[] messages, Flag[] flags, boolean value) throws MessagingException {
+        // TODO Implement this function
+    }
+
+
+}
diff --git a/src/com/android/email/mail/exchange/ExchangeSenderExample.java b/src/com/android/email/mail/exchange/ExchangeSenderExample.java
new file mode 100644
index 0000000..0ac1206
--- /dev/null
+++ b/src/com/android/email/mail/exchange/ExchangeSenderExample.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2009 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.mail.exchange;
+
+import com.android.email.mail.Message;
+import com.android.email.mail.MessagingException;
+import com.android.email.mail.Sender;
+
+import android.content.Context;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * Sample code for implementing a new Sender.  See also ExchangeSenderExample,
+ * ExchangeFolderExample, and ExchangeTransportExample.
+ * 
+ * To enable this placeholder, please add:
+ *   <sender scheme="eas" class="com.android.email.mail.exchange.ExchangeSenderExample" />
+ * to res/xml/senders.xml
+ */
+public class ExchangeSenderExample extends Sender {
+
+    private final Context mContext;
+    private final ExchangeTransportExample mTransport;
+
+    /**
+     * Factory method.
+     */
+    public static Sender newInstance(String uri, Context context) throws MessagingException {
+        return new ExchangeSenderExample(uri, context);
+    }
+
+    private ExchangeSenderExample(String _uri, Context context) throws MessagingException {
+        mContext = context;
+
+        URI uri = null;
+        try {
+            uri = new URI(_uri);
+        } catch (URISyntaxException e) {
+            throw new MessagingException("Invalid uri for ExchangeSenderExample");
+        }
+        
+        String scheme = uri.getScheme();
+        int connectionSecurity;
+        if (scheme.equals("eas")) {
+            connectionSecurity = ExchangeTransportExample.CONNECTION_SECURITY_NONE;
+        } else if (scheme.equals("eas+ssl+")) {
+            connectionSecurity = ExchangeTransportExample.CONNECTION_SECURITY_SSL_REQUIRED;
+        } else {
+            throw new MessagingException("Unsupported protocol");
+        }
+
+        mTransport = ExchangeTransportExample.getInstance(uri, context);
+    }
+
+    @Override
+    public void close() throws MessagingException {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void open() throws MessagingException {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void sendMessage(Message message) throws MessagingException {
+        // TODO Auto-generated method stub
+
+    }
+
+    /**
+     * Get class of SettingActivity for this Sender class.
+     * @return Activity class that has class method actionEditOutgoingSettings(). 
+     */
+    @Override
+    public Class<? extends android.app.Activity> getSettingActivityClass() {
+        return com.android.email.activity.setup.AccountSetupExchange.class;
+    }
+}
diff --git a/src/com/android/email/mail/exchange/ExchangeStoreExample.java b/src/com/android/email/mail/exchange/ExchangeStoreExample.java
new file mode 100644
index 0000000..d70ca06
--- /dev/null
+++ b/src/com/android/email/mail/exchange/ExchangeStoreExample.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2009 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.mail.exchange;
+
+import com.android.email.mail.Folder;
+import com.android.email.mail.MessagingException;
+import com.android.email.mail.Store;
+
+import android.content.Context;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+
+/**
+ * This is a placeholder for use in Exchange implementations.  It is based on the notion of
+ * lightweight adapter classes for Store, Folder, and Sender, and a common facade for the common
+ * Transport code.
+ * 
+ * To enable this placeholder, please add:
+ *   <store scheme="eas" class="com.android.email.mail.exchange.ExchangeStoreExample" />
+ * to res/xml/stores.xml
+ */
+public class ExchangeStoreExample extends Store {
+    
+    private final Context mContext;
+    private URI mUri;
+
+    private final ExchangeTransportExample mTransport;
+    private final HashMap<String, Folder> mFolders = new HashMap<String, Folder>();
+
+    /**
+     * Factory method.
+     */
+    public static Store newInstance(String uri, Context context)
+    throws MessagingException {
+        return new ExchangeStoreExample(uri, context);
+    }
+
+    /**
+     * eas://user:password@server/domain
+     *
+     * @param _uri
+     * @param application
+     * @throws MessagingException
+     */
+    private ExchangeStoreExample(String _uri, Context context) throws MessagingException {
+        mContext = context;
+        try {
+            mUri = new URI(_uri);
+        } catch (URISyntaxException e) {
+            throw new MessagingException("Invalid uri for ExchangeStoreExample");
+        }
+
+        String scheme = mUri.getScheme();
+        int connectionSecurity;
+        if (scheme.equals("eas")) {
+            connectionSecurity = ExchangeTransportExample.CONNECTION_SECURITY_NONE;
+        } else if (scheme.equals("eas+ssl+")) {
+            connectionSecurity = ExchangeTransportExample.CONNECTION_SECURITY_SSL_REQUIRED;
+        } else {
+            throw new MessagingException("Unsupported protocol");
+        }
+
+        mTransport = ExchangeTransportExample.getInstance(mUri, context);
+    }
+
+    /**
+     * Retrieve the underlying transport.  Used primarily for testing.
+     * @return
+     */
+    /* package */ ExchangeTransportExample getTransport() {
+        return mTransport;
+    }
+
+    @Override
+    public void checkSettings() throws MessagingException {
+        mTransport.checkSettings(mUri);
+    }
+
+    @Override
+    public Folder getFolder(String name) throws MessagingException {
+        synchronized (mFolders) {
+            Folder folder = mFolders.get(name);
+            if (folder == null) {
+                folder = new ExchangeFolderExample(this, name);
+                mFolders.put(folder.getName(), folder);
+            }
+            return folder;
+        }
+    }
+
+    @Override
+    public Folder[] getPersonalNamespaces() throws MessagingException {
+        return new Folder[] {
+                getFolder(ExchangeTransportExample.FOLDER_INBOX),
+        };
+    }
+    
+    /**
+     * Get class of SettingActivity for this Store class.
+     * @return Activity class that has class method actionEditIncomingSettings(). 
+     */
+    @Override
+    public Class<? extends android.app.Activity> getSettingActivityClass() {
+        return com.android.email.activity.setup.AccountSetupExchange.class;
+    }
+}
+
diff --git a/src/com/android/email/mail/exchange/ExchangeTransportExample.java b/src/com/android/email/mail/exchange/ExchangeTransportExample.java
new file mode 100644
index 0000000..de89c5d
--- /dev/null
+++ b/src/com/android/email/mail/exchange/ExchangeTransportExample.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2009 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.mail.exchange;
+
+import com.android.email.Email;
+import com.android.email.mail.MessagingException;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import java.net.URI;
+import java.util.HashMap;
+
+/**
+ * Sample code for implementing a new server transport.  See also ExchangeStoreExample,
+ * ExchangeFolderExample, and ExchangeSenderExample.
+ */
+public class ExchangeTransportExample {
+    public static final int CONNECTION_SECURITY_NONE = 0;
+    public static final int CONNECTION_SECURITY_SSL_REQUIRED = 1;
+    
+    public static final String FOLDER_INBOX = Email.INBOX;
+    
+    private final Context mContext;
+    
+    private String mHost;
+    private String mDomain;
+    private String mUsername;
+    private String mPassword;
+
+    private static HashMap<String, ExchangeTransportExample> sUriToInstanceMap =
+        new HashMap<String, ExchangeTransportExample>();
+    private static final HashMap<String, Integer> sFolderMap = new HashMap<String, Integer>();
+
+    
+    /**
+     * Public factory.  The transport should be a singleton (per Uri)
+     */
+    public synchronized static ExchangeTransportExample getInstance(URI uri, Context context)
+    throws MessagingException {
+        if (!uri.getScheme().equals("eas") && !uri.getScheme().equals("eas+ssl+")) {
+            throw new MessagingException("Invalid scheme");
+        }
+
+        final String key = uri.toString();
+        ExchangeTransportExample transport = sUriToInstanceMap.get(key);
+        if (transport == null) { 
+            transport = new ExchangeTransportExample(uri, context);
+            sUriToInstanceMap.put(key, transport);
+        }
+        return transport;
+    }
+
+    /**
+     * Private constructor - use public factory.
+     */
+    private ExchangeTransportExample(URI uri, Context context) throws MessagingException {
+        mContext = context;
+        setUri(uri);
+    }
+
+    /**
+     * Use the Uri to set up a newly-constructed transport
+     * @param uri
+     * @throws MessagingException
+     */
+    private void setUri(final URI uri) throws MessagingException {
+        mHost = uri.getHost();
+        if (mHost == null) {
+            throw new MessagingException("host not specified");
+        }
+
+        mDomain = uri.getPath();
+        if (!TextUtils.isEmpty(mDomain)) {
+            mDomain = mDomain.substring(1);
+        }
+
+        final String userInfo = uri.getUserInfo();
+        if (userInfo == null) {
+            throw new MessagingException("user information not specifed");
+        }
+        final String[] uinfo = userInfo.split(":", 2);
+        if (uinfo.length != 2) {
+            throw new MessagingException("user name and password not specified");
+        }
+        mUsername = uinfo[0];
+        mPassword = uinfo[1];
+    }
+
+    /**
+     * Blocking call that checks for a useable server connection, credentials, etc.
+     * @param uri the server/account to try and connect to
+     * @throws MessagingException thrown if the connection, server, account are not useable
+     */
+    public void checkSettings(URI uri) throws MessagingException {
+        setUri(uri);
+        // Perform a server connection here
+        // Throw MessageException if not useable
+    }
+    
+    /**
+     * Typical helper function:  Return existence of a given folder
+     */
+    public boolean isFolderAvailable(final String folder) {
+        return sFolderMap.containsKey(folder);
+    }
+}
\ No newline at end of file