EmailBroadcastProcessorService.java revision 314a51cb1d5bc538f069b6b13d8dffd575a5cc44
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.email.service;
18
19import com.android.email.Email;
20import com.android.email.ExchangeUtils;
21import com.android.email.Preferences;
22import com.android.email.SecurityPolicy;
23import com.android.email.VendorPolicyLoader;
24import com.android.email.activity.setup.AccountSettingsXL;
25import com.android.email.widget.WidgetManager;
26
27import android.accounts.AccountManager;
28import android.app.IntentService;
29import android.content.ComponentName;
30import android.content.Context;
31import android.content.Intent;
32import android.content.pm.PackageManager;
33import android.util.Log;
34
35/**
36 * The service that really handles broadcast intents on a worker thread.
37 *
38 * We make it a service, because:
39 * <ul>
40 *   <li>So that it's less likely for the process to get killed.
41 *   <li>Even if it does, the Intent that have started it will be re-delivered by the system,
42 *   and we can start the process again.  (Using {@link #setIntentRedelivery}).
43 * </ul>
44 *
45 * This also handles the DeviceAdminReceiver in SecurityPolicy, because it is also
46 * a BroadcastReceiver and requires the same processing semantics.
47 */
48public class EmailBroadcastProcessorService extends IntentService {
49    // Action used for BroadcastReceiver entry point
50    private static final String ACTION_BROADCAST = "broadcast_receiver";
51
52    // Dialing "*#*#36245#*#*" to open the debug screen.   "36245" = "email"
53    private static final String ACTION_SECRET_CODE = "android.provider.Telephony.SECRET_CODE";
54    private static final String SECRET_CODE_HOST_DEBUG_SCREEN = "36245";
55
56    // This is a helper used to process DeviceAdminReceiver messages
57    private static final String ACTION_DEVICE_POLICY_ADMIN = "com.android.email.devicepolicy";
58    private static final String EXTRA_DEVICE_POLICY_ADMIN = "message_code";
59
60    public EmailBroadcastProcessorService() {
61        // Class name will be the thread name.
62        super(EmailBroadcastProcessorService.class.getName());
63
64        // Intent should be redelivered if the process gets killed before completing the job.
65        setIntentRedelivery(true);
66    }
67
68    /**
69     * Entry point for {@link EmailBroadcastReceiver}.
70     */
71    public static void processBroadcastIntent(Context context, Intent broadcastIntent) {
72        Intent i = new Intent(context, EmailBroadcastProcessorService.class);
73        i.setAction(ACTION_BROADCAST);
74        i.putExtra(Intent.EXTRA_INTENT, broadcastIntent);
75        context.startService(i);
76    }
77
78    /**
79     * Entry point for {@link com.android.email.SecurityPolicy.PolicyAdmin}.  These will
80     * simply callback to {@link
81     * com.android.email.SecurityPolicy#onDeviceAdminReceiverMessage(Context, int)}.
82     */
83    public static void processDevicePolicyMessage(Context context, int message) {
84        Intent i = new Intent(context, EmailBroadcastProcessorService.class);
85        i.setAction(ACTION_DEVICE_POLICY_ADMIN);
86        i.putExtra(EXTRA_DEVICE_POLICY_ADMIN, message);
87        context.startService(i);
88    }
89
90    @Override
91    protected void onHandleIntent(Intent intent) {
92        // This method is called on a worker thread.
93
94        // Dispatch from entry point
95        final String action = intent.getAction();
96        if (ACTION_BROADCAST.equals(action)) {
97            final Intent broadcastIntent = intent.getParcelableExtra(Intent.EXTRA_INTENT);
98            final String broadcastAction = broadcastIntent.getAction();
99
100            if (Intent.ACTION_BOOT_COMPLETED.equals(broadcastAction)) {
101                onBootCompleted();
102
103            // TODO: Do a better job when we get ACTION_DEVICE_STORAGE_LOW.
104            //       The code below came from very old code....
105            } else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(broadcastAction)) {
106                // Stop IMAP/POP3 poll.
107                MailService.actionCancel(this);
108            } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(broadcastAction)) {
109                enableComponentsIfNecessary();
110            } else if (ACTION_SECRET_CODE.equals(broadcastAction)
111                    && SECRET_CODE_HOST_DEBUG_SCREEN.equals(broadcastIntent.getData().getHost())) {
112                AccountSettingsXL.actionSettingsWithDebug(this);
113            } else if (AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION.equals(broadcastAction)) {
114                onSystemAccountChanged();
115            }
116        } else if (ACTION_DEVICE_POLICY_ADMIN.equals(action)) {
117            int message = intent.getIntExtra(EXTRA_DEVICE_POLICY_ADMIN, -1);
118            SecurityPolicy.onDeviceAdminReceiverMessage(this, message);
119        }
120    }
121
122    private void enableComponentsIfNecessary() {
123        if (Email.setServicesEnabledSync(this)) {
124            // At least one account exists.
125            // TODO probably we should check if it's a POP/IMAP account.
126            MailService.actionReschedule(this);
127        }
128    }
129
130    /**
131     * Handles {@link Intent#ACTION_BOOT_COMPLETED}.  Called on a worker thread.
132     */
133    private void onBootCompleted() {
134        performOneTimeInitialization();
135
136        enableComponentsIfNecessary();
137
138        // Starts the service for Exchange, if supported.
139        ExchangeUtils.startExchangeService(this);
140    }
141
142    private void performOneTimeInitialization() {
143        final Preferences pref = Preferences.getPreferences(this);
144        int progress = pref.getOneTimeInitializationProgress();
145        final int initialProgress = progress;
146
147        if (progress < 1) {
148            Log.i(Email.LOG_TAG, "Onetime initialization: 1");
149            progress = 1;
150            if (VendorPolicyLoader.getInstance(this).useAlternateExchangeStrings()) {
151                setComponentEnabled(EasAuthenticatorServiceAlternate.class, true);
152                setComponentEnabled(EasAuthenticatorService.class, false);
153            }
154
155            ExchangeUtils.enableEasCalendarSync(this);
156        }
157
158        // Add your initialization steps here.
159        // Use "progress" to skip the initializations that's already done before.
160        // Using this preference also makes it safe when a user skips an upgrade.  (i.e. upgrading
161        // version N to version N+2)
162
163        if (progress != initialProgress) {
164            pref.setOneTimeInitializationProgress(progress);
165            Log.i(Email.LOG_TAG, "Onetime initialization: completed.");
166        }
167    }
168
169    private void setComponentEnabled(Class<?> clazz, boolean enabled) {
170        final ComponentName c = new ComponentName(this, clazz.getName());
171        getPackageManager().setComponentEnabledSetting(c,
172                enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
173                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
174                PackageManager.DONT_KILL_APP);
175    }
176
177    private void onSystemAccountChanged() {
178        Log.i(Email.LOG_TAG, "System accouns updated.");
179        MailService.reconcilePopImapAccountsSync(this);
180
181        // Let ExchangeService reconcile EAS accouts.
182        // The service will stops itself it there's no EAS accounts.
183        ExchangeUtils.startExchangeService(this);
184
185        // Let all of the widgets update
186        WidgetManager.getInstance().updateAllWidgets();
187    }
188}
189