Home | History | Annotate | Download | only in answermethod
      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
     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
     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
     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
    136   public void onDestroyView() {
    137     super.onDestroyView();
    138     if (touchHandler != null) {
    139       touchHandler.detach();
    140       touchHandler = null;
    141     }
    142   }
    143 
    144   @Override
    145   public void setHintText(@Nullable CharSequence hintText) {
    146     this.hintText = hintText;
    147     updateHintText();
    148   }
    149 
    150   @Override
    151   public void setShowIncomingWillDisconnect(boolean incomingWillDisconnect) {
    152     this.incomingWillDisconnect = incomingWillDisconnect;
    153     updateHintText();
    154   }
    155 
    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
    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 
    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 
    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
    236   public void onAnimationUpdate(ValueAnimator animation) {
    237     getParent().onAnswerProgressUpdate(((float) animation.getAnimatedValue()));
    238   }
    239 
    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