• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GesturePreference(Context context, AttributeSet attrs)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
onBindViewHolder(PreferenceViewHolder holder)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
onDetached()171     public void onDetached() {
172         if (mMediaPlayer != null) {
173             mMediaPlayer.stop();
174             mMediaPlayer.reset();
175             mMediaPlayer.release();
176         }
177         super.onDetached();
178     }
179 
setScrolling(boolean scrolling)180     void setScrolling(boolean scrolling) {
181         mScrolling = scrolling;
182     }
183 
loadPreview(LoaderManager manager, int id)184     void loadPreview(LoaderManager manager, int id) {
185         Loader<Bitmap> loader = manager.initLoader(id, Bundle.EMPTY, this);
186     }
187 
onViewVisible()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 
PreviewRetriever(Context context, Uri videoPath)197         public PreviewRetriever(Context context, Uri videoPath) {
198             super(context);
199             mVideoPath = videoPath;
200         }
201 
202         @Override
loadInBackground()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
onDiscardResult(final Bitmap result)217         public void onDiscardResult(final Bitmap result) {
218             if (result != null && !result.isRecycled()) {
219                 result.recycle();
220             }
221         }
222 
223     }
224 
225     @Override
onCreateLoader(int id, Bundle args)226     public Loader<Bitmap> onCreateLoader(int id, Bundle args) {
227         return new PreviewRetriever(mContext, mVideoPath);
228     }
229 
230     @Override
onLoadFinished(final Loader<Bitmap> loader, final Bitmap bitmap)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
onLoaderReset(Loader<Bitmap> loader)238     public void onLoaderReset(Loader<Bitmap> loader) {
239     }
240 
241 }
242