Home | History | Annotate | Download | only in tv
      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.systemui.pip.tv;
     18 
     19 import android.animation.Animator;
     20 import android.animation.AnimatorInflater;
     21 import android.content.Context;
     22 import android.content.res.TypedArray;
     23 import android.graphics.drawable.Drawable;
     24 import android.util.AttributeSet;
     25 import android.view.LayoutInflater;
     26 import android.view.View;
     27 import android.widget.ImageView;
     28 import android.widget.RelativeLayout;
     29 import android.widget.TextView;
     30 
     31 import com.android.systemui.R;
     32 
     33 /**
     34  * A view containing PIP controls including fullscreen, close, and media controls.
     35  */
     36 public class PipControlButtonView extends RelativeLayout {
     37 
     38     private OnFocusChangeListener mFocusChangeListener;
     39     private ImageView mIconImageView;
     40     ImageView mButtonImageView;
     41     private TextView mDescriptionTextView;
     42     private Animator mTextFocusGainAnimator;
     43     private Animator mButtonFocusGainAnimator;
     44     private Animator mTextFocusLossAnimator;
     45     private Animator mButtonFocusLossAnimator;
     46 
     47     private final OnFocusChangeListener mInternalFocusChangeListener =
     48             new OnFocusChangeListener() {
     49                 @Override
     50                 public void onFocusChange(View v, boolean hasFocus) {
     51                     if (hasFocus) {
     52                         startFocusGainAnimation();
     53                     } else {
     54                         startFocusLossAnimation();
     55                     }
     56 
     57                     if (mFocusChangeListener != null) {
     58                         mFocusChangeListener.onFocusChange(PipControlButtonView.this, hasFocus);
     59                     }
     60                 }
     61             };
     62 
     63     public PipControlButtonView(Context context) {
     64         this(context, null, 0, 0);
     65     }
     66 
     67     public PipControlButtonView(Context context, AttributeSet attrs) {
     68         this(context, attrs, 0, 0);
     69     }
     70 
     71     public PipControlButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
     72         this(context, attrs, defStyleAttr, 0);
     73     }
     74 
     75     public PipControlButtonView(
     76             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
     77         super(context, attrs, defStyleAttr, defStyleRes);
     78         LayoutInflater inflater = (LayoutInflater) getContext()
     79                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     80         inflater.inflate(R.layout.tv_pip_control_button, this);
     81 
     82         mIconImageView = findViewById(R.id.icon);
     83         mButtonImageView = findViewById(R.id.button);
     84         mDescriptionTextView = findViewById(R.id.desc);
     85 
     86         int[] values = new int[] {android.R.attr.src, android.R.attr.text};
     87         TypedArray typedArray =
     88             context.obtainStyledAttributes(attrs, values, defStyleAttr, defStyleRes);
     89 
     90         setImageResource(typedArray.getResourceId(0, 0));
     91         setText(typedArray.getResourceId(1, 0));
     92 
     93         typedArray.recycle();
     94     }
     95 
     96     @Override
     97     public void onFinishInflate() {
     98         super.onFinishInflate();
     99         mButtonImageView.setOnFocusChangeListener(mInternalFocusChangeListener);
    100 
    101         mTextFocusGainAnimator = AnimatorInflater.loadAnimator(getContext(),
    102                 R.anim.tv_pip_controls_focus_gain_animation);
    103         mTextFocusGainAnimator.setTarget(mDescriptionTextView);
    104         mButtonFocusGainAnimator = AnimatorInflater.loadAnimator(getContext(),
    105                 R.anim.tv_pip_controls_focus_gain_animation);
    106         mButtonFocusGainAnimator.setTarget(mButtonImageView);
    107 
    108         mTextFocusLossAnimator = AnimatorInflater.loadAnimator(getContext(),
    109                 R.anim.tv_pip_controls_focus_loss_animation);
    110         mTextFocusLossAnimator.setTarget(mDescriptionTextView);
    111         mButtonFocusLossAnimator = AnimatorInflater.loadAnimator(getContext(),
    112                 R.anim.tv_pip_controls_focus_loss_animation);
    113         mButtonFocusLossAnimator.setTarget(mButtonImageView);
    114     }
    115 
    116     @Override
    117     public void setOnClickListener(OnClickListener listener) {
    118         mButtonImageView.setOnClickListener(listener);
    119     }
    120 
    121     @Override
    122     public void setOnFocusChangeListener(OnFocusChangeListener listener) {
    123         mFocusChangeListener = listener;
    124     }
    125 
    126     /**
    127      * Sets the drawable for the button with the given drawable.
    128      */
    129     public void setImageDrawable(Drawable d) {
    130         mIconImageView.setImageDrawable(d);
    131     }
    132 
    133     /**
    134      * Sets the drawable for the button with the given resource id.
    135      */
    136     public void setImageResource(int resId) {
    137         if (resId != 0) {
    138             mIconImageView.setImageResource(resId);
    139         }
    140     }
    141 
    142     /**
    143      * Sets the text for description the with the given string.
    144      */
    145     public void setText(CharSequence text) {
    146         mButtonImageView.setContentDescription(text);
    147         mDescriptionTextView.setText(text);
    148     }
    149 
    150     /**
    151      * Sets the text for description the with the given resource id.
    152      */
    153     public void setText(int resId) {
    154         if (resId != 0) {
    155             mButtonImageView.setContentDescription(getContext().getString(resId));
    156             mDescriptionTextView.setText(resId);
    157         }
    158     }
    159 
    160     private static void cancelAnimator(Animator animator) {
    161         if (animator.isStarted()) {
    162             animator.cancel();
    163         }
    164     }
    165 
    166     /**
    167      * Starts the focus gain animation.
    168      */
    169     public void startFocusGainAnimation() {
    170         cancelAnimator(mButtonFocusLossAnimator);
    171         cancelAnimator(mTextFocusLossAnimator);
    172         mTextFocusGainAnimator.start();
    173         if (mButtonImageView.getAlpha() < 1f) {
    174             // If we had faded out the ripple drawable, run our manual focus change animation.
    175             // See the comment at {@link #startFocusLossAnimation()} for the reason of manual
    176             // animator.
    177             mButtonFocusGainAnimator.start();
    178         }
    179     }
    180 
    181     /**
    182      * Starts the focus loss animation.
    183      */
    184     public void startFocusLossAnimation() {
    185         cancelAnimator(mButtonFocusGainAnimator);
    186         cancelAnimator(mTextFocusGainAnimator);
    187         mTextFocusLossAnimator.start();
    188         if (mButtonImageView.hasFocus()) {
    189             // Button uses ripple that has the default animation for the focus changes.
    190             // Howevever, it doesn't expose the API to fade out while it is focused,
    191             // so we should manually run the fade out animation when PIP controls row loses focus.
    192             mButtonFocusLossAnimator.start();
    193         }
    194     }
    195 
    196     /**
    197      * Resets to initial state.
    198      */
    199     public void reset() {
    200         cancelAnimator(mButtonFocusGainAnimator);
    201         cancelAnimator(mTextFocusGainAnimator);
    202         cancelAnimator(mButtonFocusLossAnimator);
    203         cancelAnimator(mTextFocusLossAnimator);
    204         mButtonImageView.setAlpha(1f);
    205         mDescriptionTextView.setAlpha(mButtonImageView.hasFocus() ? 1f : 0f);
    206     }
    207 }
    208