DO NOT MERGE - Skip qt-dev-plus-aosp-without-vendor (5713463) in stage-aosp-master
Bug: 134405016
Change-Id: I7e836f2692bac2b6bd7c5c83420fde7dfa56ffc4
diff --git a/Android.mk b/Android.mk
index b04fc97..41b04fd 100644
--- a/Android.mk
+++ b/Android.mk
@@ -45,7 +45,6 @@
libchips \
libphotoviewer_appcompat \
android-opt-bitmap \
- android-opt-datetimepicker \
androidx.core_core \
androidx.media_media \
androidx.legacy_legacy-support-core-utils \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 71648e8..b4450fc 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -45,9 +45,10 @@
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- This needs to be present when we are doing unbundled releases. -->
- <uses-sdk android:targetSdkVersion="24" android:minSdkVersion="14" />
+ <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="14" />
<!-- additional uses -->
@@ -486,7 +487,9 @@
</intent-filter>
</receiver>
<service
- android:name=".service.EmailBroadcastProcessorService" />
+ android:name=".service.EmailBroadcastProcessorService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:exported="true" />
<!-- Support for DeviceAdmin / DevicePolicyManager. See SecurityPolicy class for impl. -->
<receiver
@@ -506,6 +509,7 @@
<service
android:name=".service.AttachmentService"
android:enabled="false"
+ android:permission="android.permission.BIND_JOB_SERVICE"
>
</service>
@@ -685,6 +689,7 @@
<provider
android:name=".provider.EmailProvider"
android:authorities="com.android.email.provider;com.android.email.notifier"
+ android:enabled="true"
android:exported="true"
android:permission="com.android.email.permission.ACCESS_PROVIDER"
android:label="@string/app_name"
@@ -725,6 +730,7 @@
</service>
<service android:name="com.android.email.EmailIntentService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false">
<intent-filter>
<action android:name="com.android.mail.action.RESEND_NOTIFICATIONS" />
diff --git a/emailcommon/AndroidManifest.xml b/emailcommon/AndroidManifest.xml
index bd1d35d..88573f7 100644
--- a/emailcommon/AndroidManifest.xml
+++ b/emailcommon/AndroidManifest.xml
@@ -2,5 +2,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.emailcommon"
android:versionCode="1">
- <uses-sdk android:targetSdkVersion="24" android:minSdkVersion="14" />
+ <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="14" />
</manifest>
diff --git a/provider_src/com/android/email/EmailIntentService.java b/provider_src/com/android/email/EmailIntentService.java
index 0c6d761..5924c90 100644
--- a/provider_src/com/android/email/EmailIntentService.java
+++ b/provider_src/com/android/email/EmailIntentService.java
@@ -29,12 +29,12 @@
private static final String LOG_TAG = LogTag.getLogTag();
public EmailIntentService() {
- super("EmailIntentService");
+ super();
}
@Override
- protected void onHandleIntent(final Intent intent) {
- super.onHandleIntent(intent);
+ protected void onHandleWork(final Intent intent) {
+ super.onHandleWork(intent);
if (UIProvider.ACTION_UPDATE_NOTIFICATION.equals(intent.getAction())) {
final NotificationController nc =
diff --git a/provider_src/com/android/email/provider/EmailProvider.java b/provider_src/com/android/email/provider/EmailProvider.java
index 00d608f..9dd2d2e 100644
--- a/provider_src/com/android/email/provider/EmailProvider.java
+++ b/provider_src/com/android/email/provider/EmailProvider.java
@@ -1317,8 +1317,10 @@
uri.getQueryParameter(EmailContent.SUPPRESS_COMBINED_ACCOUNT_PARAM);
final boolean suppressCombined =
suppressParam != null && Boolean.parseBoolean(suppressParam);
- c = uiAccounts(projection, suppressCombined);
- return c;
+ // TODO(rtenneti): Enable notifications.
+ // c = uiAccounts(projection, suppressCombined);
+ // return c;
+ return null;
case UI_UNDO:
return uiUndo(projection);
case UI_SUBFOLDERS:
@@ -1346,8 +1348,10 @@
c = uiQuery(match, uri, projection, unseenOnly);
return c;
case UI_FOLDERS:
- c = uiFolders(uri, projection);
- return c;
+ // TODO(rtenneti): Enable notifications.
+ // c = uiFolders(uri, projection);
+ // return c;
+ return null;
case UI_FOLDER_LOAD_MORE:
c = uiFolderLoadMore(getMailbox(uri));
return c;
@@ -1539,7 +1543,8 @@
}
if ((c != null) && !isTemporary()) {
- c.setNotificationUri(getContext().getContentResolver(), uri);
+ // TODO(rtenneti): Enable notifications.
+ // c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c;
}
@@ -2546,7 +2551,8 @@
final Set<Uri> notifications = getBatchNotificationsSet();
setBatchNotificationsSet(null);
for (final Uri uri : notifications) {
- context.getContentResolver().notifyChange(uri, null);
+ // TODO(rtenneti): Enable notifications.
+ // context.getContentResolver().notifyChange(uri, null);
}
}
}
@@ -2562,7 +2568,8 @@
@Override
public void attachmentChanged(final Context context, final long id, final int flags) {
// The default implementation delegates to the real service.
- AttachmentService.attachmentChanged(context, id, flags);
+ // TODO(rtenneti): Enable AttachmentService.
+ // AttachmentService.attachmentChanged(context, id, flags);
}
};
private EmailAttachmentService mAttachmentService = DEFAULT_ATTACHMENT_SERVICE;
@@ -3976,7 +3983,8 @@
} finally {
accountIdCursor.close();
}
- mc.setNotificationUri(context.getContentResolver(), UIPROVIDER_ALL_ACCOUNTS_NOTIFIER);
+ // TODO(rtenneti): Enable notifications.
+ // mc.setNotificationUri(context.getContentResolver(), UIPROVIDER_ALL_ACCOUNTS_NOTIFIER);
return mc;
}
@@ -4637,8 +4645,9 @@
// Return real and virtual mailboxes alike
final Cursor rawc = db.rawQuery(genQueryAccountAllMailboxes(uiProjection),
new String[] {id});
- rawc.setNotificationUri(context.getContentResolver(), notifyUri);
- vc.setNotificationUri(context.getContentResolver(), notifyUri);
+ // TODO(rtenneti): Enable notifications.
+ // rawc.setNotificationUri(context.getContentResolver(), notifyUri);
+ // vc.setNotificationUri(context.getContentResolver(), notifyUri);
if (rawc.getCount() > 0) {
c = new MergeCursor(new Cursor[]{rawc, vc});
} else {
@@ -4779,7 +4788,8 @@
break;
}
if (notifyUri != null) {
- c.setNotificationUri(resolver, notifyUri);
+ // TODO(rtenneti): Enable notifications.
+ // c.setNotificationUri(resolver, notifyUri);
}
return c;
}
@@ -5234,7 +5244,8 @@
mailPrefs.setConversationOverviewMode(overviewMode);
}
- c.getContentResolver().notifyChange(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null, false);
+ // TODO(rtenneti): Enable notifications.
+ // c.getContentResolver().notifyChange(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null, false);
return 1;
}
@@ -5711,7 +5722,8 @@
if (batchNotifications != null) {
batchNotifications.add(notifyUri);
} else {
- getContext().getContentResolver().notifyChange(notifyUri, null);
+ // TODO(rtenneti): Enable notifications.
+ // getContext().getContentResolver().notifyChange(notifyUri, null);
}
}
@@ -6357,7 +6369,7 @@
// Start/stop the various services depending on whether there are any accounts
// TODO: Make sure that the AttachmentService responds to this request as it
// expects a particular set of data in the intents that it receives or it ignores.
- startOrStopService(enabled, context, new Intent(context, AttachmentService.class));
+ startOrStopService(enabled, context);
final NotificationController controller =
NotificationControllerCreatorHolder.getInstance(context);
@@ -6367,16 +6379,16 @@
}
/**
- * Starts or stops the service as necessary.
+ * Starts or stops the attachment service as necessary.
+ *
* @param enabled If {@code true}, the service will be started. Otherwise, it will be stopped.
* @param context The context to manage the service with.
- * @param intent The intent of the service to be managed.
*/
- private static void startOrStopService(boolean enabled, Context context, Intent intent) {
+ private static void startOrStopService(boolean enabled, Context context) {
if (enabled) {
- context.startService(intent);
+ AttachmentService.startWithoutSpecificAttachmentChange(context);
} else {
- context.stopService(intent);
+ AttachmentService.stop(context);
}
}
diff --git a/provider_src/com/android/email/service/AttachmentService.java b/provider_src/com/android/email/service/AttachmentService.java
index 6321049..1a628f7 100644
--- a/provider_src/com/android/email/service/AttachmentService.java
+++ b/provider_src/com/android/email/service/AttachmentService.java
@@ -27,15 +27,20 @@
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.Uri;
+import android.os.Build.VERSION_CODES;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.text.format.DateUtils;
+import androidx.core.os.BuildCompat;
+
import com.android.email.AttachmentInfo;
import com.android.email.EmailConnectivityManager;
+import com.android.email.EmailNotificationController;
import com.android.email.NotificationControllerCreatorHolder;
import com.android.email.NotificationController;
+import com.android.email.R;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Attachment;
@@ -121,6 +126,10 @@
// Signify that we are being shut down & destroyed.
private volatile boolean mStop = false;
+ // Indicates whether this service is currently running. Currently, only used for Android O+ to
+ // decide whether to call startForegroundService or startService in start method.
+ private static volatile boolean isRunning = false;
+
EmailConnectivityManager mConnectivityManager;
// Helper class that keeps track of in progress downloads to make sure that they
@@ -586,7 +595,36 @@
debugTrace("Calling startService with extras %d & %d", id, flags);
intent.putExtra(EXTRA_ATTACHMENT_ID, id);
intent.putExtra(EXTRA_ATTACHMENT_FLAGS, flags);
- context.startService(intent);
+ start(context, intent);
+ }
+
+ public static void startWithoutSpecificAttachmentChange(Context context) {
+ LogUtils.d(LOG_TAG, "Going to start AttachmentService without specifying an attachment.");
+
+ Intent intent = new Intent(context, AttachmentService.class);
+ start(context, intent);
+ }
+
+ /**
+ * Starts running attachment service.
+ *
+ * @param intent an intent set to run AttachmentService class
+ */
+ public static void start(Context context, Intent intent) {
+ // TODO(rtenneti): Enable notifications.
+ // if (context.getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O &&
+ // !isRunning) {
+ // LogUtils.i(LOG_TAG, "startForegroundService");
+ // context.startForegroundService(intent);
+ // } else {
+ // LogUtils.i(LOG_TAG, "startService");
+ // context.startService(intent);
+ // }
+ }
+
+ public static void stop(Context context) {
+ Intent intent = new Intent(context, AttachmentService.class);
+ context.stopService(intent);
}
/**
@@ -622,6 +660,16 @@
*/
@Override
public void onCreate() {
+ isRunning = true;
+ if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) {
+ LogUtils.i(LOG_TAG, "startForeground");
+ startForeground(
+ EmailNotificationController.NOTIFICATION_ID_ONGOING_ATTACHMENT,
+ EmailNotificationController.getOngoingDownloadNotification(
+ getApplicationContext(),
+ getApplicationContext().getString(
+ R.string.notification_downloading_attachments_title)));
+ }
// Start up our service thread.
new Thread(this, "AttachmentService").start();
}
@@ -649,6 +697,7 @@
mConnectivityManager.stopWait();
mConnectivityManager = null;
}
+ isRunning = false;
}
/**
diff --git a/provider_src/com/android/email/service/EmailBroadcastProcessorService.java b/provider_src/com/android/email/service/EmailBroadcastProcessorService.java
index 7aa5467..5d264f0 100644
--- a/provider_src/com/android/email/service/EmailBroadcastProcessorService.java
+++ b/provider_src/com/android/email/service/EmailBroadcastProcessorService.java
@@ -17,7 +17,6 @@
package com.android.email.service;
import android.accounts.AccountManager;
-import android.app.IntentService;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
@@ -34,6 +33,8 @@
import android.text.TextUtils;
import android.text.format.DateUtils;
+import androidx.core.app.JobIntentService;
+
import com.android.email.EmailIntentService;
import com.android.email.Preferences;
import com.android.email.R;
@@ -69,7 +70,9 @@
* This also handles the DeviceAdminReceiver in SecurityPolicy, because it is also
* a BroadcastReceiver and requires the same processing semantics.
*/
-public class EmailBroadcastProcessorService extends IntentService {
+public class EmailBroadcastProcessorService extends JobIntentService {
+ public static final int JOB_ID = 200;
+
// Action used for BroadcastReceiver entry point
private static final String ACTION_BROADCAST = "broadcast_receiver";
@@ -81,11 +84,11 @@
private static final String ACTION_UPGRADE_BROADCAST = "upgrade_broadcast_receiver";
public EmailBroadcastProcessorService() {
- // Class name will be the thread name.
- super(EmailBroadcastProcessorService.class.getName());
+ super();
+ }
- // Intent should be redelivered if the process gets killed before completing the job.
- setIntentRedelivery(true);
+ public static void enqueueWork(Context context, Intent work) {
+ enqueueWork(context, EmailBroadcastProcessorService.class, JOB_ID, work);
}
/**
@@ -95,13 +98,13 @@
Intent i = new Intent(context, EmailBroadcastProcessorService.class);
i.setAction(ACTION_BROADCAST);
i.putExtra(Intent.EXTRA_INTENT, broadcastIntent);
- context.startService(i);
+ EmailBroadcastProcessorService.enqueueWork(context, i);
}
public static void processUpgradeBroadcastIntent(final Context context) {
final Intent i = new Intent(context, EmailBroadcastProcessorService.class);
i.setAction(ACTION_UPGRADE_BROADCAST);
- context.startService(i);
+ EmailBroadcastProcessorService.enqueueWork(context, i);
}
/**
@@ -113,11 +116,11 @@
Intent i = new Intent(context, EmailBroadcastProcessorService.class);
i.setAction(ACTION_DEVICE_POLICY_ADMIN);
i.putExtra(EXTRA_DEVICE_POLICY_ADMIN, message);
- context.startService(i);
+ EmailBroadcastProcessorService.enqueueWork(context, i);
}
@Override
- protected void onHandleIntent(Intent intent) {
+ protected void onHandleWork(Intent intent) {
// This method is called on a worker thread.
// Dispatch from entry point
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2f39425..dd1d5c1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -110,6 +110,9 @@
<!-- Notification title when a forwarded attachment couldn't be sent [CHAR LIMIT=30]-->
<string name="forward_download_failed_title">Attachment not forwarded</string>
+ <!-- Notification title when an attachment is being downloaded on Android O and later [CHAR LIMIT=30] -->
+ <string name="notification_downloading_attachments_title">Syncing mail…</string>
+
<!-- Notification ticker when email account authentication fails [CHAR LIMIT=none] -->
<string name="login_failed_ticker">
<xliff:g id="account_name">%s</xliff:g> signin unsuccessful.</string>
diff --git a/src/com/android/email/EmailNotificationController.java b/src/com/android/email/EmailNotificationController.java
index 6773f1b..c9254ad 100644
--- a/src/com/android/email/EmailNotificationController.java
+++ b/src/com/android/email/EmailNotificationController.java
@@ -68,6 +68,10 @@
private static final int NOTIFICATION_ID_ATTACHMENT_WARNING = 3;
private static final int NOTIFICATION_ID_PASSWORD_EXPIRING = 4;
private static final int NOTIFICATION_ID_PASSWORD_EXPIRED = 5;
+ private static final int NOTIFICATION_ID_PERMISSIONS_NEEDED = 6;
+ public static final int NOTIFICATION_ID_ONGOING_ATTACHMENT = 7;
+
+ public static final String NOTIFICATION_CHANNEL_ID_ATTACHMENTS = "^nc_~_z_attachments";
private static final int NOTIFICATION_ID_BASE_MASK = 0xF0000000;
private static final int NOTIFICATION_ID_BASE_LOGIN_WARNING = 0x20000000;
@@ -401,6 +405,31 @@
}
/**
+ * Creates a notification to be used with {@link com.android.email.service.AttachmentService},
+ * which should be launched as a foreground service on Android O+.
+ *
+ * <p>The notification is sent with the lowest priority and contains an indefinite loading bar,
+ * hence "ongoing".
+ *
+ * @param title The text that will be displayed on the ongoing notification.
+ */
+ public static Notification getOngoingDownloadNotification(Context context, String title) {
+ NotificationCompat.Builder builder =
+ new NotificationCompat.Builder(context)
+ .setContentTitle(title)
+ .setVisibility(Notification.VISIBILITY_SECRET)
+ .setProgress(0, 0, true)
+ .setSmallIcon(R.drawable.ic_notification_mail_24dp)
+ .setOngoing(true);
+
+ if (context.getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) {
+ builder.setChannelId(NOTIFICATION_CHANNEL_ID_ATTACHMENTS);
+ }
+
+ return builder.build();
+ }
+
+ /**
* Returns a notification ID for login failed notifications for the given account account.
*/
private static int getLoginFailedNotificationId(long accountId) {