blob: c643d6708adb0f130ce23e8f2ba8e729139bc433 [file] [log] [blame]
Jason Monk162011e2016-02-19 08:11:55 -05001/*
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
15package com.android.systemui.qs;
16
17import android.util.Log;
18import android.view.View;
19import android.view.View.OnLayoutChangeListener;
Jason Monk162011e2016-02-19 08:11:55 -050020import android.view.animation.PathInterpolator;
21import android.widget.TextView;
Jason Monk162011e2016-02-19 08:11:55 -050022import com.android.systemui.qs.PagedTileLayout.PageListener;
23import com.android.systemui.qs.QSPanel.QSTileLayout;
24import com.android.systemui.qs.QSTile.Host.Callback;
25import com.android.systemui.qs.TouchAnimator.Builder;
26import com.android.systemui.qs.TouchAnimator.Listener;
27import com.android.systemui.statusbar.phone.QSTileHost;
28
29import java.util.ArrayList;
30import java.util.Collection;
31
32public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener {
33
34 private static final String TAG = "QSAnimator";
35
36 public static final PathInterpolator TRANSLATION_Y_INTERPOLATOR =
37 new PathInterpolator(.1f, .3f, 1, 1);
38
39 public static final float EXPANDED_TILE_DELAY = .7f;
40
41 private final ArrayList<View> mAllViews = new ArrayList<>();
Jason Monke80654b2016-02-24 14:53:57 -050042 private final ArrayList<View> mTopFiveQs = new ArrayList<>();
Jason Monk162011e2016-02-19 08:11:55 -050043 private final QuickQSPanel mQuickQsPanel;
44 private final QSPanel mQsPanel;
45 private final QSContainer mQsContainer;
46
47 private boolean mOnFirstPage = true;
48 private TouchAnimator mFirstPageAnimator;
49 private TouchAnimator mFirstPageDelayedAnimator;
50 private TouchAnimator mTranslationYAnimator;
51 private TouchAnimator mNonfirstPageAnimator;
52
53 public QSAnimator(QSContainer container, QuickQSPanel quickPanel, QSPanel panel) {
54 mQsContainer = container;
55 mQuickQsPanel = quickPanel;
56 mQsPanel = panel;
Jason Monkdf5459d2016-02-29 10:47:35 -050057 container.addOnLayoutChangeListener(this);
Jason Monk162011e2016-02-19 08:11:55 -050058 QSTileLayout tileLayout = mQsPanel.getTileLayout();
59 if (tileLayout instanceof PagedTileLayout) {
60 ((PagedTileLayout) tileLayout).setPageListener(this);
61 } else {
62 Log.w(TAG, "QS Not using page layout");
63 }
64 }
65
66 public void setHost(QSTileHost qsh) {
67 qsh.addCallback(this);
68 }
69
70 @Override
Jason Monk66eaf312016-02-25 12:29:29 -050071 public void onPageChanged(boolean isFirst) {
72 if (mOnFirstPage == isFirst) return;
73 if (!isFirst) {
74 setPosition(1);
Jason Monk162011e2016-02-19 08:11:55 -050075 clearAnimationState();
76 }
Jason Monk66eaf312016-02-25 12:29:29 -050077 mOnFirstPage = isFirst;
Jason Monk162011e2016-02-19 08:11:55 -050078 }
79
80 private void updateAnimators() {
81 TouchAnimator.Builder firstPageBuilder = new Builder();
82 TouchAnimator.Builder translationYBuilder = new Builder();
83 TouchAnimator.Builder firstPageDelayedBuilder = new Builder();
84 Collection<QSTile<?>> tiles = mQsPanel.getHost().getTiles();
85 int count = 0;
86 int[] loc1 = new int[2];
87 int[] loc2 = new int[2];
88 firstPageDelayedBuilder.setStartDelay(EXPANDED_TILE_DELAY);
89 firstPageBuilder.setListener(this);
90 translationYBuilder.setInterpolator(TRANSLATION_Y_INTERPOLATOR);
Jason Monke80654b2016-02-24 14:53:57 -050091 // Fade in the tiles/labels as we reach the final position.
92 firstPageDelayedBuilder.addFloat(mQsPanel.getTileLayout(), "alpha", 0, 1);
Jason Monk162011e2016-02-19 08:11:55 -050093 mAllViews.clear();
Jason Monke80654b2016-02-24 14:53:57 -050094 mTopFiveQs.clear();
Jason Monk162011e2016-02-19 08:11:55 -050095 for (QSTile<?> tile : tiles) {
96 QSTileBaseView tileView = mQsPanel.getTileView(tile);
97 final TextView label = ((QSTileView) tileView).getLabel();
98 if (count++ < 5) {
99 // Quick tiles.
100 QSTileBaseView quickTileView = mQuickQsPanel.getTileView(tile);
101 final View tileIcon = tileView.getIcon();
102
103 getRelativePosition(loc1, quickTileView.getIcon(), mQsContainer);
104 getRelativePosition(loc2, tileIcon, mQsContainer);
105 final int xDiff = loc2[0] - loc1[0];
106 final int yDiff = loc2[1] - loc1[1];
107 // Move the quick tile right from its location to the new one.
108 firstPageBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
109 translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
110
111 // Counteract the parent translation on the tile. So we have a static base to
Jason Monke80654b2016-02-24 14:53:57 -0500112 // animate the label position off from.
Jason Monk162011e2016-02-19 08:11:55 -0500113 firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
114
Jason Monke80654b2016-02-24 14:53:57 -0500115 // Move the real tile's label from the quick tile position to its final
Jason Monk162011e2016-02-19 08:11:55 -0500116 // location.
Jason Monk162011e2016-02-19 08:11:55 -0500117 firstPageBuilder.addFloat(label, "translationX", -xDiff, 0);
118 translationYBuilder.addFloat(label, "translationY", -yDiff, 0);
119
Jason Monke80654b2016-02-24 14:53:57 -0500120 mTopFiveQs.add(tileIcon);
121 mAllViews.add(tileIcon);
Jason Monk162011e2016-02-19 08:11:55 -0500122 mAllViews.add(quickTileView);
Jason Monk162011e2016-02-19 08:11:55 -0500123 }
124 mAllViews.add(tileView);
125 mAllViews.add(label);
126 }
127 mFirstPageAnimator = firstPageBuilder.build();
128 mFirstPageDelayedAnimator = firstPageDelayedBuilder.build();
129 mTranslationYAnimator = translationYBuilder.build();
130 mNonfirstPageAnimator = new TouchAnimator.Builder()
131 .addFloat(mQuickQsPanel, "alpha", 1, 0)
132 .setEndDelay(.5f)
133 .build();
134 }
135
136 private void getRelativePosition(int[] loc1, View view, View parent) {
137 loc1[0] = 0 + view.getWidth() / 2;
138 loc1[1] = 0;
139 getRelativePositionInt(loc1, view, parent);
140 }
141
142 private void getRelativePositionInt(int[] loc1, View view, View parent) {
143 if(view == parent || view == null) return;
144 loc1[0] += view.getLeft();
145 loc1[1] += view.getTop();
146 getRelativePositionInt(loc1, (View) view.getParent(), parent);
147 }
148
149 public void setPosition(float position) {
150 if (mFirstPageAnimator == null) return;
151 if (mOnFirstPage) {
152 mQuickQsPanel.setAlpha(1);
153 mFirstPageAnimator.setPosition(position);
154 mFirstPageDelayedAnimator.setPosition(position);
155 mTranslationYAnimator.setPosition(position);
156 } else {
157 mNonfirstPageAnimator.setPosition(position);
158 }
159 }
160
161 @Override
162 public void onAnimationAtStart() {
Jason Monkdf5459d2016-02-29 10:47:35 -0500163 mQuickQsPanel.setVisibility(View.VISIBLE);
Jason Monk162011e2016-02-19 08:11:55 -0500164 }
165
166 @Override
167 public void onAnimationAtEnd() {
168 mQuickQsPanel.setVisibility(View.INVISIBLE);
Jason Monke80654b2016-02-24 14:53:57 -0500169 final int N = mTopFiveQs.size();
170 for (int i = 0; i < N; i++) {
171 mTopFiveQs.get(i).setVisibility(View.VISIBLE);
172 }
Jason Monk162011e2016-02-19 08:11:55 -0500173 }
174
175 @Override
176 public void onAnimationStarted() {
177 mQuickQsPanel.setVisibility(View.VISIBLE);
Jason Monke80654b2016-02-24 14:53:57 -0500178 if (mOnFirstPage) {
179 final int N = mTopFiveQs.size();
180 for (int i = 0; i < N; i++) {
181 mTopFiveQs.get(i).setVisibility(View.INVISIBLE);
182 }
183 }
Jason Monk162011e2016-02-19 08:11:55 -0500184 }
185
186 private void clearAnimationState() {
187 final int N = mAllViews.size();
188 mQuickQsPanel.setAlpha(0);
189 for (int i = 0; i < N; i++) {
190 View v = mAllViews.get(i);
191 v.setAlpha(1);
192 v.setTranslationX(1);
193 v.setTranslationY(1);
194 }
195 }
196
197 @Override
198 public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
199 int oldTop, int oldRight, int oldBottom) {
200 updateAnimators();
201 }
202
203 @Override
204 public void onTilesChanged() {
205 // Give the QS panels a moment to generate their new tiles, then create all new animators
206 // hooked up to the new views.
207 mQsPanel.post(mUpdateAnimators);
208 }
209
210 private Runnable mUpdateAnimators = new Runnable() {
211 @Override
212 public void run() {
213 updateAnimators();
214 }
215 };
216}