Home | History | Annotate | Download | only in gestures
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
      5  * except in compliance with the License. You may obtain a copy of the License at
      6  *
      7  *      http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the
     10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     11  * KIND, either express or implied. See the License for the specific language governing
     12  * permissions and limitations under the License.
     13  */
     14 
     15 package com.android.settings.gestures;
     16 
     17 import android.app.LoaderManager;
     18 import android.content.ContentResolver;
     19 import android.content.Context;
     20 import android.content.Loader;
     21 import android.content.res.TypedArray;
     22 import android.graphics.Bitmap;
     23 import android.graphics.drawable.BitmapDrawable;
     24 import android.graphics.SurfaceTexture;
     25 import android.media.MediaMetadataRetriever;
     26 import android.media.MediaPlayer;
     27 import android.net.Uri;
     28 import android.os.Bundle;
     29 import android.support.v14.preference.SwitchPreference;
     30 import android.support.v7.preference.PreferenceViewHolder;
     31 import android.view.View;
     32 import android.view.Surface;
     33 import android.view.TextureView;
     34 import android.widget.ImageView;
     35 import android.util.AttributeSet;
     36 import android.util.Log;
     37 
     38 import com.android.settings.R;
     39 import com.android.settings.utils.AsyncLoader;
     40 
     41 /**
     42  * Preference item for a gesture with a switch to signify if it should be enabled.
     43  * This shows the title and description of the gesture along with an animation showing how to do
     44  * the gesture
     45  */
     46 public final class GesturePreference extends SwitchPreference implements
     47         LoaderManager.LoaderCallbacks<Bitmap> {
     48     private static final String TAG = "GesturePreference";
     49     private final Context mContext;
     50 
     51     private Uri mVideoPath;
     52     private MediaPlayer mMediaPlayer;
     53     private boolean mAnimationAvailable;
     54     private boolean mVideoReady;
     55     private boolean mScrolling;
     56     private BitmapDrawable mPreviewImage;
     57 
     58     public GesturePreference(Context context, AttributeSet attrs) {
     59         super(context, attrs);
     60         mContext = context;
     61         setLayoutResource(R.layout.gesture_preference);
     62         TypedArray attributes = context.getTheme().obtainStyledAttributes(
     63                 attrs,
     64                 R.styleable.GesturePreference,
     65                 0, 0);
     66         try {
     67             int animation = attributes.getResourceId(R.styleable.GesturePreference_animation, 0);
     68             mVideoPath = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
     69                     .authority(context.getPackageName())
     70                     .appendPath(String.valueOf(animation))
     71                     .build();
     72             mMediaPlayer = MediaPlayer.create(mContext, mVideoPath);
     73             if (mMediaPlayer != null) {
     74                 mMediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
     75                     @Override
     76                     public void onSeekComplete(MediaPlayer mp) {
     77                         mVideoReady = true;
     78                     }
     79                 });
     80 
     81                 mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
     82                     @Override
     83                     public void onPrepared(MediaPlayer mediaPlayer) {
     84                         mediaPlayer.setLooping(true);
     85                     }
     86                 });
     87             }
     88             mAnimationAvailable = true;
     89 
     90         } catch (Exception e) {
     91             Log.w(TAG, "Animation resource not found. Will not show animation.");
     92         } finally {
     93             attributes.recycle();
     94         }
     95     }
     96 
     97     @Override
     98     public void onBindViewHolder(PreferenceViewHolder holder) {
     99         super.onBindViewHolder(holder);
    100         final TextureView video = (TextureView) holder.findViewById(R.id.gesture_video);
    101         final ImageView imageView = (ImageView) holder.findViewById(R.id.gesture_image);
    102         final ImageView playButton = (ImageView) holder.findViewById(R.id.gesture_play_button);
    103         final View animationFrame = holder.findViewById(R.id.gesture_animation_frame);
    104 
    105         if (!mAnimationAvailable) {
    106             animationFrame.setVisibility(View.GONE);
    107             return;
    108         }
    109 
    110         video.setOnClickListener(new View.OnClickListener() {
    111             @Override
    112             public void onClick(View v) {
    113                 if (mMediaPlayer != null) {
    114                     if (mMediaPlayer.isPlaying()) {
    115                         mMediaPlayer.pause();
    116                         playButton.setVisibility(View.VISIBLE);
    117                     } else {
    118                         mMediaPlayer.start();
    119                         playButton.setVisibility(View.GONE);
    120                     }
    121                 }
    122             }
    123         });
    124 
    125         video.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
    126             @Override
    127             public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
    128                     int height) {
    129                 if (mMediaPlayer != null) {
    130                     mMediaPlayer.setSurface(new Surface(surfaceTexture));
    131                     mVideoReady = false;
    132                     mMediaPlayer.seekTo(0);
    133                 }
    134             }
    135 
    136             @Override
    137             public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width,
    138                     int height) {
    139             }
    140 
    141             @Override
    142             public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
    143                 if (mPreviewImage != null && imageView.getDrawable() == null) {
    144                     imageView.setImageDrawable(mPreviewImage);
    145                 }
    146                 imageView.setVisibility(View.VISIBLE);
    147                 return false;
    148             }
    149 
    150             @Override
    151             public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
    152                 if (mVideoReady && imageView.getVisibility() == View.VISIBLE) {
    153                     imageView.setVisibility(View.GONE);
    154                 } else if (mScrolling) {
    155                     mScrolling = false;
    156                     if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
    157                         mMediaPlayer.pause();
    158                         playButton.setVisibility(View.VISIBLE);
    159                     }
    160                 }
    161             }
    162         });
    163 
    164         if (mPreviewImage != null) {
    165             imageView.setImageDrawable(mPreviewImage);
    166         }
    167 
    168     }
    169 
    170     @Override
    171     public void onDetached() {
    172         if (mMediaPlayer != null) {
    173             mMediaPlayer.stop();
    174             mMediaPlayer.reset();
    175             mMediaPlayer.release();
    176         }
    177         super.onDetached();
    178     }
    179 
    180     void setScrolling(boolean scrolling) {
    181         mScrolling = scrolling;
    182     }
    183 
    184     void loadPreview(LoaderManager manager, int id) {
    185         Loader<Bitmap> loader = manager.initLoader(id, Bundle.EMPTY, this);
    186     }
    187 
    188     void onViewVisible() {
    189         if (mVideoReady && mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
    190             mMediaPlayer.seekTo(0);
    191         }
    192     }
    193 
    194     private static final class PreviewRetriever extends AsyncLoader<Bitmap> {
    195         private Uri mVideoPath;
    196 
    197         public PreviewRetriever(Context context, Uri videoPath) {
    198             super(context);
    199             mVideoPath = videoPath;
    200         }
    201 
    202         @Override
    203         public Bitmap loadInBackground() {
    204             MediaMetadataRetriever mediaMetadata = new MediaMetadataRetriever();
    205             try {
    206                 mediaMetadata.setDataSource(getContext(), mVideoPath);
    207                 return mediaMetadata.getFrameAtTime(0);
    208             } catch (Exception e) {
    209                 Log.w(TAG, "Unable to get animation preview.");
    210             } finally {
    211                 mediaMetadata.release();
    212             }
    213             return null;
    214         }
    215 
    216         @Override
    217         public void onDiscardResult(final Bitmap result) {
    218             if (result != null && !result.isRecycled()) {
    219                 result.recycle();
    220             }
    221         }
    222 
    223     }
    224 
    225     @Override
    226     public Loader<Bitmap> onCreateLoader(int id, Bundle args) {
    227         return new PreviewRetriever(mContext, mVideoPath);
    228     }
    229 
    230     @Override
    231     public void onLoadFinished(final Loader<Bitmap> loader, final Bitmap bitmap) {
    232         if (bitmap != null) {
    233             mPreviewImage = new BitmapDrawable(mContext.getResources(), bitmap);
    234         }
    235     }
    236 
    237     @Override
    238     public void onLoaderReset(Loader<Bitmap> loader) {
    239     }
    240 
    241 }
    242