19fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki/*
29fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki * Copyright (C) 2010 The Android Open Source Project
39fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki *
49fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki * Licensed under the Apache License, Version 2.0 (the "License");
59fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki * you may not use this file except in compliance with the License.
69fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki * You may obtain a copy of the License at
79fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki *
89fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki *      http://www.apache.org/licenses/LICENSE-2.0
99fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki *
109fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki * Unless required by applicable law or agreed to in writing, software
119fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki * distributed under the License is distributed on an "AS IS" BASIS,
129fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki * See the License for the specific language governing permissions and
149fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki * limitations under the License.
159fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki */
169fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki
1766a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blankpackage com.android.email.service;
189fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki
1970edcf05387df33f4761b766add6b80999e425e9Marc Blankimport android.accounts.AccountManager;
2002f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Huimport android.accounts.AccountManagerCallback;
2170edcf05387df33f4761b766add6b80999e425e9Marc Blankimport android.accounts.AccountManagerFuture;
2270edcf05387df33f4761b766add6b80999e425e9Marc Blankimport android.accounts.AuthenticatorException;
2370edcf05387df33f4761b766add6b80999e425e9Marc Blankimport android.accounts.OperationCanceledException;
2403cd72805dab0379ed255d151f1c17cc60655fc3Marc Blankimport android.app.Service;
25e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blankimport android.content.ContentProviderClient;
2670edcf05387df33f4761b766add6b80999e425e9Marc Blankimport android.content.ContentResolver;
2770edcf05387df33f4761b766add6b80999e425e9Marc Blankimport android.content.ContentUris;
2870edcf05387df33f4761b766add6b80999e425e9Marc Blankimport android.content.ContentValues;
299fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onukiimport android.content.Context;
309fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onukiimport android.content.Intent;
313a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantlerimport android.content.pm.ActivityInfo;
323a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantlerimport android.content.res.Configuration;
33f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.content.res.Resources;
34f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.content.res.TypedArray;
35f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.content.res.XmlResourceParser;
3670edcf05387df33f4761b766add6b80999e425e9Marc Blankimport android.database.Cursor;
3770edcf05387df33f4761b766add6b80999e425e9Marc Blankimport android.net.Uri;
3803cd72805dab0379ed255d151f1c17cc60655fc3Marc Blankimport android.os.Bundle;
3903cd72805dab0379ed255d151f1c17cc60655fc3Marc Blankimport android.os.IBinder;
4003cd72805dab0379ed255d151f1c17cc60655fc3Marc Blankimport android.os.RemoteException;
4170edcf05387df33f4761b766add6b80999e425e9Marc Blankimport android.provider.CalendarContract;
42e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blankimport android.provider.CalendarContract.Calendars;
43e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blankimport android.provider.CalendarContract.SyncState;
4470edcf05387df33f4761b766add6b80999e425e9Marc Blankimport android.provider.ContactsContract;
453aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdonimport android.provider.ContactsContract.RawContacts;
46e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blankimport android.provider.SyncStateContract;
47e1a6088ee4e3f0e4344dd9bc38029b6d01431eabMarc Blank
48f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.email.R;
4903cd72805dab0379ed255d151f1c17cc60655fc3Marc Blankimport com.android.emailcommon.Api;
50f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.Logging;
51f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.provider.Account;
5270edcf05387df33f4761b766add6b80999e425e9Marc Blankimport com.android.emailcommon.provider.EmailContent;
5370edcf05387df33f4761b766add6b80999e425e9Marc Blankimport com.android.emailcommon.provider.EmailContent.AccountColumns;
54e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blankimport com.android.emailcommon.provider.HostAuth;
5566a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blankimport com.android.emailcommon.service.EmailServiceProxy;
5666a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blankimport com.android.emailcommon.service.IEmailService;
5766a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blankimport com.android.emailcommon.service.IEmailServiceCallback;
5803cd72805dab0379ed255d151f1c17cc60655fc3Marc Blankimport com.android.emailcommon.service.SearchParams;
5924bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdonimport com.android.emailcommon.service.ServiceProxy;
60f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.service.SyncWindow;
61560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedyimport com.android.mail.utils.LogUtils;
62b5eed31d1bdfcb8e8b316c9c49331295718001bdYu Ping Huimport com.google.common.collect.ImmutableMap;
63462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu
64f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport org.xmlpull.v1.XmlPullParserException;
65f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank
66f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport java.io.IOException;
67b5eed31d1bdfcb8e8b316c9c49331295718001bdYu Ping Huimport java.util.Collection;
6832881e8dd375f16e6059452166503f7136f14ae5Paul Westbrookimport java.util.Map;
6966a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blank
709fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki/**
7166a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blank * Utility functions for EmailService support.
729fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki */
7366a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blankpublic class EmailServiceUtils {
749fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki    /**
7524bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon     * Ask a service to kill its process. This is used when an account is deleted so that
7624bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon     * no background thread that happens to be running will continue, possibly hitting an
7724bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon     * NPE or other error when trying to operate on an account that no longer exists.
7824bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon     * TODO: This is kind of a hack, it's only needed because we fail so badly if an account
7924bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon     * is deleted out from under us while a sync or other operation is in progress. It would
8024bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon     * be a lot cleaner if our background services could handle this without crashing.
8124bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon     */
8224bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon    public static void killService(Context context, String protocol) {
8324bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon        EmailServiceInfo info = getServiceInfo(context, protocol);
8424bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon        if (info != null && info.intentAction != null) {
8524bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon            final Intent serviceIntent = getServiceIntent(info);
8624bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon            serviceIntent.putExtra(ServiceProxy.EXTRA_FORCE_SHUTDOWN, true);
8724bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon            context.startService(serviceIntent);
8824bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon        }
8924bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon    }
9024bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon
9124bb2dabd9dd7d8bd39fed53f312ae6034e373bbMartin Hibdon    /**
92f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     * Starts an EmailService by protocol
939fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki     */
94f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    public static void startService(Context context, String protocol) {
95f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        EmailServiceInfo info = getServiceInfo(context, protocol);
96f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        if (info != null && info.intentAction != null) {
97e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook            final Intent serviceIntent = getServiceIntent(info);
98e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook            context.startService(serviceIntent);
99f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        }
1009fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki    }
1019fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki
1029fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki    /**
103f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     * Starts all remote services
1049fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki     */
105f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    public static void startRemoteServices(Context context) {
106f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        for (EmailServiceInfo info: getServiceInfoList(context)) {
107f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            if (info.intentAction != null) {
108e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook                final Intent serviceIntent = getServiceIntent(info);
109e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook                context.startService(serviceIntent);
110f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            }
111f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        }
112f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    }
113f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank
114f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    /**
115f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     * Returns whether or not remote services are present on device
116f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     */
117f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    public static boolean areRemoteServicesInstalled(Context context) {
118f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        for (EmailServiceInfo info: getServiceInfoList(context)) {
119f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            if (info.intentAction != null) {
120f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                return true;
121f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            }
122f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        }
123f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        return false;
124f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    }
125f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank
126f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    /**
127f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     * Starts all remote services
128f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     */
129f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    public static void setRemoteServicesLogging(Context context, int debugBits) {
130f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        for (EmailServiceInfo info: getServiceInfoList(context)) {
131f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            if (info.intentAction != null) {
132f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                EmailServiceProxy service =
1332075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu                        EmailServiceUtils.getService(context, info.protocol);
134f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                if (service != null) {
135f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                    try {
136f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                        service.setLogging(debugBits);
137f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                    } catch (RemoteException e) {
138f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                        // Move along, nothing to see
139f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                    }
140f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                }
141f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            }
142f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        }
1433a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    }
1443a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank
1453a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank    /**
14666a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blank     * Determine if the EmailService is available
1473a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank     */
148f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    public static boolean isServiceAvailable(Context context, String protocol) {
149f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        EmailServiceInfo info = getServiceInfo(context, protocol);
150f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        if (info == null) return false;
151f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        if (info.klass != null) return true;
152e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook        final Intent serviceIntent = getServiceIntent(info);
153e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook        return new EmailServiceProxy(context, serviceIntent).test();
154e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook    }
155e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook
156e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook    private static Intent getServiceIntent(EmailServiceInfo info) {
157e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook        final Intent serviceIntent = new Intent(info.intentAction);
158e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook        serviceIntent.setPackage(info.intentPackage);
159e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook        return serviceIntent;
160f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    }
161f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank
162f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    /**
163f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     * For a given account id, return a service proxy if applicable, or null.
164f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     *
165f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     * @param accountId the message of interest
1663a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler     * @return service proxy, or null if n/a
167f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     */
1682075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu    public static EmailServiceProxy getServiceForAccount(Context context, long accountId) {
1692075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu        return getService(context, Account.getProtocol(context, accountId));
170f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    }
171f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank
172f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    /**
173f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     * Holder of service information (currently just name and class/intent); if there is a class
174f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     * member, this is a (local, i.e. same process) service; otherwise, this is a remote service
175f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     */
176f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    public static class EmailServiceInfo {
177f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public String protocol;
178f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public String name;
179f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public String accountType;
180f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        Class<? extends Service> klass;
181f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        String intentAction;
182e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook        String intentPackage;
183f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public int port;
184f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public int portSsl;
185f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean defaultSsl;
186f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean offerTls;
187f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean offerCerts;
188f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean usesSmtp;
189f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean offerLocalDeletes;
190f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public int defaultLocalDeletes;
191f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean offerPrefix;
192f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean usesAutodiscover;
193f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean offerLookback;
194f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public int defaultLookback;
195f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean syncChanges;
196f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean syncContacts;
197f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean syncCalendar;
198f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean offerAttachmentPreload;
199f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public CharSequence[] syncIntervalStrings;
200f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public CharSequence[] syncIntervals;
201f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public int defaultSyncInterval;
202b89744ecfb92a4b8fc66a23b942531d39910de44Marc Blank        public String inferPrefix;
203b82ae909d7514bf06090ee3a120aef2154ab0296Marc Blank        public boolean offerLoadMore;
204ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert        public boolean offerMoveTo;
20581b0f74efa39d80b0aa18686c96499faf0e2691fMarc Blank        public boolean requiresSetup;
2065c523858385176c33a7456bb84035de78552d22dMarc Blank        public boolean hide;
207f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank
2085c523858385176c33a7456bb84035de78552d22dMarc Blank        @Override
209f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public String toString() {
210f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            StringBuilder sb = new StringBuilder("Protocol: ");
211f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            sb.append(protocol);
212f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            sb.append(", ");
213f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            sb.append(klass != null ? "Local" : "Remote");
214af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank            sb.append(" , Account Type: ");
215af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank            sb.append(accountType);
216f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            return sb.toString();
217f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        }
21891237e9dcb0a948f17488b464edabcea0f259d31Makoto Onuki    }
21991237e9dcb0a948f17488b464edabcea0f259d31Makoto Onuki
2202075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu    public static EmailServiceProxy getService(Context context, String protocol) {
221cf3b3ae987e73453f2265673a7ba3a72a1a6b4edMarc Blank        EmailServiceInfo info = null;
222f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        // Handle the degenerate case here (account might have been deleted)
223cf3b3ae987e73453f2265673a7ba3a72a1a6b4edMarc Blank        if (protocol != null) {
224cf3b3ae987e73453f2265673a7ba3a72a1a6b4edMarc Blank            info = getServiceInfo(context, protocol);
225cf3b3ae987e73453f2265673a7ba3a72a1a6b4edMarc Blank        }
226cf3b3ae987e73453f2265673a7ba3a72a1a6b4edMarc Blank        if (info == null) {
227560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy            LogUtils.w(Logging.LOG_TAG, "Returning NullService for " + protocol);
2282075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu            return new EmailServiceProxy(context, NullService.class);
229e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank        } else  {
2302075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu            return getServiceFromInfo(context, info);
231e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank        }
232e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank    }
233e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank
2342075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu    public static EmailServiceProxy getServiceFromInfo(Context context, EmailServiceInfo info) {
235e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank        if (info.klass != null) {
2362075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu            return new EmailServiceProxy(context, info.klass);
237f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        } else {
238e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook            final Intent serviceIntent = getServiceIntent(info);
239e4ac06080ba8b8e57531982ea290354b1a9a4305Paul Westbrook            return new EmailServiceProxy(context, serviceIntent);
240f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        }
24166a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blank    }
24266a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blank
24381b0f74efa39d80b0aa18686c96499faf0e2691fMarc Blank    public static EmailServiceInfo getServiceInfoForAccount(Context context, long accountId) {
24481b0f74efa39d80b0aa18686c96499faf0e2691fMarc Blank        String protocol = Account.getProtocol(context, accountId);
24581b0f74efa39d80b0aa18686c96499faf0e2691fMarc Blank        return getServiceInfo(context, protocol);
24681b0f74efa39d80b0aa18686c96499faf0e2691fMarc Blank    }
24781b0f74efa39d80b0aa18686c96499faf0e2691fMarc Blank
2483a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler    public static EmailServiceInfo getServiceInfo(Context context, String protocol) {
2493a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler        return getServiceMap(context).get(protocol);
25066a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blank    }
25166a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blank
2523a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler    public static Collection<EmailServiceInfo> getServiceInfoList(Context context) {
2533a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler        return getServiceMap(context).values();
254c18f8f615f134a2b391d06e2d8d49434a8bb94e5Makoto Onuki    }
255c18f8f615f134a2b391d06e2d8d49434a8bb94e5Makoto Onuki
25670edcf05387df33f4761b766add6b80999e425e9Marc Blank    private static void finishAccountManagerBlocker(AccountManagerFuture<?> future) {
25770edcf05387df33f4761b766add6b80999e425e9Marc Blank        try {
25870edcf05387df33f4761b766add6b80999e425e9Marc Blank            // Note: All of the potential errors are simply logged
25970edcf05387df33f4761b766add6b80999e425e9Marc Blank            // here, as there is nothing to actually do about them.
26070edcf05387df33f4761b766add6b80999e425e9Marc Blank            future.getResult();
26170edcf05387df33f4761b766add6b80999e425e9Marc Blank        } catch (OperationCanceledException e) {
262560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy            LogUtils.w(Logging.LOG_TAG, e.toString());
26370edcf05387df33f4761b766add6b80999e425e9Marc Blank        } catch (AuthenticatorException e) {
264560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy            LogUtils.w(Logging.LOG_TAG, e.toString());
26570edcf05387df33f4761b766add6b80999e425e9Marc Blank        } catch (IOException e) {
266560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy            LogUtils.w(Logging.LOG_TAG, e.toString());
26770edcf05387df33f4761b766add6b80999e425e9Marc Blank        }
26870edcf05387df33f4761b766add6b80999e425e9Marc Blank    }
26970edcf05387df33f4761b766add6b80999e425e9Marc Blank
27002f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu    /**
27102f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu     * Add an account to the AccountManager.
27202f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu     * @param context Our {@link Context}.
27302f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu     * @param account The {@link Account} we're adding.
27402f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu     * @param email Whether the user wants to sync email on this account.
27502f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu     * @param calendar Whether the user wants to sync calendar on this account.
27602f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu     * @param contacts Whether the user wants to sync contacts on this account.
27702f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu     * @param callback A callback for when the AccountManager is done.
27802f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu     * @return The result of {@link AccountManager#addAccount}.
27902f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu     */
28002f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu    public static AccountManagerFuture<Bundle> setupAccountManagerAccount(final Context context,
28102f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu            final Account account, final boolean email, final boolean calendar,
28202f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu            final boolean contacts, final AccountManagerCallback<Bundle> callback) {
28302f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu        final Bundle options = new Bundle(5);
28402f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu        final HostAuth hostAuthRecv =
28502f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu                HostAuth.restoreHostAuthWithId(context, account.mHostAuthKeyRecv);
28602f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu        if (hostAuthRecv == null) {
28702f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu            return null;
28802f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu        }
28902f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu        // Set up username/password
29002f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu        options.putString(EasAuthenticatorService.OPTIONS_USERNAME, account.mEmailAddress);
29102f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu        options.putString(EasAuthenticatorService.OPTIONS_PASSWORD, hostAuthRecv.mPassword);
29202f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu        options.putBoolean(EasAuthenticatorService.OPTIONS_CONTACTS_SYNC_ENABLED, contacts);
29302f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu        options.putBoolean(EasAuthenticatorService.OPTIONS_CALENDAR_SYNC_ENABLED, calendar);
29402f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu        options.putBoolean(EasAuthenticatorService.OPTIONS_EMAIL_SYNC_ENABLED, email);
29502f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu        final EmailServiceInfo info = getServiceInfo(context, hostAuthRecv.mProtocol);
29602f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu        return AccountManager.get(context).addAccount(info.accountType, null, null, options, null,
29702f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu                callback, null);
29802f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu    }
29902f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu
300462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu    public static void updateAccountManagerType(Context context,
30148b14fde961ef57103f7a31196254e357987f203Yu Ping Hu            android.accounts.Account amAccount, final Map<String, String> protocolMap) {
30232881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook        final ContentResolver resolver = context.getContentResolver();
30332881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook        final Cursor c = resolver.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION,
30470edcf05387df33f4761b766add6b80999e425e9Marc Blank                AccountColumns.EMAIL_ADDRESS + "=?", new String[] { amAccount.name }, null);
30570edcf05387df33f4761b766add6b80999e425e9Marc Blank        // That's odd, isn't it?
30670edcf05387df33f4761b766add6b80999e425e9Marc Blank        if (c == null) return;
30770edcf05387df33f4761b766add6b80999e425e9Marc Blank        try {
30870edcf05387df33f4761b766add6b80999e425e9Marc Blank            if (c.moveToNext()) {
30970edcf05387df33f4761b766add6b80999e425e9Marc Blank                // Get the EmailProvider Account/HostAuth
31032881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook                final Account account = new Account();
31170edcf05387df33f4761b766add6b80999e425e9Marc Blank                account.restore(c);
31232881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook                final HostAuth hostAuth =
31370edcf05387df33f4761b766add6b80999e425e9Marc Blank                        HostAuth.restoreHostAuthWithId(context, account.mHostAuthKeyRecv);
31432881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook                if (hostAuth == null) {
31532881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook                    return;
31632881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook                }
31770edcf05387df33f4761b766add6b80999e425e9Marc Blank
318462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu                final String newProtocol = protocolMap.get(hostAuth.mProtocol);
319462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu                if (newProtocol == null) {
320462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu                    // This account doesn't need updating.
321e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    return;
322e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                }
323462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu
324560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                LogUtils.w(Logging.LOG_TAG, "Converting " + amAccount.name + " to "
325462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu                        + newProtocol);
326e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank
32732881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook                final ContentValues accountValues = new ContentValues();
32870edcf05387df33f4761b766add6b80999e425e9Marc Blank                int oldFlags = account.mFlags;
32970edcf05387df33f4761b766add6b80999e425e9Marc Blank
33070edcf05387df33f4761b766add6b80999e425e9Marc Blank                // Mark the provider account incomplete so it can't get reconciled away
33170edcf05387df33f4761b766add6b80999e425e9Marc Blank                account.mFlags |= Account.FLAGS_INCOMPLETE;
33270edcf05387df33f4761b766add6b80999e425e9Marc Blank                accountValues.put(AccountColumns.FLAGS, account.mFlags);
33332881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook                final Uri accountUri = ContentUris.withAppendedId(Account.CONTENT_URI, account.mId);
33470edcf05387df33f4761b766add6b80999e425e9Marc Blank                resolver.update(accountUri, accountValues, null, null);
33570edcf05387df33f4761b766add6b80999e425e9Marc Blank
33670edcf05387df33f4761b766add6b80999e425e9Marc Blank                // Change the HostAuth to reference the new protocol; this has to be done before
33770edcf05387df33f4761b766add6b80999e425e9Marc Blank                // trying to create the AccountManager account (below)
33832881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook                final ContentValues hostValues = new ContentValues();
339462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu                hostValues.put(HostAuth.PROTOCOL, newProtocol);
34070edcf05387df33f4761b766add6b80999e425e9Marc Blank                resolver.update(ContentUris.withAppendedId(HostAuth.CONTENT_URI, hostAuth.mId),
34170edcf05387df33f4761b766add6b80999e425e9Marc Blank                        hostValues, null, null);
342560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                LogUtils.w(Logging.LOG_TAG, "Updated HostAuths");
34370edcf05387df33f4761b766add6b80999e425e9Marc Blank
34470edcf05387df33f4761b766add6b80999e425e9Marc Blank                try {
34570edcf05387df33f4761b766add6b80999e425e9Marc Blank                    // Get current settings for the existing AccountManager account
34670edcf05387df33f4761b766add6b80999e425e9Marc Blank                    boolean email = ContentResolver.getSyncAutomatically(amAccount,
34770edcf05387df33f4761b766add6b80999e425e9Marc Blank                            EmailContent.AUTHORITY);
348e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    if (!email) {
349e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        // Try our old provider name
350e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        email = ContentResolver.getSyncAutomatically(amAccount,
351e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                                "com.android.email.provider");
352e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    }
35332881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook                    final boolean contacts = ContentResolver.getSyncAutomatically(amAccount,
35470edcf05387df33f4761b766add6b80999e425e9Marc Blank                            ContactsContract.AUTHORITY);
35532881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook                    final boolean calendar = ContentResolver.getSyncAutomatically(amAccount,
35670edcf05387df33f4761b766add6b80999e425e9Marc Blank                            CalendarContract.AUTHORITY);
357560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                    LogUtils.w(Logging.LOG_TAG, "Email: " + email + ", Contacts: " + contacts + ","
358560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                            + " Calendar: " + calendar);
359e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank
360e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    // Get sync keys for calendar/contacts
36132881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook                    final String amName = amAccount.name;
36232881e8dd375f16e6059452166503f7136f14ae5Paul Westbrook                    final String oldType = amAccount.type;
363e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    ContentProviderClient client = context.getContentResolver()
364e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                            .acquireContentProviderClient(CalendarContract.CONTENT_URI);
365e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    byte[] calendarSyncKey = null;
366e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    try {
367e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        calendarSyncKey = SyncStateContract.Helpers.get(client,
368e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                                asCalendarSyncAdapter(SyncState.CONTENT_URI, amName, oldType),
369e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                                new android.accounts.Account(amName, oldType));
370e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    } catch (RemoteException e) {
371560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                        LogUtils.w(Logging.LOG_TAG, "Get calendar key FAILED");
372e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    } finally {
373e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        client.release();
374e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    }
375e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    client = context.getContentResolver()
376e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                            .acquireContentProviderClient(ContactsContract.AUTHORITY_URI);
377e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    byte[] contactsSyncKey = null;
378e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    try {
379e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        contactsSyncKey = SyncStateContract.Helpers.get(client,
380e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                                ContactsContract.SyncState.CONTENT_URI,
381e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                                new android.accounts.Account(amName, oldType));
382e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    } catch (RemoteException e) {
383560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                        LogUtils.w(Logging.LOG_TAG, "Get contacts key FAILED");
384e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    } finally {
385e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        client.release();
386e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    }
387e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    if (calendarSyncKey != null) {
388560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                        LogUtils.w(Logging.LOG_TAG, "Got calendar key: "
389560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                                + new String(calendarSyncKey));
390e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    }
391e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    if (contactsSyncKey != null) {
392560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                        LogUtils.w(Logging.LOG_TAG, "Got contacts key: "
393560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                                + new String(contactsSyncKey));
394e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    }
395e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank
396e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    // Set up a new AccountManager account with new type and old settings
39702f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu                    AccountManagerFuture<?> amFuture = setupAccountManagerAccount(context, account,
39802f0b1eee8f5de651ad5f0289146f88fea99bce0Yu Ping Hu                            email, calendar, contacts, null);
399e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    finishAccountManagerBlocker(amFuture);
400560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                    LogUtils.w(Logging.LOG_TAG, "Created new AccountManager account");
40170edcf05387df33f4761b766add6b80999e425e9Marc Blank
4023aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                    // TODO: Clean up how we determine the type.
4033aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                    final String accountType = protocolMap.get(hostAuth.mProtocol + "_type");
4043aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                    // Move calendar and contacts data from the old account to the new one.
4053aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                    // We must do this before deleting the old account or the data is lost.
4063aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                    moveCalendarData(context.getContentResolver(), amName, oldType, accountType);
4073aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                    moveContactsData(context.getContentResolver(), amName, oldType, accountType);
4087d6d8c87f86a17cae59af645637458b17e72c716Martin Hibdon
40970edcf05387df33f4761b766add6b80999e425e9Marc Blank                    // Delete the AccountManager account
410e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    amFuture = AccountManager.get(context)
41170edcf05387df33f4761b766add6b80999e425e9Marc Blank                            .removeAccount(amAccount, null, null);
41270edcf05387df33f4761b766add6b80999e425e9Marc Blank                    finishAccountManagerBlocker(amFuture);
413560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                    LogUtils.w(Logging.LOG_TAG, "Deleted old AccountManager account");
41470edcf05387df33f4761b766add6b80999e425e9Marc Blank
415e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    // Restore sync keys for contacts/calendar
4163aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon
417462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu                    if (accountType != null &&
418462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu                            calendarSyncKey != null && calendarSyncKey.length != 0) {
419e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        client = context.getContentResolver()
420e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                                .acquireContentProviderClient(CalendarContract.CONTENT_URI);
421e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        try {
422e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                            SyncStateContract.Helpers.set(client,
423e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                                    asCalendarSyncAdapter(SyncState.CONTENT_URI, amName,
424462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu                                            accountType),
425462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu                                    new android.accounts.Account(amName, accountType),
426e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                                    calendarSyncKey);
427560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                            LogUtils.w(Logging.LOG_TAG, "Set calendar key...");
428e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        } catch (RemoteException e) {
429560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                            LogUtils.w(Logging.LOG_TAG, "Set calendar key FAILED");
430e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        } finally {
431e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                            client.release();
432e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        }
433e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    }
434462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu                    if (accountType != null &&
435462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu                            contactsSyncKey != null && contactsSyncKey.length != 0) {
436e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        client = context.getContentResolver()
437e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                                .acquireContentProviderClient(ContactsContract.AUTHORITY_URI);
438e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        try {
439e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                            SyncStateContract.Helpers.set(client,
440e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                                    ContactsContract.SyncState.CONTENT_URI,
441462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu                                    new android.accounts.Account(amName, accountType),
442e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                                    contactsSyncKey);
443560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                            LogUtils.w(Logging.LOG_TAG, "Set contacts key...");
444e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        } catch (RemoteException e) {
445560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                            LogUtils.w(Logging.LOG_TAG, "Set contacts key FAILED");
446e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                        }
447e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    }
448e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank
449e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                    // That's all folks!
450560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                    LogUtils.w(Logging.LOG_TAG, "Account update completed.");
45170edcf05387df33f4761b766add6b80999e425e9Marc Blank                } finally {
45270edcf05387df33f4761b766add6b80999e425e9Marc Blank                    // Clear the incomplete flag on the provider account
45370edcf05387df33f4761b766add6b80999e425e9Marc Blank                    accountValues.put(AccountColumns.FLAGS, oldFlags);
45470edcf05387df33f4761b766add6b80999e425e9Marc Blank                    resolver.update(accountUri, accountValues, null, null);
455560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                    LogUtils.w(Logging.LOG_TAG, "[Incomplete flag cleared]");
45670edcf05387df33f4761b766add6b80999e425e9Marc Blank                }
45770edcf05387df33f4761b766add6b80999e425e9Marc Blank            }
45870edcf05387df33f4761b766add6b80999e425e9Marc Blank        } finally {
45970edcf05387df33f4761b766add6b80999e425e9Marc Blank            c.close();
46070edcf05387df33f4761b766add6b80999e425e9Marc Blank        }
46170edcf05387df33f4761b766add6b80999e425e9Marc Blank    }
46270edcf05387df33f4761b766add6b80999e425e9Marc Blank
4633aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon    private static void moveCalendarData(final ContentResolver resolver, final String name,
4643aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon            final String oldType, final String newType) {
4653aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon        final Uri oldCalendars = Calendars.CONTENT_URI.buildUpon()
4663aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
4673aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                .appendQueryParameter(Calendars.ACCOUNT_NAME, name)
4683aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                .appendQueryParameter(Calendars.ACCOUNT_TYPE, oldType)
4693aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                .build();
4703aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon
4713aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon        // Update this calendar to have the new account type.
4723aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon        final ContentValues values = new ContentValues();
4733aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon        values.put(CalendarContract.Calendars.ACCOUNT_TYPE, newType);
4743aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon        resolver.update(oldCalendars, values,
4753aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                Calendars.ACCOUNT_NAME + "=? AND " + Calendars.ACCOUNT_TYPE + "=?",
4763aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                new String[] {name, oldType});
4773aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon    }
4783aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon
4793aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon    private static void moveContactsData(final ContentResolver resolver, final String name,
4803aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon            final String oldType, final String newType) {
4813aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon        final Uri oldContacts = RawContacts.CONTENT_URI.buildUpon()
4823aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
4833aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                .appendQueryParameter(RawContacts.ACCOUNT_NAME, name)
4843aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                .appendQueryParameter(RawContacts.ACCOUNT_TYPE, oldType)
4853aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon                .build();
4863aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon
4873aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon        // Update this calendar to have the new account type.
4883aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon        final ContentValues values = new ContentValues();
4893aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon        values.put(CalendarContract.Calendars.ACCOUNT_TYPE, newType);
4903aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon        resolver.update(oldContacts, values, null, null);
4913aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon    }
4923aad3fcb8bb916c989fe67cfbf527eb0df6fc6d1Martin Hibdon
4933a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler    private static final Configuration sOldConfiguration = new Configuration();
4943a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler    private static Map<String, EmailServiceInfo> sServiceMap = null;
4953a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler    private static final Object sServiceMapLock = new Object();
4963a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler
497c18f8f615f134a2b391d06e2d8d49434a8bb94e5Makoto Onuki    /**
498f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     * Parse services.xml file to find our available email services
49991237e9dcb0a948f17488b464edabcea0f259d31Makoto Onuki     */
5003a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler    private static Map<String, EmailServiceInfo> getServiceMap(final Context context) {
5013a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler        synchronized (sServiceMapLock) {
5023a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler            /**
5033a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler             * We cache localized strings here, so make sure to regenerate the service map if
5043a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler             * the locale changes
5053a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler             */
5063a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler            if (sServiceMap == null) {
5073a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                sOldConfiguration.setTo(context.getResources().getConfiguration());
5083a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler            }
509b5eed31d1bdfcb8e8b316c9c49331295718001bdYu Ping Hu
5103a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler            final int delta =
5113a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                    sOldConfiguration.updateFrom(context.getResources().getConfiguration());
512b5eed31d1bdfcb8e8b316c9c49331295718001bdYu Ping Hu
5133a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler            if (sServiceMap != null
5143a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                    && !Configuration.needNewResources(delta, ActivityInfo.CONFIG_LOCALE)) {
5153a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                return sServiceMap;
5163a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler            }
5173a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler
5183a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler            final ImmutableMap.Builder<String, EmailServiceInfo> builder = ImmutableMap.builder();
5193a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler
5203a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler            try {
5213a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                final Resources res = context.getResources();
5223a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                final XmlResourceParser xml = res.getXml(R.xml.services);
5233a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                int xmlEventType;
5243a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                // walk through senders.xml file.
5253a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
5263a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                    if (xmlEventType == XmlResourceParser.START_TAG &&
5273a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            "emailservice".equals(xml.getName())) {
5283a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        final EmailServiceInfo info = new EmailServiceInfo();
5293a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        final TypedArray ta =
5303a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                res.obtainAttributes(xml, R.styleable.EmailServiceInfo);
5313a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.protocol = ta.getString(R.styleable.EmailServiceInfo_protocol);
5323a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.accountType = ta.getString(R.styleable.EmailServiceInfo_accountType);
5333a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.name = ta.getString(R.styleable.EmailServiceInfo_name);
5343a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.hide = ta.getBoolean(R.styleable.EmailServiceInfo_hide, false);
5353a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        final String klass =
5363a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                ta.getString(R.styleable.EmailServiceInfo_serviceClass);
5373a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.intentAction = ta.getString(R.styleable.EmailServiceInfo_intent);
5383a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.intentPackage =
5393a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                ta.getString(R.styleable.EmailServiceInfo_intentPackage);
5403a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.defaultSsl =
5413a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                ta.getBoolean(R.styleable.EmailServiceInfo_defaultSsl, false);
5423a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.port = ta.getInteger(R.styleable.EmailServiceInfo_port, 0);
5433a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.portSsl = ta.getInteger(R.styleable.EmailServiceInfo_portSsl, 0);
5443a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.offerTls = ta.getBoolean(R.styleable.EmailServiceInfo_offerTls, false);
5453a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.offerCerts =
5463a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                ta.getBoolean(R.styleable.EmailServiceInfo_offerCerts, false);
5473a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.offerLocalDeletes =
5483a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getBoolean(R.styleable.EmailServiceInfo_offerLocalDeletes, false);
5493a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.defaultLocalDeletes =
5503a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getInteger(R.styleable.EmailServiceInfo_defaultLocalDeletes,
5513a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                    Account.DELETE_POLICY_ON_DELETE);
5523a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.offerPrefix =
5533a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getBoolean(R.styleable.EmailServiceInfo_offerPrefix, false);
5543a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.usesSmtp = ta.getBoolean(R.styleable.EmailServiceInfo_usesSmtp, false);
5553a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.usesAutodiscover =
5563a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getBoolean(R.styleable.EmailServiceInfo_usesAutodiscover, false);
5573a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.offerLookback =
5583a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getBoolean(R.styleable.EmailServiceInfo_offerLookback, false);
5593a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.defaultLookback =
5603a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getInteger(R.styleable.EmailServiceInfo_defaultLookback,
5613a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                    SyncWindow.SYNC_WINDOW_3_DAYS);
5623a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.syncChanges =
5633a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getBoolean(R.styleable.EmailServiceInfo_syncChanges, false);
5643a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.syncContacts =
5653a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getBoolean(R.styleable.EmailServiceInfo_syncContacts, false);
5663a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.syncCalendar =
5673a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getBoolean(R.styleable.EmailServiceInfo_syncCalendar, false);
5683a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.offerAttachmentPreload =
5693a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getBoolean(R.styleable.EmailServiceInfo_offerAttachmentPreload,
5703a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                    false);
5713a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.syncIntervalStrings =
5723a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getTextArray(R.styleable.EmailServiceInfo_syncIntervalStrings);
5733a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.syncIntervals =
5743a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getTextArray(R.styleable.EmailServiceInfo_syncIntervals);
5753a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.defaultSyncInterval =
5763a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            ta.getInteger(R.styleable.EmailServiceInfo_defaultSyncInterval, 15);
5773a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.inferPrefix = ta.getString(R.styleable.EmailServiceInfo_inferPrefix);
5783a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.offerLoadMore =
5793a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                ta.getBoolean(R.styleable.EmailServiceInfo_offerLoadMore, false);
580ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert                        info.offerMoveTo =
581ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert                                ta.getBoolean(R.styleable.EmailServiceInfo_offerMoveTo, false);
5823a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        info.requiresSetup =
5833a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                ta.getBoolean(R.styleable.EmailServiceInfo_requiresSetup, false);
5843a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler
5853a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        // Must have either "class" (local) or "intent" (remote)
5863a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        if (klass != null) {
5873a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            try {
5883a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                // noinspection unchecked
5893a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                info.klass = (Class<? extends Service>) Class.forName(klass);
5903a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            } catch (ClassNotFoundException e) {
5913a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                throw new IllegalStateException(
5923a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                        "Class not found in service descriptor: " + klass);
5933a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            }
5943a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        }
5953a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        if (info.klass == null && info.intentAction == null) {
596f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                            throw new IllegalStateException(
5973a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                    "No class or intent action specified in service descriptor");
598f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                        }
5993a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        if (info.klass != null && info.intentAction != null) {
6003a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                            throw new IllegalStateException(
6013a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                                    "Both class and intent action specified in service descriptor");
6023a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        }
6033a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                        builder.put(info.protocol, info);
604f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                    }
605f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                }
6063a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler            } catch (XmlPullParserException e) {
6073a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                // ignore
6083a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler            } catch (IOException e) {
6093a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler                // ignore
610f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            }
6113a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler            sServiceMap = builder.build();
6123a8c86b18265eb3786bf32b5c043b5942ddb4e45Tony Mantler            return sServiceMap;
61303cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
614f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    }
61503cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
616e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank    private static Uri asCalendarSyncAdapter(Uri uri, String account, String accountType) {
617e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank        return uri.buildUpon().appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
618e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
619e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank                .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
620e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank    }
621e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank
622f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    /**
623f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     * A no-op service that can be returned for non-existent/null protocols
624f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank     */
625f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank    class NullService implements IEmailService {
626f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
627f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public IBinder asBinder() {
628f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            return null;
62903cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
63003cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
631f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
632f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public Bundle validate(HostAuth hostauth) throws RemoteException {
633f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            return null;
63403cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
63503cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
636f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
63717d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu        public void startSync(long mailboxId, boolean userRequest, int deltaMessageCount)
63817d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu                throws RemoteException {
63903cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
64003cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
641f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
642f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public void stopSync(long mailboxId) throws RemoteException {
64303cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
64403cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
645f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
646f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public void loadMore(long messageId) throws RemoteException {
647f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        }
648f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank
649f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
650d5acf0bbc00cbe9a2c075e1bd4825ccbd9851d8dYu Ping Hu        public void loadAttachment(final IEmailServiceCallback cb, final long attachmentId,
651d5acf0bbc00cbe9a2c075e1bd4825ccbd9851d8dYu Ping Hu                final boolean background) throws RemoteException {
65203cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
65303cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
654f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
655f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public void updateFolderList(long accountId) throws RemoteException {
65603cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
65703cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
658f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
659f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean createFolder(long accountId, String name) throws RemoteException {
66003cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank            return false;
66103cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
66203cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
663f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
664f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean deleteFolder(long accountId, String name) throws RemoteException {
665f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            return false;
66603cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
66703cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
668f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
669f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public boolean renameFolder(long accountId, String oldName, String newName)
670f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                throws RemoteException {
671f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            return false;
67203cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
67303cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
674f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
675f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public void setLogging(int on) throws RemoteException {
67603cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
67703cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
678f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
679f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public void hostChanged(long accountId) throws RemoteException {
68003cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
68103cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
682f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
683f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public Bundle autoDiscover(String userName, String password) throws RemoteException {
684f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            return null;
68503cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
68603cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
687f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
688f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public void sendMeetingResponse(long messageId, int response) throws RemoteException {
68903cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
69003cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
691f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
6929a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu        public void deleteAccountPIMData(final String emailAddress) throws RemoteException {
69303cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
69403cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
695f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
696f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public int getApiLevel() throws RemoteException {
697f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            return Api.LEVEL;
698f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        }
699f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank
700f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
701f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public int searchMessages(long accountId, SearchParams params, long destMailboxId)
702f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank                throws RemoteException {
70303cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank            return 0;
70403cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
70503cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
706f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        @Override
707f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank        public void sendMail(long accountId) throws RemoteException {
70803cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        }
70903cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank
71003cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank        @Override
711e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank        public void serviceUpdated(String emailAddress) throws RemoteException {
712e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank        }
713e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank
714e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank        @Override
7150b5f15d61ebf7c0e8428100637bc479ed93a4cb2Marc Blank        public int getCapabilities(Account acct) throws RemoteException {
716f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank            return 0;
717f19f9cf4d3e5229715da77fe05a1a2bbd8da3f41Marc Blank        }
7189fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki    }
7199fe51f632965f5d085ae45a1089c7c97dcec8881Makoto Onuki}
720