blob: 375459f0f30ce37a23ae9081129b90382866360e [file] [log] [blame]
Mady Mellor4b80b102016-01-22 08:03:58 -08001/*
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
17package com.android.systemui.statusbar;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.ValueAnimator;
22import android.content.Context;
23import android.util.AttributeSet;
24import android.view.View;
Mady Mellor4b80b102016-01-22 08:03:58 -080025import android.widget.FrameLayout;
26
27import com.android.systemui.Interpolators;
28import com.android.systemui.R;
29
30public class NotificationSettingsIconRow extends FrameLayout implements View.OnClickListener {
31
32 public interface SettingsIconRowListener {
33 /**
34 * Called when the gear behind a notification is touched.
35 */
Mady Mellorb53bc272016-02-11 18:28:23 -080036 public void onGearTouched(ExpandableNotificationRow row, int x, int y);
Mady Mellor4b80b102016-01-22 08:03:58 -080037 }
38
39 private ExpandableNotificationRow mParent;
40 private AlphaOptimizedImageView mGearIcon;
41 private float mHorizSpaceForGear;
42 private SettingsIconRowListener mListener;
43
44 private ValueAnimator mFadeAnimator;
45 private boolean mSettingsFadedIn = false;
46 private boolean mAnimating = false;
47 private boolean mOnLeft = true;
Mady Mellorb53bc272016-02-11 18:28:23 -080048 private int[] mGearLocation = new int[2];
49 private int[] mParentLocation = new int[2];
Mady Mellor4b80b102016-01-22 08:03:58 -080050
51 public NotificationSettingsIconRow(Context context) {
52 this(context, null);
53 }
54
55 public NotificationSettingsIconRow(Context context, AttributeSet attrs) {
56 this(context, attrs, 0);
57 }
58
59 public NotificationSettingsIconRow(Context context, AttributeSet attrs, int defStyleAttr) {
60 this(context, attrs, defStyleAttr, 0);
61 }
62
63 public NotificationSettingsIconRow(Context context, AttributeSet attrs, int defStyleAttr,
64 int defStyleRes) {
65 super(context, attrs);
66 }
67
68 @Override
69 protected void onFinishInflate() {
70 super.onFinishInflate();
71 mGearIcon = (AlphaOptimizedImageView) findViewById(R.id.gear_icon);
72 mGearIcon.setOnClickListener(this);
Mady Mellorf0625802016-02-11 18:03:48 -080073 setOnClickListener(this);
74 mHorizSpaceForGear =
75 getResources().getDimensionPixelOffset(R.dimen.notification_gear_width);
Mady Mellor4b80b102016-01-22 08:03:58 -080076 resetState();
77 }
78
Mady Mellorb53bc272016-02-11 18:28:23 -080079 public void resetState() {
80 setGearAlpha(0f);
81 mAnimating = false;
82 setIconLocation(true /* on left */);
83 }
84
Mady Mellor4b80b102016-01-22 08:03:58 -080085 public void setGearListener(SettingsIconRowListener listener) {
86 mListener = listener;
87 }
88
89 public void setNotificationRowParent(ExpandableNotificationRow parent) {
90 mParent = parent;
91 }
92
93 public ExpandableNotificationRow getNotificationParent() {
94 return mParent;
95 }
96
Mady Mellor4b80b102016-01-22 08:03:58 -080097 private void setGearAlpha(float alpha) {
98 if (alpha == 0) {
99 mSettingsFadedIn = false; // Can fade in again once it's gone.
Mady Mellorf153f5f2016-02-29 14:54:53 -0800100 setVisibility(View.INVISIBLE);
Mady Mellor4b80b102016-01-22 08:03:58 -0800101 } else {
102 if (alpha == 1) {
103 mSettingsFadedIn = true;
104 }
Mady Mellorf153f5f2016-02-29 14:54:53 -0800105 setVisibility(View.VISIBLE);
Mady Mellor4b80b102016-01-22 08:03:58 -0800106 }
107 mGearIcon.setAlpha(alpha);
108 }
109
110 /**
111 * Returns the horizontal space in pixels required to display the gear behind a notification.
112 */
113 public float getSpaceForGear() {
114 return mHorizSpaceForGear;
115 }
116
117 /**
118 * Indicates whether the gear is visible at 1 alpha. Does not indicate
119 * if entire view is visible.
120 */
121 public boolean isVisible() {
122 return mSettingsFadedIn;
123 }
124
125 public void cancelFadeAnimator() {
126 if (mFadeAnimator != null) {
127 mFadeAnimator.cancel();
128 }
129 }
130
131 public void updateSettingsIcons(final float transX, final float size) {
132 if (mAnimating || (mGearIcon.getAlpha() == 0)) {
133 // Don't adjust when animating or settings aren't visible
134 return;
135 }
136 setIconLocation(transX > 0 /* fromLeft */);
137 final float fadeThreshold = size * 0.3f;
138 final float absTrans = Math.abs(transX);
139 float desiredAlpha = 0;
140
Mady Mellor4b80b102016-01-22 08:03:58 -0800141 if (absTrans <= fadeThreshold) {
142 desiredAlpha = 1;
143 } else {
144 desiredAlpha = 1 - ((absTrans - fadeThreshold) / (size - fadeThreshold));
145 }
146 setGearAlpha(desiredAlpha);
147 }
148
149 public void fadeInSettings(final boolean fromLeft, final float transX,
150 final float notiThreshold) {
151 setIconLocation(transX > 0 /* fromLeft */);
152 mFadeAnimator = ValueAnimator.ofFloat(mGearIcon.getAlpha(), 1);
153 mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
154 @Override
155 public void onAnimationUpdate(ValueAnimator animation) {
156 final float absTrans = Math.abs(transX);
157
158 boolean pastGear = (fromLeft && transX <= notiThreshold)
159 || (!fromLeft && absTrans <= notiThreshold);
160 if (pastGear && !mSettingsFadedIn) {
161 setGearAlpha((float) animation.getAnimatedValue());
162 }
163 }
164 });
165 mFadeAnimator.addListener(new AnimatorListenerAdapter() {
166 @Override
167 public void onAnimationCancel(Animator animation) {
168 super.onAnimationCancel(animation);
169 mAnimating = false;
170 mSettingsFadedIn = false;
171 }
172
173 @Override
174 public void onAnimationStart(Animator animation) {
175 super.onAnimationStart(animation);
176 mAnimating = true;
177 }
178
179 @Override
180 public void onAnimationEnd(Animator animation) {
181 super.onAnimationEnd(animation);
182 mAnimating = false;
183 mSettingsFadedIn = true;
184 }
185 });
186 mFadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
187 mFadeAnimator.setDuration(200);
188 mFadeAnimator.start();
189 }
190
Mady Mellor4b80b102016-01-22 08:03:58 -0800191 private void setIconLocation(boolean onLeft) {
192 if (onLeft == mOnLeft) {
193 // Same side? Do nothing.
194 return;
195 }
Mady Mellorf0625802016-02-11 18:03:48 -0800196
197 setTranslationX(onLeft ? 0 : (mParent.getWidth() - mHorizSpaceForGear));
Mady Mellor4b80b102016-01-22 08:03:58 -0800198 mOnLeft = onLeft;
199 }
Mady Mellorf0625802016-02-11 18:03:48 -0800200
201 @Override
202 public void onClick(View v) {
203 if (v.getId() == R.id.gear_icon) {
204 if (mListener != null) {
Mady Mellorb53bc272016-02-11 18:28:23 -0800205 mGearIcon.getLocationOnScreen(mGearLocation);
206 mParent.getLocationOnScreen(mParentLocation);
207
208 final int centerX = (int) (mHorizSpaceForGear / 2);
209 // Top / bottom padding are not equal, need to subtract them to get center of gear.
210 final int centerY = (int) (mGearIcon.getHeight() - mGearIcon.getPaddingTop()
211 - mGearIcon.getPaddingBottom()) / 2 + mGearIcon.getPaddingTop();
212 final int x = mGearLocation[0] - mParentLocation[0] + centerX;
213 final int y = mGearLocation[1] - mParentLocation[1] + centerY;
214 mListener.onGearTouched(mParent, x, y);
Mady Mellorf0625802016-02-11 18:03:48 -0800215 }
216 } else {
217 // Do nothing when the background is touched.
218 }
219 }
Mady Mellor4b80b102016-01-22 08:03:58 -0800220}