• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.deskclock.alarms.dataadapter;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.AnimatorSet;
22 import android.animation.ObjectAnimator;
23 import android.content.Context;
24 import android.graphics.Rect;
25 import android.support.v7.widget.RecyclerView.ViewHolder;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.widget.TextView;
30 
31 import com.android.deskclock.AnimatorUtils;
32 import com.android.deskclock.ItemAdapter;
33 import com.android.deskclock.R;
34 import com.android.deskclock.data.DataModel;
35 import com.android.deskclock.data.Weekdays;
36 import com.android.deskclock.events.Events;
37 import com.android.deskclock.provider.Alarm;
38 import com.android.deskclock.provider.AlarmInstance;
39 
40 import java.util.Calendar;
41 import java.util.List;
42 
43 /**
44  * A ViewHolder containing views for an alarm item in collapsed stated.
45  */
46 public final class CollapsedAlarmViewHolder extends AlarmItemViewHolder {
47 
48     public static final int VIEW_TYPE = R.layout.alarm_time_collapsed;
49 
50     private final TextView alarmLabel;
51     public final TextView daysOfWeek;
52     private final TextView upcomingInstanceLabel;
53     private final View hairLine;
54 
CollapsedAlarmViewHolder(View itemView)55     private CollapsedAlarmViewHolder(View itemView) {
56         super(itemView);
57 
58         alarmLabel = (TextView) itemView.findViewById(R.id.label);
59         daysOfWeek = (TextView) itemView.findViewById(R.id.days_of_week);
60         upcomingInstanceLabel = (TextView) itemView.findViewById(R.id.upcoming_instance_label);
61         hairLine = itemView.findViewById(R.id.hairline);
62 
63         // Expand handler
64         itemView.setOnClickListener(new View.OnClickListener() {
65             @Override
66             public void onClick(View v) {
67                 Events.sendAlarmEvent(R.string.action_expand_implied, R.string.label_deskclock);
68                 getItemHolder().expand();
69             }
70         });
71         alarmLabel.setOnClickListener(new View.OnClickListener() {
72             @Override
73             public void onClick(View v) {
74                 Events.sendAlarmEvent(R.string.action_expand_implied, R.string.label_deskclock);
75                 getItemHolder().expand();
76             }
77         });
78         arrow.setOnClickListener(new View.OnClickListener() {
79             @Override
80             public void onClick(View v) {
81                 Events.sendAlarmEvent(R.string.action_expand, R.string.label_deskclock);
82                 getItemHolder().expand();
83             }
84         });
85         // Edit time handler
86         clock.setOnClickListener(new View.OnClickListener() {
87             @Override
88             public void onClick(View v) {
89                 getItemHolder().getAlarmTimeClickHandler().onClockClicked(getItemHolder().item);
90                 Events.sendAlarmEvent(R.string.action_expand_implied, R.string.label_deskclock);
91                 getItemHolder().expand();
92             }
93         });
94 
95         itemView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
96     }
97 
98     @Override
onBindItemView(AlarmItemHolder itemHolder)99     protected void onBindItemView(AlarmItemHolder itemHolder) {
100         super.onBindItemView(itemHolder);
101         final Alarm alarm = itemHolder.item;
102         final AlarmInstance alarmInstance = itemHolder.getAlarmInstance();
103         final Context context = itemView.getContext();
104         bindRepeatText(context, alarm);
105         bindReadOnlyLabel(context, alarm);
106         bindUpcomingInstance(context, alarm);
107         bindPreemptiveDismissButton(context, alarm, alarmInstance);
108     }
109 
bindReadOnlyLabel(Context context, Alarm alarm)110     private void bindReadOnlyLabel(Context context, Alarm alarm) {
111         if (alarm.label != null && alarm.label.length() != 0) {
112             alarmLabel.setText(alarm.label);
113             alarmLabel.setVisibility(View.VISIBLE);
114             alarmLabel.setContentDescription(context.getString(R.string.label_description)
115                     + " " + alarm.label);
116         } else {
117             alarmLabel.setVisibility(View.GONE);
118         }
119     }
120 
bindRepeatText(Context context, Alarm alarm)121     private void bindRepeatText(Context context, Alarm alarm) {
122         if (alarm.daysOfWeek.isRepeating()) {
123             final Weekdays.Order weekdayOrder = DataModel.getDataModel().getWeekdayOrder();
124             final String daysOfWeekText = alarm.daysOfWeek.toString(context, weekdayOrder);
125             daysOfWeek.setText(daysOfWeekText);
126 
127             final String string = alarm.daysOfWeek.toAccessibilityString(context, weekdayOrder);
128             daysOfWeek.setContentDescription(string);
129 
130             daysOfWeek.setVisibility(View.VISIBLE);
131         } else {
132             daysOfWeek.setVisibility(View.GONE);
133         }
134     }
135 
bindUpcomingInstance(Context context, Alarm alarm)136     private void bindUpcomingInstance(Context context, Alarm alarm) {
137         if (alarm.daysOfWeek.isRepeating()) {
138             upcomingInstanceLabel.setVisibility(View.GONE);
139         } else {
140             upcomingInstanceLabel.setVisibility(View.VISIBLE);
141             final String labelText = Alarm.isTomorrow(alarm, Calendar.getInstance()) ?
142                     context.getString(R.string.alarm_tomorrow) :
143                     context.getString(R.string.alarm_today);
144             upcomingInstanceLabel.setText(labelText);
145         }
146     }
147 
148     @Override
onAnimateChange(List<Object> payloads, int fromLeft, int fromTop, int fromRight, int fromBottom, long duration)149     public Animator onAnimateChange(List<Object> payloads, int fromLeft, int fromTop, int fromRight,
150             int fromBottom, long duration) {
151         /* There are no possible partial animations for collapsed view holders. */
152         return null;
153     }
154 
155     @Override
onAnimateChange(final ViewHolder oldHolder, ViewHolder newHolder, long duration)156     public Animator onAnimateChange(final ViewHolder oldHolder, ViewHolder newHolder,
157             long duration) {
158         if (!(oldHolder instanceof AlarmItemViewHolder)
159                 || !(newHolder instanceof AlarmItemViewHolder)) {
160             return null;
161         }
162 
163         final boolean isCollapsing = this == newHolder;
164         setChangingViewsAlpha(isCollapsing ? 0f : 1f);
165 
166         final Animator changeAnimatorSet = isCollapsing
167                 ? createCollapsingAnimator((AlarmItemViewHolder) oldHolder, duration)
168                 : createExpandingAnimator((AlarmItemViewHolder) newHolder, duration);
169         changeAnimatorSet.addListener(new AnimatorListenerAdapter() {
170             @Override
171             public void onAnimationEnd(Animator animator) {
172                 clock.setVisibility(View.VISIBLE);
173                 onOff.setVisibility(View.VISIBLE);
174                 arrow.setVisibility(View.VISIBLE);
175                 arrow.setTranslationY(0f);
176                 setChangingViewsAlpha(1f);
177                 arrow.jumpDrawablesToCurrentState();
178             }
179         });
180         return changeAnimatorSet;
181     }
182 
createExpandingAnimator(AlarmItemViewHolder newHolder, long duration)183     private Animator createExpandingAnimator(AlarmItemViewHolder newHolder, long duration) {
184         clock.setVisibility(View.INVISIBLE);
185         onOff.setVisibility(View.INVISIBLE);
186         arrow.setVisibility(View.INVISIBLE);
187 
188         final AnimatorSet alphaAnimatorSet = new AnimatorSet();
189         alphaAnimatorSet.playTogether(
190                 ObjectAnimator.ofFloat(alarmLabel, View.ALPHA, 0f),
191                 ObjectAnimator.ofFloat(daysOfWeek, View.ALPHA, 0f),
192                 ObjectAnimator.ofFloat(upcomingInstanceLabel, View.ALPHA, 0f),
193                 ObjectAnimator.ofFloat(preemptiveDismissButton, View.ALPHA, 0f),
194                 ObjectAnimator.ofFloat(hairLine, View.ALPHA, 0f));
195         alphaAnimatorSet.setDuration((long) (duration * ANIM_SHORT_DURATION_MULTIPLIER));
196 
197         final View oldView = itemView;
198         final View newView = newHolder.itemView;
199         final Animator boundsAnimator = AnimatorUtils.getBoundsAnimator(oldView, oldView, newView)
200                 .setDuration(duration);
201         boundsAnimator.setInterpolator(AnimatorUtils.INTERPOLATOR_FAST_OUT_SLOW_IN);
202 
203         final AnimatorSet animatorSet = new AnimatorSet();
204         animatorSet.playTogether(alphaAnimatorSet, boundsAnimator);
205         return animatorSet;
206     }
207 
createCollapsingAnimator(AlarmItemViewHolder oldHolder, long duration)208     private Animator createCollapsingAnimator(AlarmItemViewHolder oldHolder, long duration) {
209         final AnimatorSet alphaAnimatorSet = new AnimatorSet();
210         alphaAnimatorSet.playTogether(
211                 ObjectAnimator.ofFloat(alarmLabel, View.ALPHA, 1f),
212                 ObjectAnimator.ofFloat(daysOfWeek, View.ALPHA, 1f),
213                 ObjectAnimator.ofFloat(upcomingInstanceLabel, View.ALPHA, 1f),
214                 ObjectAnimator.ofFloat(preemptiveDismissButton, View.ALPHA, 1f),
215                 ObjectAnimator.ofFloat(hairLine, View.ALPHA, 1f));
216         final long standardDelay = (long) (duration * ANIM_STANDARD_DELAY_MULTIPLIER);
217         alphaAnimatorSet.setDuration(standardDelay);
218         alphaAnimatorSet.setStartDelay(duration - standardDelay);
219 
220         final View oldView = oldHolder.itemView;
221         final View newView = itemView;
222         final Animator boundsAnimator = AnimatorUtils.getBoundsAnimator(newView, oldView, newView)
223                 .setDuration(duration);
224         boundsAnimator.setInterpolator(AnimatorUtils.INTERPOLATOR_FAST_OUT_SLOW_IN);
225 
226         final View oldArrow = oldHolder.arrow;
227         final Rect oldArrowRect = new Rect(0, 0, oldArrow.getWidth(), oldArrow.getHeight());
228         final Rect newArrowRect = new Rect(0, 0, arrow.getWidth(), arrow.getHeight());
229         ((ViewGroup) newView).offsetDescendantRectToMyCoords(arrow, newArrowRect);
230         ((ViewGroup) oldView).offsetDescendantRectToMyCoords(oldArrow, oldArrowRect);
231         final float arrowTranslationY = oldArrowRect.bottom - newArrowRect.bottom;
232         arrow.setTranslationY(arrowTranslationY);
233         arrow.setVisibility(View.VISIBLE);
234         clock.setVisibility(View.VISIBLE);
235         onOff.setVisibility(View.VISIBLE);
236 
237         final Animator arrowAnimation = ObjectAnimator.ofFloat(arrow, View.TRANSLATION_Y, 0f)
238                 .setDuration(duration);
239         arrowAnimation.setInterpolator(AnimatorUtils.INTERPOLATOR_FAST_OUT_SLOW_IN);
240 
241         final AnimatorSet animatorSet = new AnimatorSet();
242         animatorSet.playTogether(alphaAnimatorSet, boundsAnimator, arrowAnimation);
243         animatorSet.addListener(new AnimatorListenerAdapter() {
244             @Override
245             public void onAnimationStart(Animator animator) {
246                 AnimatorUtils.startDrawableAnimation(arrow);
247             }
248         });
249         return animatorSet;
250     }
251 
setChangingViewsAlpha(float alpha)252     private void setChangingViewsAlpha(float alpha) {
253         alarmLabel.setAlpha(alpha);
254         daysOfWeek.setAlpha(alpha);
255         upcomingInstanceLabel.setAlpha(alpha);
256         hairLine.setAlpha(alpha);
257         preemptiveDismissButton.setAlpha(alpha);
258     }
259 
260     public static class Factory implements ItemAdapter.ItemViewHolder.Factory {
261         private final LayoutInflater mLayoutInflater;
262 
Factory(LayoutInflater layoutInflater)263         public Factory(LayoutInflater layoutInflater) {
264             mLayoutInflater = layoutInflater;
265         }
266 
267         @Override
createViewHolder(ViewGroup parent, int viewType)268         public ItemAdapter.ItemViewHolder<?> createViewHolder(ViewGroup parent, int viewType) {
269             return new CollapsedAlarmViewHolder(mLayoutInflater.inflate(
270                     viewType, parent, false /* attachToRoot */));
271         }
272     }
273 }