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