Merge "Revert "Revert "AOSP/Email - Bump targetSdkVersion to 28."""
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9dd32c2..4fc82cb 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -508,6 +508,7 @@
<service
android:name=".service.AttachmentService"
android:enabled="false"
+ android:permission="android.permission.BIND_JOB_SERVICE"
>
</service>
diff --git a/provider_src/com/android/email/provider/EmailProvider.java b/provider_src/com/android/email/provider/EmailProvider.java
index 00d608f..1f0956b 100644
--- a/provider_src/com/android/email/provider/EmailProvider.java
+++ b/provider_src/com/android/email/provider/EmailProvider.java
@@ -6357,7 +6357,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 +6367,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..50ee429 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,35 @@
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) {
+ 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 +659,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 +696,7 @@
mConnectivityManager.stopWait();
mConnectivityManager = null;
}
+ isRunning = false;
}
/**
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) {