1898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki/* 2898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * Copyright (C) 2010 The Android Open Source Project 3898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * 4898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * Licensed under the Apache License, Version 2.0 (the "License"); 5898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * you may not use this file except in compliance with the License. 6898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * You may obtain a copy of the License at 7898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * 8898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * http://www.apache.org/licenses/LICENSE-2.0 9898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * 10898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * Unless required by applicable law or agreed to in writing, software 11898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * distributed under the License is distributed on an "AS IS" BASIS, 12898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * See the License for the specific language governing permissions and 14898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * limitations under the License. 15898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki */ 16898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 17898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onukipackage com.android.email.service; 18898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 19c50b6f685ba26a38b8110f6ca0115b12f84d643cMakoto Onukiimport android.accounts.AccountManager; 20898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onukiimport android.app.IntentService; 21898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onukiimport android.content.ComponentName; 228c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedyimport android.content.ContentResolver; 238c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedyimport android.content.ContentUris; 248c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedyimport android.content.ContentValues; 25898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onukiimport android.content.Context; 26898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onukiimport android.content.Intent; 2748b14fde961ef57103f7a31196254e357987f203Yu Ping Huimport android.content.PeriodicSync; 28898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onukiimport android.content.pm.PackageManager; 298c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedyimport android.database.Cursor; 308c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedyimport android.net.Uri; 3148b14fde961ef57103f7a31196254e357987f203Yu Ping Huimport android.os.Bundle; 3248b14fde961ef57103f7a31196254e357987f203Yu Ping Huimport android.provider.CalendarContract; 3348b14fde961ef57103f7a31196254e357987f203Yu Ping Huimport android.provider.ContactsContract; 34bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Huimport android.text.TextUtils; 3548b14fde961ef57103f7a31196254e357987f203Yu Ping Huimport android.text.format.DateUtils; 36898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 378196f82ce207f0c7a1088996d0f3017a16c3637eTony Mantlerimport com.android.email.EmailIntentService; 3866a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blankimport com.android.email.Preferences; 395c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.email.R; 4066a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blankimport com.android.email.SecurityPolicy; 41afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Huimport com.android.email.provider.AccountReconciler; 4266a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blankimport com.android.emailcommon.Logging; 4366a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blankimport com.android.emailcommon.provider.Account; 4448b14fde961ef57103f7a31196254e357987f203Yu Ping Huimport com.android.emailcommon.provider.EmailContent; 4566a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blankimport com.android.emailcommon.provider.EmailContent.AccountColumns; 4666a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blankimport com.android.emailcommon.provider.HostAuth; 478196f82ce207f0c7a1088996d0f3017a16c3637eTony Mantlerimport com.android.mail.providers.UIProvider; 48560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedyimport com.android.mail.utils.LogUtils; 49ac03b5576516f9e14a089b79b00dd7bf2dd48cfaRégis Décampsimport com.android.mail.utils.NotificationActionUtils; 50bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Huimport com.google.common.annotations.VisibleForTesting; 5148b14fde961ef57103f7a31196254e357987f203Yu Ping Huimport com.google.common.collect.Maps; 5266a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blank 5348b14fde961ef57103f7a31196254e357987f203Yu Ping Huimport java.util.Collections; 54bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Huimport java.util.HashSet; 5548b14fde961ef57103f7a31196254e357987f203Yu Ping Huimport java.util.List; 5648b14fde961ef57103f7a31196254e357987f203Yu Ping Huimport java.util.Map; 57bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Huimport java.util.Set; 58462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu 59898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki/** 60898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * The service that really handles broadcast intents on a worker thread. 61898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * 62898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * We make it a service, because: 63898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * <ul> 64898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * <li>So that it's less likely for the process to get killed. 65898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * <li>Even if it does, the Intent that have started it will be re-delivered by the system, 66898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * and we can start the process again. (Using {@link #setIntentRedelivery}). 67898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * </ul> 68a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler * 69a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler * This also handles the DeviceAdminReceiver in SecurityPolicy, because it is also 70a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler * a BroadcastReceiver and requires the same processing semantics. 71898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki */ 72898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onukipublic class EmailBroadcastProcessorService extends IntentService { 73a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler // Action used for BroadcastReceiver entry point 74a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler private static final String ACTION_BROADCAST = "broadcast_receiver"; 75a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler 76a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler // This is a helper used to process DeviceAdminReceiver messages 77a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler private static final String ACTION_DEVICE_POLICY_ADMIN = "com.android.email.devicepolicy"; 78a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler private static final String EXTRA_DEVICE_POLICY_ADMIN = "message_code"; 79a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler 80462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu // Action used for EmailUpgradeBroadcastReceiver. 81462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu private static final String ACTION_UPGRADE_BROADCAST = "upgrade_broadcast_receiver"; 82462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu 83898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki public EmailBroadcastProcessorService() { 84898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki // Class name will be the thread name. 85898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki super(EmailBroadcastProcessorService.class.getName()); 86898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 87898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki // Intent should be redelivered if the process gets killed before completing the job. 88898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki setIntentRedelivery(true); 89898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki } 90898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 91898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki /** 92898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * Entry point for {@link EmailBroadcastReceiver}. 93898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki */ 94898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki public static void processBroadcastIntent(Context context, Intent broadcastIntent) { 95898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki Intent i = new Intent(context, EmailBroadcastProcessorService.class); 96a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler i.setAction(ACTION_BROADCAST); 97898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki i.putExtra(Intent.EXTRA_INTENT, broadcastIntent); 98898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki context.startService(i); 99898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki } 100898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 101462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu public static void processUpgradeBroadcastIntent(final Context context) { 102462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu final Intent i = new Intent(context, EmailBroadcastProcessorService.class); 103462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu i.setAction(ACTION_UPGRADE_BROADCAST); 104462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu context.startService(i); 105462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu } 106462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu 107a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler /** 108a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler * Entry point for {@link com.android.email.SecurityPolicy.PolicyAdmin}. These will 109a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler * simply callback to {@link 110a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler * com.android.email.SecurityPolicy#onDeviceAdminReceiverMessage(Context, int)}. 111a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler */ 112a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler public static void processDevicePolicyMessage(Context context, int message) { 113a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler Intent i = new Intent(context, EmailBroadcastProcessorService.class); 114a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler i.setAction(ACTION_DEVICE_POLICY_ADMIN); 115a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler i.putExtra(EXTRA_DEVICE_POLICY_ADMIN, message); 116a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler context.startService(i); 117a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler } 118a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler 119898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki @Override 120898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki protected void onHandleIntent(Intent intent) { 121898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki // This method is called on a worker thread. 122898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 123a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler // Dispatch from entry point 124a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler final String action = intent.getAction(); 125a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler if (ACTION_BROADCAST.equals(action)) { 126a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler final Intent broadcastIntent = intent.getParcelableExtra(Intent.EXTRA_INTENT); 127a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler final String broadcastAction = broadcastIntent.getAction(); 128898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 129a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler if (Intent.ACTION_BOOT_COMPLETED.equals(broadcastAction)) { 130a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler onBootCompleted(); 131c50b6f685ba26a38b8110f6ca0115b12f84d643cMakoto Onuki } else if (AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION.equals(broadcastAction)) { 132c50b6f685ba26a38b8110f6ca0115b12f84d643cMakoto Onuki onSystemAccountChanged(); 13319b7e95d646b768ee66ff54497aab3067628869cAndrew Sapperstein } else if (Intent.ACTION_LOCALE_CHANGED.equals(broadcastAction) || 13419b7e95d646b768ee66ff54497aab3067628869cAndrew Sapperstein UIProvider.ACTION_UPDATE_NOTIFICATION.equals((broadcastAction))) { 1358196f82ce207f0c7a1088996d0f3017a16c3637eTony Mantler broadcastIntent.setClass(this, EmailIntentService.class); 1368196f82ce207f0c7a1088996d0f3017a16c3637eTony Mantler startService(broadcastIntent); 137a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler } 138a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler } else if (ACTION_DEVICE_POLICY_ADMIN.equals(action)) { 139a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler int message = intent.getIntExtra(EXTRA_DEVICE_POLICY_ADMIN, -1); 140a2269e84c6134bfd3506e5489c7ccfd60c32d41fAndy Stadler SecurityPolicy.onDeviceAdminReceiverMessage(this, message); 141462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu } else if (ACTION_UPGRADE_BROADCAST.equals(action)) { 142462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu onAppUpgrade(); 143898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki } 144898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki } 145898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 146462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu private void disableComponent(final Class<?> klass) { 147462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu getPackageManager().setComponentEnabledSetting(new ComponentName(this, klass), 148462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); 149462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu } 150462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu 1517acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler private boolean isComponentDisabled(final Class<?> klass) { 1527acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler return getPackageManager().getComponentEnabledSetting(new ComponentName(this, klass)) 1537acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler == PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 1547acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler } 1557acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler 156462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu private void updateAccountManagerAccountsOfType(final String amAccountType, 15748b14fde961ef57103f7a31196254e357987f203Yu Ping Hu final Map<String, String> protocolMap) { 158462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu final android.accounts.Account[] amAccounts = 159462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu AccountManager.get(this).getAccountsByType(amAccountType); 160462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu 161462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu for (android.accounts.Account amAccount: amAccounts) { 162462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu EmailServiceUtils.updateAccountManagerType(this, amAccount, protocolMap); 163462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu } 164462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu } 165462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu 16648b14fde961ef57103f7a31196254e357987f203Yu Ping Hu /** 16748b14fde961ef57103f7a31196254e357987f203Yu Ping Hu * Delete all periodic syncs for an account. 16848b14fde961ef57103f7a31196254e357987f203Yu Ping Hu * @param amAccount The account for which to disable syncs. 16948b14fde961ef57103f7a31196254e357987f203Yu Ping Hu * @param authority The authority for which to disable syncs. 17048b14fde961ef57103f7a31196254e357987f203Yu Ping Hu */ 1719e521deb6bb525b33365cc2926cb2d0faa7095e2Scott Kennedy private static void removePeriodicSyncs(final android.accounts.Account amAccount, 17248b14fde961ef57103f7a31196254e357987f203Yu Ping Hu final String authority) { 17348b14fde961ef57103f7a31196254e357987f203Yu Ping Hu final List<PeriodicSync> syncs = 17448b14fde961ef57103f7a31196254e357987f203Yu Ping Hu ContentResolver.getPeriodicSyncs(amAccount, authority); 17548b14fde961ef57103f7a31196254e357987f203Yu Ping Hu for (final PeriodicSync sync : syncs) { 17648b14fde961ef57103f7a31196254e357987f203Yu Ping Hu ContentResolver.removePeriodicSync(amAccount, authority, sync.extras); 17748b14fde961ef57103f7a31196254e357987f203Yu Ping Hu } 17848b14fde961ef57103f7a31196254e357987f203Yu Ping Hu } 17948b14fde961ef57103f7a31196254e357987f203Yu Ping Hu 18048b14fde961ef57103f7a31196254e357987f203Yu Ping Hu /** 18148b14fde961ef57103f7a31196254e357987f203Yu Ping Hu * Remove all existing periodic syncs for an account type, and add the necessary syncs. 18248b14fde961ef57103f7a31196254e357987f203Yu Ping Hu * @param amAccountType The account type to handle. 18348b14fde961ef57103f7a31196254e357987f203Yu Ping Hu * @param syncIntervals The map of all account addresses to sync intervals in the DB. 18448b14fde961ef57103f7a31196254e357987f203Yu Ping Hu */ 18548b14fde961ef57103f7a31196254e357987f203Yu Ping Hu private void fixPeriodicSyncs(final String amAccountType, 18648b14fde961ef57103f7a31196254e357987f203Yu Ping Hu final Map<String, Integer> syncIntervals) { 18748b14fde961ef57103f7a31196254e357987f203Yu Ping Hu final android.accounts.Account[] amAccounts = 18848b14fde961ef57103f7a31196254e357987f203Yu Ping Hu AccountManager.get(this).getAccountsByType(amAccountType); 18948b14fde961ef57103f7a31196254e357987f203Yu Ping Hu for (android.accounts.Account amAccount : amAccounts) { 19048b14fde961ef57103f7a31196254e357987f203Yu Ping Hu // First delete existing periodic syncs. 19148b14fde961ef57103f7a31196254e357987f203Yu Ping Hu removePeriodicSyncs(amAccount, EmailContent.AUTHORITY); 19248b14fde961ef57103f7a31196254e357987f203Yu Ping Hu removePeriodicSyncs(amAccount, CalendarContract.AUTHORITY); 19348b14fde961ef57103f7a31196254e357987f203Yu Ping Hu removePeriodicSyncs(amAccount, ContactsContract.AUTHORITY); 19448b14fde961ef57103f7a31196254e357987f203Yu Ping Hu 19548b14fde961ef57103f7a31196254e357987f203Yu Ping Hu // Add back a sync for this account if necessary (i.e. the account has a positive 19648b14fde961ef57103f7a31196254e357987f203Yu Ping Hu // sync interval in the DB). This assumes that the email app requires unique email 19748b14fde961ef57103f7a31196254e357987f203Yu Ping Hu // addresses for each account, which is currently the case. 19848b14fde961ef57103f7a31196254e357987f203Yu Ping Hu final Integer syncInterval = syncIntervals.get(amAccount.name); 19948b14fde961ef57103f7a31196254e357987f203Yu Ping Hu if (syncInterval != null && syncInterval > 0) { 20048b14fde961ef57103f7a31196254e357987f203Yu Ping Hu // Sync interval is stored in minutes in DB, but we want the value in seconds. 20148b14fde961ef57103f7a31196254e357987f203Yu Ping Hu ContentResolver.addPeriodicSync(amAccount, EmailContent.AUTHORITY, Bundle.EMPTY, 20248b14fde961ef57103f7a31196254e357987f203Yu Ping Hu syncInterval * DateUtils.MINUTE_IN_MILLIS / DateUtils.SECOND_IN_MILLIS); 20348b14fde961ef57103f7a31196254e357987f203Yu Ping Hu } 20448b14fde961ef57103f7a31196254e357987f203Yu Ping Hu } 20548b14fde961ef57103f7a31196254e357987f203Yu Ping Hu } 20648b14fde961ef57103f7a31196254e357987f203Yu Ping Hu 20748b14fde961ef57103f7a31196254e357987f203Yu Ping Hu /** Projection used for getting sync intervals for all accounts. */ 20848b14fde961ef57103f7a31196254e357987f203Yu Ping Hu private static final String[] ACCOUNT_SYNC_INTERVAL_PROJECTION = 20948b14fde961ef57103f7a31196254e357987f203Yu Ping Hu { AccountColumns.EMAIL_ADDRESS, AccountColumns.SYNC_INTERVAL }; 21048b14fde961ef57103f7a31196254e357987f203Yu Ping Hu private static final int ACCOUNT_SYNC_INTERVAL_ADDRESS_COLUMN = 0; 21148b14fde961ef57103f7a31196254e357987f203Yu Ping Hu private static final int ACCOUNT_SYNC_INTERVAL_INTERVAL_COLUMN = 1; 21248b14fde961ef57103f7a31196254e357987f203Yu Ping Hu 21348b14fde961ef57103f7a31196254e357987f203Yu Ping Hu /** 21448b14fde961ef57103f7a31196254e357987f203Yu Ping Hu * Get the sync interval for all accounts, as stored in the DB. 21548b14fde961ef57103f7a31196254e357987f203Yu Ping Hu * @return The map of all sync intervals by account email address. 21648b14fde961ef57103f7a31196254e357987f203Yu Ping Hu */ 21748b14fde961ef57103f7a31196254e357987f203Yu Ping Hu private Map<String, Integer> getSyncIntervals() { 21848b14fde961ef57103f7a31196254e357987f203Yu Ping Hu final Cursor c = getContentResolver().query(Account.CONTENT_URI, 21948b14fde961ef57103f7a31196254e357987f203Yu Ping Hu ACCOUNT_SYNC_INTERVAL_PROJECTION, null, null, null); 22048b14fde961ef57103f7a31196254e357987f203Yu Ping Hu if (c != null) { 22148b14fde961ef57103f7a31196254e357987f203Yu Ping Hu final Map<String, Integer> periodicSyncs = 22248b14fde961ef57103f7a31196254e357987f203Yu Ping Hu Maps.newHashMapWithExpectedSize(c.getCount()); 22348b14fde961ef57103f7a31196254e357987f203Yu Ping Hu try { 22448b14fde961ef57103f7a31196254e357987f203Yu Ping Hu while (c.moveToNext()) { 22548b14fde961ef57103f7a31196254e357987f203Yu Ping Hu periodicSyncs.put(c.getString(ACCOUNT_SYNC_INTERVAL_ADDRESS_COLUMN), 22648b14fde961ef57103f7a31196254e357987f203Yu Ping Hu c.getInt(ACCOUNT_SYNC_INTERVAL_INTERVAL_COLUMN)); 22748b14fde961ef57103f7a31196254e357987f203Yu Ping Hu } 22848b14fde961ef57103f7a31196254e357987f203Yu Ping Hu } finally { 22948b14fde961ef57103f7a31196254e357987f203Yu Ping Hu c.close(); 23048b14fde961ef57103f7a31196254e357987f203Yu Ping Hu } 23148b14fde961ef57103f7a31196254e357987f203Yu Ping Hu return periodicSyncs; 23248b14fde961ef57103f7a31196254e357987f203Yu Ping Hu } 23348b14fde961ef57103f7a31196254e357987f203Yu Ping Hu return Collections.emptyMap(); 23448b14fde961ef57103f7a31196254e357987f203Yu Ping Hu } 23548b14fde961ef57103f7a31196254e357987f203Yu Ping Hu 236bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu @VisibleForTesting 237bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu protected static void removeNoopUpgrades(final Map<String, String> protocolMap) { 238bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu final Set<String> keySet = new HashSet<String>(protocolMap.keySet()); 239bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu for (final String key : keySet) { 240bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu if (TextUtils.equals(key, protocolMap.get(key))) { 241bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu protocolMap.remove(key); 242bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu } 243bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu } 244bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu } 245bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu 246462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu private void onAppUpgrade() { 2477acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler if (isComponentDisabled(EmailUpgradeBroadcastReceiver.class)) { 2487acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler return; 2497acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler } 250bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu // When upgrading to a version that changes the protocol strings, we need to essentially 251bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu // rename the account manager type for all existing accounts, so we add new ones and delete 252bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu // the old. 253462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu // We specify the translations in this map. We map from old protocol name to new protocol 254462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu // name, and from protocol name + "_type" to new account manager type name. (Email1 did 255462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu // not use distinct account manager types for POP and IMAP, but Email2 does, hence this 256462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu // weird mapping.) 25748b14fde961ef57103f7a31196254e357987f203Yu Ping Hu final Map<String, String> protocolMap = Maps.newHashMapWithExpectedSize(4); 258462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu protocolMap.put("imap", getString(R.string.protocol_legacy_imap)); 259462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu protocolMap.put("pop3", getString(R.string.protocol_pop3)); 260bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu removeNoopUpgrades(protocolMap); 261bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu if (!protocolMap.isEmpty()) { 262bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu protocolMap.put("imap_type", getString(R.string.account_manager_type_legacy_imap)); 263bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu protocolMap.put("pop3_type", getString(R.string.account_manager_type_pop3)); 264bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu updateAccountManagerAccountsOfType("com.android.email", protocolMap); 265bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu } 266462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu 267462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu protocolMap.clear(); 268462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu protocolMap.put("eas", getString(R.string.protocol_eas)); 269bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu removeNoopUpgrades(protocolMap); 270bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu if (!protocolMap.isEmpty()) { 271bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu protocolMap.put("eas_type", getString(R.string.account_manager_type_exchange)); 272bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu updateAccountManagerAccountsOfType("com.android.exchange", protocolMap); 273bc8bc050b080287c35241f5ab0c310bbbdb6e805Yu Ping Hu } 274462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu 275462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu // Disable the old authenticators. 276462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu disableComponent(LegacyEmailAuthenticatorService.class); 277462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu disableComponent(LegacyEasAuthenticatorService.class); 278462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu 27948b14fde961ef57103f7a31196254e357987f203Yu Ping Hu // Fix periodic syncs. 28048b14fde961ef57103f7a31196254e357987f203Yu Ping Hu final Map<String, Integer> syncIntervals = getSyncIntervals(); 281b5eed31d1bdfcb8e8b316c9c49331295718001bdYu Ping Hu for (final EmailServiceUtils.EmailServiceInfo service 282b5eed31d1bdfcb8e8b316c9c49331295718001bdYu Ping Hu : EmailServiceUtils.getServiceInfoList(this)) { 28348b14fde961ef57103f7a31196254e357987f203Yu Ping Hu fixPeriodicSyncs(service.accountType, syncIntervals); 28448b14fde961ef57103f7a31196254e357987f203Yu Ping Hu } 28548b14fde961ef57103f7a31196254e357987f203Yu Ping Hu 286462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu // Disable the upgrade broadcast receiver now that we're fully upgraded. 287462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu disableComponent(EmailUpgradeBroadcastReceiver.class); 288462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu } 289462da178b1be608a74000956c53dc8ecb438c689Yu Ping Hu 290898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki /** 291898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki * Handles {@link Intent#ACTION_BOOT_COMPLETED}. Called on a worker thread. 292898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki */ 293898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki private void onBootCompleted() { 294898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki performOneTimeInitialization(); 295f53490dc86f5a61ab09024dc4938ce8419c61fc5Marc Blank reconcileAndStartServices(); 296f53490dc86f5a61ab09024dc4938ce8419c61fc5Marc Blank } 297898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 298f53490dc86f5a61ab09024dc4938ce8419c61fc5Marc Blank private void reconcileAndStartServices() { 2997acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler /** 3007acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler * We can get here before the ACTION_UPGRADE_BROADCAST is received, so make sure the 3017acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler * accounts are converted otherwise terrible, horrible things will happen. 3027acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler */ 3037acf30e9ab077362dc03812583044fb3e23206c3Tony Mantler onAppUpgrade(); 304f53490dc86f5a61ab09024dc4938ce8419c61fc5Marc Blank // Reconcile accounts 305afe097f318a7eeac9d240d2bedbc5caba7640ea8Yu Ping Hu AccountReconciler.reconcileAccounts(this); 306f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Starts remote services, if any 307f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank EmailServiceUtils.startRemoteServices(this); 308898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki } 309898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 310898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki private void performOneTimeInitialization() { 311898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki final Preferences pref = Preferences.getPreferences(this); 312898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki int progress = pref.getOneTimeInitializationProgress(); 313898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki final int initialProgress = progress; 314898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 315898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki if (progress < 1) { 316560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.i(Logging.LOG_TAG, "Onetime initialization: 1"); 317898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki progress = 1; 318ebe49cfeaf0328aa95f5cb82b731f08d7bae7b09Anthony Lee EmailServiceUtils.enableExchangeComponent(this); 319898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki } 320898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 3218c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy if (progress < 2) { 322560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.i(Logging.LOG_TAG, "Onetime initialization: 2"); 3238c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy progress = 2; 3248c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy setImapDeletePolicy(this); 3258c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy } 3268c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy 327898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki // Add your initialization steps here. 328898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki // Use "progress" to skip the initializations that's already done before. 329898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki // Using this preference also makes it safe when a user skips an upgrade. (i.e. upgrading 330898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki // version N to version N+2) 331898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 332898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki if (progress != initialProgress) { 333898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki pref.setOneTimeInitializationProgress(progress); 334560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.i(Logging.LOG_TAG, "Onetime initialization: completed."); 335898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki } 336898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki } 337898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki 3388c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy /** 3398c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy * Sets the delete policy to the correct value for all IMAP accounts. This will have no 3408c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy * effect on either EAS or POP3 accounts. 3418c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy */ 3428c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy /*package*/ static void setImapDeletePolicy(Context context) { 3438c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy ContentResolver resolver = context.getContentResolver(); 3448c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy Cursor c = resolver.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION, 3458c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy null, null, null); 3468c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy try { 3478c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy while (c.moveToNext()) { 3488c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy long recvAuthKey = c.getLong(Account.CONTENT_HOST_AUTH_KEY_RECV_COLUMN); 3498c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy HostAuth recvAuth = HostAuth.restoreHostAuthWithId(context, recvAuthKey); 3505c523858385176c33a7456bb84035de78552d22dMarc Blank String legacyImapProtocol = context.getString(R.string.protocol_legacy_imap); 3515c523858385176c33a7456bb84035de78552d22dMarc Blank if (legacyImapProtocol.equals(recvAuth.mProtocol)) { 3528c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy int flags = c.getInt(Account.CONTENT_FLAGS_COLUMN); 3538c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy flags &= ~Account.FLAGS_DELETE_POLICY_MASK; 3548c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy flags |= Account.DELETE_POLICY_ON_DELETE << Account.FLAGS_DELETE_POLICY_SHIFT; 3558c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy ContentValues cv = new ContentValues(); 3568c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy cv.put(AccountColumns.FLAGS, flags); 3578c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy long accountId = c.getLong(Account.CONTENT_ID_COLUMN); 3588c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, accountId); 3598c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy resolver.update(uri, cv, null, null); 3608c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy } 3618c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy } 3628c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy } finally { 3638c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy c.close(); 3648c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy } 3658c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy } 3668c89674b64f6669fa94bf593abad0f1e2255a812Todd Kennedy 367c50b6f685ba26a38b8110f6ca0115b12f84d643cMakoto Onuki private void onSystemAccountChanged() { 368560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.i(Logging.LOG_TAG, "System accounts updated."); 369f53490dc86f5a61ab09024dc4938ce8419c61fc5Marc Blank reconcileAndStartServices(); 370ac03b5576516f9e14a089b79b00dd7bf2dd48cfaRégis Décamps // Resend all notifications, so that there is no notification that points to a removed 371ac03b5576516f9e14a089b79b00dd7bf2dd48cfaRégis Décamps // account. 372ac03b5576516f9e14a089b79b00dd7bf2dd48cfaRégis Décamps NotificationActionUtils.resendNotifications(getApplicationContext(), 373ac03b5576516f9e14a089b79b00dd7bf2dd48cfaRégis Décamps null /* all accounts */, null /* all folders */); 374c50b6f685ba26a38b8110f6ca0115b12f84d643cMakoto Onuki } 375898283b6fa4f141d5c2a0831b96b19de11d587b3Makoto Onuki} 376