Merge Email1 into MR1
Change-Id: I45289d46b65faffc7a3a3dd46382899162f3aaab
40
Android.mk
|
@ -14,42 +14,38 @@
|
|||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# Build the Email application itself, along with its tests and tests for the emailcommon
|
||||
# Build the Email application itself, along with its tests and the tests for the emailcommon
|
||||
# static library. All tests can be run via runtest email
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
# Include res dir from chips, unified, and photoviewer
|
||||
# Include res dir from chips
|
||||
chips_dir := ../../../frameworks/ex/chips/res
|
||||
unified_email_dir := ../UnifiedEmail
|
||||
photo_dir := ../../../frameworks/ex/photoviewer/res
|
||||
res_dir := $(chips_dir) res $(unified_email_dir)/res $(photo_dir) build/res
|
||||
mail_common_dir := ../../../frameworks/opt/mailcommon/res
|
||||
res_dir := $(chips_dir) $(mail_common_dir) res
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, $(unified_email_dir)/src)
|
||||
LOCAL_SRC_FILES += $(call all-java-files-under, src/com/android)
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/email)
|
||||
LOCAL_SRC_FILES += $(call all-java-files-under, src/com/beetstra)
|
||||
|
||||
LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dir))
|
||||
|
||||
# Use assets dir from UnifiedEmail
|
||||
# (the default package target doesn't seem to deal with multiple asset dirs)
|
||||
LOCAL_ASSET_DIR := $(LOCAL_PATH)/$(unified_email_dir)/assets
|
||||
|
||||
LOCAL_AAPT_FLAGS := --auto-add-overlay
|
||||
LOCAL_AAPT_FLAGS += --extra-packages com.android.ex.chips:com.android.mail:com.android.email:com.android.ex.photo
|
||||
LOCAL_AAPT_FLAGS += --extra-packages com.android.ex.chips
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := android-common com.android.emailcommon2 com.android.emailsync guava android-common-chips android-common-photoviewer
|
||||
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4
|
||||
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v13
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := android-common com.android.emailcommon guava android-common-chips
|
||||
|
||||
LOCAL_PACKAGE_NAME := Email2
|
||||
LOCAL_OVERRIDES_PACKAGES := Email
|
||||
LOCAL_PACKAGE_NAME := Email
|
||||
|
||||
LOCAL_PROGUARD_FLAG_FILES := proguard.flags $(unified_email_dir)/proguard.flags
|
||||
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
|
||||
|
||||
LOCAL_SDK_VERSION := current # TODO change this to "17" once the MR1 sdk version is set to 17
|
||||
LOCAL_SDK_VERSION := 16
|
||||
|
||||
# The Emma tool analyzes code coverage when running unit tests on the
|
||||
# application. This configuration line selects which packages will be analyzed,
|
||||
# leaving out code which is tested by other means (e.g. static libraries) that
|
||||
# would dilute the coverage results. These options do not affect regular
|
||||
# production builds.
|
||||
LOCAL_EMMA_COVERAGE_FILTER := +com.android.emailcommon.*,+com.android.email.*, \
|
||||
+org.apache.james.mime4j.*,+com.beetstra.jutf7.*,+org.apache.commons.io.*
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2012 The Android Open Source Project
|
||||
<!-- Copyright (C) 2008 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.
|
||||
|
@ -14,35 +13,56 @@
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.email"
|
||||
android:versionCode="500014"
|
||||
android:versionName="4.2-014" >
|
||||
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
|
||||
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.READ_CALENDAR"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
|
||||
<uses-permission android:name="android.permission.READ_PROFILE"/>
|
||||
<uses-permission android:name="android.permission.NFC"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.email"
|
||||
android:versionCode="410000"
|
||||
android:versionName="4.1"
|
||||
>
|
||||
|
||||
<!-- This needs to be present when we are doing unbundled releases. -->
|
||||
<uses-sdk android:targetSdkVersion="17" android:minSdkVersion="14" />
|
||||
<uses-sdk android:targetSdkVersion="16" android:minSdkVersion="14" />
|
||||
|
||||
<original-package android:name="com.android.email" />
|
||||
<original-package
|
||||
android:name="com.android.email" />
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.INTERNET"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission
|
||||
android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_SYNC_SETTINGS" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_SYNC_SETTINGS"/>
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_CONTACTS"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_CONTACTS"/>
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_PROFILE"/>
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.NFC"/>
|
||||
|
||||
<!-- Only required if a store implements push mail and needs to keep network open -->
|
||||
<uses-permission
|
||||
android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_PHONE_STATE"/>
|
||||
|
||||
<!-- Grant permission to other apps to view attachments -->
|
||||
<permission
|
||||
|
@ -58,27 +78,160 @@
|
|||
android:name="android.permission.USE_CREDENTIALS"/>
|
||||
|
||||
<!-- Grant permission to system apps to access provider (see provider below) -->
|
||||
<!-- STOPSHIP: Temporarily set protection level to "dangerous" (from "signature") -->
|
||||
<permission
|
||||
android:name="com.android.email.permission.ACCESS_PROVIDER"
|
||||
android:protectionLevel="dangerous"
|
||||
android:protectionLevel="signature"
|
||||
android:label="@string/permission_access_provider_label"
|
||||
android:description="@string/permission_access_provider_desc"/>
|
||||
<uses-permission
|
||||
android:name="com.android.email.permission.ACCESS_PROVIDER"/>
|
||||
|
||||
<!-- Note: Actually, android:hardwareAccelerated could be "true", but in order to switch it
|
||||
on/off in the debug screen, we have to set it "false" here and enable it at runtime. -->
|
||||
<application
|
||||
android:icon="@mipmap/ic_launcher_mail"
|
||||
android:icon="@mipmap/ic_launcher_email"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/UnifiedEmailTheme"
|
||||
android:hardwareAccelerated="true" >
|
||||
<!-- Enable search in all activities -->
|
||||
<meta-data android:name="android.app.default_searchable"
|
||||
android:value="com.android.email2.ui.MailActivityEmail" />
|
||||
android:name="Email"
|
||||
android:theme="@style/EmailTheme"
|
||||
android:hardwareAccelerated="false"
|
||||
>
|
||||
<activity
|
||||
android:name="com.android.mail.compose.ComposeActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.Holo.Light">
|
||||
android:name=".activity.Welcome"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.intent.category.APP_EMAIL" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<data
|
||||
android:scheme="content"
|
||||
android:host="ui.email.android.com"
|
||||
android:path="/view/mailbox"
|
||||
/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Must be exported in order for the AccountManager to launch it -->
|
||||
<!-- Also available for continuous test systems to force account creation -->
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupBasics"
|
||||
android:label="@string/account_setup_basics_title"
|
||||
android:exported="true"
|
||||
>
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="com.android.email.CREATE_ACCOUNT" />
|
||||
<category
|
||||
android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupAccountType"
|
||||
android:label="@string/account_setup_account_type_title"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupIncoming"
|
||||
android:label="@string/account_setup_incoming_title"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupOutgoing"
|
||||
android:label="@string/account_setup_outgoing_title"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupExchange"
|
||||
android:label="@string/account_setup_exchange_title"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupOptions"
|
||||
android:label="@string/account_setup_options_title"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupNames"
|
||||
android:label="@string/account_setup_names_title"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSettings"
|
||||
android:label="@string/settings_activity_title"
|
||||
android:theme="@android:style/Theme.Holo.Light"
|
||||
>
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="com.android.email.activity.setup.ACCOUNT_MANAGER_ENTRY" />
|
||||
<category
|
||||
android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.EDIT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data
|
||||
android:scheme="content"
|
||||
android:host="ui.email.android.com"
|
||||
android:path="/settings"
|
||||
/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSecurity"
|
||||
android.label="@string/account_security_title"
|
||||
>
|
||||
</activity>
|
||||
|
||||
<!-- Don't need to set the title; it will be set programatically -->
|
||||
<activity
|
||||
android:name=".activity.ShortcutPicker"
|
||||
android:enabled="false"
|
||||
android:theme="@android:style/Theme.Holo.Light.DialogWhenLarge"
|
||||
>
|
||||
<intent-filter
|
||||
android:label="@string/account_shortcut_picker_name">
|
||||
<action
|
||||
android:name="android.intent.action.CREATE_SHORTCUT" />
|
||||
<category
|
||||
android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.EmailActivity"
|
||||
android:uiOptions="splitActionBarWhenNarrow"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.MessageFileView"
|
||||
>
|
||||
<intent-filter
|
||||
android:label="@string/app_name">
|
||||
<action
|
||||
android:name="android.intent.action.VIEW" />
|
||||
<data
|
||||
android:mimeType="application/eml" />
|
||||
<data
|
||||
android:mimeType="message/rfc822" />
|
||||
<category
|
||||
android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.MessageCompose"
|
||||
android:label="@string/compose_title"
|
||||
android:enabled="false"
|
||||
android:theme="@android:style/Theme.Holo.Light"
|
||||
>
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="android.intent.action.VIEW" />
|
||||
|
@ -113,189 +266,15 @@
|
|||
<action
|
||||
android:name="com.android.email.intent.action.REPLY" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category
|
||||
android:name="android.intent.category.DEFAULT" />
|
||||
<data
|
||||
android:scheme="content"
|
||||
android:host="ui.email2.android.com"
|
||||
android:pathPrefix="/compose"
|
||||
/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="mailto" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Only used to support pre-HC shortcuts -->
|
||||
<activity
|
||||
android:name=".activity.EventViewer"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.Holo.Light"
|
||||
android:name=".activity.MessageList"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category
|
||||
android:name="android.intent.category.DEFAULT" />
|
||||
<data
|
||||
android:scheme="content"
|
||||
android:host="ui.email2.android.com"
|
||||
android:pathPrefix="/event"
|
||||
/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- TODO: this activity doesn't exist. Determine what to do here -->
|
||||
<activity android:name=".ui.CreateShortcutActivity"
|
||||
android:label="@string/activity_folder_selection" />
|
||||
|
||||
<activity android:name="com.android.mail.ui.FolderSelectionActivity"
|
||||
android:label="@string/activity_folder_selection" />
|
||||
|
||||
<activity android:name="com.android.email2.ui.MailboxSelectionActivityEmail"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.android.mail.ui.ShortcutNameActivity"
|
||||
android:label="@string/shortcut_name_title"
|
||||
android:theme="@style/ShortcutWidgetTheme">
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.android.mail.ui.MailboxSelectionActivity"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.android.email2.ui.CreateShortcutActivityEmail"
|
||||
android:theme="@style/ShortcutWidgetTheme"
|
||||
android:label="@string/activity_folder_selection">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.CREATE_SHORTCUT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:label="@string/app_name"
|
||||
android:name="com.android.email2.ui.MailActivityEmail"
|
||||
android:theme="@style/PlainUnifiedEmailTheme"
|
||||
android:uiOptions="splitActionBarWhenNarrow">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="content"/>
|
||||
<data android:mimeType="@string/application_mime_type" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
|
||||
</activity>
|
||||
|
||||
<activity-alias android:name="com.android.email.activity.Welcome"
|
||||
android:targetActivity="com.android.email2.ui.MailActivityEmail"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter >
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.intent.category.APP_EMAIL" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<!-- Must be exported in order for the AccountManager to launch it -->
|
||||
<!-- Also available for continuous test systems to force account creation -->
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupBasics"
|
||||
android:label="@string/account_setup_basics_title"
|
||||
android:exported="true"
|
||||
>
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="com.android.email.CREATE_ACCOUNT" />
|
||||
<category
|
||||
android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupType"
|
||||
android:label="@string/account_setup_account_type_title"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupIncoming"
|
||||
android:label="@string/account_setup_incoming_title"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupOutgoing"
|
||||
android:label="@string/account_setup_outgoing_title"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupOptions"
|
||||
android:label="@string/account_setup_options_title"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSetupNames"
|
||||
android:label="@string/account_setup_names_title"
|
||||
>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSettings"
|
||||
android:label="@string/settings_activity_title"
|
||||
android:theme="@android:style/Theme.Holo.Light"
|
||||
>
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="com.android.email.activity.setup.ACCOUNT_MANAGER_ENTRY" />
|
||||
<category
|
||||
android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.EDIT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data
|
||||
android:scheme="content"
|
||||
android:host="ui.email.android.com"
|
||||
android:pathPrefix="/settings"
|
||||
/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".provider.FolderPickerActivity"
|
||||
android:label="@string/folder_picker_title"
|
||||
android:theme="@android:style/Theme.Holo.Light"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.EDIT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data
|
||||
android:scheme="content"
|
||||
android:host="ui.email.android.com"
|
||||
android:pathPrefix="/setup"
|
||||
/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.setup.AccountSecurity"
|
||||
android.label="@string/account_security_title"
|
||||
>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
|
@ -304,68 +283,6 @@
|
|||
>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.android.mail.photo.MailPhotoViewActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/PhotoViewTheme" >
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:authorities="com.android.email2.conversation.provider"
|
||||
android:label="@string/conversation_content_provider"
|
||||
android:multiprocess="false"
|
||||
android:exported="true"
|
||||
android:name="com.android.mail.browse.EmailConversationProvider" >
|
||||
<grant-uri-permission android:pathPattern=".*" />
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:authorities="com.android.email2.accountcache"
|
||||
android:label="@string/account_cache_provider"
|
||||
android:multiprocess="false"
|
||||
android:exported="true"
|
||||
android:name="com.android.mail.providers.EmailAccountCacheProvider" >
|
||||
<grant-uri-permission android:pathPattern=".*" />
|
||||
</provider>
|
||||
|
||||
<!-- The android:name is the name of the Provider class which is stored in
|
||||
UnifiedEmail, and has package name com.android.mail.providers and the class is
|
||||
called SuggestionsProvider. The authority name is specified in the MailAppProvider
|
||||
which is specific to the two apps separately. -->
|
||||
<provider android:name="com.android.mail.providers.SuggestionsProvider"
|
||||
android:authorities="com.android.email.suggestionsprovider"
|
||||
android:exported="true" />
|
||||
|
||||
<receiver android:name="com.android.mail.providers.protos.boot.AccountReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.email2.providers.protos.boot.intent.ACTION_PROVIDER_CREATED" />
|
||||
<action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service android:name="com.android.mail.compose.EmptyService"/>
|
||||
<!-- Widget -->
|
||||
<receiver android:name=".provider.WidgetProvider" android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="com.android.mail.ACTION_NOTIFY_DATASET_CHANGED" />
|
||||
<data android:mimeType="@string/application_mime_type" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="com.android.mail.ACTION_UPDATE_WIDGET" />
|
||||
<data android:mimeType="@string/application_mime_type" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.appwidget.provider"
|
||||
android:resource="@xml/widget_info" />
|
||||
</receiver>
|
||||
<service android:name="com.android.mail.widget.WidgetService"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- From Email application -->
|
||||
|
||||
<receiver
|
||||
android:name=".service.AttachmentDownloadService$Watchdog"
|
||||
android:enabled="true"/>
|
||||
|
@ -374,16 +291,14 @@
|
|||
android:name=".service.EmailBroadcastReceiver"
|
||||
android:enabled="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.DEVICE_STORAGE_LOW" />
|
||||
<action android:name="android.intent.action.DEVICE_STORAGE_OK" />
|
||||
<action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
|
||||
</intent-filter>
|
||||
<!-- To handle new message notifications -->
|
||||
<intent-filter>
|
||||
<action android:name="com.android.mail.action.update_notification"
|
||||
android:priority="-10" />
|
||||
<data android:mimeType="@string/application_mime_type" />
|
||||
<action
|
||||
android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action
|
||||
android:name="android.intent.action.DEVICE_STORAGE_LOW" />
|
||||
<action
|
||||
android:name="android.intent.action.DEVICE_STORAGE_OK" />
|
||||
<action
|
||||
android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
|
||||
</intent-filter>
|
||||
<!-- To handle secret code to activate the debug screen. -->
|
||||
<intent-filter>
|
||||
|
@ -415,6 +330,12 @@
|
|||
|
||||
<service
|
||||
android:name=".service.MailService"
|
||||
android:enabled="false"
|
||||
>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".Controller$ControllerService"
|
||||
android:enabled="true"
|
||||
>
|
||||
</service>
|
||||
|
@ -427,7 +348,7 @@
|
|||
|
||||
<!--Required stanza to register the PopImapAuthenticatorService with AccountManager -->
|
||||
<service
|
||||
android:name=".service.Pop3AuthenticatorService"
|
||||
android:name=".service.PopImapAuthenticatorService"
|
||||
android:exported="true"
|
||||
android:enabled="true"
|
||||
>
|
||||
|
@ -437,46 +358,20 @@
|
|||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.accounts.AccountAuthenticator"
|
||||
android:resource="@xml/authenticator_pop3"
|
||||
/>
|
||||
</service>
|
||||
<!--Required stanza to register the PopImapAuthenticatorService with AccountManager -->
|
||||
<service
|
||||
android:name=".service.ImapAuthenticatorService"
|
||||
android:exported="true"
|
||||
android:enabled="true"
|
||||
>
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="android.accounts.AccountAuthenticator" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.accounts.AccountAuthenticator"
|
||||
android:resource="@xml/authenticator_imap"
|
||||
android:resource="@xml/pop_imap_authenticator"
|
||||
/>
|
||||
</service>
|
||||
|
||||
<!--Required stanza to register the PopImapSyncAdapterService with SyncManager -->
|
||||
<service
|
||||
android:name="com.android.email.service.Pop3SyncAdapterService"
|
||||
android:name="com.android.email.service.PopImapSyncAdapterService"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="android.content.SyncAdapter" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.content.SyncAdapter"
|
||||
android:resource="@xml/syncadapter_pop3" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name="com.android.email.service.LegacyImapSyncAdapterService"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="android.content.SyncAdapter" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.content.SyncAdapter"
|
||||
android:resource="@xml/syncadapter_legacy_imap" />
|
||||
android:resource="@xml/syncadapter_pop_imap" />
|
||||
</service>
|
||||
|
||||
<!-- Require provider permission to use our Policy and Account services -->
|
||||
|
@ -502,28 +397,6 @@
|
|||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".service.ImapService"
|
||||
android:enabled="true"
|
||||
android:permission="com.android.email.permission.ACCESS_PROVIDER"
|
||||
>
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="com.android.email.IMAP_INTENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".service.Pop3Service"
|
||||
android:enabled="true"
|
||||
android:permission="com.android.email.permission.ACCESS_PROVIDER"
|
||||
>
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="com.android.email.POP3_INTENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!--Required stanza to register the EasAuthenticatorService with AccountManager -->
|
||||
<service
|
||||
android:name=".service.EasAuthenticatorService"
|
||||
|
@ -536,7 +409,7 @@
|
|||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.accounts.AccountAuthenticator"
|
||||
android:resource="@xml/authenticator_eas"
|
||||
android:resource="@xml/eas_authenticator"
|
||||
/>
|
||||
</service>
|
||||
<!--Required stanza to register the EasTestAuthenticatorService with AccountManager -->
|
||||
|
@ -572,49 +445,12 @@
|
|||
android:resource="@xml/authenticator_alternate"
|
||||
/>
|
||||
</service>
|
||||
<service
|
||||
android:name=".service.ImapAuthenticatorService"
|
||||
android:exported="true"
|
||||
android:enabled="true"
|
||||
>
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="android.accounts.AccountAuthenticator" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.accounts.AccountAuthenticator"
|
||||
android:resource="@xml/authenticator_imap"
|
||||
/>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".service.LegacyImapAuthenticatorService"
|
||||
android:exported="false"
|
||||
android:enabled="true"
|
||||
>
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="android.accounts.AccountAuthenticator" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.accounts.AccountAuthenticator"
|
||||
android:resource="@xml/authenticator_legacy_imap"
|
||||
/>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".imap2.Imap2SyncManager"
|
||||
android:enabled="true"
|
||||
android:permission="com.android.email.permission.ACCESS_PROVIDER"
|
||||
>
|
||||
</service>
|
||||
|
||||
<provider
|
||||
android:name=".provider.AttachmentProvider"
|
||||
android:authorities="com.android.email.attachmentprovider"
|
||||
android:multiprocess="true"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="true"
|
||||
android:readPermission="com.android.email.permission.READ_ATTACHMENT"
|
||||
/>
|
||||
|
||||
|
@ -624,45 +460,41 @@
|
|||
android:name=".provider.EmailProvider"
|
||||
android:authorities="com.android.email.provider;com.android.email.notifier"
|
||||
android:multiprocess="true"
|
||||
android:exported="true"
|
||||
android:permission="com.android.email.permission.ACCESS_PROVIDER"
|
||||
android:label="@string/app_name"
|
||||
/>
|
||||
|
||||
<!-- Legacy authenticators, etc. can be added below. OEMs may remove these -->
|
||||
|
||||
<service
|
||||
android:name=".service.LegacyEmailAuthenticatorService"
|
||||
android:exported="false"
|
||||
<!-- Email AppWidget definitions -->
|
||||
<activity
|
||||
android:name=".widget.WidgetConfiguration"
|
||||
android:enabled="true"
|
||||
android:theme="@android:style/Theme.Holo.Light.DialogWhenLarge"
|
||||
>
|
||||
<intent-filter
|
||||
android:label="@string/account_shortcut_picker_name">
|
||||
<action
|
||||
android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
|
||||
<category
|
||||
android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service
|
||||
android:name=".provider.WidgetProvider$WidgetService"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS"
|
||||
android:exported="false"
|
||||
/>
|
||||
<receiver
|
||||
android:name=".provider.WidgetProvider" >
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="android.accounts.AccountAuthenticator" />
|
||||
android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.accounts.AccountAuthenticator"
|
||||
android:resource="@xml/authenticator_legacy_email"
|
||||
/>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".service.LegacyEasAuthenticatorService"
|
||||
android:exported="false"
|
||||
android:enabled="true"
|
||||
>
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="android.accounts.AccountAuthenticator" />
|
||||
<action android:name="com.android.email.MESSAGE_LIST_DATASET_CHANGED" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.accounts.AccountAuthenticator"
|
||||
android:resource="@xml/authenticator_legacy_eas"
|
||||
/>
|
||||
</service>
|
||||
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/widget_info" />
|
||||
</receiver>
|
||||
</application>
|
||||
|
||||
<!-- Legacy permissions, etc. can go here -->
|
||||
|
||||
</manifest>
|
||||
|
|
37
CleanSpec.mk
|
@ -43,8 +43,37 @@
|
|||
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
|
||||
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
|
||||
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/out/target/common/obj/APPS/Email*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/out/target/common/obj/APPS/Email*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/out/target/common/obj/APPS/Exchange*)
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/JAVA_LIBRARIES/com.android.emailcommon*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes/com/android/emailcommon*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/out/target/common/obj/JAVA_LIBRARIES/com.android.emailcommon*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/EmailGoogle_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Email_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.android.emailcommon_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.android.emailcommon_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.android.emailcommon_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.android.emailcommon_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Email_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/EmailGoogle_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Email_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/EmailGoogle_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Email2_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Email_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/EmailGoogle_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Email2_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/out/target/common/obj/JAVA_LIBRARIES/com.android.emailcommon*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/EmailGoogle_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Email2_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/out/target/common/obj/JAVA_LIBRARIES/com.android.emailcommon*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/EmailGoogle_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Email2_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/out/target/common/obj/JAVA_LIBRARIES/com.android.emailcommon*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Email*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/out/target/common/obj/JAVA_LIBRARIES/com.android.emailcommon*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Email*)
|
||||
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.android.email*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Email*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.android.email*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Email*)
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
# ************************************************
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 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.
|
||||
-->
|
||||
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<!-- DO NOT TRANSLATE THESE STRINGS -->
|
||||
<string name="account_manager_type_exchange" translatable="false">com.android.exchange</string>
|
||||
<string name="account_manager_type_pop3" translatable="false">com.android.email</string>
|
||||
<string name="account_manager_type_imap" translatable="false">com.android.email</string>
|
||||
<string name="account_manager_type_legacy_imap" translatable="false">com.android.email</string>
|
||||
<string name="intent_exchange" translatable="false">com.android.email.EXCHANGE_INTENT</string>
|
||||
<string name="intent_account_manager_entry" translatable="false">com.android.email.ACCOUNT_MANAGER_ENTRY_INTENT</string>
|
||||
<string name="authority_email_provider" translatable="false">com.android.email.provider</string>
|
||||
<string name="protocol_legacy_imap" translatable="false">imap</string>
|
||||
<string name="protocol_imap" translatable="false">imap</string>
|
||||
<string name="protocol_pop3" translatable="false">pop3</string>
|
||||
<string name="protocol_eas" translatable="false">eas</string>
|
||||
<string name="application_mime_type" translatable="false">application/email-ls</string>
|
||||
</resources>
|
|
@ -1,108 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2012 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.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Email services (protocols) are defined here. For the present, these are baked into the Email
|
||||
apk; the goal is for remote services to register themselves into this file.
|
||||
|
||||
The required attributes are as follows (except that EITHER serviceClass or intent is required):
|
||||
protocol: the unique name used to identify the protocol
|
||||
name: the name of the account type option presented to users during account setup
|
||||
accountType: the AccountManager type of accounts created using this service
|
||||
serviceClass: a class implementing IEmailService (or null, if the service is remote)
|
||||
intent: the intent used to connect to a remote IEmailService
|
||||
port: the (default) port used when creating accounts using this service
|
||||
portSsl: as above, when SSL is selected
|
||||
syncIntervalStrings: a reference to an array of sync interval options
|
||||
syncIntervals: a reference to an array of values corresponding to syncIntervalStrings
|
||||
defaultSyncInterval: the default sync interval, selected from enums defined in attrs.xml
|
||||
|
||||
The following optional attributes default to "false":
|
||||
offerTls: whether a TLS option (e.g. STARTTLS) is offered for this service
|
||||
offerCerts: whether or not certificate authentication is an option for this service
|
||||
usesSmtp: whether SMTP is used as the outgoing protocol for this service
|
||||
offerPrefix: whether a "prefix" is offered to the user (for IMAP)
|
||||
offerLocalDeletes: whether an option to delete locally is offered
|
||||
syncChanges: whether non-deletion changes to messages sync back to the server
|
||||
offerAttachmentPreload: whether to offer attachment preloading (pre-caching)
|
||||
usesAutodiscover: whether to attempt using the "autodiscover" API when creating
|
||||
an account
|
||||
offerLookback: whether a sync "lookback" is offered (rather than the POP/IMAP
|
||||
legacy "25 most recent messages synced")
|
||||
defaultLookback: if "lookback" is offered, an enum of possible lookbacks
|
||||
syncCalendar: whether this service is capable of syncing a calendar (offering a checkbox)
|
||||
syncContacts: whether this service is capable of syncing contacts (offering a checkbox)
|
||||
-->
|
||||
|
||||
<emailservices xmlns:email="http://schemas.android.com/apk/res/com.android.email">
|
||||
<emailservice
|
||||
email:protocol="pop3"
|
||||
email:name="@string/pop3_name"
|
||||
email:accountType="@string/account_manager_type_pop3"
|
||||
email:serviceClass="com.android.email.service.Pop3Service"
|
||||
email:port="110"
|
||||
email:portSsl="995"
|
||||
email:syncIntervalStrings="@array/account_settings_check_frequency_entries"
|
||||
email:syncIntervals="@array/account_settings_check_frequency_values"
|
||||
email:defaultSyncInterval="mins15"
|
||||
|
||||
email:offerTls="true"
|
||||
email:usesSmtp="true"
|
||||
email:offerLocalDeletes="true"
|
||||
email:inferPrefix="pop"
|
||||
email:offerLoadMore="true"
|
||||
/>
|
||||
<emailservice
|
||||
email:protocol="imap"
|
||||
email:name="@string/imap_name"
|
||||
email:accountType="@string/account_manager_type_imap"
|
||||
email:serviceClass="com.android.email.service.ImapService"
|
||||
email:port="143"
|
||||
email:portSsl="993"
|
||||
email:syncIntervalStrings="@array/account_settings_check_frequency_entries"
|
||||
email:syncIntervals="@array/account_settings_check_frequency_values"
|
||||
email:defaultSyncInterval="mins15"
|
||||
|
||||
email:offerTls="true"
|
||||
email:usesSmtp="true"
|
||||
email:offerAttachmentPreload="true"
|
||||
email:offerPrefix="true"
|
||||
email:syncChanges="true"
|
||||
email:inferPrefix="imap"
|
||||
email:offerLoadMore="true"
|
||||
/>
|
||||
<emailservice
|
||||
email:protocol="@string/protocol_eas"
|
||||
email:name="Exchange"
|
||||
email:accountType="@string/account_manager_type_exchange"
|
||||
email:intent="com.android.email.EXCHANGE_INTENT"
|
||||
email:port="80"
|
||||
email:portSsl="443"
|
||||
email:syncIntervalStrings="@array/account_settings_check_frequency_entries_push"
|
||||
email:syncIntervals="@array/account_settings_check_frequency_values_push"
|
||||
email:defaultSyncInterval="push"
|
||||
|
||||
email:defaultSsl="true"
|
||||
email:offerCerts="true"
|
||||
email:syncChanges="true"
|
||||
email:usesAutodiscover="true"
|
||||
email:offerAttachmentPreload="true"
|
||||
email:offerLookback="true"
|
||||
email:defaultLookback="auto"
|
||||
email:syncContacts="true"
|
||||
email:syncCalendar="true"
|
||||
/>
|
||||
</emailservices>
|
|
@ -20,24 +20,24 @@ LOCAL_PATH := $(call my-dir)
|
|||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
unified_email_src_dir := ../../UnifiedEmail/src
|
||||
apache_src_dir := ../../UnifiedEmail/src/org
|
||||
unified_email_src_dir := ../src
|
||||
apache_src_dir := ../src/org
|
||||
|
||||
imported_unified_email_files := \
|
||||
$(unified_email_src_dir)/com/android/mail/utils/LogUtils.java \
|
||||
$(unified_email_src_dir)/com/android/mail/utils/LoggingInputStream.java \
|
||||
$(unified_email_src_dir)/com/android/mail/providers/UIProvider.java
|
||||
|
||||
LOCAL_MODULE := com.android.emailcommon2
|
||||
LOCAL_MODULE := com.android.emailcommon
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := guava android-common
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/emailcommon)
|
||||
LOCAL_SRC_FILES += \
|
||||
src/com/android/emailcommon/service/IEmailService.aidl \
|
||||
src/com/android/emailcommon/service/IEmailServiceCallback.aidl \
|
||||
src/com/android/emailcommon/service/IPolicyService.aidl \
|
||||
src/com/android/emailcommon/service/IAccountService.aidl
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||
LOCAL_SRC_FILES += $(call all-java-files-under, $(apache_src_dir))
|
||||
LOCAL_SRC_FILES += src/com/android/emailcommon/service/IEmailService.aidl
|
||||
LOCAL_SRC_FILES += src/com/android/emailcommon/service/IAccountService.aidl
|
||||
LOCAL_SRC_FILES += src/com/android/emailcommon/service/IPolicyService.aidl
|
||||
LOCAL_SRC_FILES += src/com/android/emailcommon/service/IEmailServiceCallback.aidl
|
||||
LOCAL_SRC_FILES += $(imported_unified_email_files)
|
||||
|
||||
LOCAL_SDK_VERSION := 14
|
||||
LOCAL_SDK_VERSION := current
|
||||
|
||||
include $(BUILD_STATIC_JAVA_LIBRARY)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
/*
|
||||
* 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.
|
||||
|
@ -14,10 +15,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.email.service;
|
||||
package com.android.emailcommon;
|
||||
|
||||
/**
|
||||
* This service needs to be declared separately from the base service
|
||||
*/
|
||||
public class LegacyImapAuthenticatorService extends AuthenticatorService {
|
||||
public class AccountManagerTypes {
|
||||
public static final String TYPE_EXCHANGE = "com.android.exchange";
|
||||
public static final String TYPE_POP_IMAP = "com.android.email";
|
||||
}
|
|
@ -21,9 +21,8 @@ package com.android.emailcommon;
|
|||
*
|
||||
* Level 1: As shipped in HC/MR1
|
||||
* Level 2: Adds searchMessages to EmailService
|
||||
* Level 3: Adds capabilities query
|
||||
*
|
||||
*/
|
||||
public class Api {
|
||||
public static final int LEVEL = 3;
|
||||
public static final int LEVEL = 2;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* 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.
|
||||
|
@ -14,10 +14,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.email.service;
|
||||
package com.android.emailcommon;
|
||||
|
||||
/**
|
||||
* This service needs to be declared separately from the base service
|
||||
* This is the only non-SDK reference in the com.android.email project, referencing the once and
|
||||
* future CalendarProvider authority name.
|
||||
*/
|
||||
public class ImapAuthenticatorService extends AuthenticatorService {
|
||||
public class CalendarProviderStub {
|
||||
public static final String AUTHORITY = "com.android.calendar";
|
||||
}
|
|
@ -19,17 +19,29 @@ package com.android.emailcommon;
|
|||
import android.content.Context;
|
||||
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.HostAuth;
|
||||
import com.android.emailcommon.utility.Utility;
|
||||
|
||||
/**
|
||||
* Constants for tagging threads for traffic stats, and associated utilities
|
||||
*
|
||||
* Example usage:
|
||||
* TrafficStats.setThreadStatsTag(accountId | DATA_EMAIL | REASON_SYNC);
|
||||
* TrafficStats.setThreadStatsTag(accountId | PROTOCOL_IMAP | DATA_EMAIL | REASON_SYNC);
|
||||
*/
|
||||
public class TrafficFlags {
|
||||
// Bits 0->15, account id
|
||||
private static final int ACCOUNT_MASK = 0x0000FFFF;
|
||||
|
||||
// Bits 16&17, protocol (0 = POP3)
|
||||
private static final int PROTOCOL_SHIFT = 16;
|
||||
private static final int PROTOCOL_MASK = 3 << PROTOCOL_SHIFT;
|
||||
public static final int PROTOCOL_POP3 = 0 << PROTOCOL_SHIFT;
|
||||
public static final int PROTOCOL_IMAP = 1 << PROTOCOL_SHIFT;
|
||||
public static final int PROTOCOL_EAS = 2 << PROTOCOL_SHIFT;
|
||||
public static final int PROTOCOL_SMTP = 3 << PROTOCOL_SHIFT;
|
||||
private static final String[] PROTOCOLS = new String[] {HostAuth.SCHEME_POP3,
|
||||
HostAuth.SCHEME_IMAP, HostAuth.SCHEME_EAS, HostAuth.SCHEME_SMTP};
|
||||
|
||||
// Bits 18&19, type (0 = EMAIL)
|
||||
private static final int DATA_SHIFT = 18;
|
||||
private static final int DATA_MASK = 3 << DATA_SHIFT;
|
||||
|
@ -56,7 +68,8 @@ public class TrafficFlags {
|
|||
* @return flags for syncing this account
|
||||
*/
|
||||
public static int getSyncFlags(Context context, Account account) {
|
||||
return (int)account.mId | REASON_SYNC;
|
||||
int protocolIndex = Utility.arrayIndex(PROTOCOLS, account.getProtocol(context));
|
||||
return (int)account.mId | REASON_SYNC | (protocolIndex << PROTOCOL_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,7 +80,8 @@ public class TrafficFlags {
|
|||
* @return flags for loading an attachment in this account
|
||||
*/
|
||||
public static int getAttachmentFlags(Context context, Account account) {
|
||||
return (int)account.mId | REASON_ATTACHMENT_USER;
|
||||
int protocolIndex = Utility.arrayIndex(PROTOCOLS, account.getProtocol(context));
|
||||
return (int)account.mId | REASON_ATTACHMENT_USER | (protocolIndex << PROTOCOL_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,7 +92,7 @@ public class TrafficFlags {
|
|||
* @return flags for sending SMTP email from this account
|
||||
*/
|
||||
public static int getSmtpFlags(Context context, Account account) {
|
||||
return (int)account.mId | REASON_SYNC;
|
||||
return (int)account.mId | REASON_SYNC | PROTOCOL_SMTP;
|
||||
}
|
||||
|
||||
public static String toString(int flags) {
|
||||
|
@ -87,6 +101,8 @@ public class TrafficFlags {
|
|||
sb.append(flags & ACCOUNT_MASK);
|
||||
sb.append(',');
|
||||
sb.append(REASONS[(flags & REASON_MASK) >> REASON_SHIFT]);
|
||||
sb.append(',');
|
||||
sb.append(PROTOCOLS[(flags & PROTOCOL_MASK) >> PROTOCOL_SHIFT]);
|
||||
int maskedData = flags & DATA_MASK;
|
||||
if (maskedData != 0) {
|
||||
sb.append(',');
|
||||
|
|
|
@ -67,7 +67,6 @@ public class MimeMessage extends Message {
|
|||
private Body mBody;
|
||||
protected int mSize;
|
||||
private boolean mInhibitLocalMessageId = false;
|
||||
private boolean mComplete = true;
|
||||
|
||||
// Shared random source for generating local message-id values
|
||||
private static final java.util.Random sRandom = new java.util.Random();
|
||||
|
@ -120,7 +119,7 @@ public class MimeMessage extends Message {
|
|||
parse(in);
|
||||
}
|
||||
|
||||
private MimeStreamParser init() {
|
||||
protected void parse(InputStream in) throws IOException, MessagingException {
|
||||
// Before parsing the input stream, clear all local fields that may be superceded by
|
||||
// the new incoming message.
|
||||
getMimeHeaders().clear();
|
||||
|
@ -135,20 +134,7 @@ public class MimeMessage extends Message {
|
|||
|
||||
MimeStreamParser parser = new MimeStreamParser();
|
||||
parser.setContentHandler(new MimeMessageBuilder());
|
||||
return parser;
|
||||
}
|
||||
|
||||
protected void parse(InputStream in) throws IOException, MessagingException {
|
||||
MimeStreamParser parser = init();
|
||||
parser.parse(new EOLConvertingInputStream(in));
|
||||
mComplete = !parser.getPrematureEof();
|
||||
}
|
||||
|
||||
public void parse(InputStream in, EOLConvertingInputStream.Callback callback)
|
||||
throws IOException, MessagingException {
|
||||
MimeStreamParser parser = init();
|
||||
parser.parse(new EOLConvertingInputStream(in, getSize(), callback));
|
||||
mComplete = !parser.getPrematureEof();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -216,10 +202,6 @@ public class MimeMessage extends Message {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return mComplete;
|
||||
}
|
||||
|
||||
public String getMimeType() throws MessagingException {
|
||||
return MimeUtility.getHeaderParameter(getContentType(), null);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package com.android.emailcommon.internet;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Base64DataException;
|
||||
import android.util.Base64InputStream;
|
||||
|
@ -407,12 +406,33 @@ public class MimeUtility {
|
|||
public static void collectParts(Part part, ArrayList<Part> viewables,
|
||||
ArrayList<Part> attachments) throws MessagingException {
|
||||
String disposition = part.getDisposition();
|
||||
String dispositionType = MimeUtility.getHeaderParameter(disposition, null);
|
||||
String dispositionType = null;
|
||||
String dispositionFilename = null;
|
||||
if (disposition != null) {
|
||||
dispositionType = MimeUtility.getHeaderParameter(disposition, null);
|
||||
dispositionFilename = MimeUtility.getHeaderParameter(disposition, "filename");
|
||||
}
|
||||
// An attachment filename can be defined in either the Content-Disposition header
|
||||
// or the Content-Type header. Content-Disposition is preferred, so we only try
|
||||
// the Content-Type header as a last resort.
|
||||
if (dispositionFilename == null) {
|
||||
String contentType = part.getContentType();
|
||||
dispositionFilename = MimeUtility.getHeaderParameter(contentType, "name");
|
||||
}
|
||||
boolean attachmentDisposition = "attachment".equalsIgnoreCase(dispositionType);
|
||||
// If a disposition is not specified, default to "inline"
|
||||
boolean inline =
|
||||
TextUtils.isEmpty(dispositionType) || "inline".equalsIgnoreCase(dispositionType);
|
||||
// The lower-case mime type
|
||||
String mimeType = part.getMimeType().toLowerCase();
|
||||
boolean inlineDisposition = dispositionType == null
|
||||
|| "inline".equalsIgnoreCase(dispositionType);
|
||||
|
||||
// A guess that this part is intended to be an attachment
|
||||
boolean attachment = attachmentDisposition
|
||||
|| (dispositionFilename != null && !inlineDisposition);
|
||||
|
||||
// A guess that this part is intended to be an inline.
|
||||
boolean inline = inlineDisposition && (dispositionFilename != null);
|
||||
|
||||
// One or the other
|
||||
boolean attachmentOrInline = attachment || inline;
|
||||
|
||||
if (part.getBody() instanceof Multipart) {
|
||||
// If the part is Multipart but not alternative it's either mixed or
|
||||
|
@ -442,11 +462,14 @@ public class MimeUtility {
|
|||
// it, pulling any viewables or attachments into the running list.
|
||||
Message message = (Message)part.getBody();
|
||||
collectParts(message, viewables, attachments);
|
||||
} else if (inline && (mimeType.startsWith("text") || (mimeType.startsWith("image")))) {
|
||||
// We'll treat text and images as viewables
|
||||
} else if ((!attachmentOrInline) && ("text/html".equalsIgnoreCase(part.getMimeType()))) {
|
||||
// If the part is HTML and we got this far, it's a viewable part of a mixed
|
||||
viewables.add(part);
|
||||
} else {
|
||||
// Everything else is an attachment.
|
||||
} else if ((!attachmentOrInline) && ("text/plain".equalsIgnoreCase(part.getMimeType()))) {
|
||||
// If the part is text and we got this far, it's a viewable part of a mixed
|
||||
viewables.add(part);
|
||||
} else if (attachmentOrInline) {
|
||||
// Finally, if it's an attachment or an inline we will include it as an attachment.
|
||||
attachments.add(part);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,12 @@
|
|||
|
||||
package com.android.emailcommon.internet;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.text.Html;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Base64OutputStream;
|
||||
|
||||
|
@ -38,9 +42,7 @@ import java.io.OutputStream;
|
|||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -50,17 +52,28 @@ import java.util.regex.Pattern;
|
|||
*/
|
||||
public class Rfc822Output {
|
||||
|
||||
private static final Pattern PATTERN_START_OF_LINE = Pattern.compile("(?m)^");
|
||||
private static final Pattern PATTERN_ENDLINE_CRLF = Pattern.compile("\r\n");
|
||||
|
||||
// In MIME, en_US-like date format should be used. In other words "MMM" should be encoded to
|
||||
// "Jan", not the other localized format like "Ene" (meaning January in locale es).
|
||||
private static final SimpleDateFormat DATE_FORMAT =
|
||||
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
|
||||
|
||||
private static final String WHERE_NOT_SMART_FORWARD = "(" + Attachment.FLAGS + "&" +
|
||||
Attachment.FLAG_SMART_FORWARD + ")=0";
|
||||
|
||||
/** A less-than-perfect pattern to pull out <body> content */
|
||||
private static final Pattern BODY_PATTERN = Pattern.compile(
|
||||
"(?:<\\s*body[^>]*>)(.*)(?:<\\s*/\\s*body\\s*>)",
|
||||
Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
|
||||
/** Match group in {@code BODDY_PATTERN} for the body HTML */
|
||||
private static final int BODY_PATTERN_GROUP = 1;
|
||||
/** Pattern to find both dos and unix newlines */
|
||||
private static final Pattern NEWLINE_PATTERN =
|
||||
Pattern.compile("\\r?\\n");
|
||||
/** HTML string to use when replacing text newlines */
|
||||
private static final String NEWLINE_HTML = "<br>";
|
||||
/** Index of the plain text version of the message body */
|
||||
private final static int INDEX_BODY_TEXT = 0;
|
||||
/** Index of the HTML version of the message body */
|
||||
|
@ -82,20 +95,78 @@ public class Rfc822Output {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an HTML encoded message alternate
|
||||
*/
|
||||
/*package*/ static String getHtmlAlternate(Body body, boolean useSmartReply) {
|
||||
if (body.mHtmlReply == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuffer altMessage = new StringBuffer();
|
||||
String htmlContent = TextUtils.htmlEncode(body.mTextContent); // Escape HTML reserved chars
|
||||
htmlContent = NEWLINE_PATTERN.matcher(htmlContent).replaceAll(NEWLINE_HTML);
|
||||
altMessage.append(htmlContent);
|
||||
if (body.mIntroText != null) {
|
||||
String htmlIntro = TextUtils.htmlEncode(body.mIntroText);
|
||||
htmlIntro = NEWLINE_PATTERN.matcher(htmlIntro).replaceAll(NEWLINE_HTML);
|
||||
altMessage.append(htmlIntro);
|
||||
}
|
||||
if (!useSmartReply) {
|
||||
String htmlBody = getHtmlBody(body.mHtmlReply);
|
||||
altMessage.append(htmlBody);
|
||||
}
|
||||
return altMessage.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets both the plain text and HTML versions of the message body.
|
||||
*/
|
||||
/*package*/ static String[] buildBodyText(Body body, int flags, boolean useSmartReply) {
|
||||
String[] messageBody = new String[] { null, null };
|
||||
if (body == null) {
|
||||
return new String[2];
|
||||
return messageBody;
|
||||
}
|
||||
String[] messageBody = new String[] { body.mTextContent, body.mHtmlContent };
|
||||
if (useSmartReply && body.mQuotedTextStartPos > 0) {
|
||||
if (messageBody[0] != null) {
|
||||
messageBody[0] = messageBody[0].substring(0, body.mQuotedTextStartPos);
|
||||
} else if (messageBody[1] != null) {
|
||||
messageBody[1] = messageBody[1].substring(0, body.mQuotedTextStartPos);
|
||||
String text = body.mTextContent;
|
||||
boolean isReply = (flags & Message.FLAG_TYPE_REPLY) != 0;
|
||||
boolean isForward = (flags & Message.FLAG_TYPE_FORWARD) != 0;
|
||||
// For all forwards/replies, we add the intro text
|
||||
if (isReply || isForward) {
|
||||
String intro = body.mIntroText == null ? "" : body.mIntroText;
|
||||
text += intro;
|
||||
}
|
||||
if (useSmartReply) {
|
||||
// useSmartReply is set to true for use by SmartReply/SmartForward in EAS.
|
||||
// SmartForward doesn't put a break between the original and new text, so we add an LF
|
||||
if (isForward) {
|
||||
text += "\n";
|
||||
}
|
||||
} else {
|
||||
String quotedText = body.mTextReply;
|
||||
// If there is no plain-text body, use de-tagified HTML as the text body
|
||||
if (quotedText == null && body.mHtmlReply != null) {
|
||||
quotedText = Html.fromHtml(body.mHtmlReply).toString();
|
||||
}
|
||||
if (quotedText != null) {
|
||||
// fix CR-LF line endings to LF-only needed by EditText.
|
||||
Matcher matcher = PATTERN_ENDLINE_CRLF.matcher(quotedText);
|
||||
quotedText = matcher.replaceAll("\n");
|
||||
}
|
||||
if (isReply) {
|
||||
if (quotedText != null) {
|
||||
Matcher matcher = PATTERN_START_OF_LINE.matcher(quotedText);
|
||||
text += matcher.replaceAll(">");
|
||||
}
|
||||
} else if (isForward) {
|
||||
if (quotedText != null) {
|
||||
text += quotedText;
|
||||
}
|
||||
}
|
||||
}
|
||||
messageBody[INDEX_BODY_TEXT] = text;
|
||||
// Exchange 2003 doesn't seem to support multipart w/SmartReply and SmartForward, so
|
||||
// we'll skip this. Really, it would only matter if we could compose HTML replies
|
||||
if (!useSmartReply) {
|
||||
messageBody[INDEX_BODY_HTML] = getHtmlAlternate(body, useSmartReply);
|
||||
}
|
||||
return messageBody;
|
||||
}
|
||||
|
@ -108,16 +179,9 @@ public class Rfc822Output {
|
|||
* @param messageId the message to write out
|
||||
* @param out the output stream to write the message to
|
||||
* @param useSmartReply whether or not quoted text is appended to a reply/forward
|
||||
* @param a list of attachments to send (or null if retrieved from the message itself)
|
||||
*/
|
||||
public static void writeTo(Context context, long messageId, OutputStream out,
|
||||
boolean useSmartReply, boolean sendBcc) throws IOException, MessagingException {
|
||||
writeTo(context, messageId, out, useSmartReply, sendBcc, null);
|
||||
}
|
||||
|
||||
public static void writeTo(Context context, long messageId, OutputStream out,
|
||||
boolean useSmartReply, boolean sendBcc, List<Attachment> attachments)
|
||||
throws IOException, MessagingException {
|
||||
Message message = Message.restoreMessageWithId(context, messageId);
|
||||
if (message == null) {
|
||||
// throw something?
|
||||
|
@ -152,53 +216,59 @@ public class Rfc822Output {
|
|||
Body body = Body.restoreBodyWithMessageId(context, message.mId);
|
||||
String[] bodyText = buildBodyText(body, message.mFlags, useSmartReply);
|
||||
|
||||
// If a list of attachments hasn't been passed in, build one from the message
|
||||
if (attachments == null) {
|
||||
attachments =
|
||||
Arrays.asList(Attachment.restoreAttachmentsWithMessageId(context, messageId));
|
||||
}
|
||||
Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, messageId);
|
||||
Cursor attachmentsCursor = context.getContentResolver().query(uri,
|
||||
Attachment.CONTENT_PROJECTION, WHERE_NOT_SMART_FORWARD, null, null);
|
||||
|
||||
boolean multipart = attachments.size() > 0;
|
||||
String multipartBoundary = null;
|
||||
String multipartType = "mixed";
|
||||
try {
|
||||
int attachmentCount = attachmentsCursor.getCount();
|
||||
boolean multipart = attachmentCount > 0;
|
||||
String multipartBoundary = null;
|
||||
String multipartType = "mixed";
|
||||
|
||||
// Simplified case for no multipart - just emit text and be done.
|
||||
if (!multipart) {
|
||||
writeTextWithHeaders(writer, stream, bodyText);
|
||||
} else {
|
||||
// continue with multipart headers, then into multipart body
|
||||
multipartBoundary = getNextBoundary();
|
||||
|
||||
// Move to the first attachment; this must succeed because multipart is true
|
||||
if (attachments.size() == 1) {
|
||||
// If we've got one attachment and it's an ics "attachment", we want to send
|
||||
// this as multipart/alternative instead of multipart/mixed
|
||||
int flags = attachments.get(0).mFlags;
|
||||
if ((flags & Attachment.FLAG_ICS_ALTERNATIVE_PART) != 0) {
|
||||
multipartType = "alternative";
|
||||
}
|
||||
}
|
||||
|
||||
writeHeader(writer, "Content-Type",
|
||||
"multipart/" + multipartType + "; boundary=\"" + multipartBoundary + "\"");
|
||||
// Finish headers and prepare for body section(s)
|
||||
writer.write("\r\n");
|
||||
|
||||
// first multipart element is the body
|
||||
if (bodyText[INDEX_BODY_TEXT] != null || bodyText[INDEX_BODY_HTML] != null) {
|
||||
writeBoundary(writer, multipartBoundary, false);
|
||||
// Simplified case for no multipart - just emit text and be done.
|
||||
if (!multipart) {
|
||||
writeTextWithHeaders(writer, stream, bodyText);
|
||||
}
|
||||
} else {
|
||||
// continue with multipart headers, then into multipart body
|
||||
multipartBoundary = getNextBoundary();
|
||||
|
||||
// Write out the attachments until we run out
|
||||
for (Attachment att: attachments) {
|
||||
writeBoundary(writer, multipartBoundary, false);
|
||||
writeOneAttachment(context, writer, stream, att);
|
||||
// Move to the first attachment; this must succeed because multipart is true
|
||||
attachmentsCursor.moveToFirst();
|
||||
if (attachmentCount == 1) {
|
||||
// If we've got one attachment and it's an ics "attachment", we want to send
|
||||
// this as multipart/alternative instead of multipart/mixed
|
||||
int flags = attachmentsCursor.getInt(Attachment.CONTENT_FLAGS_COLUMN);
|
||||
if ((flags & Attachment.FLAG_ICS_ALTERNATIVE_PART) != 0) {
|
||||
multipartType = "alternative";
|
||||
}
|
||||
}
|
||||
|
||||
writeHeader(writer, "Content-Type",
|
||||
"multipart/" + multipartType + "; boundary=\"" + multipartBoundary + "\"");
|
||||
// Finish headers and prepare for body section(s)
|
||||
writer.write("\r\n");
|
||||
}
|
||||
|
||||
// end of multipart section
|
||||
writeBoundary(writer, multipartBoundary, true);
|
||||
// first multipart element is the body
|
||||
if (bodyText[INDEX_BODY_TEXT] != null) {
|
||||
writeBoundary(writer, multipartBoundary, false);
|
||||
writeTextWithHeaders(writer, stream, bodyText);
|
||||
}
|
||||
|
||||
// Write out the attachments until we run out
|
||||
do {
|
||||
writeBoundary(writer, multipartBoundary, false);
|
||||
Attachment attachment =
|
||||
Attachment.getContent(attachmentsCursor, Attachment.class);
|
||||
writeOneAttachment(context, writer, stream, attachment);
|
||||
writer.write("\r\n");
|
||||
} while (attachmentsCursor.moveToNext());
|
||||
|
||||
// end of multipart section
|
||||
writeBoundary(writer, multipartBoundary, true);
|
||||
}
|
||||
} finally {
|
||||
attachmentsCursor.close();
|
||||
}
|
||||
|
||||
writer.flush();
|
||||
|
@ -234,7 +304,7 @@ public class Rfc822Output {
|
|||
inStream = new ByteArrayInputStream(attachment.mContentBytes);
|
||||
} else {
|
||||
// try to open the file
|
||||
Uri fileUri = Uri.parse(attachment.getContentUri());
|
||||
Uri fileUri = Uri.parse(attachment.mContentUri);
|
||||
inStream = context.getContentResolver().openInputStream(fileUri);
|
||||
}
|
||||
// switch to output stream for base64 text output
|
||||
|
@ -328,7 +398,9 @@ public class Rfc822Output {
|
|||
}
|
||||
|
||||
/**
|
||||
* Write the body text.
|
||||
* Write the body text. If only one version of the body is specified (either plain text
|
||||
* or HTML), the text is written directly. Otherwise, the plain text and HTML bodies
|
||||
* are both written with the appropriate headers.
|
||||
*
|
||||
* Note this always uses base64, even when not required. Slightly less efficient for
|
||||
* US-ASCII text, but handles all formats even when non-ascii chars are involved. A small
|
||||
|
@ -340,23 +412,49 @@ public class Rfc822Output {
|
|||
*/
|
||||
private static void writeTextWithHeaders(Writer writer, OutputStream out, String[] bodyText)
|
||||
throws IOException {
|
||||
boolean html = false;
|
||||
String text = bodyText[INDEX_BODY_TEXT];
|
||||
if (text == null) {
|
||||
text = bodyText[INDEX_BODY_HTML];
|
||||
html = true;
|
||||
}
|
||||
String html = bodyText[INDEX_BODY_HTML];
|
||||
|
||||
if (text == null) {
|
||||
writer.write("\r\n"); // a truly empty message
|
||||
} else {
|
||||
String multipartBoundary = null;
|
||||
boolean multipart = html != null;
|
||||
|
||||
// Simplified case for no multipart - just emit text and be done.
|
||||
if (multipart) {
|
||||
// continue with multipart headers, then into multipart body
|
||||
multipartBoundary = getNextBoundary();
|
||||
|
||||
writeHeader(writer, "Content-Type",
|
||||
"multipart/alternative; boundary=\"" + multipartBoundary + "\"");
|
||||
// Finish headers and prepare for body section(s)
|
||||
writer.write("\r\n");
|
||||
writeBoundary(writer, multipartBoundary, false);
|
||||
}
|
||||
|
||||
// first multipart element is the body
|
||||
String mimeType = "text/" + (html ? "html" : "plain");
|
||||
writeHeader(writer, "Content-Type", mimeType + "; charset=utf-8");
|
||||
writeHeader(writer, "Content-Type", "text/plain; charset=utf-8");
|
||||
writeHeader(writer, "Content-Transfer-Encoding", "base64");
|
||||
writer.write("\r\n");
|
||||
byte[] textBytes = text.getBytes("UTF-8");
|
||||
writer.flush();
|
||||
out.write(Base64.encode(textBytes, Base64.CRLF));
|
||||
|
||||
if (multipart) {
|
||||
// next multipart section
|
||||
writeBoundary(writer, multipartBoundary, false);
|
||||
|
||||
writeHeader(writer, "Content-Type", "text/html; charset=utf-8");
|
||||
writeHeader(writer, "Content-Transfer-Encoding", "base64");
|
||||
writer.write("\r\n");
|
||||
byte[] htmlBytes = html.getBytes("UTF-8");
|
||||
writer.flush();
|
||||
out.write(Base64.encode(htmlBytes, Base64.CRLF));
|
||||
|
||||
// end of multipart section
|
||||
writeBoundary(writer, multipartBoundary, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/* Copyright (C) 2012 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.emailcommon.provider;
|
||||
|
||||
parcelable Account;
|
|
@ -40,6 +40,16 @@ import java.util.UUID;
|
|||
|
||||
public final class Account extends EmailContent implements AccountColumns, Parcelable {
|
||||
public static final String TABLE_NAME = "Account";
|
||||
@SuppressWarnings("hiding")
|
||||
public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/account");
|
||||
public static final Uri ADD_TO_FIELD_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/accountIdAddToField");
|
||||
public static final Uri RESET_NEW_MESSAGE_COUNT_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/resetNewMessageCount");
|
||||
public static final Uri NOTIFIER_URI =
|
||||
Uri.parse(EmailContent.CONTENT_NOTIFIER_URI + "/account");
|
||||
public static final Uri DEFAULT_ACCOUNT_ID_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/account/default");
|
||||
|
||||
// Define all pseudo account IDs here to avoid conflict with one another.
|
||||
/**
|
||||
|
@ -90,8 +100,6 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
// Whether or not server-side search supports global search (i.e. all mailboxes); only valid
|
||||
// if FLAGS_SUPPORTS_SEARCH is true
|
||||
public static final int FLAGS_SUPPORTS_GLOBAL_SEARCH = 1<<12;
|
||||
// Whether or not the initial folder list has been loaded
|
||||
public static final int FLAGS_INITIAL_FOLDER_LIST_LOADED = 1<<13;
|
||||
|
||||
// Deletion policy (see FLAGS_DELETE_POLICY_MASK, above)
|
||||
public static final int DELETE_POLICY_NEVER = 0;
|
||||
|
@ -102,20 +110,6 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
public static final int CHECK_INTERVAL_NEVER = -1;
|
||||
public static final int CHECK_INTERVAL_PUSH = -2;
|
||||
|
||||
public static Uri CONTENT_URI;
|
||||
public static Uri ADD_TO_FIELD_URI;
|
||||
public static Uri RESET_NEW_MESSAGE_COUNT_URI;
|
||||
public static Uri NOTIFIER_URI;
|
||||
public static Uri DEFAULT_ACCOUNT_ID_URI;
|
||||
|
||||
public static void initAccount() {
|
||||
CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/account");
|
||||
ADD_TO_FIELD_URI = Uri.parse(EmailContent.CONTENT_URI + "/accountIdAddToField");
|
||||
RESET_NEW_MESSAGE_COUNT_URI = Uri.parse(EmailContent.CONTENT_URI + "/resetNewMessageCount");
|
||||
NOTIFIER_URI = Uri.parse(EmailContent.CONTENT_NOTIFIER_URI + "/account");
|
||||
DEFAULT_ACCOUNT_ID_URI = Uri.parse(EmailContent.CONTENT_URI + "/account/default");
|
||||
}
|
||||
|
||||
public String mDisplayName;
|
||||
public String mEmailAddress;
|
||||
public String mSyncKey;
|
||||
|
@ -134,6 +128,10 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
public String mSignature;
|
||||
public long mPolicyKey;
|
||||
|
||||
// For compatibility with Email1
|
||||
public long mNotifiedMessageId;
|
||||
public int mNotifiedMessageCount;
|
||||
|
||||
// Convenience for creating/working with an account
|
||||
public transient HostAuth mHostAuthRecv;
|
||||
public transient HostAuth mHostAuthSend;
|
||||
|
@ -159,6 +157,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
public static final int CONTENT_SECURITY_SYNC_KEY_COLUMN = 15;
|
||||
public static final int CONTENT_SIGNATURE_COLUMN = 16;
|
||||
public static final int CONTENT_POLICY_KEY = 17;
|
||||
public static final int CONTENT_NOTIFIED_MESSAGE_ID_COLUMN = 18;
|
||||
public static final int CONTENT_NOTIFIED_MESSAGE_COUNT_COLUMN = 19;
|
||||
|
||||
public static final String[] CONTENT_PROJECTION = new String[] {
|
||||
RECORD_ID, AccountColumns.DISPLAY_NAME,
|
||||
|
@ -168,7 +168,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
AccountColumns.COMPATIBILITY_UUID, AccountColumns.SENDER_NAME,
|
||||
AccountColumns.RINGTONE_URI, AccountColumns.PROTOCOL_VERSION,
|
||||
AccountColumns.NEW_MESSAGE_COUNT, AccountColumns.SECURITY_SYNC_KEY,
|
||||
AccountColumns.SIGNATURE, AccountColumns.POLICY_KEY
|
||||
AccountColumns.SIGNATURE, AccountColumns.POLICY_KEY,
|
||||
AccountColumns.NOTIFIED_MESSAGE_ID, AccountColumns.NOTIFIED_MESSAGE_COUNT
|
||||
};
|
||||
|
||||
public static final int CONTENT_MAILBOX_TYPE_COLUMN = 1;
|
||||
|
@ -200,6 +201,13 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
MailboxColumns.TYPE + " = " + Mailbox.TYPE_INBOX +
|
||||
" AND " + MailboxColumns.ACCOUNT_KEY + " =?";
|
||||
|
||||
/**
|
||||
* This projection is for searching for the default account
|
||||
*/
|
||||
private static final String[] DEFAULT_ID_PROJECTION = new String[] {
|
||||
RECORD_ID, IS_DEFAULT
|
||||
};
|
||||
|
||||
/**
|
||||
* no public constructor since this is a utility class
|
||||
*/
|
||||
|
@ -266,6 +274,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
mSecuritySyncKey = cursor.getString(CONTENT_SECURITY_SYNC_KEY_COLUMN);
|
||||
mSignature = cursor.getString(CONTENT_SIGNATURE_COLUMN);
|
||||
mPolicyKey = cursor.getLong(CONTENT_POLICY_KEY);
|
||||
mNotifiedMessageId = cursor.getLong(CONTENT_NOTIFIED_MESSAGE_ID_COLUMN);
|
||||
mNotifiedMessageCount = cursor.getInt(CONTENT_NOTIFIED_MESSAGE_COUNT_COLUMN);
|
||||
}
|
||||
|
||||
private long getId(Uri u) {
|
||||
|
@ -453,6 +463,21 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
return "local://localhost/" + context.getDatabasePath(getUuid() + ".db");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the instance is of an EAS account.
|
||||
*
|
||||
* NOTE This method accesses the DB if {@link #mHostAuthRecv} hasn't been restored yet.
|
||||
* Use caution when you use this on the main thread.
|
||||
*/
|
||||
public boolean isEasAccount(Context context) {
|
||||
return "eas".equals(getProtocol(context));
|
||||
}
|
||||
|
||||
public boolean supportsMoveMessages(Context context) {
|
||||
String protocol = getProtocol(context);
|
||||
return "eas".equals(protocol) || "imap".equals(protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the account supports "search".
|
||||
*/
|
||||
|
@ -502,7 +527,7 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
public static long getAccountIdFromShortcutSafeUri(Context context, Uri uri) {
|
||||
// Make sure the URI is in the correct format.
|
||||
if (!"content".equals(uri.getScheme())
|
||||
|| !EmailContent.AUTHORITY.equals(uri.getAuthority())) {
|
||||
|| !AUTHORITY.equals(uri.getAuthority())) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -706,7 +731,7 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
.newUpdate(ContentUris.withAppendedId(CONTENT_URI, mId))
|
||||
.withValues(cv).build());
|
||||
try {
|
||||
context.getContentResolver().applyBatch(EmailContent.AUTHORITY, ops);
|
||||
context.getContentResolver().applyBatch(AUTHORITY, ops);
|
||||
return 1;
|
||||
} catch (RemoteException e) {
|
||||
// There is nothing to be done here; fail by returning 0
|
||||
|
@ -786,7 +811,7 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
|
||||
try {
|
||||
ContentProviderResult[] results =
|
||||
context.getContentResolver().applyBatch(EmailContent.AUTHORITY, ops);
|
||||
context.getContentResolver().applyBatch(AUTHORITY, ops);
|
||||
// If saving, set the mId's of the various saved objects
|
||||
if (recvIndex >= 0) {
|
||||
long newId = getId(results[recvIndex].uri);
|
||||
|
@ -829,6 +854,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
values.put(AccountColumns.SECURITY_SYNC_KEY, mSecuritySyncKey);
|
||||
values.put(AccountColumns.SIGNATURE, mSignature);
|
||||
values.put(AccountColumns.POLICY_KEY, mPolicyKey);
|
||||
values.put(AccountColumns.NOTIFIED_MESSAGE_ID, mNotifiedMessageId);
|
||||
values.put(AccountColumns.NOTIFIED_MESSAGE_COUNT, mNotifiedMessageCount);
|
||||
return values;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ import android.os.Environment;
|
|||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.emailcommon.utility.TextUtilities;
|
||||
import com.android.emailcommon.utility.Utility;
|
||||
|
@ -60,12 +59,31 @@ import java.util.ArrayList;
|
|||
*
|
||||
*/
|
||||
public abstract class EmailContent {
|
||||
|
||||
public static final String AUTHORITY = "com.android.email.provider";
|
||||
// The notifier authority is used to send notifications regarding changes to messages (insert,
|
||||
// delete, or update) and is intended as an optimization for use by clients of message list
|
||||
// cursors (initially, the email AppWidget).
|
||||
public static final String NOTIFIER_AUTHORITY = "com.android.email.notifier";
|
||||
|
||||
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
|
||||
public static final String PARAMETER_LIMIT = "limit";
|
||||
|
||||
public static final Uri CONTENT_NOTIFIER_URI = Uri.parse("content://" + NOTIFIER_AUTHORITY);
|
||||
|
||||
public static final Uri MAILBOX_NOTIFICATION_URI =
|
||||
Uri.parse("content://" + EmailContent.AUTHORITY + "/mailboxNotification");
|
||||
public static final String[] NOTIFICATION_PROJECTION =
|
||||
new String[] {MailboxColumns.ID, MailboxColumns.UNREAD_COUNT, MailboxColumns.MESSAGE_COUNT};
|
||||
public static final int NOTIFICATION_MAILBOX_ID_COLUMN = 0;
|
||||
public static final int NOTIFICATION_MAILBOX_UNREAD_COUNT_COLUMN = 1;
|
||||
public static final int NOTIFICATION_MAILBOX_MESSAGE_COUNT_COLUMN = 2;
|
||||
|
||||
public static final Uri MAILBOX_MOST_RECENT_MESSAGE_URI =
|
||||
Uri.parse("content://" + EmailContent.AUTHORITY + "/mailboxMostRecentMessage");
|
||||
|
||||
public static final String PROVIDER_PERMISSION = "com.android.email.permission.ACCESS_PROVIDER";
|
||||
|
||||
// All classes share this
|
||||
public static final String RECORD_ID = "_id";
|
||||
|
||||
|
@ -113,57 +131,6 @@ public abstract class EmailContent {
|
|||
// Read the Content from a ContentCursor
|
||||
public abstract void restore (Cursor cursor);
|
||||
|
||||
|
||||
public static String PACKAGE_NAME;
|
||||
public static String EMAIL_PACKAGE_NAME;
|
||||
public static String AUTHORITY;
|
||||
// The notifier authority is used to send notifications regarding changes to messages (insert,
|
||||
// delete, or update) and is intended as an optimization for use by clients of message list
|
||||
// cursors (initially, the email AppWidget).
|
||||
public static String NOTIFIER_AUTHORITY;
|
||||
public static Uri CONTENT_URI;
|
||||
public static final String PARAMETER_LIMIT = "limit";
|
||||
public static Uri CONTENT_NOTIFIER_URI;
|
||||
public static Uri PICK_TRASH_FOLDER_URI;
|
||||
public static Uri PICK_SENT_FOLDER_URI;
|
||||
public static Uri MAILBOX_NOTIFICATION_URI;
|
||||
public static Uri MAILBOX_MOST_RECENT_MESSAGE_URI;
|
||||
public static Uri ACCOUNT_CHECK_URI;
|
||||
public static String PROVIDER_PERMISSION;
|
||||
|
||||
public static void init(Context context) {
|
||||
if (AUTHORITY == null) {
|
||||
PACKAGE_NAME = context.getPackageName();
|
||||
EMAIL_PACKAGE_NAME = PACKAGE_NAME;
|
||||
// If our package is com...exchange, the provider is com...email.provider
|
||||
if (PACKAGE_NAME.endsWith("exchange")) {
|
||||
int lastDot = EMAIL_PACKAGE_NAME.lastIndexOf('.');
|
||||
EMAIL_PACKAGE_NAME = PACKAGE_NAME.substring(0, lastDot + 1) + "email";
|
||||
}
|
||||
AUTHORITY = EMAIL_PACKAGE_NAME + ".provider";
|
||||
Log.d("EmailContent", "init for " + AUTHORITY);
|
||||
NOTIFIER_AUTHORITY = EMAIL_PACKAGE_NAME + ".notifier";
|
||||
CONTENT_URI = Uri.parse("content://" + AUTHORITY);
|
||||
CONTENT_NOTIFIER_URI = Uri.parse("content://" + NOTIFIER_AUTHORITY);
|
||||
PICK_TRASH_FOLDER_URI = Uri.parse("content://" + AUTHORITY + "/pickTrashFolder");
|
||||
PICK_SENT_FOLDER_URI = Uri.parse("content://" + AUTHORITY + "/pickSentFolder");
|
||||
MAILBOX_NOTIFICATION_URI = Uri.parse("content://" + AUTHORITY + "/mailboxNotification");
|
||||
MAILBOX_MOST_RECENT_MESSAGE_URI = Uri.parse("content://" + AUTHORITY +
|
||||
"/mailboxMostRecentMessage");
|
||||
ACCOUNT_CHECK_URI = Uri.parse("content://" + AUTHORITY + "/accountCheck");
|
||||
PROVIDER_PERMISSION = EMAIL_PACKAGE_NAME + ".permission.ACCESS_PROVIDER";
|
||||
// Initialize subclasses
|
||||
Account.initAccount();
|
||||
Mailbox.initMailbox();
|
||||
QuickResponse.initQuickResponse();
|
||||
HostAuth.initHostAuth();
|
||||
Policy.initPolicy();
|
||||
Message.initMessage();
|
||||
Body.initBody();
|
||||
Attachment.initAttachment();
|
||||
}
|
||||
}
|
||||
|
||||
// The Uri is lazily initialized
|
||||
public Uri getUri() {
|
||||
if (mUri == null) {
|
||||
|
@ -293,17 +260,14 @@ public abstract class EmailContent {
|
|||
// The plain text content itself
|
||||
public static final String TEXT_CONTENT = "textContent";
|
||||
// Replied-to or forwarded body (in html form)
|
||||
@Deprecated
|
||||
public static final String HTML_REPLY = "htmlReply";
|
||||
// Replied-to or forwarded body (in text form)
|
||||
@Deprecated
|
||||
public static final String TEXT_REPLY = "textReply";
|
||||
// A reference to a message's unique id used in reply/forward.
|
||||
// Protocol code can be expected to use this column in determining whether a message can be
|
||||
// deleted safely (i.e. isn't referenced by other messages)
|
||||
public static final String SOURCE_MESSAGE_KEY = "sourceMessageKey";
|
||||
// The text to be placed between a reply/forward response and the original message
|
||||
@Deprecated
|
||||
public static final String INTRO_TEXT = "introText";
|
||||
// The start of quoted text within our text content
|
||||
public static final String QUOTED_TEXT_START_POS = "quotedTextStartPos";
|
||||
|
@ -312,22 +276,16 @@ public abstract class EmailContent {
|
|||
public static final class Body extends EmailContent implements BodyColumns {
|
||||
public static final String TABLE_NAME = "Body";
|
||||
|
||||
public static Uri CONTENT_URI;
|
||||
|
||||
public static void initBody() {
|
||||
CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/body");
|
||||
}
|
||||
@SuppressWarnings("hiding")
|
||||
public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/body");
|
||||
|
||||
public static final int CONTENT_ID_COLUMN = 0;
|
||||
public static final int CONTENT_MESSAGE_KEY_COLUMN = 1;
|
||||
public static final int CONTENT_HTML_CONTENT_COLUMN = 2;
|
||||
public static final int CONTENT_TEXT_CONTENT_COLUMN = 3;
|
||||
@Deprecated
|
||||
public static final int CONTENT_HTML_REPLY_COLUMN = 4;
|
||||
@Deprecated
|
||||
public static final int CONTENT_TEXT_REPLY_COLUMN = 5;
|
||||
public static final int CONTENT_SOURCE_KEY_COLUMN = 6;
|
||||
@Deprecated
|
||||
public static final int CONTENT_INTRO_TEXT_COLUMN = 7;
|
||||
public static final int CONTENT_QUOTED_TEXT_START_POS_COLUMN = 8;
|
||||
|
||||
|
@ -343,22 +301,19 @@ public abstract class EmailContent {
|
|||
public static final String[] COMMON_PROJECTION_HTML = new String[] {
|
||||
RECORD_ID, BodyColumns.HTML_CONTENT
|
||||
};
|
||||
@Deprecated
|
||||
public static final String[] COMMON_PROJECTION_REPLY_TEXT = new String[] {
|
||||
RECORD_ID, BodyColumns.TEXT_REPLY
|
||||
};
|
||||
@Deprecated
|
||||
public static final String[] COMMON_PROJECTION_REPLY_HTML = new String[] {
|
||||
RECORD_ID, BodyColumns.HTML_REPLY
|
||||
};
|
||||
@Deprecated
|
||||
public static final String[] COMMON_PROJECTION_INTRO = new String[] {
|
||||
RECORD_ID, BodyColumns.INTRO_TEXT
|
||||
};
|
||||
public static final String[] COMMON_PROJECTION_SOURCE = new String[] {
|
||||
RECORD_ID, BodyColumns.SOURCE_MESSAGE_KEY
|
||||
};
|
||||
public static final int COMMON_PROJECTION_COLUMN_TEXT = 1;
|
||||
public static final int COMMON_PROJECTION_COLUMN_TEXT = 1;
|
||||
|
||||
private static final String[] PROJECTION_SOURCE_KEY =
|
||||
new String[] { BodyColumns.SOURCE_MESSAGE_KEY };
|
||||
|
@ -366,9 +321,7 @@ public abstract class EmailContent {
|
|||
public long mMessageKey;
|
||||
public String mHtmlContent;
|
||||
public String mTextContent;
|
||||
@Deprecated
|
||||
public String mHtmlReply;
|
||||
@Deprecated
|
||||
public String mTextReply;
|
||||
public int mQuotedTextStartPos;
|
||||
|
||||
|
@ -378,7 +331,6 @@ public abstract class EmailContent {
|
|||
* want to include quoted text.
|
||||
*/
|
||||
public long mSourceKey;
|
||||
@Deprecated
|
||||
public String mIntroText;
|
||||
|
||||
public Body() {
|
||||
|
@ -493,17 +445,14 @@ public abstract class EmailContent {
|
|||
return restoreTextWithMessageId(context, messageId, Body.COMMON_PROJECTION_HTML);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String restoreReplyTextWithMessageId(Context context, long messageId) {
|
||||
return restoreTextWithMessageId(context, messageId, Body.COMMON_PROJECTION_REPLY_TEXT);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String restoreReplyHtmlWithMessageId(Context context, long messageId) {
|
||||
return restoreTextWithMessageId(context, messageId, Body.COMMON_PROJECTION_REPLY_HTML);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String restoreIntroTextWithMessageId(Context context, long messageId) {
|
||||
return restoreTextWithMessageId(context, messageId, Body.COMMON_PROJECTION_INTRO);
|
||||
}
|
||||
|
@ -548,8 +497,8 @@ public abstract class EmailContent {
|
|||
public static final String FLAGS = "flags";
|
||||
|
||||
// Sync related identifiers
|
||||
// Saved draft info (reusing the never-used "clientId" column)
|
||||
public static final String DRAFT_INFO = "clientId";
|
||||
// Any client-required identifier
|
||||
public static final String CLIENT_ID = "clientId";
|
||||
// The message-id in the message's header
|
||||
public static final String MESSAGE_ID = "messageId";
|
||||
|
||||
|
@ -576,8 +525,6 @@ public abstract class EmailContent {
|
|||
public static final String PROTOCOL_SEARCH_INFO = "protocolSearchInfo";
|
||||
// Simple thread topic
|
||||
public static final String THREAD_TOPIC = "threadTopic";
|
||||
// For sync adapter use
|
||||
public static final String SYNC_DATA = "syncData";
|
||||
}
|
||||
|
||||
public static final class Message extends EmailContent implements SyncColumns, MessageColumns {
|
||||
|
@ -586,28 +533,17 @@ public abstract class EmailContent {
|
|||
public static final String DELETED_TABLE_NAME = "Message_Deletes";
|
||||
|
||||
// To refer to a specific message, use ContentUris.withAppendedId(CONTENT_URI, id)
|
||||
public static Uri CONTENT_URI;
|
||||
public static Uri CONTENT_URI_LIMIT_1;
|
||||
public static Uri SYNCED_CONTENT_URI;
|
||||
public static Uri SELECTED_MESSAGE_CONTENT_URI ;
|
||||
public static Uri DELETED_CONTENT_URI;
|
||||
public static Uri UPDATED_CONTENT_URI;
|
||||
public static Uri NOTIFIER_URI;
|
||||
|
||||
public static void initMessage() {
|
||||
CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/message");
|
||||
CONTENT_URI_LIMIT_1 = uriWithLimit(CONTENT_URI, 1);
|
||||
SYNCED_CONTENT_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/syncedMessage");
|
||||
SELECTED_MESSAGE_CONTENT_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/messageBySelection");
|
||||
DELETED_CONTENT_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/deletedMessage");
|
||||
UPDATED_CONTENT_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/updatedMessage");
|
||||
NOTIFIER_URI =
|
||||
Uri.parse(EmailContent.CONTENT_NOTIFIER_URI + "/message");
|
||||
}
|
||||
@SuppressWarnings("hiding")
|
||||
public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/message");
|
||||
public static final Uri CONTENT_URI_LIMIT_1 = uriWithLimit(CONTENT_URI, 1);
|
||||
public static final Uri SYNCED_CONTENT_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/syncedMessage");
|
||||
public static final Uri DELETED_CONTENT_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/deletedMessage");
|
||||
public static final Uri UPDATED_CONTENT_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/updatedMessage");
|
||||
public static final Uri NOTIFIER_URI =
|
||||
Uri.parse(EmailContent.CONTENT_NOTIFIER_URI + "/message");
|
||||
|
||||
public static final String KEY_TIMESTAMP_DESC = MessageColumns.TIMESTAMP + " desc";
|
||||
|
||||
|
@ -621,7 +557,7 @@ public abstract class EmailContent {
|
|||
public static final int CONTENT_FLAG_ATTACHMENT_COLUMN = 7;
|
||||
public static final int CONTENT_FLAGS_COLUMN = 8;
|
||||
public static final int CONTENT_SERVER_ID_COLUMN = 9;
|
||||
public static final int CONTENT_DRAFT_INFO_COLUMN = 10;
|
||||
public static final int CONTENT_CLIENT_ID_COLUMN = 10;
|
||||
public static final int CONTENT_MESSAGE_ID_COLUMN = 11;
|
||||
public static final int CONTENT_MAILBOX_KEY_COLUMN = 12;
|
||||
public static final int CONTENT_ACCOUNT_KEY_COLUMN = 13;
|
||||
|
@ -635,7 +571,6 @@ public abstract class EmailContent {
|
|||
public static final int CONTENT_SNIPPET_COLUMN = 21;
|
||||
public static final int CONTENT_PROTOCOL_SEARCH_INFO_COLUMN = 22;
|
||||
public static final int CONTENT_THREAD_TOPIC_COLUMN = 23;
|
||||
public static final int CONTENT_SYNC_DATA_COLUMN = 24;
|
||||
|
||||
public static final String[] CONTENT_PROJECTION = new String[] {
|
||||
RECORD_ID,
|
||||
|
@ -643,14 +578,14 @@ public abstract class EmailContent {
|
|||
MessageColumns.SUBJECT, MessageColumns.FLAG_READ,
|
||||
MessageColumns.FLAG_LOADED, MessageColumns.FLAG_FAVORITE,
|
||||
MessageColumns.FLAG_ATTACHMENT, MessageColumns.FLAGS,
|
||||
SyncColumns.SERVER_ID, MessageColumns.DRAFT_INFO,
|
||||
SyncColumns.SERVER_ID, MessageColumns.CLIENT_ID,
|
||||
MessageColumns.MESSAGE_ID, MessageColumns.MAILBOX_KEY,
|
||||
MessageColumns.ACCOUNT_KEY, MessageColumns.FROM_LIST,
|
||||
MessageColumns.TO_LIST, MessageColumns.CC_LIST,
|
||||
MessageColumns.BCC_LIST, MessageColumns.REPLY_TO_LIST,
|
||||
SyncColumns.SERVER_TIMESTAMP, MessageColumns.MEETING_INFO,
|
||||
MessageColumns.SNIPPET, MessageColumns.PROTOCOL_SEARCH_INFO,
|
||||
MessageColumns.THREAD_TOPIC, MessageColumns.SYNC_DATA
|
||||
MessageColumns.THREAD_TOPIC
|
||||
};
|
||||
|
||||
public static final int LIST_ID_COLUMN = 0;
|
||||
|
@ -766,7 +701,7 @@ public abstract class EmailContent {
|
|||
|
||||
public String mServerId;
|
||||
public long mServerTimeStamp;
|
||||
public int mDraftInfo;
|
||||
public String mClientId;
|
||||
public String mMessageId;
|
||||
|
||||
public long mMailboxKey;
|
||||
|
@ -787,8 +722,6 @@ public abstract class EmailContent {
|
|||
|
||||
public String mThreadTopic;
|
||||
|
||||
public String mSyncData;
|
||||
|
||||
/**
|
||||
* Base64-encoded representation of the byte array provided by servers for identifying
|
||||
* messages belonging to the same conversation thread. Currently unsupported and not
|
||||
|
@ -817,7 +750,6 @@ public abstract class EmailContent {
|
|||
public static final int FLAG_LOADED_COMPLETE = 1;
|
||||
public static final int FLAG_LOADED_PARTIAL = 2;
|
||||
public static final int FLAG_LOADED_DELETED = 3;
|
||||
public static final int FLAG_LOADED_UNKNOWN = 4;
|
||||
|
||||
// Bits used in mFlags
|
||||
// The following three states are mutually exclusive, and indicate whether the message is an
|
||||
|
@ -858,10 +790,6 @@ public abstract class EmailContent {
|
|||
// compatibility
|
||||
public static final int FLAG_TYPE_REPLY_ALL = 1 << 21;
|
||||
|
||||
// Flag used in draftInfo to indicate that the reference message should be appended
|
||||
public static final int DRAFT_INFO_APPEND_REF_MESSAGE = 1 << 24;
|
||||
public static final int DRAFT_INFO_QUOTE_POS_MASK = 0xFFFFFF;
|
||||
|
||||
/** a pseudo ID for "no message". */
|
||||
public static final long NO_MESSAGE = -1L;
|
||||
|
||||
|
@ -882,22 +810,28 @@ public abstract class EmailContent {
|
|||
values.put(MessageColumns.FLAG_FAVORITE, mFlagFavorite);
|
||||
values.put(MessageColumns.FLAG_ATTACHMENT, mFlagAttachment);
|
||||
values.put(MessageColumns.FLAGS, mFlags);
|
||||
|
||||
values.put(SyncColumns.SERVER_ID, mServerId);
|
||||
values.put(SyncColumns.SERVER_TIMESTAMP, mServerTimeStamp);
|
||||
values.put(MessageColumns.DRAFT_INFO, mDraftInfo);
|
||||
values.put(MessageColumns.CLIENT_ID, mClientId);
|
||||
values.put(MessageColumns.MESSAGE_ID, mMessageId);
|
||||
|
||||
values.put(MessageColumns.MAILBOX_KEY, mMailboxKey);
|
||||
values.put(MessageColumns.ACCOUNT_KEY, mAccountKey);
|
||||
|
||||
values.put(MessageColumns.FROM_LIST, mFrom);
|
||||
values.put(MessageColumns.TO_LIST, mTo);
|
||||
values.put(MessageColumns.CC_LIST, mCc);
|
||||
values.put(MessageColumns.BCC_LIST, mBcc);
|
||||
values.put(MessageColumns.REPLY_TO_LIST, mReplyTo);
|
||||
|
||||
values.put(MessageColumns.MEETING_INFO, mMeetingInfo);
|
||||
|
||||
values.put(MessageColumns.SNIPPET, mSnippet);
|
||||
|
||||
values.put(MessageColumns.PROTOCOL_SEARCH_INFO, mProtocolSearchInfo);
|
||||
|
||||
values.put(MessageColumns.THREAD_TOPIC, mThreadTopic);
|
||||
values.put(MessageColumns.SYNC_DATA, mSyncData);
|
||||
return values;
|
||||
}
|
||||
|
||||
|
@ -920,7 +854,7 @@ public abstract class EmailContent {
|
|||
mFlags = cursor.getInt(CONTENT_FLAGS_COLUMN);
|
||||
mServerId = cursor.getString(CONTENT_SERVER_ID_COLUMN);
|
||||
mServerTimeStamp = cursor.getLong(CONTENT_SERVER_TIMESTAMP_COLUMN);
|
||||
mDraftInfo = cursor.getInt(CONTENT_DRAFT_INFO_COLUMN);
|
||||
mClientId = cursor.getString(CONTENT_CLIENT_ID_COLUMN);
|
||||
mMessageId = cursor.getString(CONTENT_MESSAGE_ID_COLUMN);
|
||||
mMailboxKey = cursor.getLong(CONTENT_MAILBOX_KEY_COLUMN);
|
||||
mAccountKey = cursor.getLong(CONTENT_ACCOUNT_KEY_COLUMN);
|
||||
|
@ -933,7 +867,6 @@ public abstract class EmailContent {
|
|||
mSnippet = cursor.getString(CONTENT_SNIPPET_COLUMN);
|
||||
mProtocolSearchInfo = cursor.getString(CONTENT_PROTOCOL_SEARCH_INFO_COLUMN);
|
||||
mThreadTopic = cursor.getString(CONTENT_THREAD_TOPIC_COLUMN);
|
||||
mSyncData = cursor.getString(CONTENT_SYNC_DATA_COLUMN);
|
||||
}
|
||||
|
||||
public boolean update() {
|
||||
|
@ -1030,31 +963,37 @@ public abstract class EmailContent {
|
|||
if (mHtml != null) {
|
||||
cv.put(Body.HTML_CONTENT, mHtml);
|
||||
}
|
||||
if (mTextReply != null) {
|
||||
cv.put(Body.TEXT_REPLY, mTextReply);
|
||||
}
|
||||
if (mHtmlReply != null) {
|
||||
cv.put(Body.HTML_REPLY, mHtmlReply);
|
||||
}
|
||||
if (mSourceKey != 0) {
|
||||
cv.put(Body.SOURCE_MESSAGE_KEY, mSourceKey);
|
||||
}
|
||||
if (mIntroText != null) {
|
||||
cv.put(Body.INTRO_TEXT, mIntroText);
|
||||
}
|
||||
if (mQuotedTextStartPos != 0) {
|
||||
cv.put(Body.QUOTED_TEXT_START_POS, mQuotedTextStartPos);
|
||||
}
|
||||
b = ContentProviderOperation.newInsert(Body.CONTENT_URI);
|
||||
// Put our message id in the Body
|
||||
if (!isNew) {
|
||||
cv.put(Body.MESSAGE_KEY, mId);
|
||||
}
|
||||
b.withValues(cv);
|
||||
// We'll need this if we're new
|
||||
int messageBackValue = ops.size() - 1;
|
||||
// Only create a body if we've got some data
|
||||
if (!cv.keySet().isEmpty()) {
|
||||
b = ContentProviderOperation.newInsert(Body.CONTENT_URI);
|
||||
// Put our message id in the Body
|
||||
if (!isNew) {
|
||||
cv.put(Body.MESSAGE_KEY, mId);
|
||||
}
|
||||
b.withValues(cv);
|
||||
// If we're new, create a back value entry
|
||||
if (isNew) {
|
||||
ContentValues backValues = new ContentValues();
|
||||
backValues.put(Body.MESSAGE_KEY, messageBackValue);
|
||||
b.withValueBackReferences(backValues);
|
||||
}
|
||||
// And add the Body operation
|
||||
ops.add(b.build());
|
||||
// If we're new, create a back value entry
|
||||
if (isNew) {
|
||||
ContentValues backValues = new ContentValues();
|
||||
backValues.put(Body.MESSAGE_KEY, messageBackValue);
|
||||
b.withValueBackReferences(backValues);
|
||||
}
|
||||
// And add the Body operation
|
||||
ops.add(b.build());
|
||||
|
||||
// Create the attaachments, if any
|
||||
if (mAttachments != null) {
|
||||
|
@ -1181,30 +1120,17 @@ public abstract class EmailContent {
|
|||
public static final class Attachment extends EmailContent
|
||||
implements AttachmentColumns, Parcelable {
|
||||
public static final String TABLE_NAME = "Attachment";
|
||||
public static final String ATTACHMENT_PROVIDER_LEGACY_URI_PREFIX =
|
||||
"content://com.android.email.attachmentprovider";
|
||||
|
||||
public static Uri CONTENT_URI;
|
||||
@SuppressWarnings("hiding")
|
||||
public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/attachment");
|
||||
// This must be used with an appended id: ContentUris.withAppendedId(MESSAGE_ID_URI, id)
|
||||
public static Uri MESSAGE_ID_URI;
|
||||
public static String ATTACHMENT_PROVIDER_URI_PREFIX;
|
||||
public static boolean sUsingLegacyPrefix;
|
||||
|
||||
public static void initAttachment() {
|
||||
CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/attachment");
|
||||
MESSAGE_ID_URI = Uri.parse(
|
||||
EmailContent.CONTENT_URI + "/attachment/message");
|
||||
ATTACHMENT_PROVIDER_URI_PREFIX = "content://" + EmailContent.EMAIL_PACKAGE_NAME +
|
||||
".attachmentprovider";
|
||||
sUsingLegacyPrefix =
|
||||
ATTACHMENT_PROVIDER_URI_PREFIX.equals(ATTACHMENT_PROVIDER_LEGACY_URI_PREFIX);
|
||||
}
|
||||
public static final Uri MESSAGE_ID_URI = Uri.parse(
|
||||
EmailContent.CONTENT_URI + "/attachment/message");
|
||||
|
||||
public String mFileName;
|
||||
public String mMimeType;
|
||||
public long mSize;
|
||||
public String mContentId;
|
||||
private String mContentUri;
|
||||
public String mContentUri;
|
||||
public long mMessageKey;
|
||||
public String mLocation;
|
||||
public String mEncoding;
|
||||
|
@ -1280,31 +1206,6 @@ public abstract class EmailContent {
|
|||
mBaseUri = CONTENT_URI;
|
||||
}
|
||||
|
||||
public void setContentUri(String contentUri) {
|
||||
mContentUri = contentUri;
|
||||
}
|
||||
|
||||
public String getContentUri() {
|
||||
if (mContentUri == null) return null; //
|
||||
// If we're not using the legacy prefix and the uri IS, we need to modify it
|
||||
if (!Attachment.sUsingLegacyPrefix &&
|
||||
mContentUri.startsWith(Attachment.ATTACHMENT_PROVIDER_LEGACY_URI_PREFIX)) {
|
||||
// In an upgrade scenario, we may still have legacy attachment Uri's
|
||||
// Skip past content://
|
||||
int prefix = mContentUri.indexOf('/', 10);
|
||||
if (prefix > 0) {
|
||||
// Create a proper uri string using the actual provider
|
||||
return ATTACHMENT_PROVIDER_URI_PREFIX + "/" + mContentUri.substring(prefix);
|
||||
} else {
|
||||
Log.e("Attachment", "Improper contentUri format: " + mContentUri);
|
||||
// Belt & suspenders; can't really happen
|
||||
return mContentUri;
|
||||
}
|
||||
} else {
|
||||
return mContentUri;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore an Attachment from the database, given its unique id
|
||||
* @param context
|
||||
|
@ -1534,6 +1435,10 @@ public abstract class EmailContent {
|
|||
public static final String SIGNATURE = "signature";
|
||||
// A foreign key into the Policy table
|
||||
public static final String POLICY_KEY = "policyKey";
|
||||
// For compatibility w/ Email1
|
||||
public static final String NOTIFIED_MESSAGE_ID = "notifiedMessageId";
|
||||
// For compatibility w/ Email1
|
||||
public static final String NOTIFIED_MESSAGE_COUNT = "notifiedMessageCount";
|
||||
}
|
||||
|
||||
public interface QuickResponseColumns {
|
||||
|
@ -1591,8 +1496,8 @@ public abstract class EmailContent {
|
|||
public static final String LAST_NOTIFIED_MESSAGE_COUNT = "lastNotifiedMessageCount";
|
||||
// The total number of messages in the remote mailbox
|
||||
public static final String TOTAL_COUNT = "totalCount";
|
||||
// The full hierarchical name of this folder, in the form a/b/c
|
||||
public static final String HIERARCHICAL_NAME = "hierarchicalName";
|
||||
// For compatibility with Email1
|
||||
public static final String LAST_SEEN_MESSAGE_KEY = "lastSeenMessageKey";
|
||||
}
|
||||
|
||||
public interface HostAuthColumns {
|
||||
|
@ -1615,8 +1520,6 @@ public abstract class EmailContent {
|
|||
static final String CLIENT_CERT_ALIAS = "certAlias";
|
||||
// DEPRECATED - Will not be set or stored
|
||||
static final String ACCOUNT_KEY = "accountKey";
|
||||
// A blob containing an X509 server certificate
|
||||
static final String SERVER_CERT = "serverCert";
|
||||
}
|
||||
|
||||
public interface PolicyColumns {
|
||||
|
|
|
@ -34,15 +34,14 @@ import java.net.URISyntaxException;
|
|||
|
||||
public final class HostAuth extends EmailContent implements HostAuthColumns, Parcelable {
|
||||
public static final String TABLE_NAME = "HostAuth";
|
||||
public static Uri CONTENT_URI;
|
||||
|
||||
public static void initHostAuth() {
|
||||
CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/hostauth");
|
||||
}
|
||||
|
||||
// These legacy constants should be used in code created prior to Email2
|
||||
public static final String LEGACY_SCHEME_SMTP = "smtp";
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/hostauth");
|
||||
// TODO the three following constants duplicate constants in Store.java; remove those and
|
||||
// just reference these.
|
||||
public static final String SCHEME_IMAP = "imap";
|
||||
public static final String SCHEME_POP3 = "pop3";
|
||||
public static final String SCHEME_EAS = "eas";
|
||||
public static final String SCHEME_SMTP = "smtp";
|
||||
public static final String SCHEME_TRUST_ALL_CERTS = "trustallcerts";
|
||||
|
||||
public static final int PORT_UNKNOWN = -1;
|
||||
|
@ -63,8 +62,6 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
|
|||
public String mPassword;
|
||||
public String mDomain;
|
||||
public String mClientCertAlias = null;
|
||||
// NOTE: The server certificate is NEVER automatically retrieved from EmailProvider
|
||||
public byte[] mServerCert = null;
|
||||
|
||||
public static final int CONTENT_ID_COLUMN = 0;
|
||||
public static final int CONTENT_PROTOCOL_COLUMN = 1;
|
||||
|
@ -272,7 +269,19 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
|
|||
mPort = port;
|
||||
if (mPort == PORT_UNKNOWN) {
|
||||
boolean useSSL = ((mFlags & FLAG_SSL) != 0);
|
||||
if (LEGACY_SCHEME_SMTP.equals(mProtocol)) {
|
||||
// infer port# from protocol + security
|
||||
// SSL implies a different port - TLS runs in the "regular" port
|
||||
// NOTE: Although the port should be setup in the various setup screens, this
|
||||
// block cannot easily be moved because we get process URIs from other sources
|
||||
// (e.g. for tests, provider templates and account restore) that may or may not
|
||||
// have a port specified.
|
||||
if (SCHEME_POP3.equals(mProtocol)) {
|
||||
mPort = useSSL ? 995 : 110;
|
||||
} else if (SCHEME_IMAP.equals(mProtocol)) {
|
||||
mPort = useSSL ? 993 : 143;
|
||||
} else if (SCHEME_EAS.equals(mProtocol)) {
|
||||
mPort = useSSL ? 443 : 80;
|
||||
} else if (SCHEME_SMTP.equals(mProtocol)) {
|
||||
mPort = useSSL ? 465 : 587;
|
||||
}
|
||||
}
|
||||
|
@ -280,6 +289,10 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
|
|||
mClientCertAlias = clientCertAlias;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if this is an EAS connection; otherwise, {@code false}. */
|
||||
public boolean isEasConnection() {
|
||||
return SCHEME_EAS.equals(mProtocol);
|
||||
}
|
||||
|
||||
/** Convenience method to determine if SSL is used. */
|
||||
public boolean shouldUseSsl() {
|
||||
|
@ -355,7 +368,6 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
|
|||
}
|
||||
HostAuth that = (HostAuth)o;
|
||||
return mPort == that.mPort
|
||||
&& mId == that.mId
|
||||
&& mFlags == that.mFlags
|
||||
&& Utility.areStringsEqual(mProtocol, that.mProtocol)
|
||||
&& Utility.areStringsEqual(mAddress, that.mAddress)
|
||||
|
@ -363,7 +375,6 @@ public final class HostAuth extends EmailContent implements HostAuthColumns, Par
|
|||
&& Utility.areStringsEqual(mPassword, that.mPassword)
|
||||
&& Utility.areStringsEqual(mDomain, that.mDomain)
|
||||
&& Utility.areStringsEqual(mClientCertAlias, that.mClientCertAlias);
|
||||
// We don't care about the server certificate for equals
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,17 +33,12 @@ import com.android.emailcommon.utility.Utility;
|
|||
|
||||
public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns, Parcelable {
|
||||
public static final String TABLE_NAME = "Mailbox";
|
||||
|
||||
public static Uri CONTENT_URI;
|
||||
public static Uri ADD_TO_FIELD_URI;
|
||||
public static Uri FROM_ACCOUNT_AND_TYPE_URI;
|
||||
|
||||
public static void initMailbox() {
|
||||
CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/mailbox");
|
||||
ADD_TO_FIELD_URI = Uri.parse(EmailContent.CONTENT_URI + "/mailboxIdAddToField");
|
||||
FROM_ACCOUNT_AND_TYPE_URI = Uri.parse(EmailContent.CONTENT_URI +
|
||||
"/mailboxIdFromAccountAndType");
|
||||
}
|
||||
@SuppressWarnings("hiding")
|
||||
public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/mailbox");
|
||||
public static final Uri ADD_TO_FIELD_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/mailboxIdAddToField");
|
||||
public static final Uri FROM_ACCOUNT_AND_TYPE_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/mailboxIdFromAccountAndType");
|
||||
|
||||
public String mDisplayName;
|
||||
public String mServerId;
|
||||
|
@ -66,7 +61,7 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns
|
|||
public long mLastNotifiedMessageKey;
|
||||
public int mLastNotifiedMessageCount;
|
||||
public int mTotalCount;
|
||||
public String mHierarchicalName;
|
||||
public long mLastSeenMessageKey;
|
||||
|
||||
public static final int CONTENT_ID_COLUMN = 0;
|
||||
public static final int CONTENT_DISPLAY_NAME_COLUMN = 1;
|
||||
|
@ -90,7 +85,7 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns
|
|||
public static final int CONTENT_LAST_NOTIFIED_MESSAGE_KEY_COLUMN = 19;
|
||||
public static final int CONTENT_LAST_NOTIFIED_MESSAGE_COUNT_COLUMN = 20;
|
||||
public static final int CONTENT_TOTAL_COUNT_COLUMN = 21;
|
||||
public static final int CONTENT_HIERARCHICAL_NAME_COLUMN = 22;
|
||||
public static final int CONTENT_LAST_SEEN_MESSAGE_KEY_COLUMN = 22;
|
||||
|
||||
/**
|
||||
* <em>NOTE</em>: If fields are added or removed, the method {@link #getHashes()}
|
||||
|
@ -105,7 +100,7 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns
|
|||
MailboxColumns.SYNC_STATUS, MailboxColumns.PARENT_KEY, MailboxColumns.LAST_TOUCHED_TIME,
|
||||
MailboxColumns.UI_SYNC_STATUS, MailboxColumns.UI_LAST_SYNC_RESULT,
|
||||
MailboxColumns.LAST_NOTIFIED_MESSAGE_KEY, MailboxColumns.LAST_NOTIFIED_MESSAGE_COUNT,
|
||||
MailboxColumns.TOTAL_COUNT, MailboxColumns.HIERARCHICAL_NAME
|
||||
MailboxColumns.TOTAL_COUNT, MailboxColumns.LAST_SEEN_MESSAGE_KEY
|
||||
};
|
||||
|
||||
private static final String ACCOUNT_AND_MAILBOX_TYPE_SELECTION =
|
||||
|
@ -337,7 +332,7 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns
|
|||
mLastNotifiedMessageKey = cursor.getLong(CONTENT_LAST_NOTIFIED_MESSAGE_KEY_COLUMN);
|
||||
mLastNotifiedMessageCount = cursor.getInt(CONTENT_LAST_NOTIFIED_MESSAGE_COUNT_COLUMN);
|
||||
mTotalCount = cursor.getInt(CONTENT_TOTAL_COUNT_COLUMN);
|
||||
mHierarchicalName = cursor.getString(CONTENT_HIERARCHICAL_NAME_COLUMN);
|
||||
mLastSeenMessageKey = cursor.getLong(CONTENT_LAST_SEEN_MESSAGE_KEY_COLUMN);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -364,7 +359,7 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns
|
|||
values.put(MailboxColumns.LAST_NOTIFIED_MESSAGE_KEY, mLastNotifiedMessageKey);
|
||||
values.put(MailboxColumns.LAST_NOTIFIED_MESSAGE_COUNT, mLastNotifiedMessageCount);
|
||||
values.put(MailboxColumns.TOTAL_COUNT, mTotalCount);
|
||||
values.put(MailboxColumns.HIERARCHICAL_NAME, mHierarchicalName);
|
||||
values.put(MailboxColumns.LAST_SEEN_MESSAGE_KEY, mLastSeenMessageKey);
|
||||
return values;
|
||||
}
|
||||
|
||||
|
@ -497,9 +492,43 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns
|
|||
case TYPE_MAIL:
|
||||
case TYPE_TRASH:
|
||||
case TYPE_JUNK:
|
||||
case TYPE_SENT:
|
||||
return true;
|
||||
}
|
||||
return false; // TYPE_DRAFTS, TYPE_OUTBOX, TYPE_SENT, etc
|
||||
return false; // TYPE_DRAFTS, TYPE_OUTBOX, etc
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether or not this mailbox retrieves its data from the server (as opposed to just
|
||||
* a local mailbox that is never synced).
|
||||
*/
|
||||
public boolean loadsFromServer(String protocol) {
|
||||
if (HostAuth.SCHEME_EAS.equals(protocol)) {
|
||||
return mType != Mailbox.TYPE_DRAFTS
|
||||
&& mType != Mailbox.TYPE_OUTBOX
|
||||
&& mType != Mailbox.TYPE_SEARCH
|
||||
&& mType < Mailbox.TYPE_NOT_SYNCABLE;
|
||||
|
||||
} else if (HostAuth.SCHEME_IMAP.equals(protocol)) {
|
||||
// TODO: actually use a sync flag when creating the mailboxes. Right now we use an
|
||||
// approximation for IMAP.
|
||||
return mType != Mailbox.TYPE_DRAFTS
|
||||
&& mType != Mailbox.TYPE_OUTBOX
|
||||
&& mType != Mailbox.TYPE_SEARCH;
|
||||
|
||||
} else if (HostAuth.SCHEME_POP3.equals(protocol)) {
|
||||
return TYPE_INBOX == mType;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean uploadsToServer(Context context) {
|
||||
if (mType == TYPE_DRAFTS || mType == TYPE_OUTBOX || mType == TYPE_SEARCH) {
|
||||
return false;
|
||||
}
|
||||
String protocol = Account.getProtocol(context, mAccountKey);
|
||||
return (!protocol.equals(HostAuth.SCHEME_POP3));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -560,8 +589,6 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns
|
|||
= mLastNotifiedMessageCount;
|
||||
hash[CONTENT_TOTAL_COUNT_COLUMN]
|
||||
= mTotalCount;
|
||||
hash[CONTENT_HIERARCHICAL_NAME_COLUMN]
|
||||
= mHierarchicalName;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
@ -597,7 +624,7 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns
|
|||
dest.writeLong(mLastNotifiedMessageKey);
|
||||
dest.writeInt(mLastNotifiedMessageCount);
|
||||
dest.writeInt(mTotalCount);
|
||||
dest.writeString(mHierarchicalName);
|
||||
dest.writeLong(mLastSeenMessageKey);
|
||||
}
|
||||
|
||||
public Mailbox(Parcel in) {
|
||||
|
@ -624,7 +651,7 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns
|
|||
mLastNotifiedMessageKey = in.readLong();
|
||||
mLastNotifiedMessageCount = in.readInt();
|
||||
mTotalCount = in.readInt();
|
||||
mHierarchicalName = in.readString();
|
||||
mLastSeenMessageKey = in.readLong();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Mailbox> CREATOR = new Parcelable.Creator<Mailbox>() {
|
||||
|
|
|
@ -1,274 +0,0 @@
|
|||
/*
|
||||
* 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.emailcommon.provider;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.os.Debug;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class MailboxUtilities {
|
||||
public static final String WHERE_PARENT_KEY_UNINITIALIZED =
|
||||
"(" + MailboxColumns.PARENT_KEY + " isnull OR " + MailboxColumns.PARENT_KEY + "=" +
|
||||
Mailbox.PARENT_KEY_UNINITIALIZED + ")";
|
||||
// The flag we use in Account to indicate a mailbox change in progress
|
||||
private static final int ACCOUNT_MAILBOX_CHANGE_FLAG = Account.FLAGS_SYNC_ADAPTER;
|
||||
|
||||
/**
|
||||
* Recalculate a mailbox's flags and the parent key of any children
|
||||
* @param context the caller's context
|
||||
* @param parentCursor a cursor to a mailbox that requires fixup
|
||||
*/
|
||||
public static void setFlagsAndChildrensParentKey(Context context, Cursor parentCursor,
|
||||
String accountSelector) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
String[] selectionArgs = new String[1];
|
||||
ContentValues parentValues = new ContentValues();
|
||||
// Get the data we need first
|
||||
long parentId = parentCursor.getLong(Mailbox.CONTENT_ID_COLUMN);
|
||||
int parentFlags = 0;
|
||||
int parentType = parentCursor.getInt(Mailbox.CONTENT_TYPE_COLUMN);
|
||||
String parentServerId = parentCursor.getString(Mailbox.CONTENT_SERVER_ID_COLUMN);
|
||||
// All email-type boxes hold mail
|
||||
if (parentType <= Mailbox.TYPE_NOT_EMAIL) {
|
||||
parentFlags |= Mailbox.FLAG_HOLDS_MAIL + Mailbox.FLAG_SUPPORTS_SETTINGS;
|
||||
}
|
||||
// Outbox, Drafts, and Sent don't allow mail to be moved to them
|
||||
if (parentType == Mailbox.TYPE_MAIL || parentType == Mailbox.TYPE_TRASH ||
|
||||
parentType == Mailbox.TYPE_JUNK || parentType == Mailbox.TYPE_INBOX) {
|
||||
parentFlags |= Mailbox.FLAG_ACCEPTS_MOVED_MAIL;
|
||||
}
|
||||
// There's no concept of "append" in EAS so FLAG_ACCEPTS_APPENDED_MAIL is never used
|
||||
// Mark parent mailboxes as parents & add parent key to children
|
||||
// An example of a mailbox with a null serverId would be an Outbox that we create locally
|
||||
// for hotmail accounts (which don't have a server-based Outbox)
|
||||
if (parentServerId != null) {
|
||||
selectionArgs[0] = parentServerId;
|
||||
Cursor childCursor = resolver.query(Mailbox.CONTENT_URI,
|
||||
Mailbox.ID_PROJECTION, MailboxColumns.PARENT_SERVER_ID + "=? AND " +
|
||||
accountSelector, selectionArgs, null);
|
||||
if (childCursor == null) return;
|
||||
try {
|
||||
while (childCursor.moveToNext()) {
|
||||
parentFlags |= Mailbox.FLAG_HAS_CHILDREN | Mailbox.FLAG_CHILDREN_VISIBLE;
|
||||
ContentValues childValues = new ContentValues();
|
||||
childValues.put(Mailbox.PARENT_KEY, parentId);
|
||||
long childId = childCursor.getLong(Mailbox.ID_PROJECTION_COLUMN);
|
||||
resolver.update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, childId),
|
||||
childValues, null, null);
|
||||
}
|
||||
} finally {
|
||||
childCursor.close();
|
||||
}
|
||||
} else {
|
||||
// Mark this is having no parent, so that we don't examine this mailbox again
|
||||
parentValues.put(Mailbox.PARENT_KEY, Mailbox.NO_MAILBOX);
|
||||
Log.w(Logging.LOG_TAG, "Mailbox with null serverId: " +
|
||||
parentCursor.getString(Mailbox.CONTENT_DISPLAY_NAME_COLUMN) + ", type: " +
|
||||
parentType);
|
||||
}
|
||||
// Save away updated flags and parent key (if any)
|
||||
parentValues.put(Mailbox.FLAGS, parentFlags);
|
||||
resolver.update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, parentId),
|
||||
parentValues, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate a mailbox's flags and the parent key of any children
|
||||
* @param context the caller's context
|
||||
* @param accountSelector (see description below in fixupUninitializedParentKeys)
|
||||
* @param serverId the server id of an individual mailbox
|
||||
*/
|
||||
public static void setFlagsAndChildrensParentKey(Context context, String accountSelector,
|
||||
String serverId) {
|
||||
Cursor cursor = context.getContentResolver().query(Mailbox.CONTENT_URI,
|
||||
Mailbox.CONTENT_PROJECTION, MailboxColumns.SERVER_ID + "=? AND " + accountSelector,
|
||||
new String[] {serverId}, null);
|
||||
if (cursor == null) return;
|
||||
try {
|
||||
if (cursor.moveToFirst()) {
|
||||
setFlagsAndChildrensParentKey(context, cursor, accountSelector);
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an account selector, specifying the account(s) on which to work, create the parentKey
|
||||
* and flags for each mailbox in the account(s) that is uninitialized (parentKey = 0 or null)
|
||||
*
|
||||
* @param accountSelector a sqlite WHERE clause expression to be used in determining the
|
||||
* mailboxes to be acted upon, e.g. accountKey IN (1, 2), accountKey = 12, etc.
|
||||
*/
|
||||
public static void fixupUninitializedParentKeys(Context context, String accountSelector) {
|
||||
// Sanity check first on our arguments
|
||||
if (accountSelector == null) throw new IllegalArgumentException();
|
||||
// The selection we'll use to find uninitialized parent key mailboxes
|
||||
String noParentKeySelection = WHERE_PARENT_KEY_UNINITIALIZED + " AND " + accountSelector;
|
||||
|
||||
// We'll loop through mailboxes with an uninitialized parent key
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Cursor noParentKeyMailboxCursor =
|
||||
resolver.query(Mailbox.CONTENT_URI, Mailbox.CONTENT_PROJECTION,
|
||||
noParentKeySelection, null, null);
|
||||
if (noParentKeyMailboxCursor == null) return;
|
||||
try {
|
||||
while (noParentKeyMailboxCursor.moveToNext()) {
|
||||
setFlagsAndChildrensParentKey(context, noParentKeyMailboxCursor, accountSelector);
|
||||
String parentServerId =
|
||||
noParentKeyMailboxCursor.getString(Mailbox.CONTENT_PARENT_SERVER_ID_COLUMN);
|
||||
// Fixup the parent so that the children's parentKey is updated
|
||||
if (parentServerId != null) {
|
||||
setFlagsAndChildrensParentKey(context, accountSelector, parentServerId);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
noParentKeyMailboxCursor.close();
|
||||
}
|
||||
|
||||
// Any mailboxes without a parent key should have parentKey set to -1 (no parent)
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Mailbox.PARENT_KEY, Mailbox.NO_MAILBOX);
|
||||
resolver.update(Mailbox.CONTENT_URI, values, noParentKeySelection, null);
|
||||
}
|
||||
|
||||
private static void setAccountSyncAdapterFlag(Context context, long accountId, boolean start) {
|
||||
Account account = Account.restoreAccountWithId(context, accountId);
|
||||
if (account == null) return;
|
||||
// Set temporary flag indicating state of update of mailbox list
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(Account.FLAGS, start ? (account.mFlags | ACCOUNT_MAILBOX_CHANGE_FLAG) :
|
||||
account.mFlags & ~ACCOUNT_MAILBOX_CHANGE_FLAG);
|
||||
context.getContentResolver().update(
|
||||
ContentUris.withAppendedId(Account.CONTENT_URI, account.mId), cv, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the specified account is starting the process of changing its mailbox list
|
||||
* @param context the caller's context
|
||||
* @param accountId the account that is starting to change its mailbox list
|
||||
*/
|
||||
public static void startMailboxChanges(Context context, long accountId) {
|
||||
setAccountSyncAdapterFlag(context, accountId, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the specified account is ending the process of changing its mailbox list
|
||||
* @param context the caller's context
|
||||
* @param accountId the account that is finished with changes to its mailbox list
|
||||
*/
|
||||
public static void endMailboxChanges(Context context, long accountId) {
|
||||
setAccountSyncAdapterFlag(context, accountId, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that we didn't leave the account's mailboxes in a (possibly) inconsistent state
|
||||
* If we did, make them consistent again
|
||||
* @param context the caller's context
|
||||
* @param accountId the account whose mailboxes are to be checked
|
||||
*/
|
||||
public static void checkMailboxConsistency(Context context, long accountId) {
|
||||
// If our temporary flag is set, we were interrupted during an update
|
||||
// First, make sure we're current (really fast w/ caching)
|
||||
Account account = Account.restoreAccountWithId(context, accountId);
|
||||
if (account == null) return;
|
||||
if ((account.mFlags & ACCOUNT_MAILBOX_CHANGE_FLAG) != 0) {
|
||||
Log.w(Logging.LOG_TAG, "Account " + account.mDisplayName +
|
||||
" has inconsistent mailbox data; fixing up...");
|
||||
// Set all account mailboxes to uninitialized parent key
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Mailbox.PARENT_KEY, Mailbox.PARENT_KEY_UNINITIALIZED);
|
||||
String accountSelector = Mailbox.ACCOUNT_KEY + "=" + account.mId;
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
resolver.update(Mailbox.CONTENT_URI, values, accountSelector, null);
|
||||
// Fix up keys and flags
|
||||
MailboxUtilities.fixupUninitializedParentKeys(context, accountSelector);
|
||||
// Clear the temporary flag
|
||||
endMailboxChanges(context, accountId);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String[] HIERARCHY_PROJECTION = new String[] {
|
||||
MailboxColumns.ID, MailboxColumns.DISPLAY_NAME, MailboxColumns.PARENT_KEY,
|
||||
MailboxColumns.HIERARCHICAL_NAME
|
||||
};
|
||||
private static final int HIERARCHY_ID = 0;
|
||||
private static final int HIERARCHY_NAME = 1;
|
||||
private static final int HIERARCHY_PARENT_KEY = 2;
|
||||
private static final int HIERARCHY_HIERARCHICAL_NAME = 3;
|
||||
|
||||
private static String getHierarchicalName(Context context, long id, HashMap<Long, String> map,
|
||||
String name, long parentId) {
|
||||
String hierarchicalName;
|
||||
if (map.containsKey(id)) {
|
||||
return map.get(id);
|
||||
} else if (parentId == Mailbox.NO_MAILBOX) {
|
||||
hierarchicalName = name;
|
||||
} else {
|
||||
Mailbox parent = Mailbox.restoreMailboxWithId(context, parentId);
|
||||
if (parent == null) return name + "/" + "??";
|
||||
hierarchicalName = getHierarchicalName(context, parentId, map, parent.mDisplayName,
|
||||
parent.mParentKey) + "/" + name;
|
||||
}
|
||||
map.put(id, hierarchicalName);
|
||||
return hierarchicalName;
|
||||
}
|
||||
|
||||
public static void setupHierarchicalNames(Context context, long accountId) {
|
||||
Account account = Account.restoreAccountWithId(context, accountId);
|
||||
if (account == null) return;
|
||||
// Start by clearing all names
|
||||
ContentValues values = new ContentValues();
|
||||
String accountSelector = Mailbox.ACCOUNT_KEY + "=" + account.mId;
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
HashMap<Long, String> nameMap = new HashMap<Long, String>();
|
||||
Cursor c = resolver.query(Mailbox.CONTENT_URI, HIERARCHY_PROJECTION, accountSelector,
|
||||
null, null);
|
||||
try {
|
||||
while(c.moveToNext()) {
|
||||
long id = c.getLong(HIERARCHY_ID);
|
||||
String displayName = c.getString(HIERARCHY_NAME);
|
||||
String name = getHierarchicalName(context, id, nameMap, displayName,
|
||||
c.getLong(HIERARCHY_PARENT_KEY));
|
||||
String oldHierarchicalName = c.getString(HIERARCHY_HIERARCHICAL_NAME);
|
||||
// Don't write the name unless it has changed or we don't need one (it's top-level)
|
||||
if (name.equals(oldHierarchicalName) ||
|
||||
((name.equals(displayName)) && TextUtils.isEmpty(oldHierarchicalName))) {
|
||||
continue;
|
||||
}
|
||||
// If the name has changed, update it
|
||||
values.put(MailboxColumns.HIERARCHICAL_NAME, name);
|
||||
resolver.update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, id), values, null,
|
||||
null);
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,11 +40,8 @@ public final class Policy extends EmailContent implements EmailContent.PolicyCol
|
|||
public static final String TAG = "Email/Policy";
|
||||
|
||||
public static final String TABLE_NAME = "Policy";
|
||||
public static Uri CONTENT_URI;
|
||||
|
||||
public static void initPolicy() {
|
||||
CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/policy");
|
||||
}
|
||||
@SuppressWarnings("hiding")
|
||||
public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/policy");
|
||||
|
||||
/* Convert days to mSec (used for password expiration) */
|
||||
private static final long DAYS_TO_MSEC = 24 * 60 * 60 * 1000;
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
|
||||
package com.android.emailcommon.provider;
|
||||
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.QuickResponseColumns;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
|
@ -25,9 +29,6 @@ import android.net.Uri;
|
|||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.emailcommon.provider.EmailContent.QuickResponseColumns;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* A user-modifiable message that may be quickly inserted into the body while user is composing
|
||||
* a message. Tied to a specific account.
|
||||
|
@ -35,13 +36,11 @@ import com.google.common.base.Objects;
|
|||
public final class QuickResponse extends EmailContent
|
||||
implements QuickResponseColumns, Parcelable {
|
||||
public static final String TABLE_NAME = "QuickResponse";
|
||||
public static Uri CONTENT_URI;
|
||||
public static Uri ACCOUNT_ID_URI;
|
||||
|
||||
public static void initQuickResponse() {
|
||||
CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/quickresponse");
|
||||
ACCOUNT_ID_URI = Uri.parse(EmailContent.CONTENT_URI + "/quickresponse/account");
|
||||
}
|
||||
@SuppressWarnings("hiding")
|
||||
public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI
|
||||
+ "/quickresponse");
|
||||
public static final Uri ACCOUNT_ID_URI = Uri.parse(
|
||||
EmailContent.CONTENT_URI + "/quickresponse/account");
|
||||
|
||||
private String mText;
|
||||
private long mAccountKey;
|
||||
|
|
|
@ -24,13 +24,14 @@ import android.os.RemoteException;
|
|||
|
||||
public class AccountServiceProxy extends ServiceProxy implements IAccountService {
|
||||
|
||||
public static final String ACCOUNT_INTENT = "com.android.email.ACCOUNT_INTENT";
|
||||
public static final int DEFAULT_ACCOUNT_COLOR = 0xFF0000FF;
|
||||
|
||||
private IAccountService mService = null;
|
||||
private Object mReturn;
|
||||
|
||||
public AccountServiceProxy(Context _context) {
|
||||
super(_context, getIntentForEmailPackage(_context, "ACCOUNT_INTENT"));
|
||||
super(_context, new Intent(ACCOUNT_INTENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -44,11 +45,11 @@ public class AccountServiceProxy extends ServiceProxy implements IAccountService
|
|||
}
|
||||
|
||||
@Override
|
||||
public void notifyLoginFailed(final long accountId, final String reason) {
|
||||
public void notifyLoginFailed(final long accountId) {
|
||||
setTask(new ProxyTask() {
|
||||
@Override
|
||||
public void run() throws RemoteException {
|
||||
mService.notifyLoginFailed(accountId, reason);
|
||||
mService.notifyLoginFailed(accountId);
|
||||
}
|
||||
}, "notifyLoginFailed");
|
||||
}
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
/* Copyright (C) 2012 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.emailcommon.service;
|
||||
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.emailcommon.service.IEmailServiceCallback.Stub;
|
||||
|
||||
public class EmailServiceCallback extends Stub {
|
||||
|
||||
private final RemoteCallbackList<IEmailServiceCallback> mCallbackList;
|
||||
|
||||
public EmailServiceCallback(RemoteCallbackList<IEmailServiceCallback> callbackList) {
|
||||
mCallbackList = callbackList;
|
||||
}
|
||||
/**
|
||||
* Broadcast a callback to the everyone that's registered
|
||||
*
|
||||
* @param wrapper the ServiceCallbackWrapper used in the broadcast
|
||||
*/
|
||||
private synchronized void broadcastCallback(ServiceCallbackWrapper wrapper) {
|
||||
RemoteCallbackList<IEmailServiceCallback> callbackList = mCallbackList;
|
||||
if (callbackList != null) {
|
||||
// Call everyone on our callback list
|
||||
int count = callbackList.beginBroadcast();
|
||||
try {
|
||||
for (int i = 0; i < count; i++) {
|
||||
try {
|
||||
wrapper.call(callbackList.getBroadcastItem(i));
|
||||
} catch (RemoteException e) {
|
||||
// Safe to ignore
|
||||
} catch (RuntimeException e) {
|
||||
// We don't want an exception in one call to prevent other calls, so
|
||||
// we'll just log this and continue
|
||||
Log.e("EmailServiceCallback", "Caught RuntimeException in broadcast", e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// No matter what, we need to finish the broadcast
|
||||
callbackList.finishBroadcast();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAttachmentStatus(final long messageId, final long attachmentId,
|
||||
final int status, final int progress) {
|
||||
broadcastCallback(new ServiceCallbackWrapper() {
|
||||
@Override
|
||||
public void call(IEmailServiceCallback cb) throws RemoteException {
|
||||
cb.loadAttachmentStatus(messageId, attachmentId, status, progress);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMessageStatus(final long messageId, final int status, final int progress) {
|
||||
broadcastCallback(new ServiceCallbackWrapper() {
|
||||
@Override
|
||||
public void call(IEmailServiceCallback cb) throws RemoteException {
|
||||
cb.loadMessageStatus(messageId, status, progress);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessageStatus(final long messageId, final String subject, final int status,
|
||||
final int progress) {
|
||||
broadcastCallback(new ServiceCallbackWrapper() {
|
||||
@Override
|
||||
public void call(IEmailServiceCallback cb) throws RemoteException {
|
||||
cb.sendMessageStatus(messageId, subject, status, progress);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncMailboxListStatus(final long accountId, final int status,
|
||||
final int progress) {
|
||||
broadcastCallback(new ServiceCallbackWrapper() {
|
||||
@Override
|
||||
public void call(IEmailServiceCallback cb) throws RemoteException {
|
||||
cb.syncMailboxListStatus(accountId, status, progress);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncMailboxStatus(final long mailboxId, final int status,
|
||||
final int progress) {
|
||||
broadcastCallback(new ServiceCallbackWrapper() {
|
||||
@Override
|
||||
public void call(IEmailServiceCallback cb) throws RemoteException {
|
||||
cb.syncMailboxStatus(mailboxId, status, progress);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private interface ServiceCallbackWrapper {
|
||||
public void call(IEmailServiceCallback cb) throws RemoteException;
|
||||
}
|
||||
}
|
|
@ -27,7 +27,6 @@ import com.android.emailcommon.Api;
|
|||
import com.android.emailcommon.Device;
|
||||
import com.android.emailcommon.TempDirectory;
|
||||
import com.android.emailcommon.mail.MessagingException;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.HostAuth;
|
||||
import com.android.emailcommon.provider.Policy;
|
||||
|
||||
|
@ -51,6 +50,10 @@ import java.io.IOException;
|
|||
public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||
private static final String TAG = "EmailServiceProxy";
|
||||
|
||||
// Private intent that will be used to connect to an independent Exchange service
|
||||
public static final String EXCHANGE_INTENT = "com.android.email.EXCHANGE_INTENT";
|
||||
public static final String IMAP_INTENT = "com.android.email.IMAP_INTENT";
|
||||
|
||||
public static final String AUTO_DISCOVER_BUNDLE_ERROR_CODE = "autodiscover_error_code";
|
||||
public static final String AUTO_DISCOVER_BUNDLE_HOST_AUTH = "autodiscover_host_auth";
|
||||
|
||||
|
@ -411,7 +414,9 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
|||
}, "deleteAccountPIMData");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PRELIMINARY
|
||||
* Search for messages given a query string. The string is interpreted as the logical AND of
|
||||
* terms separated by white space. The search is performed on the specified mailbox in the
|
||||
* specified account (including subfolders, as specified by the includeSubfolders parameter).
|
||||
|
@ -459,40 +464,6 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
|||
}, "sendMail");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCapabilities(final Account acct) throws RemoteException {
|
||||
setTask(new ProxyTask() {
|
||||
@Override
|
||||
public void run() throws RemoteException{
|
||||
if (mCallback != null) mService.setCallback(mCallback);
|
||||
mReturn = mService.getCapabilities(acct);
|
||||
}
|
||||
}, "getCapabilities");
|
||||
waitForCompletion();
|
||||
if (mReturn == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return (Integer)mReturn;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Request that the account be updated for this service; this call is synchronous
|
||||
*
|
||||
* @param the email address of the account to be updated
|
||||
*/
|
||||
@Override
|
||||
public void serviceUpdated(final String emailAddress) throws RemoteException {
|
||||
setTask(new ProxyTask() {
|
||||
@Override
|
||||
public void run() throws RemoteException{
|
||||
if (mCallback != null) mService.setCallback(mCallback);
|
||||
mService.serviceUpdated(emailAddress);
|
||||
}
|
||||
}, "settingsUpdate");
|
||||
waitForCompletion();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IBinder asBinder() {
|
||||
return null;
|
||||
|
|
|
@ -19,7 +19,7 @@ package com.android.emailcommon.service;
|
|||
import android.os.Bundle;
|
||||
|
||||
interface IAccountService {
|
||||
oneway void notifyLoginFailed(long accountId, String reason);
|
||||
oneway void notifyLoginFailed(long accountId);
|
||||
oneway void notifyLoginSucceeded(long accountId);
|
||||
|
||||
void reconcileAccounts(String protocol, String accountManagerType);
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
package com.android.emailcommon.service;
|
||||
|
||||
import com.android.emailcommon.provider.HostAuth;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.service.IEmailServiceCallback;
|
||||
import com.android.emailcommon.service.SearchParams;
|
||||
import android.os.Bundle;
|
||||
|
@ -60,9 +59,4 @@ interface IEmailService {
|
|||
int searchMessages(long accountId, in SearchParams params, long destMailboxId);
|
||||
|
||||
void sendMail(long accountId);
|
||||
|
||||
// API level 3
|
||||
int getCapabilities(in Account acct);
|
||||
|
||||
void serviceUpdated(String emailAddress);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package com.android.emailcommon.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
@ -28,11 +29,14 @@ public class PolicyServiceProxy extends ServiceProxy implements IPolicyService {
|
|||
private static final boolean DEBUG_PROXY = false; // DO NOT CHECK THIS IN SET TO TRUE
|
||||
private static final String TAG = "PolicyServiceProxy";
|
||||
|
||||
// The intent used by sync adapter services to connect to the PolicyService
|
||||
public static final String POLICY_INTENT = "com.android.email.POLICY_INTENT";
|
||||
|
||||
private IPolicyService mService = null;
|
||||
private Object mReturn = null;
|
||||
|
||||
public PolicyServiceProxy(Context _context) {
|
||||
super(_context, getIntentForEmailPackage(_context, "POLICY_INTENT"));
|
||||
super(_context, new Intent(POLICY_INTENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -56,27 +56,6 @@ public abstract class ServiceProxy {
|
|||
private long mStartTime;
|
||||
private boolean mDead = false;
|
||||
|
||||
public static Intent getIntentForEmailPackage(Context context, String actionName) {
|
||||
return new Intent(getIntentStringForEmailPackage(context, actionName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Intent action based on the Email package name
|
||||
* Package com.android.email + ACTION -> com.android.email.ACTION
|
||||
* Package com.google.android.email + ACTION -> com.google.android.email.ACTION
|
||||
* Package com.android.exchange + ACTION -> com.android.email.ACTION
|
||||
* Package com.google.exchange + ACTION -> com.google.android.email.ACTION
|
||||
*
|
||||
* @param context the caller's context
|
||||
* @param actionName the Intent action
|
||||
* @return an Intent action based on the package name
|
||||
*/
|
||||
public static String getIntentStringForEmailPackage(Context context, String actionName) {
|
||||
String packageName = context.getPackageName();
|
||||
int lastDot = packageName.lastIndexOf('.');
|
||||
return packageName.substring(0, lastDot + 1) + "email." + actionName;
|
||||
}
|
||||
|
||||
public abstract void onConnected(IBinder binder);
|
||||
|
||||
public ServiceProxy(Context _context, Intent _intent) {
|
||||
|
@ -92,8 +71,7 @@ public abstract class ServiceProxy {
|
|||
public void onServiceConnected(ComponentName name, IBinder binder) {
|
||||
onConnected(binder);
|
||||
if (DEBUG_PROXY) {
|
||||
Log.v(mTag, "Connected: " + name.getShortClassName() + " at " +
|
||||
(System.currentTimeMillis() - mStartTime) + "ms");
|
||||
Log.v(mTag, "Connected: " + name.getShortClassName());
|
||||
}
|
||||
// Run our task on a new thread
|
||||
new Thread(new Runnable() {
|
||||
|
@ -108,8 +86,7 @@ public abstract class ServiceProxy {
|
|||
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
if (DEBUG_PROXY) {
|
||||
Log.v(mTag, "Disconnected: " + name.getShortClassName() + " at " +
|
||||
(System.currentTimeMillis() - mStartTime) + "ms");
|
||||
Log.v(mTag, "Disconnected: " + name.getShortClassName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,9 +169,8 @@ public abstract class ServiceProxy {
|
|||
// Can be ignored safely
|
||||
}
|
||||
if (DEBUG_PROXY) {
|
||||
Log.v(mTag, "Wait for " + mName + (mDead ? " finished in " : " timed out in ") +
|
||||
Log.v(mTag, "Wait for " + mName + " finished in " +
|
||||
(System.currentTimeMillis() - time) + "ms");
|
||||
mDead = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,25 +26,4 @@ public class SyncWindow {
|
|||
public static final int SYNC_WINDOW_2_WEEKS = 4;
|
||||
public static final int SYNC_WINDOW_1_MONTH = 5;
|
||||
public static final int SYNC_WINDOW_ALL = 6;
|
||||
|
||||
public static int toDays(int window) {
|
||||
switch(window) {
|
||||
case SYNC_WINDOW_1_DAY:
|
||||
return 1;
|
||||
case SYNC_WINDOW_3_DAYS:
|
||||
return 3;
|
||||
case SYNC_WINDOW_1_WEEK:
|
||||
return 7;
|
||||
case SYNC_WINDOW_2_WEEKS:
|
||||
return 14;
|
||||
case SYNC_WINDOW_1_MONTH:
|
||||
return 30;
|
||||
case SYNC_WINDOW_ALL:
|
||||
return 365*10;
|
||||
case SYNC_WINDOW_UNKNOWN:
|
||||
case SYNC_WINDOW_AUTO:
|
||||
default:
|
||||
return 14;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,8 +32,6 @@ import android.webkit.MimeTypeMap;
|
|||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||
import com.android.emailcommon.provider.EmailContent.AttachmentColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Body;
|
||||
import com.android.emailcommon.provider.EmailContent.BodyColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||
import com.android.mail.providers.UIProvider;
|
||||
|
@ -44,9 +42,10 @@ import java.io.File;
|
|||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class AttachmentUtilities {
|
||||
public static final String AUTHORITY = "com.android.email.attachmentprovider";
|
||||
public static final Uri CONTENT_URI = Uri.parse( "content://" + AUTHORITY);
|
||||
|
||||
public static final String FORMAT_RAW = "RAW";
|
||||
public static final String FORMAT_THUMBNAIL = "THUMBNAIL";
|
||||
|
@ -135,16 +134,23 @@ public class AttachmentUtilities {
|
|||
*/
|
||||
public static final int MAX_ATTACHMENT_UPLOAD_SIZE = (5 * 1024 * 1024);
|
||||
|
||||
private static Uri sUri;
|
||||
public static Uri getAttachmentUri(long accountId, long id) {
|
||||
if (sUri == null) {
|
||||
sUri = Uri.parse(Attachment.ATTACHMENT_PROVIDER_URI_PREFIX);
|
||||
}
|
||||
return sUri.buildUpon()
|
||||
.appendPath(Long.toString(accountId))
|
||||
.appendPath(Long.toString(id))
|
||||
.appendPath(FORMAT_RAW)
|
||||
.build();
|
||||
return CONTENT_URI.buildUpon()
|
||||
.appendPath(Long.toString(accountId))
|
||||
.appendPath(Long.toString(id))
|
||||
.appendPath(FORMAT_RAW)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static Uri getAttachmentThumbnailUri(long accountId, long id,
|
||||
int width, int height) {
|
||||
return CONTENT_URI.buildUpon()
|
||||
.appendPath(Long.toString(accountId))
|
||||
.appendPath(Long.toString(id))
|
||||
.appendPath(FORMAT_THUMBNAIL)
|
||||
.appendPath(Integer.toString(width))
|
||||
.appendPath(Integer.toString(height))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,6 +235,24 @@ public class AttachmentUtilities {
|
|||
return resultType.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mime-type for a {@link Uri}.
|
||||
* - Use {@link ContentResolver#getType} for a content: URI.
|
||||
* - Use {@link #inferMimeType} for a file: URI.
|
||||
* - Otherwise returns null.
|
||||
*/
|
||||
public static String inferMimeTypeForUri(Context context, Uri uri) {
|
||||
final String scheme = uri.getScheme();
|
||||
if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
|
||||
return context.getContentResolver().getType(uri);
|
||||
} else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
|
||||
return inferMimeType(uri.getLastPathSegment(), "");
|
||||
} else {
|
||||
Log.e(Logging.LOG_TAG, "Unable to determine MIME type for uri=" + uri, new Error());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract and return filename's extension, converted to lower case, and not including the "."
|
||||
*
|
||||
|
@ -338,7 +362,8 @@ public class AttachmentUtilities {
|
|||
}
|
||||
}
|
||||
|
||||
private static long copyFile(InputStream in, OutputStream out) throws IOException {
|
||||
private static long copyFile(InputStream in, File file) throws IOException {
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
long size = IOUtils.copy(in, out);
|
||||
in.close();
|
||||
out.flush();
|
||||
|
@ -354,20 +379,24 @@ public class AttachmentUtilities {
|
|||
ContentValues cv = new ContentValues();
|
||||
long attachmentId = attachment.mId;
|
||||
long accountId = attachment.mAccountKey;
|
||||
String contentUri = null;
|
||||
String contentUri;
|
||||
long size;
|
||||
try {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
if (attachment.mUiDestination == UIProvider.AttachmentDestination.CACHE) {
|
||||
Uri attUri = getAttachmentUri(accountId, attachmentId);
|
||||
size = copyFile(in, resolver.openOutputStream(attUri));
|
||||
contentUri = attUri.toString();
|
||||
File saveIn = getAttachmentDirectory(context, accountId);
|
||||
if (!saveIn.exists()) {
|
||||
saveIn.mkdirs();
|
||||
}
|
||||
File file = getAttachmentFilename(context, accountId, attachmentId);
|
||||
file.createNewFile();
|
||||
size = copyFile(in, file);
|
||||
contentUri = getAttachmentUri(accountId, attachmentId).toString();
|
||||
} else if (Utility.isExternalStorageMounted()) {
|
||||
File downloads = Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_DOWNLOADS);
|
||||
downloads.mkdirs();
|
||||
File file = Utility.createUniqueFile(downloads, attachment.mFileName);
|
||||
size = copyFile(in, new FileOutputStream(file));
|
||||
size = copyFile(in, file);
|
||||
String absolutePath = file.getAbsolutePath();
|
||||
|
||||
// Although the download manager can scan media files, scanning only happens
|
||||
|
@ -400,20 +429,5 @@ public class AttachmentUtilities {
|
|||
}
|
||||
context.getContentResolver().update(uri, cv, null, null);
|
||||
|
||||
// If this is an inline attachment, update the body
|
||||
if (contentUri != null && attachment.mContentId != null) {
|
||||
Body body = Body.restoreBodyWithMessageId(context, attachment.mMessageKey);
|
||||
if (body != null && body.mHtmlContent != null) {
|
||||
cv.clear();
|
||||
String html = body.mHtmlContent;
|
||||
String contentIdRe =
|
||||
"\\s+(?i)src=\"cid(?-i):\\Q" + attachment.mContentId + "\\E\"";
|
||||
String srcContentUri = " src=\"" + contentUri + "\"";
|
||||
html = html.replaceAll(contentIdRe, srcContentUri);
|
||||
cv.put(BodyColumns.HTML_CONTENT, html);
|
||||
context.getContentResolver().update(
|
||||
ContentUris.withAppendedId(Body.CONTENT_URI, body.mId), cv, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,10 +42,9 @@ import javax.net.ssl.KeyManager;
|
|||
*/
|
||||
public class EmailClientConnectionManager extends ThreadSafeClientConnManager {
|
||||
|
||||
private static final boolean LOG_ENABLED = false;
|
||||
private static final int STANDARD_PORT = 80;
|
||||
private static final int STANDARD_SSL_PORT = 443;
|
||||
private static final boolean LOG_ENABLED = false;
|
||||
|
||||
/**
|
||||
* A {@link KeyManager} to track client certificate requests from servers.
|
||||
*/
|
||||
|
@ -60,11 +59,9 @@ public class EmailClientConnectionManager extends ThreadSafeClientConnManager {
|
|||
mTrackingKeyManager = keyManager;
|
||||
}
|
||||
|
||||
public static EmailClientConnectionManager newInstance(Context context, HttpParams params,
|
||||
HostAuth hostAuth) {
|
||||
public static EmailClientConnectionManager newInstance(HttpParams params, boolean ssl,
|
||||
int port) {
|
||||
TrackingKeyManager keyManager = new TrackingKeyManager();
|
||||
boolean ssl = hostAuth.shouldUseSsl();
|
||||
int port = hostAuth.mPort;
|
||||
|
||||
// Create a registry for our three schemes; http and https will use built-in factories
|
||||
SchemeRegistry registry = new SchemeRegistry();
|
||||
|
@ -72,11 +69,10 @@ public class EmailClientConnectionManager extends ThreadSafeClientConnManager {
|
|||
ssl ? STANDARD_PORT : port));
|
||||
// Register https with the secure factory
|
||||
registry.register(new Scheme("https",
|
||||
SSLUtils.getHttpSocketFactory(context, hostAuth, keyManager, false),
|
||||
ssl ? port : STANDARD_SSL_PORT));
|
||||
SSLUtils.getHttpSocketFactory(false, keyManager), ssl ? port : STANDARD_SSL_PORT));
|
||||
// Register the httpts scheme with our insecure factory
|
||||
registry.register(new Scheme("httpts",
|
||||
SSLUtils.getHttpSocketFactory(context, hostAuth, keyManager, true),
|
||||
SSLUtils.getHttpSocketFactory(true /*insecure*/, keyManager),
|
||||
ssl ? port : STANDARD_SSL_PORT));
|
||||
|
||||
return new EmailClientConnectionManager(params, registry, keyManager);
|
||||
|
@ -102,10 +98,11 @@ public class EmailClientConnectionManager extends ThreadSafeClientConnManager {
|
|||
}
|
||||
KeyManager keyManager =
|
||||
KeyChainKeyManager.fromAlias(context, hostAuth.mClientCertAlias);
|
||||
boolean insecure = hostAuth.shouldTrustAllServerCerts();
|
||||
SSLSocketFactory ssf =
|
||||
SSLUtils.getHttpSocketFactory(context, hostAuth, keyManager, insecure);
|
||||
registry.register(new Scheme(schemeName, ssf, hostAuth.mPort));
|
||||
SSLCertificateSocketFactory underlying = SSLUtils.getSSLSocketFactory(
|
||||
hostAuth.shouldTrustAllServerCerts());
|
||||
underlying.setKeyManagers(new KeyManager[] { keyManager });
|
||||
registry.register(
|
||||
new Scheme(schemeName, new SSLSocketFactory(underlying), hostAuth.mPort));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,139 +16,46 @@
|
|||
|
||||
package com.android.emailcommon.utility;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.SSLCertificateSocketFactory;
|
||||
import android.security.KeyChain;
|
||||
import android.security.KeyChainException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.emailcommon.provider.EmailContent.HostAuthColumns;
|
||||
import com.android.emailcommon.provider.HostAuth;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.security.Principal;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
public class SSLUtils {
|
||||
// All secure factories are the same; all insecure factories are associated with HostAuth's
|
||||
private static SSLCertificateSocketFactory sInsecureFactory;
|
||||
private static SSLCertificateSocketFactory sSecureFactory;
|
||||
|
||||
private static final boolean LOG_ENABLED = false;
|
||||
private static final String TAG = "Email.Ssl";
|
||||
|
||||
/**
|
||||
* A trust manager specific to a particular HostAuth. The first time a server certificate is
|
||||
* encountered for the HostAuth, its certificate is saved; subsequent checks determine whether
|
||||
* the PublicKey of the certificate presented matches that of the saved certificate
|
||||
* TODO: UI to ask user about changed certificates
|
||||
*/
|
||||
private static class SameCertificateCheckingTrustManager implements X509TrustManager {
|
||||
private final HostAuth mHostAuth;
|
||||
private final Context mContext;
|
||||
// The public key associated with the HostAuth; we'll lazily initialize it
|
||||
private PublicKey mPublicKey;
|
||||
|
||||
SameCertificateCheckingTrustManager(Context context, HostAuth hostAuth) {
|
||||
mContext = context;
|
||||
mHostAuth = hostAuth;
|
||||
// We must load the server cert manually (the ContentCache won't handle blobs
|
||||
Cursor c = context.getContentResolver().query(HostAuth.CONTENT_URI,
|
||||
new String[] {HostAuthColumns.SERVER_CERT}, HostAuth.ID + "=?",
|
||||
new String[] {Long.toString(hostAuth.mId)}, null);
|
||||
if (c != null) {
|
||||
try {
|
||||
if (c.moveToNext()) {
|
||||
mHostAuth.mServerCert = c.getBlob(0);
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
||||
throws CertificateException {
|
||||
// We don't check client certificates
|
||||
throw new CertificateException("We don't check client certificates");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
||||
throws CertificateException {
|
||||
if (chain.length == 0) {
|
||||
throw new CertificateException("No certificates?");
|
||||
} else {
|
||||
X509Certificate serverCert = chain[0];
|
||||
if (mHostAuth.mServerCert != null) {
|
||||
// Compare with the current public key
|
||||
if (mPublicKey == null) {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(mHostAuth.mServerCert);
|
||||
Certificate storedCert =
|
||||
CertificateFactory.getInstance("X509").generateCertificate(bais);
|
||||
mPublicKey = storedCert.getPublicKey();
|
||||
try {
|
||||
bais.close();
|
||||
} catch (IOException e) {
|
||||
// Yeah, right.
|
||||
}
|
||||
}
|
||||
if (!mPublicKey.equals(serverCert.getPublicKey())) {
|
||||
throw new CertificateException(
|
||||
"PublicKey has changed since initial connection!");
|
||||
}
|
||||
} else {
|
||||
// First time; save this away
|
||||
byte[] encodedCert = serverCert.getEncoded();
|
||||
mHostAuth.mServerCert = encodedCert;
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(HostAuthColumns.SERVER_CERT, encodedCert);
|
||||
mContext.getContentResolver().update(
|
||||
ContentUris.withAppendedId(HostAuth.CONTENT_URI, mHostAuth.mId),
|
||||
values, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link javax.net.ssl.SSLSocketFactory}.
|
||||
* Optionally bypass all SSL certificate checks.
|
||||
*
|
||||
* @param insecure if true, bypass all SSL certificate checks
|
||||
*/
|
||||
public synchronized static SSLCertificateSocketFactory getSSLSocketFactory(Context context,
|
||||
HostAuth hostAuth, boolean insecure) {
|
||||
public synchronized static SSLCertificateSocketFactory getSSLSocketFactory(
|
||||
boolean insecure) {
|
||||
if (insecure) {
|
||||
SSLCertificateSocketFactory insecureFactory = (SSLCertificateSocketFactory)
|
||||
SSLCertificateSocketFactory.getDefault(0, null);
|
||||
insecureFactory.setTrustManagers(
|
||||
new TrustManager[] {
|
||||
new SameCertificateCheckingTrustManager(context, hostAuth)});
|
||||
return insecureFactory;
|
||||
if (sInsecureFactory == null) {
|
||||
sInsecureFactory = (SSLCertificateSocketFactory)
|
||||
SSLCertificateSocketFactory.getInsecure(0, null);
|
||||
}
|
||||
return sInsecureFactory;
|
||||
} else {
|
||||
if (sSecureFactory == null) {
|
||||
sSecureFactory = (SSLCertificateSocketFactory)
|
||||
|
@ -162,9 +69,8 @@ public class SSLUtils {
|
|||
* Returns a {@link org.apache.http.conn.ssl.SSLSocketFactory SSLSocketFactory} for use with the
|
||||
* Apache HTTP stack.
|
||||
*/
|
||||
public static SSLSocketFactory getHttpSocketFactory(Context context, HostAuth hostAuth,
|
||||
KeyManager keyManager, boolean insecure) {
|
||||
SSLCertificateSocketFactory underlying = getSSLSocketFactory(context, hostAuth, insecure);
|
||||
public static SSLSocketFactory getHttpSocketFactory(boolean insecure, KeyManager keyManager) {
|
||||
SSLCertificateSocketFactory underlying = getSSLSocketFactory(insecure);
|
||||
if (keyManager != null) {
|
||||
underlying.setKeyManagers(new KeyManager[] { keyManager });
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ import com.android.emailcommon.provider.EmailContent.AttachmentColumns;
|
|||
import com.android.emailcommon.provider.EmailContent.HostAuthColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||
import com.android.emailcommon.provider.HostAuth;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
import com.android.emailcommon.provider.ProviderUnavailableException;
|
||||
|
@ -363,7 +364,6 @@ public class Utility {
|
|||
cal.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
return cal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a time in milliseconds from an email date string that represents a date/time in GMT
|
||||
* @param date string in format 2010-02-23T16:00:00.000Z (ISO 8601, rfc3339)
|
||||
|
@ -745,28 +745,25 @@ public class Utility {
|
|||
return false;
|
||||
} else if (attachment.mContentBytes != null) {
|
||||
return true;
|
||||
} else {
|
||||
String contentUri = attachment.getContentUri();
|
||||
if (TextUtils.isEmpty(contentUri)) {
|
||||
return false;
|
||||
}
|
||||
} else if (TextUtils.isEmpty(attachment.mContentUri)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Uri fileUri = Uri.parse(attachment.mContentUri);
|
||||
try {
|
||||
Uri fileUri = Uri.parse(contentUri);
|
||||
InputStream inStream = context.getContentResolver().openInputStream(fileUri);
|
||||
try {
|
||||
InputStream inStream = context.getContentResolver().openInputStream(fileUri);
|
||||
try {
|
||||
inStream.close();
|
||||
} catch (IOException e) {
|
||||
// Nothing to be done if can't close the stream
|
||||
}
|
||||
return true;
|
||||
} catch (FileNotFoundException e) {
|
||||
return false;
|
||||
inStream.close();
|
||||
} catch (IOException e) {
|
||||
// Nothing to be done if can't close the stream
|
||||
}
|
||||
} catch (RuntimeException re) {
|
||||
Log.w(Logging.LOG_TAG, "attachmentExists RuntimeException=" + re);
|
||||
return true;
|
||||
} catch (FileNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
} catch (RuntimeException re) {
|
||||
Log.w(Logging.LOG_TAG, "attachmentExists RuntimeException=" + re);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -792,18 +789,8 @@ public class Utility {
|
|||
Attachment.FLAG_DOWNLOAD_USER_REQUEST)) == 0) {
|
||||
Log.d(Logging.LOG_TAG, "Unloaded attachment isn't marked for download: " +
|
||||
att.mFileName + ", #" + att.mId);
|
||||
Account acct = Account.restoreAccountWithId(context, msg.mAccountKey);
|
||||
if (acct == null) return true;
|
||||
// If smart forward is set and the message is a forward, we'll act as though
|
||||
// the attachment has been loaded
|
||||
// In Email1 this test wasn't necessary, as the UI handled it...
|
||||
if ((msg.mFlags & Message.FLAG_TYPE_FORWARD) != 0) {
|
||||
if ((acct.mFlags & Account.FLAGS_SUPPORTS_SMART_FORWARD) != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Attachment.delete(context, Attachment.CONTENT_URI, att.mId);
|
||||
} else if (att.getContentUri() != null) {
|
||||
} else if (att.mContentUri != null) {
|
||||
// In this case, the attachment file is gone from the cache; let's clear the
|
||||
// contentUri; this should be a very unusual case
|
||||
ContentValues cv = new ContentValues();
|
||||
|
@ -1163,4 +1150,72 @@ public class Utility {
|
|||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the last seen message key in the mailbox data base for the INBOX of the currently
|
||||
* shown account. If the account is {@link Account#ACCOUNT_ID_COMBINED_VIEW}, the INBOX for
|
||||
* all accounts are updated.
|
||||
* @return an {@link EmailAsyncTask} for test only.
|
||||
*/
|
||||
public static EmailAsyncTask<Void, Void, Void> updateLastSeenMessageKey(final Context context,
|
||||
final long accountId) {
|
||||
return EmailAsyncTask.runAsyncParallel(new Runnable() {
|
||||
private void updateLastSeenMessageKeyForAccount(long accountId) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
if (accountId == Account.ACCOUNT_ID_COMBINED_VIEW) {
|
||||
Cursor c = resolver.query(
|
||||
Account.CONTENT_URI, EmailContent.ID_PROJECTION, null, null, null);
|
||||
if (c == null) throw new ProviderUnavailableException();
|
||||
try {
|
||||
while (c.moveToNext()) {
|
||||
final long id = c.getLong(EmailContent.ID_PROJECTION_COLUMN);
|
||||
updateLastSeenMessageKeyForAccount(id);
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
} else if (accountId > 0L) {
|
||||
Mailbox mailbox =
|
||||
Mailbox.restoreMailboxOfType(context, accountId, Mailbox.TYPE_INBOX);
|
||||
|
||||
// mailbox has been removed
|
||||
if (mailbox == null) {
|
||||
return;
|
||||
}
|
||||
// We use the highest _id for the account the mailbox table as the "last seen
|
||||
// message key". We don't care if the message has been read or not. We only
|
||||
// need a point at which we can compare against in the future. By setting this
|
||||
// value, we are claiming that every message before this has potentially been
|
||||
// seen by the user.
|
||||
long messageId = Utility.getFirstRowLong(
|
||||
context,
|
||||
Message.CONTENT_URI,
|
||||
EmailContent.ID_PROJECTION,
|
||||
MessageColumns.MAILBOX_KEY + "=?",
|
||||
new String[] { Long.toString(mailbox.mId) },
|
||||
MessageColumns.ID + " DESC",
|
||||
EmailContent.ID_PROJECTION_COLUMN, 0L);
|
||||
long oldLastSeenMessageId = Utility.getFirstRowLong(
|
||||
context, ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailbox.mId),
|
||||
new String[] { MailboxColumns.LAST_SEEN_MESSAGE_KEY },
|
||||
null, null, null, 0, 0L);
|
||||
// Only update the db if the value has changed
|
||||
if (messageId != oldLastSeenMessageId) {
|
||||
ContentValues values = mailbox.toContentValues();
|
||||
values.put(MailboxColumns.LAST_SEEN_MESSAGE_KEY, messageId);
|
||||
resolver.update(
|
||||
Mailbox.CONTENT_URI,
|
||||
values,
|
||||
EmailContent.ID_SELECTION,
|
||||
new String[] { Long.toString(mailbox.mId) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
updateLastSeenMessageKeyForAccount(accountId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
# Copyright 2012, 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.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# Build the com.android.emailcommon static library. At the moment, this includes
|
||||
# the emailcommon files themselves plus everything under src/org (apache code). All of our
|
||||
# AIDL files are also compiled into the static library
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
|
||||
LOCAL_MODULE := com.android.emailsync
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/emailsync)
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := com.android.emailcommon2
|
||||
|
||||
LOCAL_SDK_VERSION := 14
|
||||
|
||||
include $(BUILD_STATIC_JAVA_LIBRARY)
|
|
@ -1,307 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2009 Marc Blank
|
||||
* Licensed to 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.emailsync;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.HostAuth;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* Base class for all protocol services SyncManager (extends Service, implements
|
||||
* Runnable) instantiates subclasses to run a sync (either timed, or push, or
|
||||
* mail placed in outbox, etc.) EasSyncService is currently implemented; my goal
|
||||
* would be to move IMAP to this structure when it comes time to introduce push
|
||||
* functionality.
|
||||
*/
|
||||
public abstract class AbstractSyncService implements Runnable {
|
||||
|
||||
public String TAG = "AbstractSyncService";
|
||||
|
||||
public static final int SECONDS = 1000;
|
||||
public static final int MINUTES = 60*SECONDS;
|
||||
public static final int HOURS = 60*MINUTES;
|
||||
public static final int DAYS = 24*HOURS;
|
||||
|
||||
public static final int CONNECT_TIMEOUT = 30*SECONDS;
|
||||
public static final int NETWORK_WAIT = 15*SECONDS;
|
||||
|
||||
public static final int EXIT_DONE = 0;
|
||||
public static final int EXIT_IO_ERROR = 1;
|
||||
public static final int EXIT_LOGIN_FAILURE = 2;
|
||||
public static final int EXIT_EXCEPTION = 3;
|
||||
public static final int EXIT_SECURITY_FAILURE = 4;
|
||||
public static final int EXIT_ACCESS_DENIED = 5;
|
||||
|
||||
public Mailbox mMailbox;
|
||||
protected long mMailboxId;
|
||||
protected int mExitStatus = EXIT_EXCEPTION;
|
||||
protected String mExitReason;
|
||||
protected String mMailboxName;
|
||||
public Account mAccount;
|
||||
public Context mContext;
|
||||
public int mChangeCount = 0;
|
||||
public volatile int mSyncReason = 0;
|
||||
protected volatile boolean mStop = false;
|
||||
public volatile Thread mThread;
|
||||
protected final Object mSynchronizer = new Object();
|
||||
// Whether or not the sync service is valid (usable)
|
||||
public boolean mIsValid = true;
|
||||
|
||||
public boolean mUserLog = true; // STOPSHIP
|
||||
public boolean mFileLog = false;
|
||||
|
||||
protected volatile long mRequestTime = 0;
|
||||
protected LinkedBlockingQueue<Request> mRequestQueue = new LinkedBlockingQueue<Request>();
|
||||
|
||||
/**
|
||||
* Sent by SyncManager to request that the service stop itself cleanly
|
||||
*/
|
||||
public abstract void stop();
|
||||
|
||||
/**
|
||||
* Sent by SyncManager to indicate that an alarm has fired for this service, and that its
|
||||
* pending (network) operation has timed out. The service is NOT automatically stopped,
|
||||
* although the behavior is service dependent.
|
||||
*
|
||||
* @return true if the operation was stopped normally; false if the thread needed to be
|
||||
* interrupted.
|
||||
*/
|
||||
public abstract boolean alarm();
|
||||
|
||||
/**
|
||||
* Sent by SyncManager to request that the service reset itself cleanly; the meaning of this
|
||||
* operation is service dependent.
|
||||
*/
|
||||
public abstract void reset();
|
||||
|
||||
/**
|
||||
* Called to validate an account; abstract to allow each protocol to do what
|
||||
* is necessary. For consistency with the Email app's original
|
||||
* functionality, success is indicated by a failure to throw an Exception
|
||||
* (ugh). Parameters are self-explanatory
|
||||
*
|
||||
* @param hostAuth
|
||||
* @return a Bundle containing a result code and, depending on the result, a PolicySet or an
|
||||
* error message
|
||||
*/
|
||||
public abstract Bundle validateAccount(HostAuth hostAuth, Context context);
|
||||
|
||||
/**
|
||||
* Called to clear the syncKey for the calendar associated with this service; this is necessary
|
||||
* because changes to calendar sync state cause a reset of data.
|
||||
*/
|
||||
public abstract void resetCalendarSyncKey();
|
||||
|
||||
public AbstractSyncService(Context _context, Mailbox _mailbox) {
|
||||
mContext = _context;
|
||||
mMailbox = _mailbox;
|
||||
mMailboxId = _mailbox.mId;
|
||||
mMailboxName = _mailbox.mServerId;
|
||||
mAccount = Account.restoreAccountWithId(_context, _mailbox.mAccountKey);
|
||||
}
|
||||
|
||||
// Will be required when subclasses are instantiated by name
|
||||
public AbstractSyncService(String prefix) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The UI can call this static method to perform account validation. This method wraps each
|
||||
* protocol's validateAccount method. Arguments are self-explanatory, except where noted.
|
||||
*
|
||||
* @param klass the protocol class (EasSyncService.class for example)
|
||||
* @param hostAuth
|
||||
* @param context
|
||||
* @return a Bundle containing a result code and, depending on the result, a PolicySet or an
|
||||
* error message
|
||||
*/
|
||||
public static Bundle validate(Class<? extends AbstractSyncService> klass,
|
||||
HostAuth hostAuth, Context context) {
|
||||
AbstractSyncService svc;
|
||||
try {
|
||||
svc = klass.newInstance();
|
||||
return svc.validateAccount(hostAuth, context);
|
||||
} catch (IllegalAccessException e) {
|
||||
} catch (InstantiationException e) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class ValidationResult {
|
||||
static final int NO_FAILURE = 0;
|
||||
static final int CONNECTION_FAILURE = 1;
|
||||
static final int VALIDATION_FAILURE = 2;
|
||||
static final int EXCEPTION = 3;
|
||||
|
||||
static final ValidationResult succeeded = new ValidationResult(true, NO_FAILURE, null);
|
||||
boolean success;
|
||||
int failure = NO_FAILURE;
|
||||
String reason = null;
|
||||
Exception exception = null;
|
||||
|
||||
ValidationResult(boolean _success, int _failure, String _reason) {
|
||||
success = _success;
|
||||
failure = _failure;
|
||||
reason = _reason;
|
||||
}
|
||||
|
||||
ValidationResult(boolean _success) {
|
||||
success = _success;
|
||||
}
|
||||
|
||||
ValidationResult(Exception e) {
|
||||
success = false;
|
||||
failure = EXCEPTION;
|
||||
exception = e;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isStopped() {
|
||||
return mStop;
|
||||
}
|
||||
|
||||
public Object getSynchronizer() {
|
||||
return mSynchronizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience methods to do user logging (i.e. connection activity). Saves a bunch of
|
||||
* repetitive code.
|
||||
*/
|
||||
public void userLog(String string, int code, String string2) {
|
||||
if (mUserLog) {
|
||||
userLog(string + code + string2);
|
||||
}
|
||||
}
|
||||
|
||||
public void userLog(String string, int code) {
|
||||
if (mUserLog) {
|
||||
userLog(string + code);
|
||||
}
|
||||
}
|
||||
|
||||
public void userLog(String str, Exception e) {
|
||||
if (mUserLog) {
|
||||
Log.e(TAG, str, e);
|
||||
} else {
|
||||
Log.e(TAG, str + e);
|
||||
}
|
||||
if (mFileLog) {
|
||||
FileLogger.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard logging for EAS.
|
||||
* If user logging is active, we concatenate any arguments and log them using Log.d
|
||||
* We also check for file logging, and log appropriately
|
||||
* @param strings strings to concatenate and log
|
||||
*/
|
||||
public void userLog(String ...strings) {
|
||||
if (mUserLog) {
|
||||
String logText;
|
||||
if (strings.length == 1) {
|
||||
logText = strings[0];
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder(64);
|
||||
for (String string: strings) {
|
||||
sb.append(string);
|
||||
}
|
||||
logText = sb.toString();
|
||||
}
|
||||
Log.d(TAG, logText);
|
||||
if (mFileLog) {
|
||||
FileLogger.log(TAG, logText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error log is used for serious issues that should always be logged
|
||||
* @param str the string to log
|
||||
*/
|
||||
public void errorLog(String str) {
|
||||
Log.e(TAG, str);
|
||||
if (mFileLog) {
|
||||
FileLogger.log(TAG, str);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for up to 10 seconds for network connectivity; returns whether or not there is
|
||||
* network connectivity.
|
||||
*
|
||||
* @return whether there is network connectivity
|
||||
*/
|
||||
public boolean hasConnectivity() {
|
||||
ConnectivityManager cm =
|
||||
(ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
int tries = 0;
|
||||
while (tries++ < 1) {
|
||||
// Use the same test as in ExchangeService#waitForConnectivity
|
||||
// TODO: Create common code for this test in emailcommon
|
||||
NetworkInfo info = cm.getActiveNetworkInfo();
|
||||
if (info != null) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(10*SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request handling (common functionality)
|
||||
* Can be overridden if desired
|
||||
*/
|
||||
|
||||
public void addRequest(Request req) {
|
||||
if (!mRequestQueue.contains(req)) {
|
||||
mRequestQueue.offer(req);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeRequest(Request req) {
|
||||
mRequestQueue.remove(req);
|
||||
}
|
||||
|
||||
public boolean hasPendingRequests() {
|
||||
return !mRequestQueue.isEmpty();
|
||||
}
|
||||
|
||||
public void clearRequests() {
|
||||
mRequestQueue.clear();
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2009 Marc Blank
|
||||
* Licensed to 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.emailsync;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||
import com.android.emailcommon.provider.ProviderUnavailableException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* EmailSyncAlarmReceiver (USAR) is used by the SyncManager to start up-syncs of user-modified data
|
||||
* back to the Exchange server.
|
||||
*
|
||||
* Here's how this works for Email, for example:
|
||||
*
|
||||
* 1) User modifies or deletes an email from the UI.
|
||||
* 2) SyncManager, which has a ContentObserver watching the Message class, is alerted to a change
|
||||
* 3) SyncManager sets an alarm (to be received by USAR) for a few seconds in the
|
||||
* future (currently 15), the delay preventing excess syncing (think of it as a debounce mechanism).
|
||||
* 4) ESAR Receiver's onReceive method is called
|
||||
* 5) ESAR goes through all change and deletion records and compiles a list of mailboxes which have
|
||||
* changes to be uploaded.
|
||||
* 6) ESAR calls SyncManager to start syncs of those mailboxes
|
||||
*
|
||||
* If EmailProvider isn't available, the upsyncs will happen the next time ExchangeService starts
|
||||
*
|
||||
*/
|
||||
public class EmailSyncAlarmReceiver extends BroadcastReceiver {
|
||||
final String[] MAILBOX_DATA_PROJECTION = {MessageColumns.MAILBOX_KEY};
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
handleReceive(context);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void handleReceive(Context context) {
|
||||
ArrayList<Long> mailboxesToNotify = new ArrayList<Long>();
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
|
||||
// Get a selector for EAS accounts (we don't want to sync on changes to POP/IMAP messages)
|
||||
String selector = SyncManager.getAccountSelector();
|
||||
|
||||
try {
|
||||
// Find all of the deletions
|
||||
Cursor c = cr.query(Message.DELETED_CONTENT_URI, MAILBOX_DATA_PROJECTION, selector,
|
||||
null, null);
|
||||
if (c == null) throw new ProviderUnavailableException();
|
||||
try {
|
||||
// Keep track of which mailboxes to notify; we'll only notify each one once
|
||||
while (c.moveToNext()) {
|
||||
long mailboxId = c.getLong(0);
|
||||
if (!mailboxesToNotify.contains(mailboxId)) {
|
||||
mailboxesToNotify.add(mailboxId);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
||||
// Now, find changed messages
|
||||
c = cr.query(Message.UPDATED_CONTENT_URI, MAILBOX_DATA_PROJECTION, selector,
|
||||
null, null);
|
||||
if (c == null) throw new ProviderUnavailableException();
|
||||
try {
|
||||
// Keep track of which mailboxes to notify; we'll only notify each one once
|
||||
while (c.moveToNext()) {
|
||||
long mailboxId = c.getLong(0);
|
||||
if (!mailboxesToNotify.contains(mailboxId)) {
|
||||
mailboxesToNotify.add(mailboxId);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
||||
// Request service from the mailbox
|
||||
for (Long mailboxId: mailboxesToNotify) {
|
||||
SyncManager.serviceRequest(mailboxId, SyncManager.SYNC_UPSYNC);
|
||||
}
|
||||
} catch (ProviderUnavailableException e) {
|
||||
Log.e("EmailSyncAlarmReceiver", "EmailProvider unavailable; aborting alarm receiver");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 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.emailsync;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Date;
|
||||
|
||||
public class FileLogger {
|
||||
private static FileLogger LOGGER = null;
|
||||
private static FileWriter sLogWriter = null;
|
||||
public static String LOG_FILE_NAME =
|
||||
Environment.getExternalStorageDirectory() + "/emaillog.txt";
|
||||
|
||||
public synchronized static FileLogger getLogger (Context c) {
|
||||
LOGGER = new FileLogger();
|
||||
return LOGGER;
|
||||
}
|
||||
|
||||
private FileLogger() {
|
||||
try {
|
||||
sLogWriter = new FileWriter(LOG_FILE_NAME, true);
|
||||
} catch (IOException e) {
|
||||
// Doesn't matter
|
||||
}
|
||||
}
|
||||
|
||||
static public synchronized void close() {
|
||||
if (sLogWriter != null) {
|
||||
try {
|
||||
sLogWriter.close();
|
||||
} catch (IOException e) {
|
||||
// Doesn't matter
|
||||
}
|
||||
sLogWriter = null;
|
||||
}
|
||||
}
|
||||
|
||||
static public synchronized void log(Exception e) {
|
||||
if (sLogWriter != null) {
|
||||
log("Exception", "Stack trace follows...");
|
||||
PrintWriter pw = new PrintWriter(sLogWriter);
|
||||
e.printStackTrace(pw);
|
||||
pw.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
|
||||
// I don't use DateFormat here because (in my experience), it's much slower
|
||||
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();
|
||||
|
||||
if (sLogWriter != null) {
|
||||
try {
|
||||
sLogWriter.write(s);
|
||||
sLogWriter.flush();
|
||||
} catch (IOException e) {
|
||||
// Something might have happened to the sdcard
|
||||
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
|
||||
// If the card is mounted and we can create the writer, retry
|
||||
LOGGER = new FileLogger();
|
||||
if (sLogWriter != null) {
|
||||
try {
|
||||
log("FileLogger", "Exception writing log; recreating...");
|
||||
log(prefix, str);
|
||||
} catch (Exception e1) {
|
||||
// Nothing to do at this point
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2009 Marc Blank
|
||||
* Licensed to 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.emailsync;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
|
||||
/**
|
||||
* MailboxAlarmReceiver is used to "wake up" the ExchangeService at the appropriate time(s). It may
|
||||
* also be used for individual sync adapters, but this isn't implemented at the present time.
|
||||
*
|
||||
*/
|
||||
public class MailboxAlarmReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
long mailboxId = intent.getLongExtra("mailbox", SyncManager.EXTRA_MAILBOX_ID);
|
||||
// EXCHANGE_SERVICE_MAILBOX_ID tells us that the service is asking to be started
|
||||
if (mailboxId == SyncManager.SYNC_SERVICE_MAILBOX_ID) {
|
||||
context.startService(new Intent(context, SyncManager.class));
|
||||
} else {
|
||||
SyncManager.alert(context, mailboxId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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.emailsync;
|
||||
|
||||
import com.android.emailsync.Request;
|
||||
|
||||
/**
|
||||
* MessageMoveRequest is the EAS wrapper for requesting a "move to folder"
|
||||
*/
|
||||
public class MessageMoveRequest extends Request {
|
||||
public final long mMailboxId;
|
||||
|
||||
public MessageMoveRequest(long messageId, long mailboxId) {
|
||||
super(messageId);
|
||||
mMailboxId = mailboxId;
|
||||
}
|
||||
|
||||
// MessageMoveRequests are unique by their message id (i.e. it's meaningless to have two
|
||||
// separate message moves queued at the same time)
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof MessageMoveRequest)) return false;
|
||||
return ((MessageMoveRequest)o).mMessageId == mMessageId;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return (int)mMessageId;
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2009 Marc Blank
|
||||
* Licensed to 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.emailsync;
|
||||
|
||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||
|
||||
/**
|
||||
* PartRequest is the wrapper for attachment loading requests. In addition to information about
|
||||
* the attachment to be loaded, it also contains the callback to be used for status/progress
|
||||
* updates to the UI.
|
||||
*/
|
||||
public class PartRequest extends Request {
|
||||
public final Attachment mAttachment;
|
||||
public final String mDestination;
|
||||
public final String mContentUriString;
|
||||
public final String mLocation;
|
||||
|
||||
public PartRequest(Attachment _att, String _destination, String _contentUriString) {
|
||||
super(_att.mMessageKey);
|
||||
mAttachment = _att;
|
||||
mLocation = mAttachment.mLocation;
|
||||
mDestination = _destination;
|
||||
mContentUriString = _contentUriString;
|
||||
}
|
||||
|
||||
// PartRequests are unique by their attachment id (i.e. multiple attachments might be queued
|
||||
// for a particular message, but any individual attachment can only be loaded once)
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof PartRequest)) return false;
|
||||
return ((PartRequest)o).mAttachment.mId == mAttachment.mId;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return (int)mAttachment.mId;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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.emailsync;
|
||||
|
||||
/**
|
||||
* Requests for mailbox actions are handled by subclasses of this abstract class.
|
||||
* Three subclasses are now defined: PartRequest (attachment load), MeetingResponseRequest
|
||||
* (respond to a meeting invitation), and MessageMoveRequest (move a message to another folder)
|
||||
*/
|
||||
public abstract class Request {
|
||||
public final long mTimeStamp = System.currentTimeMillis();
|
||||
public final long mMessageId;
|
||||
|
||||
public Request(long messageId) {
|
||||
mMessageId = messageId;
|
||||
}
|
||||
|
||||
// Subclasses of Request may have different semantics regarding equality; therefore,
|
||||
// we force them to implement the equals method
|
||||
public abstract boolean equals(Object o);
|
||||
public abstract int hashCode();
|
||||
}
|
|
@ -215,3 +215,8 @@
|
|||
*** toByteArray(java.io.Reader, java.lang.String);
|
||||
*** toByteArray(java.lang.String);
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class com.android.email.activity.ThreePaneLayout {
|
||||
*** setMessageListWidthAnim(...);
|
||||
*** setMailboxListLeftAnim(...);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2010 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.
|
||||
|
||||
#
|
||||
# You can remove exchange by running this script.
|
||||
#
|
||||
|
||||
set -e # fail fast
|
||||
|
||||
# Step 0. Make sure we're in the right directory, and the user really wants it.
|
||||
|
||||
if [[ ! -d src/com/android/email/ ]] ; then
|
||||
echo "Run the script in the root of the email source tree." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -n "Do you wish to remove exchange support from the email app? (y/N):"
|
||||
|
||||
read answer
|
||||
if [[ "$answer" != y ]] ; then
|
||||
echo "Aborted." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Step 1. Remove all Exchange related packages.
|
||||
|
||||
rm -fr src/com/android/exchange/ \
|
||||
tests/src/com/android/exchange/
|
||||
|
||||
|
||||
# Step 2. Remove lines surrounded by START-EXCHANGE and END-EXCHANGE
|
||||
|
||||
find . \( -name '*.java' -o -name '*.xml' -o -name 'Android.mk' \) -print0 |
|
||||
xargs -0 sed -i "" -e '/EXCHANGE-REMOVE-SECTION-START/,/EXCHANGE-REMOVE-SECTION-END/d'
|
||||
|
||||
|
||||
# Step 3. Remove all imports from com.android.exchange (and its subpackages).
|
||||
|
||||
find . -name '*.java' -print0 |
|
||||
xargs -0 sed -i "" -e '/^import com\.android\.exchange/d'
|
||||
|
||||
|
||||
echo ""
|
||||
echo "Exchange support has been successfully removed."
|
||||
|
||||
exit 0
|
After Width: | Height: | Size: 288 B |
After Width: | Height: | Size: 119 B |
After Width: | Height: | Size: 374 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1020 B |
After Width: | Height: | Size: 705 B |
After Width: | Height: | Size: 325 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 541 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 105 B |
After Width: | Height: | Size: 425 B |
After Width: | Height: | Size: 428 B |
After Width: | Height: | Size: 214 B |
After Width: | Height: | Size: 395 B |
After Width: | Height: | Size: 141 B |
After Width: | Height: | Size: 239 B |
After Width: | Height: | Size: 309 B |
After Width: | Height: | Size: 150 B |
After Width: | Height: | Size: 312 B |
After Width: | Height: | Size: 287 B |
After Width: | Height: | Size: 417 B |
After Width: | Height: | Size: 786 B |
After Width: | Height: | Size: 350 B |
After Width: | Height: | Size: 300 B |
After Width: | Height: | Size: 436 B |
After Width: | Height: | Size: 393 B |
After Width: | Height: | Size: 832 B |
After Width: | Height: | Size: 566 B |
After Width: | Height: | Size: 845 B |
After Width: | Height: | Size: 409 B |
After Width: | Height: | Size: 432 B |
After Width: | Height: | Size: 951 B |
After Width: | Height: | Size: 501 B |
After Width: | Height: | Size: 692 B |
After Width: | Height: | Size: 530 B |
After Width: | Height: | Size: 844 B |
After Width: | Height: | Size: 937 B |
After Width: | Height: | Size: 830 B |
After Width: | Height: | Size: 923 B |
After Width: | Height: | Size: 806 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 526 B |
After Width: | Height: | Size: 428 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 260 B |
After Width: | Height: | Size: 140 B |
After Width: | Height: | Size: 266 B |
After Width: | Height: | Size: 127 B |
After Width: | Height: | Size: 322 B |
After Width: | Height: | Size: 817 B |
After Width: | Height: | Size: 715 B |
After Width: | Height: | Size: 538 B |
After Width: | Height: | Size: 419 B |
After Width: | Height: | Size: 1.0 KiB |