From 5676546cb746db3fa5f5338c59812de89c794fa0 Mon Sep 17 00:00:00 2001 From: Oli Lan Date: Tue, 15 Mar 2022 16:54:43 +0000 Subject: [PATCH] Add a delay between the photo picker and the crop UI. This adds a short delay before showing the crop UI after the photo picker, to allow the photo picker exit animation to complete. An interaction between the picker exit animation and the crop entry animation causes visual jank without this delay. Bug: 224477967 Test: install and exercise UI Change-Id: Iaae0703617c1a6eb2f0337e7642059d1788be058 --- .../users/AvatarPhotoController.java | 23 +++++++++++++++---- .../settingslib/utils/ThreadUtils.java | 7 ++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java index 0cb2c0b22a4c5..63a9f0c5c7f44 100644 --- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java +++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java @@ -78,6 +78,11 @@ class AvatarPhotoController { static final int REQUEST_CODE_TAKE_PHOTO = 1002; static final int REQUEST_CODE_CROP_PHOTO = 1003; + /** + * Delay to allow the photo picker exit animation to complete before the crop activity opens. + */ + private static final long DELAY_BEFORE_CROP_MILLIS = 150; + private static final String IMAGES_DIR = "multi_user"; private static final String PRE_CROP_PICTURE_FILE_NAME = "PreCropEditUserPhoto.jpg"; private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg"; @@ -131,13 +136,15 @@ class AvatarPhotoController { mAvatarUi.returnUriResult(pictureUri); return true; case REQUEST_CODE_TAKE_PHOTO: - case REQUEST_CODE_CHOOSE_PHOTO: if (mTakePictureUri.equals(pictureUri)) { cropPhoto(pictureUri); } else { - copyAndCropPhoto(pictureUri); + copyAndCropPhoto(pictureUri, false); } return true; + case REQUEST_CODE_CHOOSE_PHOTO: + copyAndCropPhoto(pictureUri, true); + return true; } return false; } @@ -154,7 +161,7 @@ class AvatarPhotoController { mAvatarUi.startActivityForResult(intent, REQUEST_CODE_CHOOSE_PHOTO); } - private void copyAndCropPhoto(final Uri pictureUri) { + private void copyAndCropPhoto(final Uri pictureUri, boolean delayBeforeCrop) { try { ThreadUtils.postOnBackgroundThread(() -> { final ContentResolver cr = mContextInjector.getContentResolver(); @@ -165,11 +172,17 @@ class AvatarPhotoController { Log.w(TAG, "Failed to copy photo", e); return; } - ThreadUtils.postOnMainThread(() -> { + Runnable cropRunnable = () -> { if (!mAvatarUi.isFinishing()) { cropPhoto(mPreCropPictureUri); } - }); + }; + if (delayBeforeCrop) { + ThreadUtils.postOnMainThreadDelayed(cropRunnable, DELAY_BEFORE_CROP_MILLIS); + } else { + ThreadUtils.postOnMainThread(cropRunnable); + } + }).get(); } catch (InterruptedException | ExecutionException e) { Log.e(TAG, "Error performing copy-and-crop", e); diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java index 69f1c17f97b11..2c1d5da5e9416 100644 --- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java @@ -84,6 +84,13 @@ public class ThreadUtils { getUiThreadHandler().post(runnable); } + /** + * Posts the runnable on the main thread with a delay. + */ + public static void postOnMainThreadDelayed(Runnable runnable, long delayMillis) { + getUiThreadHandler().postDelayed(runnable, delayMillis); + } + private static synchronized ExecutorService getThreadExecutor() { if (sThreadExecutor == null) { sThreadExecutor = Executors.newFixedThreadPool(