Clear error states on network reconnect; add temporary notifications; see details
* When we get a network connect broadcast, clear error states so sync can restart for any boxes in an error state * Add temporary notification code for the testers * Add file-based debug logger * Add Exchange logging to debug screen (adds additional exchange debugging) * Add Exchange sd card logging to debug screen (logs to sd card) * Change setLogging service API to send an int rather than a boolean * Make sure push mailboxes are set up again when account changes to push * Make sure push mailboxes are set up again when account mailbox starts * (Fixed contacts sync bug found during debugging these changes)
This commit is contained in:
parent
71132ff6b7
commit
cc402e42ab
|
@ -37,4 +37,16 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:text="@string/debug_enable_sensitive_logging_label"
|
||||
/>
|
||||
<CheckBox
|
||||
android:id="@+id/exchange_logging"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/debug_enable_exchange_logging_label"
|
||||
/>
|
||||
<CheckBox
|
||||
android:id="@+id/exchange_file_logging"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/debug_enable_exchange_file_logging_label"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -154,6 +154,10 @@
|
|||
<string name="debug_enable_debug_logging_label">Enable extra debug logging?</string>
|
||||
<!-- Checkbox label, shown only on debug screen -->
|
||||
<string name="debug_enable_sensitive_logging_label">Enable sensitive information debug logging? (May show passwords in logs.)</string>
|
||||
<!-- Checkbox label, shown only on debug screen -->
|
||||
<string name="debug_enable_exchange_logging_label">Enable exchange debug logging?</string>
|
||||
<!-- Checkbox label, shown only on debug screen -->
|
||||
<string name="debug_enable_exchange_file_logging_label">Enable exchange sd card logging?</string>
|
||||
|
||||
<!-- The text in the small separator between smart folders and the accounts -->
|
||||
<string name="account_folder_list_separator_accounts">Accounts</string>
|
||||
|
|
|
@ -124,7 +124,7 @@ public class Controller {
|
|||
*
|
||||
* Generally this should be called by anybody who changes Email.DEBUG
|
||||
*/
|
||||
public void serviceLogging(boolean debugEnabled) {
|
||||
public void serviceLogging(int debugEnabled) {
|
||||
IEmailService service =
|
||||
new EmailServiceProxy(mContext, SyncManager.class, mServiceCallback);
|
||||
try {
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.android.email.mail.internet.BinaryTempFileBody;
|
|||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.service.BootReceiver;
|
||||
import com.android.email.service.MailService;
|
||||
import com.android.exchange.Eas;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.ComponentName;
|
||||
|
@ -57,7 +58,7 @@ public class Email extends Application {
|
|||
*/
|
||||
public static boolean DEBUG_SENSITIVE = false;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Set this to 'true' to enable as much Email logging as possible.
|
||||
* Do not check-in with it set to 'true'!
|
||||
*/
|
||||
|
@ -68,7 +69,7 @@ public class Email extends Application {
|
|||
* to open a chooser with a list of filter types, so the chooser is only opened with the first
|
||||
* item in the list. The entire list will be used to filter down attachments that are added
|
||||
* with Intent.ACTION_SEND.
|
||||
*
|
||||
*
|
||||
* TODO: It should be legal to send anything requested by another app. This would provide
|
||||
* parity with Gmail's behavior.
|
||||
*/
|
||||
|
@ -146,7 +147,7 @@ public class Email extends Application {
|
|||
Cursor c = null;
|
||||
try {
|
||||
c = context.getContentResolver().query(
|
||||
EmailContent.Account.CONTENT_URI,
|
||||
EmailContent.Account.CONTENT_URI,
|
||||
EmailContent.Account.ID_PROJECTION,
|
||||
null, null, null);
|
||||
boolean enable = c.getCount() > 0;
|
||||
|
@ -204,12 +205,12 @@ public class Email extends Application {
|
|||
Preferences prefs = Preferences.getPreferences(this);
|
||||
DEBUG = prefs.geteEnableDebugLogging();
|
||||
DEBUG_SENSITIVE = prefs.getEnableSensitiveLogging();
|
||||
|
||||
|
||||
// Reset all accounts to default visible window
|
||||
Cursor c = null;
|
||||
try {
|
||||
c = getContentResolver().query(
|
||||
EmailContent.Account.CONTENT_URI,
|
||||
EmailContent.Account.CONTENT_URI,
|
||||
EmailContent.Account.CONTENT_PROJECTION,
|
||||
null, null, null);
|
||||
while (c.moveToNext()) {
|
||||
|
@ -227,9 +228,13 @@ public class Email extends Application {
|
|||
* doesn't work in Android and MimeMessage does not have access to a Context.
|
||||
*/
|
||||
BinaryTempFileBody.setTempDirectory(getCacheDir());
|
||||
|
||||
|
||||
// Enable logging in the EAS service, so it starts up as early as possible.
|
||||
Controller.getInstance(this).serviceLogging(DEBUG);
|
||||
int debugLogging = prefs.geteEnableDebugLogging() ? Eas.DEBUG_BIT : 0;
|
||||
int exchangeLogging = prefs.getEnableExchangeLogging() ? Eas.DEBUG_EXCHANGE_BIT : 0;
|
||||
int fileLogging = prefs.getEnableExchangeFileLogging() ? Eas.DEBUG_FILE_BIT : 0;
|
||||
int debugBits = debugLogging + exchangeLogging + fileLogging;
|
||||
Controller.getInstance(this).serviceLogging(debugBits);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,12 +16,9 @@
|
|||
|
||||
package com.android.email;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
|
||||
public class Preferences {
|
||||
|
@ -142,6 +139,22 @@ public class Preferences {
|
|||
return mSharedPreferences.getBoolean("enableSensitiveLogging", false);
|
||||
}
|
||||
|
||||
public void setEnableExchangeLogging(boolean value) {
|
||||
mSharedPreferences.edit().putBoolean("enableExchangeLogging", value).commit();
|
||||
}
|
||||
|
||||
public boolean getEnableExchangeLogging() {
|
||||
return mSharedPreferences.getBoolean("enableExchgangeLogging", false);
|
||||
}
|
||||
|
||||
public void setEnableExchangeFileLogging(boolean value) {
|
||||
mSharedPreferences.edit().putBoolean("enableExchangeFileLogging", value).commit();
|
||||
}
|
||||
|
||||
public boolean getEnableExchangeFileLogging() {
|
||||
return mSharedPreferences.getBoolean("enableExchgangeFileLogging", false);
|
||||
}
|
||||
|
||||
public void save() {
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,13 @@
|
|||
|
||||
package com.android.email.activity;
|
||||
|
||||
import com.android.email.Controller;
|
||||
import com.android.email.Email;
|
||||
import com.android.email.Preferences;
|
||||
import com.android.email.R;
|
||||
import com.android.exchange.Eas;
|
||||
import com.android.exchange.utility.FileLogger;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
|
@ -25,15 +32,12 @@ import android.widget.CompoundButton;
|
|||
import android.widget.TextView;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
|
||||
import com.android.email.Controller;
|
||||
import com.android.email.Email;
|
||||
import com.android.email.Preferences;
|
||||
import com.android.email.R;
|
||||
|
||||
public class Debug extends Activity implements OnCheckedChangeListener {
|
||||
private TextView mVersionView;
|
||||
private CheckBox mEnableDebugLoggingView;
|
||||
private CheckBox mEnableSensitiveLoggingView;
|
||||
private CheckBox mEnableExchangeLoggingView;
|
||||
private CheckBox mEnableExchangeFileLoggingView;
|
||||
|
||||
private Preferences mPreferences;
|
||||
|
||||
|
@ -48,26 +52,59 @@ public class Debug extends Activity implements OnCheckedChangeListener {
|
|||
mVersionView = (TextView)findViewById(R.id.version);
|
||||
mEnableDebugLoggingView = (CheckBox)findViewById(R.id.debug_logging);
|
||||
mEnableSensitiveLoggingView = (CheckBox)findViewById(R.id.sensitive_logging);
|
||||
mEnableExchangeLoggingView = (CheckBox)findViewById(R.id.exchange_logging);
|
||||
mEnableExchangeFileLoggingView = (CheckBox)findViewById(R.id.exchange_file_logging);
|
||||
|
||||
mEnableDebugLoggingView.setOnCheckedChangeListener(this);
|
||||
mEnableSensitiveLoggingView.setOnCheckedChangeListener(this);
|
||||
mEnableExchangeLoggingView.setOnCheckedChangeListener(this);
|
||||
mEnableExchangeFileLoggingView.setOnCheckedChangeListener(this);
|
||||
|
||||
mVersionView.setText(String.format(getString(R.string.debug_version_fmt).toString(),
|
||||
getString(R.string.build_number)));
|
||||
|
||||
mEnableDebugLoggingView.setChecked(Email.DEBUG);
|
||||
mEnableSensitiveLoggingView.setChecked(Email.DEBUG_SENSITIVE);
|
||||
mEnableExchangeLoggingView.setChecked(Eas.USER_LOG);
|
||||
mEnableExchangeFileLoggingView.setChecked(Eas.FILE_LOG);
|
||||
}
|
||||
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
int debugLogging = mPreferences.geteEnableDebugLogging() ? Eas.DEBUG_BIT : 0;
|
||||
int exchangeLogging = mPreferences.getEnableExchangeLogging() ? Eas.DEBUG_EXCHANGE_BIT : 0;
|
||||
int fileLogging = mPreferences.getEnableExchangeFileLogging() ? Eas.DEBUG_FILE_BIT : 0;
|
||||
int debugBits = debugLogging + exchangeLogging + fileLogging;
|
||||
|
||||
if (buttonView.getId() == R.id.debug_logging) {
|
||||
Email.DEBUG = isChecked;
|
||||
mPreferences.setEnableDebugLogging(Email.DEBUG);
|
||||
Controller.getInstance(getApplication()).serviceLogging(Email.DEBUG);
|
||||
if (isChecked) {
|
||||
debugBits |= Eas.DEBUG_BIT;
|
||||
} else {
|
||||
debugBits &= ~Eas.DEBUG_BIT;
|
||||
}
|
||||
} else if (buttonView.getId() == R.id.sensitive_logging) {
|
||||
Email.DEBUG_SENSITIVE = isChecked;
|
||||
mPreferences.setEnableSensitiveLogging(Email.DEBUG_SENSITIVE);
|
||||
} else if (buttonView.getId() == R.id.exchange_logging) {
|
||||
mPreferences.setEnableExchangeLogging(isChecked);
|
||||
if (isChecked) {
|
||||
debugBits |= Eas.DEBUG_EXCHANGE_BIT;
|
||||
} else {
|
||||
debugBits &= ~Eas.DEBUG_EXCHANGE_BIT;
|
||||
}
|
||||
} else if (buttonView.getId() == R.id.exchange_file_logging) {
|
||||
if (!isChecked) {
|
||||
FileLogger.close();
|
||||
}
|
||||
mPreferences.setEnableExchangeFileLogging(isChecked);
|
||||
if (isChecked) {
|
||||
debugBits |= Eas.DEBUG_FILE_BIT;
|
||||
} else {
|
||||
debugBits &= ~Eas.DEBUG_FILE_BIT;
|
||||
}
|
||||
}
|
||||
Controller.getInstance(getApplication()).serviceLogging(debugBits);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,12 +24,10 @@ import com.android.email.Utility;
|
|||
import com.android.email.activity.Debug;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
import com.android.email.provider.EmailContent.AccountColumns;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.ContentValues;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.XmlResourceParser;
|
||||
|
@ -67,7 +65,7 @@ public class AccountSetupBasics extends Activity
|
|||
private final static int DIALOG_NOTE = 1;
|
||||
private final static String STATE_KEY_PROVIDER =
|
||||
"com.android.email.AccountSetupBasics.provider";
|
||||
|
||||
|
||||
// NOTE: If you change this value, confirm that the new interval exists in arrays.xml
|
||||
private final static int DEFAULT_ACCOUNT_CHECK_INTERVAL = 15;
|
||||
|
||||
|
@ -109,7 +107,7 @@ public class AccountSetupBasics extends Activity
|
|||
Cursor c = null;
|
||||
try {
|
||||
c = getContentResolver().query(
|
||||
EmailContent.Account.CONTENT_URI,
|
||||
EmailContent.Account.CONTENT_URI,
|
||||
EmailContent.Account.ID_PROJECTION,
|
||||
null, null, null);
|
||||
if (c.getCount() > 0) {
|
||||
|
@ -320,11 +318,13 @@ public class AccountSetupBasics extends Activity
|
|||
String[] emailParts = email.split("@");
|
||||
String user = emailParts[0].trim();
|
||||
String domain = emailParts[1].trim();
|
||||
|
||||
|
||||
// Alternate entry to the debug options screen (for devices without a physical keyboard:
|
||||
// Username: d@d.d
|
||||
// Password: debug
|
||||
if (ENTER_DEBUG_SCREEN && "d@d.d".equals(email) && "debug".equals(password)) {
|
||||
mEmailView.setText("");
|
||||
mPasswordView.setText("");
|
||||
startActivity(new Intent(this, Debug.class));
|
||||
return;
|
||||
}
|
||||
|
@ -387,9 +387,9 @@ public class AccountSetupBasics extends Activity
|
|||
* Search the list of known Email providers looking for one that matches the user's email
|
||||
* domain. We look in providers_product.xml first, followed by the entries in
|
||||
* platform providers.xml. This provides a nominal override capability.
|
||||
*
|
||||
*
|
||||
* A match is defined as any provider entry for which the "domain" attribute matches.
|
||||
*
|
||||
*
|
||||
* @param domain The domain portion of the user's email address
|
||||
* @return suitable Provider definition, or null if no match found
|
||||
*/
|
||||
|
|
|
@ -215,7 +215,7 @@ public class EmailServiceProxy implements IEmailService {
|
|||
});
|
||||
}
|
||||
|
||||
public void setLogging(final boolean on) throws RemoteException {
|
||||
public void setLogging(final int on) throws RemoteException {
|
||||
setTask(new Runnable () {
|
||||
public void run() {
|
||||
try {
|
||||
|
|
|
@ -20,6 +20,7 @@ package com.android.exchange;
|
|||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
import com.android.email.provider.EmailContent.Mailbox;
|
||||
import com.android.exchange.utility.FileLogger;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
|
@ -208,6 +209,9 @@ public abstract class AbstractSyncService implements Runnable {
|
|||
public void userLog(String str) {
|
||||
if (Eas.USER_LOG) {
|
||||
Log.i(TAG, str);
|
||||
if (Eas.FILE_LOG) {
|
||||
FileLogger.log(TAG, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,6 +221,9 @@ public abstract class AbstractSyncService implements Runnable {
|
|||
*/
|
||||
public void errorLog(String str) {
|
||||
Log.e(TAG, str);
|
||||
if (Eas.FILE_LOG) {
|
||||
FileLogger.log(TAG, str);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
package com.android.exchange;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Constants used throughout the EAS implementation are stored here.
|
||||
*
|
||||
|
@ -24,13 +26,18 @@ package com.android.exchange;
|
|||
public class Eas {
|
||||
// For debugging
|
||||
public static boolean WAIT_DEBUG = false; // DO NOT CHECK IN WITH THIS SET TO TRUE
|
||||
public static boolean DEBUG = false; // DO NOT CHECK IN WITH THIS SET TO TRUE
|
||||
public static boolean DEBUG = false; // DO NOT CHECK IN WITH THIS SET TO TRUE
|
||||
|
||||
// The following two are for user logging (the second providing more detail)
|
||||
public static boolean USER_LOG = false; // DO NOT CHECK IN WITH THIS SET TO TRUE
|
||||
public static boolean PARSER_LOG = false; // DO NOT CHECK IN WITH THIS SET TO TRUE
|
||||
public static boolean FILE_LOG = false; // DO NOT CHECK IN WITH THIS SET TO TRUE
|
||||
|
||||
public static final String VERSION = "0.2";
|
||||
public static final int DEBUG_BIT = 1;
|
||||
public static final int DEBUG_EXCHANGE_BIT = 2;
|
||||
public static final int DEBUG_FILE_BIT = 4;
|
||||
|
||||
public static final String VERSION = "0.3";
|
||||
public static final String ACCOUNT_MANAGER_TYPE = "com.android.exchange";
|
||||
public static final String ACCOUNT_MAILBOX = "__eas";
|
||||
|
||||
|
@ -63,10 +70,20 @@ public class Eas {
|
|||
|
||||
public static final int EXCHANGE_ERROR_NOTIFICATION = 0x10;
|
||||
|
||||
public static void setUserDebug(boolean state) {
|
||||
public static void setUserDebug(int state) {
|
||||
// DEBUG takes precedence and is never true in a user build
|
||||
if (!DEBUG) {
|
||||
USER_LOG = state;
|
||||
USER_LOG = (state & DEBUG_BIT) != 0;
|
||||
PARSER_LOG = (state & DEBUG_EXCHANGE_BIT) != 0;
|
||||
FILE_LOG = (state & DEBUG_FILE_BIT) != 0;
|
||||
if (FILE_LOG) {
|
||||
PARSER_LOG = true;
|
||||
USER_LOG = true;
|
||||
} else if (PARSER_LOG) {
|
||||
USER_LOG = true;
|
||||
}
|
||||
Log.d("Eas Debug", "Logging: " + (USER_LOG ? "User " : "") +
|
||||
(PARSER_LOG ? "Parser " : "") + (FILE_LOG ? "File" : ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
|
@ -116,7 +117,7 @@ public class EasSyncService extends AbstractSyncService {
|
|||
public ContentResolver mContentResolver;
|
||||
String[] mBindArguments = new String[2];
|
||||
InputStream mPendingPartInputStream = null;
|
||||
private boolean mTriedReloadFolderList = false;
|
||||
//private boolean mTriedReloadFolderList = false;
|
||||
|
||||
public EasSyncService(Context _context, Mailbox _mailbox) {
|
||||
super(_context, _mailbox);
|
||||
|
@ -154,7 +155,8 @@ public class EasSyncService extends AbstractSyncService {
|
|||
}
|
||||
|
||||
private boolean isAuthError(int code) {
|
||||
return (code == HttpURLConnection.HTTP_UNAUTHORIZED || code == HttpURLConnection.HTTP_FORBIDDEN
|
||||
return (code == HttpURLConnection.HTTP_UNAUTHORIZED
|
||||
|| code == HttpURLConnection.HTTP_FORBIDDEN
|
||||
|| code == HttpURLConnection.HTTP_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
|
@ -450,11 +452,22 @@ public class EasSyncService extends AbstractSyncService {
|
|||
}
|
||||
}
|
||||
|
||||
while (!mStop) {
|
||||
// Change all pushable boxes to push when we start the account mailbox
|
||||
if (mAccount.mSyncInterval == Account.CHECK_INTERVAL_PUSH) {
|
||||
cv = new ContentValues();
|
||||
cv.put(Mailbox.SYNC_INTERVAL, Account.CHECK_INTERVAL_PUSH);
|
||||
if (mContentResolver.update(Mailbox.CONTENT_URI, cv,
|
||||
SyncManager.WHERE_IN_ACCOUNT_AND_PUSHABLE,
|
||||
new String[] {Long.toString(mAccount.mId)}) > 0) {
|
||||
userLog("Push account; set pushable boxes to push...");
|
||||
}
|
||||
}
|
||||
|
||||
while (!mStop) {
|
||||
userLog("Sending Account syncKey: " + mAccount.mSyncKey);
|
||||
Serializer s = new Serializer();
|
||||
s.start(Tags.FOLDER_FOLDER_SYNC).start(Tags.FOLDER_SYNC_KEY)
|
||||
.text(mAccount.mSyncKey).end().end().done();
|
||||
.text(mAccount.mSyncKey).end().end().done();
|
||||
HttpResponse resp = sendHttpClientPost("FolderSync", s.toByteArray());
|
||||
if (mStop) break;
|
||||
int code = resp.getStatusLine().getStatusCode();
|
||||
|
@ -521,12 +534,12 @@ public class EasSyncService extends AbstractSyncService {
|
|||
|
||||
void pushFallback() {
|
||||
// We'll try reloading folders first; this has been observed to work in some cases
|
||||
if (!mTriedReloadFolderList) {
|
||||
errorLog("*** PING LOOP: Trying to reload folder list...");
|
||||
SyncManager.reloadFolderList(mContext, mAccount.mId, true);
|
||||
mTriedReloadFolderList = true;
|
||||
// If we've tried that, set all mailboxes (except the account mailbox) to 5 minute sync
|
||||
} else {
|
||||
// if (!mTriedReloadFolderList) {
|
||||
// errorLog("*** PING LOOP: Trying to reload folder list...");
|
||||
// SyncManager.reloadFolderList(mContext, mAccount.mId, true);
|
||||
// mTriedReloadFolderList = true;
|
||||
// // If we've tried that, set all mailboxes (except the account mailbox) to 5 minute sync
|
||||
// } else {
|
||||
errorLog("*** PING LOOP: Turning off push due to ping loop...");
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(Mailbox.SYNC_INTERVAL, 5);
|
||||
|
@ -538,6 +551,9 @@ public class EasSyncService extends AbstractSyncService {
|
|||
cv.put(Account.SYNC_INTERVAL, 5);
|
||||
mContentResolver.update(ContentUris.withAppendedId(Account.CONTENT_URI, mAccount.mId),
|
||||
cv, null, null);
|
||||
// Let the SyncManager know that something's changed
|
||||
SyncManager.kick("push fallback");
|
||||
|
||||
// TODO Discuss the best way to alert the user
|
||||
// Alert the user about what we've done
|
||||
NotificationManager nm = (NotificationManager)mContext
|
||||
|
@ -552,7 +568,7 @@ public class EasSyncService extends AbstractSyncService {
|
|||
mContext.getString(R.string.notification_ping_loop_title),
|
||||
mContext.getString(R.string.notification_ping_loop_text), pi);
|
||||
nm.notify(Eas.EXCHANGE_ERROR_NOTIFICATION, note);
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
void runPingLoop() throws IOException, StaleFolderListException {
|
||||
|
@ -582,9 +598,12 @@ public class EasSyncService extends AbstractSyncService {
|
|||
// 1) SyncManager tells us the mailbox is syncable (not running, not stopped)
|
||||
// 2) The syncKey isn't "0" (i.e. it's synced at least once)
|
||||
long mailboxId = c.getLong(Mailbox.CONTENT_ID_COLUMN);
|
||||
if (SyncManager.canSync(mailboxId)) {
|
||||
int pingStatus = SyncManager.pingStatus(mailboxId);
|
||||
String mailboxName = c.getString(Mailbox.CONTENT_DISPLAY_NAME_COLUMN);
|
||||
if (pingStatus == SyncManager.PING_STATUS_OK) {
|
||||
String syncKey = c.getString(Mailbox.CONTENT_SYNC_KEY_COLUMN);
|
||||
if (syncKey == null || syncKey.equals("0")) {
|
||||
pushCount--;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -630,13 +649,16 @@ public class EasSyncService extends AbstractSyncService {
|
|||
.data(Tags.PING_ID, c.getString(Mailbox.CONTENT_SERVER_ID_COLUMN))
|
||||
.data(Tags.PING_CLASS, folderClass)
|
||||
.end();
|
||||
userLog("Ping ready for: " + folderClass + ", " +
|
||||
c.getString(Mailbox.CONTENT_SERVER_ID_COLUMN) + " (" +
|
||||
c.getString(Mailbox.CONTENT_DISPLAY_NAME_COLUMN) + ')');
|
||||
userLog("Ping ready for: " + folderClass + ", " + mailboxName + " (" +
|
||||
c.getString(Mailbox.CONTENT_SERVER_ID_COLUMN) + ')');
|
||||
pushBoxes.add(new Mailbox().restore(c));
|
||||
} else {
|
||||
userLog(c.getString(Mailbox.CONTENT_DISPLAY_NAME_COLUMN) +
|
||||
" not ready for ping");
|
||||
} else if (pingStatus == SyncManager.PING_STATUS_RUNNING ||
|
||||
pingStatus == SyncManager.PING_STATUS_WAITING) {
|
||||
userLog(mailboxName + " not ready for ping");
|
||||
} else if (pingStatus == SyncManager.PING_STATUS_UNABLE) {
|
||||
pushCount--;
|
||||
userLog(mailboxName + " in error state; ignore");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
@ -689,7 +711,9 @@ public class EasSyncService extends AbstractSyncService {
|
|||
sleep(10*SECS);
|
||||
} else {
|
||||
// We've got nothing to do, so let's hang out for a while
|
||||
sleep(20*MINS);
|
||||
SyncManager.runAsleep(mMailboxId, 30*MINS);
|
||||
sleep(30*MINS);
|
||||
SyncManager.runAwake(mMailboxId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -957,7 +981,7 @@ public class EasSyncService extends AbstractSyncService {
|
|||
userLog("Caught IOException");
|
||||
mExitStatus = EXIT_IO_ERROR;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "Uncaught exception in EasSyncService", e);
|
||||
} finally {
|
||||
if (!mStop) {
|
||||
userLog(mMailbox.mDisplayName + ": sync finished");
|
||||
|
@ -978,6 +1002,7 @@ public class EasSyncService extends AbstractSyncService {
|
|||
break;
|
||||
default:
|
||||
status = EmailServiceStatus.REMOTE_EXCEPTION;
|
||||
errorLog("Sync ended due to an exception.");
|
||||
break;
|
||||
}
|
||||
try {
|
||||
|
|
|
@ -37,5 +37,5 @@ interface IEmailService {
|
|||
|
||||
void setCallback(IEmailServiceCallback cb);
|
||||
|
||||
void setLogging(boolean on);
|
||||
void setLogging(int on);
|
||||
}
|
|
@ -27,6 +27,7 @@ import com.android.email.provider.EmailContent.MailboxColumns;
|
|||
import com.android.email.provider.EmailContent.Message;
|
||||
import com.android.email.provider.EmailContent.MessageColumns;
|
||||
import com.android.email.provider.EmailContent.SyncColumns;
|
||||
import com.android.exchange.utility.FileLogger;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
|
@ -86,6 +87,7 @@ public class SyncManager extends Service implements Runnable {
|
|||
public static final int SECS = 1000;
|
||||
public static final int MINS = 60 * SECS;
|
||||
|
||||
// Reason codes when SyncManager.kick is called (mainly for debugging)
|
||||
public static final int SYNC_UPSYNC = 0;
|
||||
public static final int SYNC_SCHEDULED = 1;
|
||||
public static final int SYNC_PUSH = 2;
|
||||
|
@ -98,6 +100,9 @@ public class SyncManager extends Service implements Runnable {
|
|||
MailboxColumns.ACCOUNT_KEY + "=? and " + MailboxColumns.TYPE + "!=" +
|
||||
Mailbox.TYPE_EAS_ACCOUNT_MAILBOX + " and " + MailboxColumns.SYNC_INTERVAL +
|
||||
" IN (" + Account.CHECK_INTERVAL_PING + ',' + Account.CHECK_INTERVAL_PUSH + ')';
|
||||
public static final String WHERE_IN_ACCOUNT_AND_PUSHABLE =
|
||||
MailboxColumns.ACCOUNT_KEY + "=? and type in (" + Mailbox.TYPE_INBOX + ','
|
||||
/*+ Mailbox.TYPE_CALENDAR + ','*/ + Mailbox.TYPE_CONTACTS + ')';
|
||||
|
||||
// Offsets into the syncStatus data for EAS that indicate type, exit status, and change count
|
||||
// The format is S<type_char>:<exit_char>:<change_count>
|
||||
|
@ -105,6 +110,15 @@ public class SyncManager extends Service implements Runnable {
|
|||
public static final int STATUS_EXIT_CHAR = 3;
|
||||
public static final int STATUS_CHANGE_COUNT_OFFSET = 5;
|
||||
|
||||
// Ready for ping
|
||||
public static final int PING_STATUS_OK = 0;
|
||||
// Service already running (can't ping)
|
||||
public static final int PING_STATUS_RUNNING = 1;
|
||||
// Service waiting after I/O error (can't ping)
|
||||
public static final int PING_STATUS_WAITING = 2;
|
||||
// Service had a fatal error; can't run
|
||||
public static final int PING_STATUS_UNABLE = 3;
|
||||
|
||||
static SyncManager INSTANCE;
|
||||
static Object mSyncToken = new Object();
|
||||
static Thread mServiceThread = null;
|
||||
|
@ -208,7 +222,7 @@ public class SyncManager extends Service implements Runnable {
|
|||
reloadFolderList(SyncManager.this, accountId, false);
|
||||
}
|
||||
|
||||
public void setLogging(boolean on) throws RemoteException {
|
||||
public void setLogging(int on) throws RemoteException {
|
||||
Eas.setUserDebug(on);
|
||||
}
|
||||
|
||||
|
@ -312,10 +326,23 @@ public class SyncManager extends Service implements Runnable {
|
|||
// Here's one that has...
|
||||
INSTANCE.log("Account " + account.mDisplayName +
|
||||
" changed; stopping running syncs...");
|
||||
// If account is push, set contacts and inbox to push
|
||||
Account updatedAccount =
|
||||
Account.restoreAccountWithId(getContext(), account.mId);
|
||||
if (updatedAccount.mSyncInterval == Account.CHECK_INTERVAL_PUSH) {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(MailboxColumns.SYNC_INTERVAL, Account.CHECK_INTERVAL_PUSH);
|
||||
getContext().getContentResolver().update(Mailbox.CONTENT_URI, cv,
|
||||
WHERE_IN_ACCOUNT_AND_PUSHABLE,
|
||||
new String[] {Long.toString(account.mId)});
|
||||
}
|
||||
// Stop all current syncs; the appropriate ones will restart
|
||||
stopAccountSyncs(account.mId, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look for new accounts
|
||||
for (Account account: currentAccounts) {
|
||||
if (!mAccounts.contains(account.mId)) {
|
||||
// This is an addition; create our magic hidden mailbox...
|
||||
|
@ -323,7 +350,10 @@ public class SyncManager extends Service implements Runnable {
|
|||
mAccounts.add(account);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
||||
// Finally, make sure mAccounts is up to date
|
||||
mAccounts = currentAccounts;
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
||||
|
@ -485,6 +515,9 @@ public class SyncManager extends Service implements Runnable {
|
|||
public void log(String str) {
|
||||
if (Eas.USER_LOG) {
|
||||
Log.d(TAG, str);
|
||||
if (Eas.FILE_LOG) {
|
||||
FileLogger.log(TAG, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -778,6 +811,8 @@ public class SyncManager extends Service implements Runnable {
|
|||
if (state == State.CONNECTED) {
|
||||
info += " CONNECTED";
|
||||
kick("connected");
|
||||
// Clear our sync error map when we get connected
|
||||
mSyncErrorMap.clear();
|
||||
} else if (state == State.CONNECTING) {
|
||||
info += " CONNECTING";
|
||||
} else if (state == State.DISCONNECTED) {
|
||||
|
@ -1124,16 +1159,21 @@ public class SyncManager extends Service implements Runnable {
|
|||
* @param mailboxId
|
||||
* @return whether or not the Mailbox is available for syncing (i.e. is a valid push target)
|
||||
*/
|
||||
static public boolean canSync(long mailboxId) {
|
||||
static public int pingStatus(long mailboxId) {
|
||||
// Already syncing...
|
||||
if (INSTANCE.mServiceMap.get(mailboxId) != null) {
|
||||
return false;
|
||||
return PING_STATUS_RUNNING;
|
||||
}
|
||||
// Blocked from syncing (transient or permanent)
|
||||
if (INSTANCE.mSyncErrorMap.get(mailboxId) != null) {
|
||||
return false;
|
||||
// No errors or a transient error, don't ping...
|
||||
SyncError error = INSTANCE.mSyncErrorMap.get(mailboxId);
|
||||
if (error != null) {
|
||||
if (error.fatal) {
|
||||
return PING_STATUS_UNABLE;
|
||||
} else {
|
||||
return PING_STATUS_WAITING;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return PING_STATUS_OK;
|
||||
}
|
||||
|
||||
static public int getSyncStatus(long mailboxId) {
|
||||
|
@ -1243,8 +1283,11 @@ public class SyncManager extends Service implements Runnable {
|
|||
case AbstractSyncService.EXIT_IO_ERROR:
|
||||
if (syncError != null) {
|
||||
syncError.escalate();
|
||||
INSTANCE.log("Mailbox " + mailboxId + " now held for "
|
||||
+ syncError.holdDelay + "s");
|
||||
} else {
|
||||
errorMap.put(mailboxId, INSTANCE.new SyncError(exitStatus, false));
|
||||
INSTANCE.log("Mailbox " + mailboxId + " added to syncErrorMap");
|
||||
}
|
||||
kick("i/o error in sync");
|
||||
break;
|
||||
|
|
|
@ -1046,11 +1046,13 @@ public class ContactsSyncAdapter extends AbstractSyncAdapter {
|
|||
}
|
||||
|
||||
public void addNickname(Entity entity, String name) {
|
||||
SmartBuilder builder = createBuilder(entity, Nickname.CONTENT_ITEM_TYPE, -1);
|
||||
SmartBuilder builder =
|
||||
createBuilder(entity, Nickname.CONTENT_ITEM_TYPE, Nickname.TYPE_DEFAULT);
|
||||
ContentValues cv = builder.cv;
|
||||
if (cv != null && cvCompareString(cv, Nickname.NAME, name)) {
|
||||
return;
|
||||
}
|
||||
builder.withValue(Nickname.TYPE, Nickname.TYPE_DEFAULT);
|
||||
builder.withValue(Nickname.NAME, name);
|
||||
add(builder.build());
|
||||
}
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
|
||||
package com.android.exchange.adapter;
|
||||
|
||||
import com.android.email.R;
|
||||
import com.android.email.activity.MessageList;
|
||||
import com.android.email.mail.Address;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailProvider;
|
||||
import com.android.email.provider.EmailContent.Attachment;
|
||||
import com.android.email.provider.EmailContent.Mailbox;
|
||||
|
@ -27,14 +30,20 @@ import com.android.email.provider.EmailContent.SyncColumns;
|
|||
import com.android.exchange.Eas;
|
||||
import com.android.exchange.EasSyncService;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.OperationApplicationException;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.RemoteException;
|
||||
import android.text.TextUtils;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -389,6 +398,7 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
|
|||
ArrayList<Message> newEmails = new ArrayList<Message>();
|
||||
ArrayList<Long> deletedEmails = new ArrayList<Long>();
|
||||
ArrayList<ServerChange> changedEmails = new ArrayList<ServerChange>();
|
||||
int notifyCount = 0;
|
||||
|
||||
while (nextTag(Tags.SYNC_COMMANDS) != END) {
|
||||
if (tag == Tags.SYNC_ADD) {
|
||||
|
@ -407,8 +417,11 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
|
|||
// Use a batch operation to handle the changes
|
||||
// TODO New mail notifications? Who looks for these?
|
||||
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
|
||||
for (Message content : newEmails) {
|
||||
content.addSaveOps(ops);
|
||||
for (Message msg: newEmails) {
|
||||
if (!msg.mFlagRead) {
|
||||
notifyCount++;
|
||||
}
|
||||
msg.addSaveOps(ops);
|
||||
}
|
||||
for (Long id : deletedEmails) {
|
||||
ops.add(ContentProviderOperation.newDelete(
|
||||
|
@ -450,8 +463,30 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
|
|||
// There is nothing to be done here; fail by returning null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Remove this temporary notification code
|
||||
if (notifyCount > 0) {
|
||||
NotificationManager notifMgr =
|
||||
(NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
Notification notif = new Notification(R.drawable.stat_notify_email_generic,
|
||||
mContext.getString(R.string.notification_new_title),
|
||||
System.currentTimeMillis());
|
||||
Intent i = MessageList.actionHandleAccountIntent(mContext, mAccount.mId,
|
||||
Mailbox.TYPE_INBOX);
|
||||
PendingIntent pi = PendingIntent.getActivity(mContext, 0, i, 0);
|
||||
notif.setLatestEventInfo(mContext,
|
||||
mContext.getString(R.string.notification_new_title),
|
||||
"You've got new mail!", pi);
|
||||
boolean vibrate = ((mAccount.getFlags() & EmailContent.Account.FLAGS_VIBRATE) != 0);
|
||||
String ringtone = mAccount.getRingtone();
|
||||
notif.defaults = Notification.DEFAULT_LIGHTS;
|
||||
notif.sound = TextUtils.isEmpty(ringtone) ? null : Uri.parse(ringtone);
|
||||
if (vibrate) {
|
||||
notif.defaults |= Notification.DEFAULT_VIBRATE;
|
||||
}
|
||||
notifMgr.notify(1, notif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -47,7 +47,9 @@ public class PingParser extends Parser {
|
|||
while (nextTag(Tags.PING_FOLDERS) != END) {
|
||||
if (tag == Tags.PING_FOLDER) {
|
||||
// Here we'll keep track of which mailboxes need syncing
|
||||
syncList.add(getValue());
|
||||
String serverId = getValue();
|
||||
syncList.add(serverId);
|
||||
mService.userLog("Changes found in: " + serverId);
|
||||
} else {
|
||||
skipTag();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
package com.android.exchange.utility;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
public class FileLogger {
|
||||
private static FileLogger LOGGER = null;
|
||||
private static FileWriter mLogWriter = null;
|
||||
public static String LOG_FILE_NAME = "/sdcard/emaillog.txt";
|
||||
private static Object mLock = new Object();
|
||||
|
||||
public synchronized static FileLogger getLogger (Context c) {
|
||||
LOGGER = new FileLogger();
|
||||
return LOGGER;
|
||||
}
|
||||
|
||||
private FileLogger () {
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
mLogWriter = new FileWriter(LOG_FILE_NAME, true);
|
||||
} catch (IOException e) {
|
||||
// Doesn't matter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public synchronized void close() {
|
||||
if (mLogWriter != null) {
|
||||
try {
|
||||
mLogWriter.close();
|
||||
} catch (IOException e) {
|
||||
// Doesn't matter
|
||||
}
|
||||
mLogWriter = null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
static public synchronized void log (String prefix, String str) {
|
||||
if (LOGGER == null) {
|
||||
LOGGER = new FileLogger();
|
||||
log("Logger", "\r\n\r\n --- New Log ---");
|
||||
}
|
||||
Date d = new Date();
|
||||
int hr = d.getHours();
|
||||
int min = d.getMinutes();
|
||||
int sec = d.getSeconds();
|
||||
|
||||
StringBuffer sb = new StringBuffer(256);
|
||||
sb.append('[');
|
||||
sb.append(hr);
|
||||
sb.append(':');
|
||||
if (min < 10)
|
||||
sb.append('0');
|
||||
sb.append(min);
|
||||
sb.append(':');
|
||||
if (sec < 10) {
|
||||
sb.append('0');
|
||||
}
|
||||
sb.append(sec);
|
||||
sb.append("] ");
|
||||
if (prefix != null) {
|
||||
sb.append(prefix);
|
||||
sb.append("| ");
|
||||
}
|
||||
sb.append(str);
|
||||
sb.append("\r\n");
|
||||
String s = sb.toString();
|
||||
|
||||
synchronized (mLock) {
|
||||
if (mLogWriter != null) {
|
||||
try {
|
||||
mLogWriter.write(s);
|
||||
mLogWriter.flush();
|
||||
} catch (IOException e) {
|
||||
// Doesn't matter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue