From de991f457d0fae9c2a084df02147374d379caa41 Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Tue, 19 Jul 2016 15:46:50 -0700 Subject: [PATCH] Get gestures animation preview image in async loader. When user scrolls in Gestures Settings, the textureview used for the animation video will be destroyed if the view is scrolled outside the screen. When the view is scrolled back in, a slight flicker is seen as the animation video is not instantly made available on the new surface texture. We are now retrieving the preview image in an async loader after the preference is created, so that it will not delay the original loading of the gestures settings page, but the preview will be made available while we initialize the animation video in the new surface texture. Bug: 29790087 Change-Id: I83f4a5bc4f24b7aab4c0cc851cb524c10e74f328 --- .../settings/gestures/GesturePreference.java | 84 ++++++++++++++++--- .../settings/gestures/GestureSettings.java | 17 ++-- 2 files changed, 85 insertions(+), 16 deletions(-) diff --git a/src/com/android/settings/gestures/GesturePreference.java b/src/com/android/settings/gestures/GesturePreference.java index c6ee0a7c0d4..a11455a34b2 100644 --- a/src/com/android/settings/gestures/GesturePreference.java +++ b/src/com/android/settings/gestures/GesturePreference.java @@ -14,13 +14,18 @@ package com.android.settings.gestures; +import android.app.LoaderManager; import android.content.ContentResolver; import android.content.Context; +import android.content.Loader; import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; import android.graphics.SurfaceTexture; import android.media.MediaMetadataRetriever; import android.media.MediaPlayer; import android.net.Uri; +import android.os.Bundle; import android.support.v14.preference.SwitchPreference; import android.support.v7.preference.PreferenceViewHolder; import android.view.View; @@ -31,22 +36,24 @@ import android.util.AttributeSet; import android.util.Log; import com.android.settings.R; +import com.android.settings.utils.AsyncLoader; /** * Preference item for a gesture with a switch to signify if it should be enabled. * This shows the title and description of the gesture along with an animation showing how to do * the gesture */ -public final class GesturePreference extends SwitchPreference { +public final class GesturePreference extends SwitchPreference implements + LoaderManager.LoaderCallbacks { private static final String TAG = "GesturePreference"; private final Context mContext; private Uri mVideoPath; private MediaPlayer mMediaPlayer; - private MediaMetadataRetriever mMediaMetadata; private boolean mAnimationAvailable; - private boolean mPreviewReady; + private boolean mVideoReady; private boolean mScrolling; + private BitmapDrawable mPreviewImage; public GesturePreference(Context context, AttributeSet attrs) { super(context, attrs); @@ -62,15 +69,12 @@ public final class GesturePreference extends SwitchPreference { .authority(context.getPackageName()) .appendPath(String.valueOf(animation)) .build(); - mMediaMetadata = new MediaMetadataRetriever(); - mMediaMetadata.setDataSource(mContext, mVideoPath); mMediaPlayer = MediaPlayer.create(mContext, mVideoPath); if (mMediaPlayer != null) { mMediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() { @Override public void onSeekComplete(MediaPlayer mp) { - mPreviewReady = true; - mMediaPlayer.setOnSeekCompleteListener(null); + mVideoReady = true; } }); @@ -82,6 +86,7 @@ public final class GesturePreference extends SwitchPreference { }); } mAnimationAvailable = true; + } catch (Exception e) { Log.w(TAG, "Animation resource not found. Will not show animation."); } finally { @@ -125,6 +130,7 @@ public final class GesturePreference extends SwitchPreference { int height) { if (mMediaPlayer != null) { mMediaPlayer.setSurface(new Surface(surfaceTexture)); + mVideoReady = false; mMediaPlayer.seekTo(0); } } @@ -136,12 +142,16 @@ public final class GesturePreference extends SwitchPreference { @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { + if (mPreviewImage != null && imageView.getDrawable() == null) { + imageView.setImageDrawable(mPreviewImage); + } + imageView.setVisibility(View.VISIBLE); return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { - if (mPreviewReady && imageView.getVisibility() == View.VISIBLE) { + if (mVideoReady && imageView.getVisibility() == View.VISIBLE) { imageView.setVisibility(View.GONE); } else if (mScrolling) { mScrolling = false; @@ -153,13 +163,14 @@ public final class GesturePreference extends SwitchPreference { } }); + if (mPreviewImage != null) { + imageView.setImageDrawable(mPreviewImage); + } + } @Override public void onDetached() { - if (mMediaMetadata != null) { - mMediaMetadata.release(); - } if (mMediaPlayer != null) { mMediaPlayer.stop(); mMediaPlayer.reset(); @@ -172,4 +183,55 @@ public final class GesturePreference extends SwitchPreference { mScrolling = scrolling; } + void loadPreview(LoaderManager manager, int id) { + Loader loader = manager.initLoader(id, Bundle.EMPTY, this); + } + + private static final class PreviewRetriever extends AsyncLoader { + private Uri mVideoPath; + + public PreviewRetriever(Context context, Uri videoPath) { + super(context); + mVideoPath = videoPath; + } + + @Override + public Bitmap loadInBackground() { + MediaMetadataRetriever mediaMetadata = new MediaMetadataRetriever(); + try { + mediaMetadata.setDataSource(getContext(), mVideoPath); + return mediaMetadata.getFrameAtTime(0); + } catch (Exception e) { + Log.w(TAG, "Unable to get animation preview."); + } finally { + mediaMetadata.release(); + } + return null; + } + + @Override + public void onDiscardResult(final Bitmap result) { + if (result != null && !result.isRecycled()) { + result.recycle(); + } + } + + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new PreviewRetriever(mContext, mVideoPath); + } + + @Override + public void onLoadFinished(final Loader loader, final Bitmap bitmap) { + if (bitmap != null) { + mPreviewImage = new BitmapDrawable(mContext.getResources(), bitmap); + } + } + + @Override + public void onLoaderReset(Loader loader) { + } + } diff --git a/src/com/android/settings/gestures/GestureSettings.java b/src/com/android/settings/gestures/GestureSettings.java index a61509fbf02..37dcc7e26ea 100644 --- a/src/com/android/settings/gestures/GestureSettings.java +++ b/src/com/android/settings/gestures/GestureSettings.java @@ -56,6 +56,10 @@ public class GestureSettings extends SettingsPreferenceFragment implements private static final String PREF_KEY_SWIPE_DOWN_FINGERPRINT = "gesture_swipe_down_fingerprint"; private static final String DEBUG_DOZE_COMPONENT = "debug.doze.component"; private static final String ARG_SCROLL_TO_PREFERENCE = "gesture_scroll_to_preference"; + private static final int PREF_ID_DOUBLE_TAP_POWER = 0; + private static final int PREF_ID_DOUBLE_TWIST = 1; + private static final int PREF_ID_PICK_UP_AND_NUDG = 2; + private static final int PREF_ID_SWIPE_DOWN_FINGERPRINT = 3; private int mScrollPosition = -1; private List mPreferences; @@ -71,7 +75,7 @@ public class GestureSettings extends SettingsPreferenceFragment implements if (isCameraDoubleTapPowerGestureAvailable(getResources())) { int cameraDisabled = Secure.getInt( getContentResolver(), Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0); - addPreference(PREF_KEY_DOUBLE_TAP_POWER, cameraDisabled == 0); + addPreference(PREF_KEY_DOUBLE_TAP_POWER, cameraDisabled == 0, PREF_ID_DOUBLE_TAP_POWER); } else { removePreference(PREF_KEY_DOUBLE_TAP_POWER); } @@ -79,14 +83,15 @@ public class GestureSettings extends SettingsPreferenceFragment implements // Ambient Display if (isDozeAvailable(context)) { int dozeEnabled = Secure.getInt(getContentResolver(), Secure.DOZE_ENABLED, 1); - addPreference(PREF_KEY_PICK_UP_AND_NUDGE, dozeEnabled != 0); + addPreference(PREF_KEY_PICK_UP_AND_NUDGE, dozeEnabled != 0, PREF_ID_DOUBLE_TWIST); } else { removePreference(PREF_KEY_PICK_UP_AND_NUDGE); } // Fingerprint slide for notifications if (isSystemUINavigationAvailable(context)) { - addPreference(PREF_KEY_SWIPE_DOWN_FINGERPRINT, isSystemUINavigationEnabled(context)); + addPreference(PREF_KEY_SWIPE_DOWN_FINGERPRINT, isSystemUINavigationEnabled(context), + PREF_ID_PICK_UP_AND_NUDG); } else { removePreference(PREF_KEY_SWIPE_DOWN_FINGERPRINT); } @@ -95,7 +100,8 @@ public class GestureSettings extends SettingsPreferenceFragment implements if (isDoubleTwistAvailable(context)) { int doubleTwistEnabled = Secure.getInt( getContentResolver(), Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED, 1); - addPreference(PREF_KEY_DOUBLE_TWIST, doubleTwistEnabled != 0); + addPreference(PREF_KEY_DOUBLE_TWIST, doubleTwistEnabled != 0, + PREF_ID_SWIPE_DOWN_FINGERPRINT); } else { removePreference(PREF_KEY_DOUBLE_TWIST); } @@ -211,10 +217,11 @@ public class GestureSettings extends SettingsPreferenceFragment implements return false; } - private void addPreference(String key, boolean enabled) { + private void addPreference(String key, boolean enabled, int id) { GesturePreference preference = (GesturePreference) findPreference(key); preference.setChecked(enabled); preference.setOnPreferenceChangeListener(this); + preference.loadPreview(getLoaderManager(), id); mPreferences.add(preference); }