Controller.java revision bcec088320fc56cd5b5e1bbc706e4b7e304b95bf
1/*
2 * Copyright (C) 2009 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;
18
19import com.android.email.mail.MessagingException;
20import com.android.email.mail.Store;
21import com.android.email.provider.EmailContent;
22
23import android.content.Context;
24
25import java.util.HashSet;
26
27/**
28 * New central controller/dispatcher for Email activities that may require remote operations.
29 * Handles disambiguating between legacy MessagingController operations and newer provider/sync
30 * based code.
31 */
32public class Controller {
33
34    static Controller sInstance;
35    private Context mContext;
36    private MessagingController mLegacyController;
37    private HashSet<Result> mListeners = new HashSet<Result>();
38
39    protected Controller(Context _context) {
40        mContext = _context;
41        mLegacyController = MessagingController.getInstance(mContext);
42    }
43
44    /**
45     * Gets or creates the singleton instance of Controller. Application is used to
46     * provide a Context to classes that need it.
47     * @param _context
48     */
49    public synchronized static Controller getInstance(Context _context) {
50        if (sInstance == null) {
51            sInstance = new Controller(_context);
52        }
53        return sInstance;
54    }
55
56    /**
57     * Any UI code that wishes for callback results (on async ops) should register their callback
58     * here (typically from onResume()).  Unregistered callbacks will never be called, to prevent
59     * problems when the command completes and the activity has already paused or finished.
60     * @param listener The callback that may be used in action methods
61     */
62    public void addResultCallback(Result listener) {
63        synchronized (mListeners) {
64            mListeners.add(listener);
65        }
66    }
67
68    /**
69     * Any UI code that no longer wishes for callback results (on async ops) should unregister
70     * their callback here (typically from onPause()).  Unregistered callbacks will never be called,
71     * to prevent problems when the command completes and the activity has already paused or
72     * finished.
73     * @param listener The callback that may no longer be used
74     */
75    public void removeResultCallback(Result listener) {
76        synchronized (mListeners) {
77            mListeners.remove(listener);
78        }
79    }
80
81    private boolean isActiveResultCallback(Result listener) {
82        synchronized (mListeners) {
83            return mListeners.contains(listener);
84        }
85    }
86
87    /**
88     * Request a remote update of mailboxes for an account.
89     *
90     * TODO: Implement (if any) for non-MessagingController
91     * TODO: Probably the right way is to create a fake "service" for MessagingController ops
92     */
93    public void updateMailboxList(final EmailContent.Account account, final Result callback) {
94
95        // 1. determine if we can use MessagingController for this
96        boolean legacyController = isMessagingController(account);
97
98        // 2. if not...?
99        // TODO: for now, just pretend "it worked"
100        if (!legacyController) {
101            if (callback != null) {
102                callback.onResult(null, account.mId, -1, -1);
103            }
104            return;
105        }
106
107        // 3. if so, make the call
108        new Thread() {
109            @Override
110            public void run() {
111                MessagingListener listener = new LegacyListener(callback);
112                mLegacyController.addListener(listener);
113                mLegacyController.listFolders(account, listener);
114            }
115        }.start();
116    }
117
118    /**
119     * Simple helper to determine if legacy MessagingController should be used
120     */
121    private boolean isMessagingController(EmailContent.Account account) {
122        Store.StoreInfo info =
123            Store.StoreInfo.getStoreInfo(account.getStoreUri(mContext), mContext);
124        String scheme = info.mScheme;
125
126        return ("pop3".equals(scheme) || "imap".equals(scheme));
127    }
128
129    /**
130     * Simple callback for synchronous commands.  For many commands, this can be largely ignored
131     * and the result is observed via provider cursors.  The callback will *not* necessarily be
132     * made from the UI thread, so you may need further handlers to safely make UI updates.
133     */
134    public interface Result {
135
136        /**
137         * Callback for operations affecting an account, mailbox, or message
138         *
139         * @param result If null, the operation completed without error
140         * @param accountKey The account being operated on
141         * @param mailboxKey The mailbox being operated on, or -1 if account-wide
142         * @param messageKey The message being operated on, or -1 if mailbox- or account- wide.
143         */
144        public void onResult(MessagingException result,
145                long accountKey, long mailboxKey, long messageKey);
146    }
147
148    /**
149     * Support for receiving callbacks from MessagingController and dealing with UI going
150     * out of scope.
151     */
152    private class LegacyListener extends MessagingListener {
153        Result mResultCallback;
154
155        public LegacyListener(Result callback) {
156            mResultCallback = callback;
157        }
158
159        @Override
160        public void listFoldersFailed(EmailContent.Account account, String message) {
161            if (mResultCallback != null && isActiveResultCallback(mResultCallback)) {
162                mResultCallback.onResult(new MessagingException(message), account.mId, -1, -1);
163            }
164            mLegacyController.removeListener(this);
165        }
166
167        @Override
168        public void listFoldersFinished(EmailContent.Account account) {
169            if (mResultCallback != null && isActiveResultCallback(mResultCallback)) {
170                mResultCallback.onResult(null, account.mId, -1, -1);
171            }
172            mLegacyController.removeListener(this);
173        }
174    }
175
176
177}
178