1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.widget; 18 19 import android.content.ContentResolver; 20 import android.content.Context; 21 import android.content.res.TypedArray; 22 import android.graphics.SurfaceTexture; 23 import android.media.MediaPlayer; 24 import android.net.Uri; 25 import android.support.annotation.VisibleForTesting; 26 import android.support.v7.preference.Preference; 27 import android.support.v7.preference.PreferenceViewHolder; 28 import android.util.AttributeSet; 29 import android.util.Log; 30 import android.view.Surface; 31 import android.view.TextureView; 32 import android.view.View; 33 import android.widget.ImageView; 34 35 import com.android.settings.R; 36 37 /** 38 * A full width preference that hosts a MP4 video. 39 */ 40 public class VideoPreference extends Preference { 41 42 private static final String TAG = "VideoPreference"; 43 private final Context mContext; 44 45 private Uri mVideoPath; 46 @VisibleForTesting 47 MediaPlayer mMediaPlayer; 48 @VisibleForTesting 49 boolean mAnimationAvailable; 50 private boolean mVideoReady; 51 private boolean mVideoPaused; 52 private float mAspectRadio = 1.0f; 53 private int mPreviewResource; 54 VideoPreference(Context context, AttributeSet attrs)55 public VideoPreference(Context context, AttributeSet attrs) { 56 super(context, attrs); 57 mContext = context; 58 TypedArray attributes = context.getTheme().obtainStyledAttributes( 59 attrs, 60 com.android.settings.R.styleable.VideoPreference, 61 0, 0); 62 try { 63 int animation = attributes.getResourceId(R.styleable.VideoPreference_animation, 0); 64 mVideoPath = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) 65 .authority(context.getPackageName()) 66 .appendPath(String.valueOf(animation)) 67 .build(); 68 mMediaPlayer = MediaPlayer.create(mContext, mVideoPath); 69 if (mMediaPlayer != null && mMediaPlayer.getDuration() > 0) { 70 setVisible(true); 71 setLayoutResource(R.layout.video_preference); 72 73 mPreviewResource = attributes.getResourceId( 74 R.styleable.VideoPreference_preview, 0); 75 76 mMediaPlayer.setOnSeekCompleteListener(mp -> mVideoReady = true); 77 78 mMediaPlayer.setOnPreparedListener(mediaPlayer -> mediaPlayer.setLooping(true)); 79 mAnimationAvailable = true; 80 updateAspectRatio(); 81 } else { 82 setVisible(false); 83 } 84 } catch (Exception e) { 85 Log.w(TAG, "Animation resource not found. Will not show animation."); 86 } finally { 87 attributes.recycle(); 88 } 89 } 90 91 @Override onBindViewHolder(PreferenceViewHolder holder)92 public void onBindViewHolder(PreferenceViewHolder holder) { 93 super.onBindViewHolder(holder); 94 95 if (!mAnimationAvailable) { 96 return; 97 } 98 99 final TextureView video = (TextureView) holder.findViewById(R.id.video_texture_view); 100 final ImageView imageView = (ImageView) holder.findViewById(R.id.video_preview_image); 101 final ImageView playButton = (ImageView) holder.findViewById(R.id.video_play_button); 102 final AspectRatioFrameLayout layout = (AspectRatioFrameLayout) holder.findViewById( 103 R.id.video_container); 104 105 imageView.setImageResource(mPreviewResource); 106 layout.setAspectRatio(mAspectRadio); 107 108 video.setOnClickListener(v -> { 109 if (mMediaPlayer != null) { 110 if (mMediaPlayer.isPlaying()) { 111 mMediaPlayer.pause(); 112 playButton.setVisibility(View.VISIBLE); 113 mVideoPaused = true; 114 } else { 115 mMediaPlayer.start(); 116 playButton.setVisibility(View.GONE); 117 mVideoPaused = false; 118 } 119 } 120 }); 121 122 video.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { 123 @Override 124 public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, 125 int height) { 126 if (mMediaPlayer != null) { 127 mMediaPlayer.setSurface(new Surface(surfaceTexture)); 128 mVideoReady = false; 129 mMediaPlayer.seekTo(0); 130 } 131 } 132 133 @Override 134 public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, 135 int height) { 136 } 137 138 @Override 139 public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { 140 imageView.setVisibility(View.VISIBLE); 141 return false; 142 } 143 144 @Override 145 public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { 146 if (mVideoReady) { 147 if (imageView.getVisibility() == View.VISIBLE) { 148 imageView.setVisibility(View.GONE); 149 } 150 if (!mVideoPaused && mMediaPlayer != null && !mMediaPlayer.isPlaying()) { 151 mMediaPlayer.start(); 152 playButton.setVisibility(View.GONE); 153 } 154 } 155 if (mMediaPlayer != null && !mMediaPlayer.isPlaying() && 156 playButton.getVisibility() != View.VISIBLE) { 157 playButton.setVisibility(View.VISIBLE); 158 } 159 } 160 }); 161 } 162 163 @Override onDetached()164 public void onDetached() { 165 if (mMediaPlayer != null) { 166 mMediaPlayer.stop(); 167 mMediaPlayer.reset(); 168 mMediaPlayer.release(); 169 } 170 super.onDetached(); 171 } 172 onViewVisible(boolean videoPaused)173 public void onViewVisible(boolean videoPaused) { 174 mVideoPaused = videoPaused; 175 if (mVideoReady && mMediaPlayer != null && !mMediaPlayer.isPlaying()) { 176 mMediaPlayer.seekTo(0); 177 } 178 } 179 onViewInvisible()180 public void onViewInvisible() { 181 if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { 182 mMediaPlayer.pause(); 183 } 184 } 185 isVideoPaused()186 public boolean isVideoPaused() { 187 return mVideoPaused; 188 } 189 190 @VisibleForTesting updateAspectRatio()191 void updateAspectRatio() { 192 mAspectRadio = mMediaPlayer.getVideoWidth() / (float)mMediaPlayer.getVideoHeight(); 193 } 194 195 } 196