Create a new notification service
We can remove the preferences stuff 'cuz the service "should be" longer living. And, even if the service is terminated (either by the user or by the system) we'll receive a new notification when the service comes back. This is probably desired behaviour anyway. Change-Id: I4850a9473401536e8fb20385b780d4736ce80a8e
This commit is contained in:
parent
83693a6aca
commit
71bd208ddd
|
@ -339,6 +339,12 @@
|
|||
>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".service.NotificationService"
|
||||
android:enabled="false"
|
||||
>
|
||||
</service>
|
||||
|
||||
<!--Required stanza to register the PopImapAuthenticatorService with AccountManager -->
|
||||
<service
|
||||
android:name=".service.PopImapAuthenticatorService"
|
||||
|
|
|
@ -20,10 +20,12 @@ import com.android.email.activity.AccountShortcutPicker;
|
|||
import com.android.email.activity.MessageCompose;
|
||||
import com.android.email.service.AttachmentDownloadService;
|
||||
import com.android.email.service.MailService;
|
||||
import com.android.email.service.NotificationService;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.TempDirectory;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.service.EmailServiceProxy;
|
||||
import com.android.emailcommon.utility.EmailAsyncTask;
|
||||
import com.android.emailcommon.utility.Utility;
|
||||
|
||||
import android.app.Application;
|
||||
|
@ -106,7 +108,7 @@ public class Email extends Application {
|
|||
* @param context
|
||||
*/
|
||||
public static void setServicesEnabledAsync(final Context context) {
|
||||
Utility.runAsync(new Runnable() {
|
||||
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setServicesEnabledSync(context);
|
||||
|
@ -172,6 +174,11 @@ public class Email extends Application {
|
|||
enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||
PackageManager.DONT_KILL_APP);
|
||||
pm.setComponentEnabledSetting(
|
||||
new ComponentName(context, NotificationService.class),
|
||||
enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||
PackageManager.DONT_KILL_APP);
|
||||
if (enabled && pm.getComponentEnabledSetting(
|
||||
new ComponentName(context, MailService.class)) ==
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
|
||||
|
@ -181,8 +188,19 @@ public class Email extends Application {
|
|||
*/
|
||||
MailService.actionReschedule(context);
|
||||
}
|
||||
// Start/stop the AttachmentDownloadService, depending on whether there are any accounts
|
||||
Intent intent = new Intent(context, AttachmentDownloadService.class);
|
||||
|
||||
// Start/stop the various services depending on whether there are any accounts
|
||||
startOrStopService(enabled, context, new Intent(context, AttachmentDownloadService.class));
|
||||
startOrStopService(enabled, context, new Intent(context, NotificationService.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts or stops the service as necessary.
|
||||
* @param enabled If {@code true}, the service will be started. Otherwise, it will be stopped.
|
||||
* @param context The context to manage the service with.
|
||||
* @param intent The intent of the service to be managed.
|
||||
*/
|
||||
private static void startOrStopService(boolean enabled, Context context, Intent intent) {
|
||||
if (enabled) {
|
||||
context.startService(intent);
|
||||
} else {
|
||||
|
|
|
@ -75,10 +75,6 @@ public class NotificationController {
|
|||
Account.FLAGS + "&" + Account.FLAGS_NOTIFY_NEW_MAIL + " != 0";
|
||||
/** special account ID for the new message notification APIs to specify "all accounts" */
|
||||
private static final long ALL_ACCOUNTS = -1L;
|
||||
/** Index into notification table returned from system preferences */
|
||||
private static final int NOTIFIED_MESSAGE_ID_INDEX = 0;
|
||||
/** Index into notification table returned from system preferences */
|
||||
private static final int NOTIFIED_MESSAGE_COUNT_INDEX = 1;
|
||||
|
||||
private static NotificationThread sNewMessageThread;
|
||||
private static Handler sNewMessageHandler;
|
||||
|
@ -212,13 +208,6 @@ public class NotificationController {
|
|||
ContentResolver resolver = mContext.getContentResolver();
|
||||
HashMap<Long, long[]> table;
|
||||
if (!watch) {
|
||||
table = new HashMap<Long, long[]>();
|
||||
for (Long key : mNotificationMap.keySet()) {
|
||||
MessageData data = mNotificationMap.get(key);
|
||||
table.put(key,
|
||||
new long[] { data.mNotifiedMessageId, data.mNotifiedMessageCount });
|
||||
}
|
||||
Preferences.getPreferences(mContext).setMessageNotificationTable(table);
|
||||
unregisterMessageNotification(ALL_ACCOUNTS);
|
||||
// TODO cancel existing account observers
|
||||
|
||||
|
@ -231,18 +220,6 @@ public class NotificationController {
|
|||
|
||||
// otherwise, start new observers for all notified accounts
|
||||
registerMessageNotification(ALL_ACCOUNTS);
|
||||
// Need to load preferences _after_ starting the notifications. Otherwise, the
|
||||
// notification map will not be built.
|
||||
table = Preferences.getPreferences(mContext).getMessageNotificationTable();
|
||||
for (Long key : table.keySet()) {
|
||||
MessageData data = mNotificationMap.get(key);
|
||||
if (data != null) {
|
||||
long[] value = table.get(key);
|
||||
|
||||
data.mNotifiedMessageId = value[NOTIFIED_MESSAGE_ID_INDEX];
|
||||
data.mNotifiedMessageCount = (int) value[NOTIFIED_MESSAGE_COUNT_INDEX];
|
||||
}
|
||||
}
|
||||
// Loop through the observers and fire them once
|
||||
for (MessageData data : mNotificationMap.values()) {
|
||||
if (data.mObserver != null) {
|
||||
|
|
|
@ -23,7 +23,6 @@ import android.content.SharedPreferences;
|
|||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Preferences {
|
||||
|
@ -45,7 +44,6 @@ public class Preferences {
|
|||
private static final String AUTO_ADVANCE_DIRECTION = "autoAdvance";
|
||||
private static final String TEXT_ZOOM = "textZoom";
|
||||
private static final String BACKGROUND_ATTACHMENTS = "backgroundAttachments";
|
||||
private static final String MESSAGE_NOTIFICATION_TABLE = "messageNotificationTable";
|
||||
|
||||
public static final int AUTO_ADVANCE_NEWER = 0;
|
||||
public static final int AUTO_ADVANCE_OLDER = 1;
|
||||
|
@ -251,55 +249,6 @@ public class Preferences {
|
|||
mSharedPreferences.edit().putBoolean(BACKGROUND_ATTACHMENTS, allowed).apply();
|
||||
}
|
||||
|
||||
public HashMap<Long, long[]> getMessageNotificationTable() {
|
||||
HashMap<Long, long[]> table = new HashMap<Long, long[]>();
|
||||
// The table is encoded as a string with the following format:
|
||||
// K:V1,V2;K:V1,V2;...
|
||||
// Where 'K' is the table key and 'V1' and 'V2' are the array values associated with the key
|
||||
// Multiple key/value pairs are separated from one another by a ';'.
|
||||
String preference = mSharedPreferences.getString(MESSAGE_NOTIFICATION_TABLE, "");
|
||||
String[] entries = preference.split(";");
|
||||
for (String entry : entries) {
|
||||
try {
|
||||
String hash[] = entry.split(":");
|
||||
if (hash.length != 2) continue;
|
||||
String stringValues[] = hash[1].split(",");
|
||||
if (stringValues.length != 2) continue;
|
||||
long key = Long.parseLong(hash[0]);
|
||||
long[] value = new long[2];
|
||||
value[0] = Long.parseLong(stringValues[0]);
|
||||
value[1] = Long.parseLong(stringValues[1]);
|
||||
table.put(key, value);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(Logging.LOG_TAG, "notification table preference corrupt");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the message notification table.
|
||||
* @throws IllegalArgumentException if the given table is null or any of the value arrays do
|
||||
* not have exactly 2 elements.
|
||||
*/
|
||||
public void setMessageNotificationTable(HashMap<Long, long[]> notificationTable) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
boolean first = true;
|
||||
if (notificationTable == null) throw new IllegalArgumentException("table cannot be null");
|
||||
for (Long key : notificationTable.keySet()) {
|
||||
if (!first) {
|
||||
sb.append(';');
|
||||
}
|
||||
long[] value = notificationTable.get(key);
|
||||
if (value == null || value.length != 2) {
|
||||
throw new IllegalArgumentException("value array must contain 2 elements");
|
||||
}
|
||||
sb.append(key).append(':').append(value[0]).append(',').append(value[1]);
|
||||
first = false;
|
||||
}
|
||||
mSharedPreferences.edit().putString(MESSAGE_NOTIFICATION_TABLE, sb.toString()).apply();
|
||||
}
|
||||
public void save() {
|
||||
}
|
||||
|
||||
|
|
|
@ -212,7 +212,6 @@ public class MailService extends Service {
|
|||
mContext = this;
|
||||
|
||||
final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
NotificationController.getInstance(mContext).watchForMessages(true);
|
||||
|
||||
if (ACTION_CHECK_MAIL.equals(action)) {
|
||||
// DB access required to satisfy this intent, so offload from UI thread
|
||||
|
@ -341,7 +340,6 @@ public class MailService extends Service {
|
|||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
NotificationController.getInstance(mContext).watchForMessages(false);
|
||||
Controller.getInstance(getApplication()).removeResultCallback(mControllerCallback);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.email.service;
|
||||
|
||||
import com.android.email.NotificationController;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
|
||||
public class NotificationService extends Service {
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
NotificationController.getInstance(this).watchForMessages(true);
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
NotificationController.getInstance(this).watchForMessages(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -21,8 +21,6 @@ import android.net.Uri;
|
|||
import android.test.AndroidTestCase;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This is a series of unit tests for the Preferences class.
|
||||
*
|
||||
|
@ -44,27 +42,6 @@ public class PreferencesUnitTests extends AndroidTestCase {
|
|||
mPreferences = Preferences.getPreferences(mMockContext);
|
||||
}
|
||||
|
||||
/** Just because this does exist anywhere else */
|
||||
private void assertEquals(long[] expected, long[] actual) {
|
||||
assertNotNull(actual);
|
||||
assertEquals(expected.length, actual.length);
|
||||
for (int i = expected.length - 1; i >= 0; i--) {
|
||||
if (expected[i] != actual[i]) {
|
||||
fail("expected array element[" + i + "]:<"
|
||||
+ expected[i] + "> but was:<" + actual[i] + '>');
|
||||
}
|
||||
}
|
||||
}
|
||||
private void assertEquals(HashMap<Long, long[]> expected, HashMap<Long, long[]> actual) {
|
||||
assertNotNull(actual);
|
||||
assertEquals(expected.size(), actual.size());
|
||||
for (Long key : expected.keySet()) {
|
||||
assertTrue(actual.containsKey(key));
|
||||
long[] expectedArray = expected.get(key);
|
||||
long[] actualArray = actual.get(key);
|
||||
assertEquals(expectedArray, actualArray);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Test the new getAccountByContentUri() API. This should return null if no
|
||||
* accounts are configured, or the Uri doesn't match, and it should return a desired account
|
||||
|
@ -97,142 +74,4 @@ public class PreferencesUnitTests extends AndroidTestCase {
|
|||
lookup = mPreferences.getAccountByContentUri(testAccountUri);
|
||||
assertNull(lookup);
|
||||
}
|
||||
|
||||
public void testSetMessageNotificationTable() {
|
||||
HashMap<Long, long[]> testTable = new HashMap<Long, long[]>();
|
||||
String testString;
|
||||
|
||||
// One account
|
||||
testTable.clear();
|
||||
testTable.put(5L, new long[] { 2L, 3L });
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "value_unset").apply();
|
||||
mPreferences.setMessageNotificationTable(testTable);
|
||||
testString = mPreferences.mSharedPreferences.getString("messageNotificationTable", null);
|
||||
assertEquals("5:2,3", testString);
|
||||
|
||||
// Multiple accounts
|
||||
// NOTE: This assumes a very specific order in the hash map and is fragile; if the hash
|
||||
// map is ever changed, this may break unexpectedly.
|
||||
testTable.clear();
|
||||
testTable.put(5L, new long[] { 2L, 3L });
|
||||
testTable.put(3L, new long[] { 1L, 8L });
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "value_unset").apply();
|
||||
mPreferences.setMessageNotificationTable(testTable);
|
||||
testString = mPreferences.mSharedPreferences.getString("messageNotificationTable", null);
|
||||
assertEquals("5:2,3;3:1,8", testString);
|
||||
|
||||
// Wrong number of elements in the array
|
||||
// NOTE: This assumes a very specific order in the hash map and is fragile; if the hash
|
||||
// map is ever changed, this may break unexpectedly.
|
||||
testTable.clear();
|
||||
testTable.put(5L, new long[] { 2L, 3L, 8L }); // too many
|
||||
testTable.put(3L, new long[] { 1L, 8L });
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "value_unset_1").apply();
|
||||
try {
|
||||
mPreferences.setMessageNotificationTable(testTable);
|
||||
fail("expected an IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
testString = mPreferences.mSharedPreferences.getString("messageNotificationTable", null);
|
||||
assertEquals("value_unset_1", testString);
|
||||
testTable.clear();
|
||||
testTable.put(5L, new long[] { 2L }); // too few
|
||||
testTable.put(3L, new long[] { 1L, 8L });
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "value_unset_2").apply();
|
||||
try {
|
||||
mPreferences.setMessageNotificationTable(testTable);
|
||||
fail("expected an IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
testString = mPreferences.mSharedPreferences.getString("messageNotificationTable", null);
|
||||
assertEquals("value_unset_2", testString);
|
||||
|
||||
// Nulls in strange places
|
||||
testTable.clear();
|
||||
testTable.put(5L, null); // no array
|
||||
testTable.put(3L, new long[] { 1L, 8L });
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "value_unset_3").apply();
|
||||
try {
|
||||
mPreferences.setMessageNotificationTable(testTable);
|
||||
fail("expected an IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
testString = mPreferences.mSharedPreferences.getString("messageNotificationTable", null);
|
||||
assertEquals("value_unset_3", testString);
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "value_unset_4").apply();
|
||||
try {
|
||||
mPreferences.setMessageNotificationTable(null); // no table
|
||||
fail("expected an IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
testString = mPreferences.mSharedPreferences.getString("messageNotificationTable", null);
|
||||
assertEquals("value_unset_4", testString);
|
||||
}
|
||||
|
||||
public void testGetMessageNotificationTable() {
|
||||
HashMap<Long, long[]> testTable;
|
||||
HashMap<Long, long[]> expectedTable = new HashMap<Long, long[]>();
|
||||
|
||||
// Test initial condition
|
||||
assertFalse(mPreferences.mSharedPreferences.contains("messageNotificationTable"));
|
||||
|
||||
// One account
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "5:2,3").apply();
|
||||
testTable = mPreferences.getMessageNotificationTable();
|
||||
expectedTable.clear();
|
||||
expectedTable.put(5L, new long[] { 2L, 3L });
|
||||
assertEquals(expectedTable, testTable);
|
||||
|
||||
// Multiple accounts
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "5:2,3;3:1,8;6:5,3").apply();
|
||||
testTable = mPreferences.getMessageNotificationTable();
|
||||
expectedTable.clear();
|
||||
expectedTable.put(5L, new long[] { 2L, 3L });
|
||||
expectedTable.put(3L, new long[] { 1L, 8L });
|
||||
expectedTable.put(6L, new long[] { 5L, 3L });
|
||||
assertEquals(expectedTable, testTable);
|
||||
|
||||
// Empty account
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "5:2,3;").apply();
|
||||
testTable = mPreferences.getMessageNotificationTable();
|
||||
expectedTable.clear();
|
||||
expectedTable.put(5L, new long[] { 2L, 3L });
|
||||
assertEquals(expectedTable, testTable);
|
||||
|
||||
// Empty fields
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "5:2,3;3:").apply();
|
||||
testTable = mPreferences.getMessageNotificationTable();
|
||||
expectedTable.clear();
|
||||
expectedTable.put(5L, new long[] { 2L, 3L });
|
||||
assertEquals(expectedTable, testTable);
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "5:2,3;3:1,").apply();
|
||||
testTable = mPreferences.getMessageNotificationTable();
|
||||
expectedTable.clear();
|
||||
expectedTable.put(5L, new long[] { 2L, 3L });
|
||||
assertEquals(expectedTable, testTable);
|
||||
|
||||
// Garbage
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "blahblahblah").apply();
|
||||
testTable = mPreferences.getMessageNotificationTable();
|
||||
expectedTable.clear();
|
||||
assertEquals(expectedTable, testTable); // empty table
|
||||
mPreferences.mSharedPreferences.edit()
|
||||
.putString("messageNotificationTable", "5:2,3;blahblahblah").apply();
|
||||
testTable = mPreferences.getMessageNotificationTable();
|
||||
expectedTable.clear();
|
||||
expectedTable.put(5L, new long[] { 2L, 3L });
|
||||
assertEquals(expectedTable, testTable);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue