• 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");
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.tv.pip;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorInflater;
21 import android.animation.AnimatorListenerAdapter;
22 import android.animation.AnimatorSet;
23 import android.content.Context;
24 import android.graphics.Rect;
25 import android.util.AttributeSet;
26 import android.view.KeyEvent;
27 import android.view.View;
28 import android.view.View.OnFocusChangeListener;
29 import android.widget.FrameLayout;
30 
31 import com.android.systemui.R;
32 
33 import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PLAYING;
34 import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_PAUSED;
35 import static com.android.systemui.tv.pip.PipManager.PLAYBACK_STATE_UNAVAILABLE;
36 
37 /**
38  * An FrameLayout that contains {@link PipControlsView} with its scrim.
39  */
40 public class PipRecentsControlsView extends FrameLayout {
41     /**
42      * An interface to listen user action.
43      */
44     public interface Listener extends PipControlsView.Listener {
45         /**
46          * Called when an user presses BACK key and up.
47          */
onBackPressed()48         abstract void onBackPressed();
49     }
50 
51     private final PipManager mPipManager = PipManager.getInstance();
52     private Listener mListener;
53     private PipControlsView mPipControlsView;
54     private View mScrim;
55     private Animator mFocusGainAnimator;
56     private AnimatorSet mFocusLossAnimatorSet;
57 
PipRecentsControlsView(Context context)58     public PipRecentsControlsView(Context context) {
59         this(context, null, 0, 0);
60     }
61 
PipRecentsControlsView(Context context, AttributeSet attrs)62     public PipRecentsControlsView(Context context, AttributeSet attrs) {
63         this(context, attrs, 0, 0);
64     }
65 
PipRecentsControlsView(Context context, AttributeSet attrs, int defStyleAttr)66     public PipRecentsControlsView(Context context, AttributeSet attrs, int defStyleAttr) {
67         this(context, attrs, defStyleAttr, 0);
68     }
69 
PipRecentsControlsView( Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)70     public PipRecentsControlsView(
71             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
72         super(context, attrs, defStyleAttr, defStyleRes);
73     }
74 
75     @Override
onFinishInflate()76     public void onFinishInflate() {
77         super.onFinishInflate();
78 
79         mPipControlsView = (PipControlsView) findViewById(R.id.pip_control_contents);
80         mScrim = findViewById(R.id.scrim);
81 
82         mFocusGainAnimator = loadAnimator(mPipControlsView,
83                 R.anim.tv_pip_controls_in_recents_focus_gain_animation);
84 
85         mFocusLossAnimatorSet = new AnimatorSet();
86         mFocusLossAnimatorSet.playSequentially(
87                 loadAnimator(mPipControlsView,
88                         R.anim.tv_pip_controls_in_recents_focus_loss_animation),
89                 loadAnimator(mScrim, R.anim.tv_pip_controls_in_recents_scrim_fade_in_animation));
90 
91         Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
92         setPadding(0, pipBounds.bottom, 0, 0);
93     }
94 
loadAnimator(View view, int animatorResId)95     private Animator loadAnimator(View view, int animatorResId) {
96         Animator animator = AnimatorInflater.loadAnimator(getContext(), animatorResId);
97         animator.setTarget(view);
98         return animator;
99     }
100 
101     /**
102      * Starts focus gain animation.
103      */
startFocusGainAnimation()104     public void startFocusGainAnimation() {
105         // Hides the scrim view as soon as possible, before the PIP resize animation starts.
106         // If we don't, PIP will be moved down a bit and a gap between the scrim and PIP will be
107         // shown at the bottom of the PIP.
108         mScrim.setAlpha(0);
109         PipControlButtonView focus = mPipControlsView.getFocusedButton();
110         if (focus != null) {
111             focus.startFocusGainAnimation();
112         }
113         startAnimator(mFocusGainAnimator, mFocusLossAnimatorSet);
114     }
115 
116     /**
117      * Starts focus loss animation.
118      */
startFocusLossAnimation()119     public void startFocusLossAnimation() {
120         PipControlButtonView focus = mPipControlsView.getFocusedButton();
121         if (focus != null) {
122             focus.startFocusLossAnimation();
123         }
124         startAnimator(mFocusLossAnimatorSet, mFocusGainAnimator);
125     }
126 
127     /**
128      * Resets the view to the initial state. (i.e. end of the focus gain)
129      */
reset()130     public void reset() {
131         cancelAnimator(mFocusGainAnimator);
132         cancelAnimator(mFocusLossAnimatorSet);
133 
134         // Reset to initial state (i.e. end of focused)
135         mScrim.setAlpha(0);
136         mPipControlsView.setTranslationY(0);
137         mPipControlsView.setScaleX(1);
138         mPipControlsView.setScaleY(1);
139         mPipControlsView.reset();
140     }
141 
startAnimator(Animator animator, Animator previousAnimator)142     private static void startAnimator(Animator animator, Animator previousAnimator) {
143         cancelAnimator(previousAnimator);
144         if (!animator.isStarted()) {
145             animator.start();
146         }
147     }
148 
cancelAnimator(Animator animator)149     private static void cancelAnimator(Animator animator) {
150         if (animator.isStarted()) {
151             animator.cancel();
152         }
153     }
154 
155     /**
156      * Sets listeners.
157      */
setListener(Listener listener)158     public void setListener(Listener listener) {
159         mPipControlsView.setListener(listener);
160     }
161 
162     @Override
dispatchKeyEvent(KeyEvent event)163     public boolean dispatchKeyEvent(KeyEvent event) {
164         if (!event.isCanceled()) {
165             if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
166                     && event.getAction() == KeyEvent.ACTION_UP) {
167                 if (mPipControlsView.mListener != null) {
168                     ((PipRecentsControlsView.Listener) mPipControlsView.mListener).onBackPressed();
169                 }
170                 return true;
171             } else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
172                 if (event.getAction() == KeyEvent.ACTION_DOWN) {
173                     mPipManager.getPipRecentsOverlayManager().clearFocus();
174                 }
175                 // Consume the down event always to prevent warning logs from ViewRootImpl.
176                 return true;
177             }
178         }
179         return super.dispatchKeyEvent(event);
180     }
181 }
182