| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.settings.widget; |
| |
| import android.content.Context; |
| import android.content.res.TypedArray; |
| import android.util.AttributeSet; |
| import android.util.Log; |
| import android.util.TypedValue; |
| import android.view.TextureView; |
| import android.view.View; |
| import android.widget.ImageView; |
| import android.widget.LinearLayout; |
| |
| import androidx.annotation.VisibleForTesting; |
| import androidx.preference.Preference; |
| import androidx.preference.PreferenceViewHolder; |
| import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat; |
| |
| import com.android.settings.R; |
| |
| /** |
| * A full width preference that hosts a MP4 video or a {@link AnimatedVectorDrawableCompat}. |
| */ |
| public class VideoPreference extends Preference { |
| |
| private static final String TAG = "VideoPreference"; |
| private final Context mContext; |
| |
| @VisibleForTesting |
| AnimationController mAnimationController; |
| @VisibleForTesting |
| boolean mAnimationAvailable; |
| |
| private float mAspectRatio = 1.0f; |
| private int mPreviewId; |
| private int mAnimationId; |
| private int mVectorAnimationId; |
| private int mHeight = LinearLayout.LayoutParams.MATCH_PARENT - 1; // video height in pixels |
| private TextureView mVideo; |
| private ImageView mPreviewImage; |
| private ImageView mPlayButton; |
| |
| public VideoPreference(Context context) { |
| super(context); |
| mContext = context; |
| initialize(context, null); |
| } |
| |
| public VideoPreference(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| mContext = context; |
| initialize(context, attrs); |
| } |
| |
| private void initialize(Context context, AttributeSet attrs) { |
| TypedArray attributes = context.getTheme().obtainStyledAttributes( |
| attrs, |
| R.styleable.VideoPreference, |
| 0, 0); |
| try { |
| // if these are already set that means they were set dynamically and don't need |
| // to be loaded from xml |
| mAnimationAvailable = false; |
| mAnimationId = mAnimationId == 0 |
| ? attributes.getResourceId(R.styleable.VideoPreference_animation, 0) |
| : mAnimationId; |
| mPreviewId = mPreviewId == 0 |
| ? attributes.getResourceId(R.styleable.VideoPreference_preview, 0) |
| : mPreviewId; |
| mVectorAnimationId = attributes.getResourceId( |
| R.styleable.VideoPreference_vectorAnimation, 0); |
| if (mPreviewId == 0 && mAnimationId == 0 && mVectorAnimationId == 0) { |
| setVisible(false); |
| return; |
| } |
| initAnimationController(); |
| if (mAnimationController != null && mAnimationController.getDuration() > 0) { |
| setVisible(true); |
| setLayoutResource(R.layout.video_preference); |
| mAnimationAvailable = true; |
| updateAspectRatio(); |
| } else { |
| setVisible(false); |
| } |
| } catch (Exception e) { |
| Log.w(TAG, "Animation resource not found. Will not show animation."); |
| } finally { |
| attributes.recycle(); |
| } |
| } |
| |
| @Override |
| public void onBindViewHolder(PreferenceViewHolder holder) { |
| super.onBindViewHolder(holder); |
| |
| if (!mAnimationAvailable) { |
| return; |
| } |
| |
| mVideo = (TextureView) holder.findViewById(R.id.video_texture_view); |
| mPreviewImage = (ImageView) holder.findViewById(R.id.video_preview_image); |
| mPlayButton = (ImageView) holder.findViewById(R.id.video_play_button); |
| final AspectRatioFrameLayout layout = (AspectRatioFrameLayout) holder.findViewById( |
| R.id.video_container); |
| |
| mPreviewImage.setImageResource(mPreviewId); |
| layout.setAspectRatio(mAspectRatio); |
| if (mHeight >= LinearLayout.LayoutParams.MATCH_PARENT) { |
| layout.setLayoutParams(new LinearLayout.LayoutParams( |
| LinearLayout.LayoutParams.MATCH_PARENT, mHeight)); |
| } |
| if (mAnimationController != null) { |
| mAnimationController.attachView(mVideo, mPreviewImage, mPlayButton); |
| } |
| } |
| |
| @Override |
| public void onDetached() { |
| releaseAnimationController(); |
| super.onDetached(); |
| } |
| |
| /** |
| * Called from {@link VideoPreferenceController} when the view is onResume |
| */ |
| public void onViewVisible() { |
| initAnimationController(); |
| } |
| |
| /** |
| * Called from {@link VideoPreferenceController} when the view is onPause |
| */ |
| public void onViewInvisible() { |
| releaseAnimationController(); |
| } |
| |
| /** |
| * Sets the video for this preference. If a previous video was set this one will override it |
| * and properly release any resources and re-initialize the preference to play the new video. |
| * |
| * @param videoId The raw res id of the video |
| * @param previewId The drawable res id of the preview image to use if the video fails to load. |
| */ |
| public void setVideo(int videoId, int previewId) { |
| mAnimationId = videoId; |
| mPreviewId = previewId; |
| releaseAnimationController(); |
| initialize(mContext, null); |
| } |
| |
| private void initAnimationController() { |
| if (mVectorAnimationId != 0) { |
| mAnimationController = new VectorAnimationController(mContext, mVectorAnimationId); |
| return; |
| } |
| if (mAnimationId != 0) { |
| mAnimationController = new MediaAnimationController(mContext, mAnimationId); |
| if (mVideo != null) { |
| mAnimationController.attachView(mVideo, mPreviewImage, mPlayButton); |
| } |
| } |
| } |
| |
| private void releaseAnimationController() { |
| if (mAnimationController != null) { |
| mAnimationController.release(); |
| mAnimationController = null; |
| } |
| } |
| |
| public boolean isAnimationAvailable() { |
| return mAnimationAvailable; |
| } |
| |
| /** |
| * sets the height of the video preference |
| * |
| * @param height in dp |
| */ |
| public void setHeight(float height) { |
| mHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, |
| mContext.getResources().getDisplayMetrics()); |
| } |
| |
| @VisibleForTesting |
| void updateAspectRatio() { |
| mAspectRatio = mAnimationController.getVideoWidth() |
| / (float) mAnimationController.getVideoHeight(); |
| } |
| |
| /** |
| * Handle animation operations. |
| */ |
| interface AnimationController { |
| /** |
| * Pauses the animation. |
| */ |
| void pause(); |
| |
| /** |
| * Starts the animation. |
| */ |
| void start(); |
| |
| /** |
| * Releases the animation object. |
| */ |
| void release(); |
| |
| /** |
| * Attaches the animation to UI view. |
| */ |
| void attachView(TextureView video, View preview, View playButton); |
| |
| /** |
| * Returns the animation Width. |
| */ |
| int getVideoWidth(); |
| |
| /** |
| * Returns the animation Height. |
| */ |
| int getVideoHeight(); |
| |
| /** |
| * Returns the animation duration. |
| */ |
| int getDuration(); |
| |
| /** |
| * Returns if the animation is playing. |
| */ |
| boolean isPlaying(); |
| } |
| } |