• 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.incallui.answer.impl.answermethod;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.AnimatorSet;
22 import android.animation.ObjectAnimator;
23 import android.animation.PropertyValuesHolder;
24 import android.animation.ValueAnimator;
25 import android.animation.ValueAnimator.AnimatorUpdateListener;
26 import android.os.Bundle;
27 import android.support.annotation.FloatRange;
28 import android.support.annotation.NonNull;
29 import android.support.annotation.Nullable;
30 import android.text.TextUtils;
31 import android.view.LayoutInflater;
32 import android.view.MotionEvent;
33 import android.view.View;
34 import android.view.View.OnClickListener;
35 import android.view.ViewGroup;
36 import android.widget.TextView;
37 import com.android.dialer.common.Assert;
38 import com.android.dialer.common.LogUtil;
39 import com.android.dialer.compat.ActivityCompat;
40 import com.android.incallui.answer.impl.answermethod.FlingUpDownTouchHandler.OnProgressChangedListener;
41 import com.android.incallui.util.AccessibilityUtil;
42 
43 /** Answer method that shows two buttons for answer/reject. */
44 public class TwoButtonMethod extends AnswerMethod
45     implements OnClickListener, AnimatorUpdateListener {
46 
47   private static final String STATE_HINT_TEXT = "hintText";
48   private static final String STATE_INCOMING_WILL_DISCONNECT = "incomingWillDisconnect";
49 
50   private View answerButton;
51   private View answerLabel;
52   private View declineButton;
53   private View declineLabel;
54   private TextView hintTextView;
55   private boolean incomingWillDisconnect;
56   private boolean buttonClicked;
57   private CharSequence hintText;
58   @Nullable private FlingUpDownTouchHandler touchHandler;
59 
60   @Override
onCreate(@ullable Bundle bundle)61   public void onCreate(@Nullable Bundle bundle) {
62     super.onCreate(bundle);
63     if (bundle != null) {
64       incomingWillDisconnect = bundle.getBoolean(STATE_INCOMING_WILL_DISCONNECT);
65       hintText = bundle.getCharSequence(STATE_HINT_TEXT);
66     }
67   }
68 
69   @Override
onSaveInstanceState(Bundle bundle)70   public void onSaveInstanceState(Bundle bundle) {
71     super.onSaveInstanceState(bundle);
72     bundle.putBoolean(STATE_INCOMING_WILL_DISCONNECT, incomingWillDisconnect);
73     bundle.putCharSequence(STATE_HINT_TEXT, hintText);
74   }
75 
76   @Nullable
77   @Override
onCreateView( LayoutInflater layoutInflater, @Nullable ViewGroup viewGroup, @Nullable Bundle bundle)78   public View onCreateView(
79       LayoutInflater layoutInflater, @Nullable ViewGroup viewGroup, @Nullable Bundle bundle) {
80     View view = layoutInflater.inflate(R.layout.two_button_method, viewGroup, false);
81 
82     hintTextView = (TextView) view.findViewById(R.id.two_button_hint_text);
83     updateHintText();
84 
85     answerButton = view.findViewById(R.id.two_button_answer_button);
86     answerLabel = view.findViewById(R.id.two_button_answer_label);
87     declineButton = view.findViewById(R.id.two_button_decline_button);
88     declineLabel = view.findViewById(R.id.two_button_decline_label);
89 
90     boolean showLabels = getResources().getBoolean(R.bool.two_button_show_button_labels);
91     answerLabel.setVisibility(showLabels ? View.VISIBLE : View.GONE);
92     declineLabel.setVisibility(showLabels ? View.VISIBLE : View.GONE);
93 
94     answerButton.setOnClickListener(this);
95     declineButton.setOnClickListener(this);
96 
97     if (AccessibilityUtil.isTouchExplorationEnabled(getContext())) {
98       /* Falsing already handled by AccessibilityManager */
99       touchHandler =
100           FlingUpDownTouchHandler.attach(
101               view,
102               new OnProgressChangedListener() {
103                 @Override
104                 public void onProgressChanged(@FloatRange(from = -1f, to = 1f) float progress) {}
105 
106                 @Override
107                 public void onTrackingStart() {}
108 
109                 @Override
110                 public void onTrackingStopped() {}
111 
112                 @Override
113                 public void onMoveReset(boolean showHint) {}
114 
115                 @Override
116                 public void onMoveFinish(boolean accept) {
117                   if (accept) {
118                     answerCall();
119                   } else {
120                     rejectCall();
121                   }
122                 }
123 
124                 @Override
125                 public boolean shouldUseFalsing(@NonNull MotionEvent downEvent) {
126                   return false;
127                 }
128               },
129               null /* Falsing already handled by AccessibilityManager */);
130       touchHandler.setFlingEnabled(false);
131     }
132     return view;
133   }
134 
135   @Override
onDestroyView()136   public void onDestroyView() {
137     super.onDestroyView();
138     if (touchHandler != null) {
139       touchHandler.detach();
140       touchHandler = null;
141     }
142   }
143 
144   @Override
setHintText(@ullable CharSequence hintText)145   public void setHintText(@Nullable CharSequence hintText) {
146     this.hintText = hintText;
147     updateHintText();
148   }
149 
150   @Override
setShowIncomingWillDisconnect(boolean incomingWillDisconnect)151   public void setShowIncomingWillDisconnect(boolean incomingWillDisconnect) {
152     this.incomingWillDisconnect = incomingWillDisconnect;
153     updateHintText();
154   }
155 
updateHintText()156   private void updateHintText() {
157     if (hintTextView == null) {
158       return;
159     }
160     hintTextView.setVisibility(
161         ActivityCompat.isInMultiWindowMode(getActivity()) ? View.GONE : View.VISIBLE);
162     if (!TextUtils.isEmpty(hintText) && !buttonClicked) {
163       hintTextView.setText(hintText);
164       hintTextView.animate().alpha(1f).start();
165     } else if (incomingWillDisconnect && !buttonClicked) {
166       hintTextView.setText(R.string.call_incoming_will_disconnect);
167       hintTextView.animate().alpha(1f).start();
168     } else {
169       hintTextView.animate().alpha(0f).start();
170     }
171   }
172 
173   @Override
onClick(View view)174   public void onClick(View view) {
175     if (view == answerButton) {
176       answerCall();
177       LogUtil.v("TwoButtonMethod.onClick", "Call answered");
178     } else if (view == declineButton) {
179       rejectCall();
180       LogUtil.v("TwoButtonMethod.onClick", "two_buttonMethod Call rejected");
181     } else {
182       Assert.fail("Unknown click from view: " + view);
183     }
184     buttonClicked = true;
185   }
186 
answerCall()187   private void answerCall() {
188     ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
189     animator.addUpdateListener(this);
190     animator.addListener(
191         new AnimatorListenerAdapter() {
192           private boolean canceled;
193 
194           @Override
195           public void onAnimationCancel(Animator animation) {
196             canceled = true;
197           }
198 
199           @Override
200           public void onAnimationEnd(Animator animation) {
201             if (!canceled) {
202               getParent().answerFromMethod();
203             }
204           }
205         });
206     AnimatorSet animatorSet = new AnimatorSet();
207     animatorSet.play(animator).with(createViewHideAnimation());
208     animatorSet.start();
209   }
210 
rejectCall()211   private void rejectCall() {
212     ValueAnimator animator = ValueAnimator.ofFloat(0, -1);
213     animator.addUpdateListener(this);
214     animator.addListener(
215         new AnimatorListenerAdapter() {
216           private boolean canceled;
217 
218           @Override
219           public void onAnimationCancel(Animator animation) {
220             canceled = true;
221           }
222 
223           @Override
224           public void onAnimationEnd(Animator animation) {
225             if (!canceled) {
226               getParent().rejectFromMethod();
227             }
228           }
229         });
230     AnimatorSet animatorSet = new AnimatorSet();
231     animatorSet.play(animator).with(createViewHideAnimation());
232     animatorSet.start();
233   }
234 
235   @Override
onAnimationUpdate(ValueAnimator animation)236   public void onAnimationUpdate(ValueAnimator animation) {
237     getParent().onAnswerProgressUpdate(((float) animation.getAnimatedValue()));
238   }
239 
createViewHideAnimation()240   private Animator createViewHideAnimation() {
241     ObjectAnimator answerButtonHide =
242         ObjectAnimator.ofPropertyValuesHolder(
243             answerButton,
244             PropertyValuesHolder.ofFloat(View.SCALE_X, 0f),
245             PropertyValuesHolder.ofFloat(View.SCALE_Y, 0f));
246 
247     ObjectAnimator declineButtonHide =
248         ObjectAnimator.ofPropertyValuesHolder(
249             declineButton,
250             PropertyValuesHolder.ofFloat(View.SCALE_X, 0f),
251             PropertyValuesHolder.ofFloat(View.SCALE_Y, 0f));
252 
253     ObjectAnimator answerLabelHide = ObjectAnimator.ofFloat(answerLabel, View.ALPHA, 0f);
254 
255     ObjectAnimator declineLabelHide = ObjectAnimator.ofFloat(declineLabel, View.ALPHA, 0f);
256 
257     ObjectAnimator hintHide = ObjectAnimator.ofFloat(hintTextView, View.ALPHA, 0f);
258 
259     AnimatorSet hideSet = new AnimatorSet();
260     hideSet
261         .play(answerButtonHide)
262         .with(declineButtonHide)
263         .with(answerLabelHide)
264         .with(declineLabelHide)
265         .with(hintHide);
266     return hideSet;
267   }
268 }
269