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
This commit is contained in:
Doris Ling
2016-07-19 15:46:50 -07:00
parent 9d83a9fbbb
commit de991f457d
2 changed files with 85 additions and 16 deletions

View File

@@ -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<Bitmap> {
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<Bitmap> loader = manager.initLoader(id, Bundle.EMPTY, this);
}
private static final class PreviewRetriever extends AsyncLoader<Bitmap> {
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<Bitmap> onCreateLoader(int id, Bundle args) {
return new PreviewRetriever(mContext, mVideoPath);
}
@Override
public void onLoadFinished(final Loader<Bitmap> loader, final Bitmap bitmap) {
if (bitmap != null) {
mPreviewImage = new BitmapDrawable(mContext.getResources(), bitmap);
}
}
@Override
public void onLoaderReset(Loader<Bitmap> loader) {
}
}