[automerger] AOSP/Email - bug fix: do not allow composing message with hidden private data attachments. am: e81f6f92bb am: 2f17f9f018 am: 34534259de am: 33587b4e1d am: 30a7c1118c am: ef35412cb6 am: f7005dabcd am: 86e89cca74
am: 800736df79

Change-Id: I7602dcd26fe1d1a31a86c7e1df8b143208e01b6c
diff --git a/Android.mk b/Android.mk
index cfc205b..c354471 100644
--- a/Android.mk
+++ b/Android.mk
@@ -45,17 +45,17 @@
     libphotoviewer_appcompat \
     android-opt-bitmap \
     android-opt-datetimepicker \
-    android-support-compat \
-    android-support-media-compat \
-    android-support-core-utils \
-    android-support-core-ui \
-    android-support-fragment \
-    android-support-v7-appcompat \
-    android-support-v7-gridlayout \
-    android-support-v13
+    androidx.core_core \
+    androidx.media_media \
+    androidx.legacy_legacy-support-core-utils \
+    androidx.legacy_legacy-support-core-ui \
+    androidx.fragment_fragment \
+    androidx.appcompat_appcompat \
+    androidx.gridlayout_gridlayout \
+    androidx.legacy_legacy-support-v13
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-annotations \
+    androidx.annotation_annotation \
     android-common \
     guava \
     owasp-html-sanitizer
@@ -64,6 +64,8 @@
 
 LOCAL_PACKAGE_NAME := Email
 
+LOCAL_PRODUCT_MODULE := true
+
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags $(unified_email_dir)/proguard.flags
 ifeq (eng,$(TARGET_BUILD_VARIANT))
   LOCAL_PROGUARD_FLAG_FILES += proguard-test.flags
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ae13064..4fc82cb 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -47,7 +47,7 @@
     <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
 
     <!-- This needs to be present when we are doing unbundled releases. -->
-    <uses-sdk android:targetSdkVersion="21" android:minSdkVersion="14" />
+    <uses-sdk android:targetSdkVersion="24" android:minSdkVersion="14" />
 
     <!-- additional uses -->
 
@@ -486,7 +486,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 +508,7 @@
         <service
             android:name=".service.AttachmentService"
             android:enabled="false"
+            android:permission="android.permission.BIND_JOB_SERVICE"
             >
         </service>
 
@@ -725,6 +728,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/CleanSpec.mk b/CleanSpec.mk
index 1d28a67..dafdcaa 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -60,3 +60,4 @@
 $(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 $(PRODUCT_OUT)/system/app/Email)
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..8d2595f
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,3 @@
+# Please update this list if you find better candidates.
+jeffbailey@google.com
+rtenneti@google.com
diff --git a/emailcommon/Android.mk b/emailcommon/Android.mk
index fc47652..165f302 100644
--- a/emailcommon/Android.mk
+++ b/emailcommon/Android.mk
@@ -34,12 +34,12 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     guava \
     android-common \
-    android-support-annotations
+    androidx.annotation_annotation
 
 LOCAL_JAVA_LIBRARIES := \
     org.apache.http.legacy
 
-LOCAL_STATIC_ANDROID_LIBRARIES += android-support-compat
+LOCAL_STATIC_ANDROID_LIBRARIES += androidx.core_core
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/emailcommon)
 LOCAL_SRC_FILES += \
diff --git a/emailcommon/AndroidManifest.xml b/emailcommon/AndroidManifest.xml
index 4659bbb..bd1d35d 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="19" android:minSdkVersion="14" />
+    <uses-sdk android:targetSdkVersion="24" android:minSdkVersion="14" />
 </manifest>
diff --git a/emailcommon/src/com/android/emailcommon/provider/MessageMove.java b/emailcommon/src/com/android/emailcommon/provider/MessageMove.java
index 9d0cae1..2b67544 100644
--- a/emailcommon/src/com/android/emailcommon/provider/MessageMove.java
+++ b/emailcommon/src/com/android/emailcommon/provider/MessageMove.java
@@ -5,7 +5,7 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
-import android.support.v4.util.LongSparseArray;
+import androidx.collection.LongSparseArray;
 
 import com.android.mail.utils.LogUtils;
 
diff --git a/emailcommon/src/com/android/emailcommon/provider/MessageStateChange.java b/emailcommon/src/com/android/emailcommon/provider/MessageStateChange.java
index 78b84cc..2feea0d 100644
--- a/emailcommon/src/com/android/emailcommon/provider/MessageStateChange.java
+++ b/emailcommon/src/com/android/emailcommon/provider/MessageStateChange.java
@@ -4,7 +4,7 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
-import android.support.v4.util.LongSparseArray;
+import androidx.collection.LongSparseArray;
 
 import com.android.mail.utils.LogUtils;
 
diff --git a/emailcommon/src/com/android/emailcommon/utility/EmailAsyncTask.java b/emailcommon/src/com/android/emailcommon/utility/EmailAsyncTask.java
index e0db427..492816b 100644
--- a/emailcommon/src/com/android/emailcommon/utility/EmailAsyncTask.java
+++ b/emailcommon/src/com/android/emailcommon/utility/EmailAsyncTask.java
@@ -263,14 +263,17 @@
         return mInnerTask.get();
     }
 
+    @VisibleForTesting
     /* package */ final Result callDoInBackgroundForTest(Params... params) {
         return mInnerTask.doInBackground(params);
     }
 
+    @VisibleForTesting
     /* package */ final void callOnCancelledForTest(Result result) {
         mInnerTask.onCancelled(result);
     }
 
+    @VisibleForTesting
     /* package */ final void callOnPostExecuteForTest(Result result) {
         mInnerTask.onPostExecute(result);
     }
diff --git a/proguard-test.flags b/proguard-test.flags
index 26d7dea..3daa0be 100644
--- a/proguard-test.flags
+++ b/proguard-test.flags
@@ -91,8 +91,12 @@
   *** tempFileExistsForTest();
 }
 
+-keepclasseswithmembers class com.android.emailcommon.utility.EmailAsyncTask {
+  *** callDoInBackgroundForTest(Params...);
+}
 -keepclasseswithmembers class com.android.emailcommon.utility.EmailAsyncTask$Tracker {
   <init>();
   *** getTaskCountForTest();
   *** containsTaskForTest(com.android.emailcommon.utility.EmailAsyncTask);
 }
+-keep class com.android.emailcommon.utility.DelayedOperations
diff --git a/proguard.flags b/proguard.flags
index ce50245..0a9c2f1 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -5,4 +5,4 @@
 }
 
 -keep class com.android.email.activity.setup.AccountSetupFinal
--keep class com.android.email.activity.setup.AccountSettingsFragment
\ No newline at end of file
+-keep class com.android.email.activity.setup.AccountSettingsFragment
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 4bd9d4d..1f0956b 100644
--- a/provider_src/com/android/email/provider/EmailProvider.java
+++ b/provider_src/com/android/email/provider/EmailProvider.java
@@ -129,6 +129,7 @@
 import com.android.mail.utils.MimeType;
 import com.android.mail.utils.Utils;
 import com.android.mail.widget.BaseWidgetProvider;
+import com.android.mail.widget.WidgetService;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
@@ -6139,6 +6140,9 @@
         Context context = getContext();
         // Lazily initialize these
         if (mAppWidgetManager == null) {
+            if (!WidgetService.isWidgetSupported(context)) {
+                return;
+            }
             mAppWidgetManager = AppWidgetManager.getInstance(context);
             mEmailComponent = new ComponentName(context, WidgetProvider.getProviderName(context));
         }
@@ -6353,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);
 
@@ -6363,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/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/provider_src/com/android/email/service/EmailServiceUtils.java b/provider_src/com/android/email/service/EmailServiceUtils.java
index 3532689..183c0cd 100644
--- a/provider_src/com/android/email/service/EmailServiceUtils.java
+++ b/provider_src/com/android/email/service/EmailServiceUtils.java
@@ -46,7 +46,7 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.RawContacts;
 import android.provider.SyncStateContract;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
 import android.text.TextUtils;
 
 import com.android.email.R;
diff --git a/res/layout-w600dp/account_setup_options_fragment.xml b/res/layout-w600dp/account_setup_options_fragment.xml
index e92b2eb..140d078 100644
--- a/res/layout-w600dp/account_setup_options_fragment.xml
+++ b/res/layout-w600dp/account_setup_options_fragment.xml
@@ -24,7 +24,7 @@
     android:orientation="vertical"
     >
     <!-- Spinners in a table to line everything up nicely -->
-    <android.support.v7.widget.GridLayout
+    <androidx.gridlayout.widget.GridLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         app:columnCount="2" >
@@ -56,7 +56,7 @@
             app:layout_gravity="center_vertical|fill_horizontal"
             android:visibility="gone" />
 
-    </android.support.v7.widget.GridLayout>
+    </androidx.gridlayout.widget.GridLayout>
     <CheckBox
         android:id="@+id/account_notify"
         style="@style/account_setup_checkbox"
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&#8230;</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 e57b418..c9254ad 100644
--- a/src/com/android/email/EmailNotificationController.java
+++ b/src/com/android/email/EmailNotificationController.java
@@ -32,7 +32,7 @@
 import android.os.Looper;
 import android.os.Process;
 import android.provider.Settings;
-import android.support.v4.app.NotificationCompat;
+import androidx.core.app.NotificationCompat;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 
@@ -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;
@@ -114,7 +118,7 @@
     }
 
     /**
-     * Returns a {@link android.support.v4.app.NotificationCompat.Builder} for an event with the
+     * Returns a {@link androidx.core.app.NotificationCompat.Builder} for an event with the
      * given account. The account contains specific rules on ring tone usage and these will be used
      * to modify the notification behaviour.
      *
@@ -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) {
diff --git a/src/com/android/email/activity/setup/AccountSettingsFragment.java b/src/com/android/email/activity/setup/AccountSettingsFragment.java
index 30c3d9c..a1cea58 100644
--- a/src/com/android/email/activity/setup/AccountSettingsFragment.java
+++ b/src/com/android/email/activity/setup/AccountSettingsFragment.java
@@ -41,7 +41,7 @@
 import android.provider.CalendarContract;
 import android.provider.ContactsContract;
 import android.provider.Settings;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
 import android.text.TextUtils;
 import android.view.Menu;
 import android.view.MenuInflater;
diff --git a/src/com/android/email/activity/setup/AccountSetupFinal.java b/src/com/android/email/activity/setup/AccountSetupFinal.java
index adaa32a..0eabebf 100644
--- a/src/com/android/email/activity/setup/AccountSetupFinal.java
+++ b/src/com/android/email/activity/setup/AccountSetupFinal.java
@@ -36,7 +36,7 @@
 import android.database.Cursor;
 import android.os.Bundle;
 import android.provider.ContactsContract;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
diff --git a/src/com/android/email/activity/setup/EmailPreferenceActivity.java b/src/com/android/email/activity/setup/EmailPreferenceActivity.java
index cbb47b9..c8e8928 100644
--- a/src/com/android/email/activity/setup/EmailPreferenceActivity.java
+++ b/src/com/android/email/activity/setup/EmailPreferenceActivity.java
@@ -21,7 +21,7 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
diff --git a/src/com/android/email/activity/setup/MailboxSettings.java b/src/com/android/email/activity/setup/MailboxSettings.java
index 42ae407..eecb797 100644
--- a/src/com/android/email/activity/setup/MailboxSettings.java
+++ b/src/com/android/email/activity/setup/MailboxSettings.java
@@ -34,7 +34,7 @@
 import android.preference.Preference.OnPreferenceChangeListener;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceFragment;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
 import android.text.TextUtils;
 import android.view.MenuItem;
 
diff --git a/tests/Android.mk b/tests/Android.mk
index 5598c2e..d5e9d96 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -24,7 +24,7 @@
 # We only want this apk build for tests.
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
 
 # For LOCAL_JAVA_LANGUAGE_VERSION >= 1.7, OpenJDK 9 javac generates synthetic calls to
 # Objects.requireNonNull() which was only added in Android API level 19. Thus, this must
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 8169f68..b5e087c 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -28,9 +28,9 @@
     <!--
     This declares that this app uses the instrumentation test runner targeting
     the package of com.android.email.  To run the tests use the command:
-    "adb shell am instrument -w com.android.email.tests/android.support.test.runner.AndroidJUnitRunner"
+    "adb shell am instrument -w com.android.email.tests/androidx.test.runner.AndroidJUnitRunner"
     -->
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="com.android.email"
                      android:label="Tests for Email."/>
 
diff --git a/tests/src/com/android/email/DummyFlakyTest.java b/tests/src/com/android/email/DummyFlakyTest.java
index a7278b6..99e37b4 100644
--- a/tests/src/com/android/email/DummyFlakyTest.java
+++ b/tests/src/com/android/email/DummyFlakyTest.java
@@ -16,7 +16,8 @@
 
 package com.android.email;
 
-import android.support.test.filters.FlakyTest;
+import androidx.test.filters.FlakyTest;
+
 import org.junit.Test;
 
 /**
diff --git a/tests/src/com/android/email/ThrottleTest.java b/tests/src/com/android/email/ThrottleTest.java
index 49adea7..e31c513 100644
--- a/tests/src/com/android/email/ThrottleTest.java
+++ b/tests/src/com/android/email/ThrottleTest.java
@@ -17,6 +17,7 @@
 package com.android.email;
 
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -37,7 +38,8 @@
     private final CountingRunnable mRunnable = new CountingRunnable();
     private final MockClock mClock = new MockClock();
     private final MockTimer mTimer = new MockTimer(mClock);
-    private final Throttle mTarget = new Throttle("test", mRunnable, new CallItNowHandler(),
+    private final Throttle mTarget = new Throttle("test", mRunnable,
+            new CallItNowHandler(Looper.getMainLooper()),
             MIN_TIMEOUT, MAX_TIMEOUT, mClock, mTimer);
 
     /**
@@ -155,9 +157,13 @@
 
     /**
      * Dummy {@link Handler} that executes {@link Runnable}s passed to {@link Handler#post}
-     * immediately on the current thread.
+     * immediately via the provided {@link Looper}.
      */
     private static class CallItNowHandler extends Handler {
+        public CallItNowHandler(Looper looper) {
+            super(looper);
+        }
+
         @Override
         public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
             msg.getCallback().run();