Merge "Use separate AnswerFragment for Talkback" into ub-contactsdialer-a-dev am: 7e5e6be79a
am: d75c0347fa

* commit 'd75c0347fa7be401e66d21ebc696ae55bce37fe8':
  Use separate AnswerFragment for Talkback
diff --git a/InCallUI/res/drawable/ic_lockscreen_answer_activated_layer.xml b/InCallUI/res/drawable/ic_lockscreen_answer_activated_layer.xml
index c615295..f22b87e 100644
--- a/InCallUI/res/drawable/ic_lockscreen_answer_activated_layer.xml
+++ b/InCallUI/res/drawable/ic_lockscreen_answer_activated_layer.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/fab_blue" />
+    <item android:drawable="@drawable/fab_green"/>
     <item>
         <bitmap
             android:gravity="center"
diff --git a/InCallUI/res/layout/accessible_answer_fragment.xml b/InCallUI/res/layout/accessible_answer_fragment.xml
new file mode 100644
index 0000000..90fe577
--- /dev/null
+++ b/InCallUI/res/layout/accessible_answer_fragment.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+~ Copyright (C) 2013 The Android Open Source Project
+~
+~ Licensed under the Apache License, Version 2.0 (the "License");
+~ you may not use this file except in compliance with the License.
+~ You may obtain a copy of the License at
+~
+~      http://www.apache.org/licenses/LICENSE-2.0
+~
+~ Unless required by applicable law or agreed to in writing, software
+~ distributed under the License is distributed on an "AS IS" BASIS,
+~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~ See the License for the specific language governing permissions and
+~ limitations under the License
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center_horizontal"
+    android:background="@color/glowpad_background_color">
+    <RelativeLayout
+        android:id="@+id/accessible_answer_fragment_answer"
+        android:orientation="vertical"
+        android:layout_width="120dp"
+        android:layout_height="120dp"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        android:clickable="true"
+        android:layout_alignParentRight="true"
+        android:layout_centerVertical="true"
+        android:layout_marginLeft="16dp"
+        android:layout_marginRight="16dp">
+        <ImageView
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:src="@drawable/ic_lockscreen_answer_activated_layer"
+            android:layout_centerInParent="true">
+        </ImageView>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/description_target_answer"
+            android:textSize="12sp"
+            android:textColor="@color/accessible_answer_hint_text_color"
+            android:layout_alignParentBottom="true"
+            android:layout_centerHorizontal="true"
+            android:layout_marginBottom="8dp"/>
+    </RelativeLayout>
+    <RelativeLayout
+        android:id="@+id/accessible_answer_fragment_decline"
+        android:orientation="vertical"
+        android:layout_width="120dp"
+        android:layout_height="120dp"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        android:clickable="true"
+        android:layout_alignParentLeft="true"
+        android:layout_centerVertical="true"
+        android:layout_marginLeft="16dp"
+        android:layout_marginRight="16dp">
+        <ImageView
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:src="@drawable/ic_lockscreen_decline_activated_layer"
+            android:layout_centerInParent="true">
+        </ImageView>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/description_target_decline"
+            android:textSize="12sp"
+            android:textColor="@color/accessible_answer_hint_text_color"
+            android:layout_alignParentBottom="true"
+            android:layout_centerHorizontal="true"
+            android:layout_marginBottom="8dp"/>
+    </RelativeLayout>
+    <LinearLayout
+        android:id="@+id/accessible_answer_fragment_text"
+        android:orientation="vertical"
+        android:layout_width="92dp"
+        android:layout_height="92dp"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        android:clickable="true"
+        android:layout_alignParentEnd="false"
+        android:layout_alignParentStart="false"
+        android:layout_above="@+id/accessible_answer_fragment_decline"
+        android:layout_alignWithParentIfMissing="false"
+        android:layout_alignParentTop="false"
+        android:layout_alignParentLeft="false"
+        android:layout_alignParentBottom="false"
+        android:layout_alignParentRight="false"
+        android:layout_centerHorizontal="true"
+        android:contentDescription="@string/description_target_send_sms"
+        android:gravity="center">
+        <ImageView
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:src="@drawable/ic_lockscreen_text">
+        </ImageView>
+    </LinearLayout>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/InCallUI/res/values/colors.xml b/InCallUI/res/values/colors.xml
index 3697e11..60a017c 100644
--- a/InCallUI/res/values/colors.xml
+++ b/InCallUI/res/values/colors.xml
@@ -73,11 +73,14 @@
     <color name="glowpad_text_widget_ring_color">#ffffff</color>
     <color name="glowpad_widget_active_color">#ffffff</color>
     <color name="glowpad_text_widget_normal_tint">#cccccc</color>
-    <color name="glowpad_call_widget_normal_tint">@color/dialtacts_theme_color</color>
+    <color name="glowpad_call_widget_normal_tint">#00c853</color>
     <color name="glowpad_end_call_widget_normal_tint">#ff1744</color>
     <color name="glowpad_incoming_widget_tint">#a3a3a3</color>
     <color name="glowpad_incoming_widget_background_tint">#ffffff</color>
 
+    <!-- 70% opacity, white. -->
+    <color name="accessible_answer_hint_text_color">#B2FFFFFF</color>
+
     <!-- 20% opacity, theme color. -->
     <color name="incall_dialpad_touch_tint">#330288d1</color>
 
diff --git a/InCallUI/src/com/android/incallui/AccessibleAnswerFragment.java b/InCallUI/src/com/android/incallui/AccessibleAnswerFragment.java
new file mode 100644
index 0000000..89c78ec
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/AccessibleAnswerFragment.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.incallui;
+
+import android.os.Bundle;
+import android.telecom.VideoProfile;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.dialer.R;
+
+/**
+ * AnswerFragment to use when touch exploration is enabled in accessibility.
+ */
+public class AccessibleAnswerFragment extends AnswerFragment {
+
+    private static final String TAG = AccessibleAnswerFragment.class.getSimpleName();
+    private static final int SWIPE_THRESHOLD = 100;
+
+    private View mAnswer;
+    private View mDecline;
+    private View mText;
+
+    private TouchListener mTouchListener;
+    private GestureDetector mGestureDetector;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        ViewGroup group = (ViewGroup) inflater.inflate(R.layout.accessible_answer_fragment,
+                container, false);
+
+        mTouchListener = new TouchListener();
+        mGestureDetector = new GestureDetector(getContext(), new SimpleOnGestureListener() {
+            @Override
+            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
+                    float velocityY) {
+                return AccessibleAnswerFragment.this.onFling(e1, e2, velocityX, velocityX);
+            }
+        });
+
+        mAnswer = group.findViewById(R.id.accessible_answer_fragment_answer);
+        mAnswer.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Log.d(TAG, "Answer Button Clicked");
+                onAnswer(VideoProfile.STATE_AUDIO_ONLY, getContext());
+            }
+        });
+        mDecline = group.findViewById(R.id.accessible_answer_fragment_decline);
+        mDecline.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Log.d(TAG, "Decline Button Clicked");
+                onDecline(getContext());
+            }
+        });
+
+        mText = group.findViewById(R.id.accessible_answer_fragment_text);
+        mText.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Log.d(TAG, "Text Button Clicked");
+                onText();
+            }
+        });
+        return group;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        // Intercept all touch events for full screen swiping gesture.
+        InCallActivity activity = (InCallActivity) getActivity();
+        activity.setDispatchTouchEventListener(mTouchListener);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        InCallActivity activity = (InCallActivity) getActivity();
+        activity.setDispatchTouchEventListener(null);
+    }
+
+    private class TouchListener implements View.OnTouchListener {
+        @Override
+        public boolean onTouch(View v, MotionEvent event) {
+            return mGestureDetector.onTouchEvent(event);
+        }
+    }
+
+    private boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
+            float velocityY) {
+        if (hasPendingDialogs()) {
+            return false;
+        }
+
+        float diffY = e2.getY() - e1.getY();
+        float diffX = e2.getX() - e1.getX();
+        if (Math.abs(diffX) > Math.abs(diffY)) {
+            if (Math.abs(diffX) > SWIPE_THRESHOLD) {
+                if (diffX > 0) {
+                    onSwipeRight();
+                } else {
+                    onSwipeLeft();
+                }
+            }
+            return true;
+        } else if (Math.abs(diffY) > SWIPE_THRESHOLD) {
+            if (diffY > 0) {
+                onSwipeDown();
+            } else {
+                onSwipeUp();
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    private void onSwipeUp() {
+        Log.d(TAG, "onSwipeUp");
+        onText();
+    }
+
+    private void onSwipeDown() {
+        Log.d(TAG, "onSwipeDown");
+    }
+
+    private void onSwipeLeft() {
+        Log.d(TAG, "onSwipeLeft");
+        onDecline(getContext());
+    }
+
+    private void onSwipeRight() {
+        Log.d(TAG, "onSwipeRight");
+        onAnswer(VideoProfile.STATE_AUDIO_ONLY, getContext());
+    }
+}
diff --git a/InCallUI/src/com/android/incallui/AnswerFragment.java b/InCallUI/src/com/android/incallui/AnswerFragment.java
index 7c67719..44ddfcd 100644
--- a/InCallUI/src/com/android/incallui/AnswerFragment.java
+++ b/InCallUI/src/com/android/incallui/AnswerFragment.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.os.Bundle;
-import android.telecom.VideoProfile;
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.view.LayoutInflater;
@@ -34,17 +33,17 @@
 import android.widget.EditText;
 import android.widget.ListView;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
+import com.android.dialer.R;
 
 import java.util.ArrayList;
 import java.util.List;
 
+
 /**
- *
+ * Provides only common interface and functions. Should be derived to implement the actual UI.
  */
-public class AnswerFragment extends BaseFragment<AnswerPresenter, AnswerPresenter.AnswerUi>
-        implements GlowPadWrapper.AnswerListener, AnswerPresenter.AnswerUi {
+public abstract class AnswerFragment extends BaseFragment<AnswerPresenter, AnswerPresenter.AnswerUi>
+        implements AnswerPresenter.AnswerUi {
 
     public static final int TARGET_SET_FOR_AUDIO_WITHOUT_SMS = 0;
     public static final int TARGET_SET_FOR_AUDIO_WITH_SMS = 1;
@@ -53,6 +52,13 @@
     public static final int TARGET_SET_FOR_VIDEO_ACCEPT_REJECT_REQUEST = 4;
 
     /**
+     * This fragment implement no UI at all. Derived class should do it.
+     */
+    @Override
+    public abstract View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState);
+
+    /**
      * The popup showing the list of canned responses.
      *
      * This is an AlertDialog containing a ListView showing the possible choices.  This may be null
@@ -70,11 +76,6 @@
 
     private final List<String> mSmsResponses = new ArrayList<>();
 
-    private GlowPadWrapper mGlowpad;
-
-    public AnswerFragment() {
-    }
-
     @Override
     public AnswerPresenter createPresenter() {
         return InCallPresenter.getInstance().getAnswerPresenter();
@@ -86,113 +87,6 @@
     }
 
     @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        mGlowpad = (GlowPadWrapper) inflater.inflate(R.layout.answer_fragment,
-                container, false);
-
-        Log.d(this, "Creating view for answer fragment ", this);
-        Log.d(this, "Created from activity", getActivity());
-        mGlowpad.setAnswerListener(this);
-
-        return mGlowpad;
-    }
-
-    @Override
-    public void onDestroyView() {
-        Log.d(this, "onDestroyView");
-        if (mGlowpad != null) {
-            mGlowpad.stopPing();
-            mGlowpad = null;
-        }
-        super.onDestroyView();
-    }
-
-    @Override
-    public void onShowAnswerUi(boolean shown) {
-        Log.d(this, "Show answer UI: " + shown);
-        if (shown) {
-            mGlowpad.startPing();
-        } else {
-            mGlowpad.stopPing();
-        }
-    }
-
-    /**
-     * Sets targets on the glowpad according to target set identified by the parameter.
-     * @param targetSet Integer identifying the set of targets to use.
-     */
-    public void showTargets(int targetSet) {
-        showTargets(targetSet, VideoProfile.STATE_BIDIRECTIONAL);
-    }
-
-    /**
-     * Sets targets on the glowpad according to target set identified by the parameter.
-     * @param targetSet Integer identifying the set of targets to use.
-     */
-    @Override
-    public void showTargets(int targetSet, int videoState) {
-        final int targetResourceId;
-        final int targetDescriptionsResourceId;
-        final int directionDescriptionsResourceId;
-        final int handleDrawableResourceId;
-        mGlowpad.setVideoState(videoState);
-
-        switch (targetSet) {
-            case TARGET_SET_FOR_AUDIO_WITH_SMS:
-                targetResourceId = R.array.incoming_call_widget_audio_with_sms_targets;
-                targetDescriptionsResourceId =
-                        R.array.incoming_call_widget_audio_with_sms_target_descriptions;
-                directionDescriptionsResourceId =
-                        R.array.incoming_call_widget_audio_with_sms_direction_descriptions;
-                handleDrawableResourceId = R.drawable.ic_incall_audio_handle;
-                break;
-            case TARGET_SET_FOR_VIDEO_WITHOUT_SMS:
-                targetResourceId = R.array.incoming_call_widget_video_without_sms_targets;
-                targetDescriptionsResourceId =
-                        R.array.incoming_call_widget_video_without_sms_target_descriptions;
-                directionDescriptionsResourceId =
-                        R.array.incoming_call_widget_video_without_sms_direction_descriptions;
-                handleDrawableResourceId = R.drawable.ic_incall_video_handle;
-                break;
-            case TARGET_SET_FOR_VIDEO_WITH_SMS:
-                targetResourceId = R.array.incoming_call_widget_video_with_sms_targets;
-                targetDescriptionsResourceId =
-                        R.array.incoming_call_widget_video_with_sms_target_descriptions;
-                directionDescriptionsResourceId =
-                        R.array.incoming_call_widget_video_with_sms_direction_descriptions;
-                handleDrawableResourceId = R.drawable.ic_incall_video_handle;
-                break;
-            case TARGET_SET_FOR_VIDEO_ACCEPT_REJECT_REQUEST:
-                targetResourceId =
-                    R.array.incoming_call_widget_video_request_targets;
-                targetDescriptionsResourceId =
-                        R.array.incoming_call_widget_video_request_target_descriptions;
-                directionDescriptionsResourceId = R.array
-                        .incoming_call_widget_video_request_target_direction_descriptions;
-                handleDrawableResourceId = R.drawable.ic_incall_video_handle;
-                break;
-            case TARGET_SET_FOR_AUDIO_WITHOUT_SMS:
-            default:
-                targetResourceId = R.array.incoming_call_widget_audio_without_sms_targets;
-                targetDescriptionsResourceId =
-                        R.array.incoming_call_widget_audio_without_sms_target_descriptions;
-                directionDescriptionsResourceId =
-                        R.array.incoming_call_widget_audio_without_sms_direction_descriptions;
-                handleDrawableResourceId = R.drawable.ic_incall_audio_handle;
-                break;
-        }
-
-        if (targetResourceId != mGlowpad.getTargetResourceId()) {
-            mGlowpad.setTargetResources(targetResourceId);
-            mGlowpad.setTargetDescriptionsResourceId(targetDescriptionsResourceId);
-            mGlowpad.setDirectionDescriptionsResourceId(directionDescriptionsResourceId);
-            mGlowpad.setHandleDrawable(handleDrawableResourceId);
-            mGlowpad.reset(false);
-        }
-    }
-
-    @Override
     public void showMessageDialog() {
         final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
 
@@ -207,9 +101,7 @@
                 new DialogInterface.OnCancelListener() {
                     @Override
                     public void onCancel(DialogInterface dialogInterface) {
-                        if (mGlowpad != null) {
-                            mGlowpad.startPing();
-                        }
+                        onMessageDialogCancel();
                         dismissCannedResponsePopup();
                         getPresenter().onDismissDialog();
                     }
@@ -239,7 +131,7 @@
      * This is safe to call even if the popup is already dismissed, and even if you never called
      * showRespondViaSmsPopup() in the first place.
      */
-    private void dismissCannedResponsePopup() {
+    protected void dismissCannedResponsePopup() {
         if (mCannedResponsePopup != null) {
             mCannedResponsePopup.dismiss();  // safe even if already dismissed
             mCannedResponsePopup = null;
@@ -250,10 +142,10 @@
      * Dismiss the custom compose message popup.
      */
     private void dismissCustomMessagePopup() {
-       if (mCustomMessagePopup != null) {
-           mCustomMessagePopup.dismiss();
-           mCustomMessagePopup = null;
-       }
+        if (mCustomMessagePopup != null) {
+            mCustomMessagePopup.dismiss();
+            mCustomMessagePopup = null;
+        }
     }
 
     public void dismissPendingDialogs() {
@@ -280,23 +172,23 @@
         builder.setCancelable(true).setView(et)
                 .setPositiveButton(R.string.custom_message_send,
                         new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        // The order is arranged in a way that the popup will be destroyed when the
-                        // InCallActivity is about to finish.
-                        final String textMessage = et.getText().toString().trim();
-                        dismissCustomMessagePopup();
-                        getPresenter().rejectCallWithMessage(textMessage);
-                    }
-                })
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                // The order is arranged in a way that the popup will be destroyed
+                                // when the InCallActivity is about to finish.
+                                final String textMessage = et.getText().toString().trim();
+                                dismissCustomMessagePopup();
+                                getPresenter().rejectCallWithMessage(textMessage);
+                            }
+                        })
                 .setNegativeButton(R.string.custom_message_cancel,
                         new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        dismissCustomMessagePopup();
-                        getPresenter().onDismissDialog();
-                    }
-                })
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                dismissCustomMessagePopup();
+                                getPresenter().onDismissDialog();
+                            }
+                        })
                 .setOnCancelListener(new DialogInterface.OnCancelListener() {
                     @Override
                     public void onCancel(DialogInterface dialogInterface) {
@@ -352,23 +244,19 @@
         return getActivity();
     }
 
-    @Override
     public void onAnswer(int videoState, Context context) {
         Log.d(this, "onAnswer videoState=" + videoState + " context=" + context);
         getPresenter().onAnswer(videoState, context);
     }
 
-    @Override
     public void onDecline(Context context) {
         getPresenter().onDecline(context);
     }
 
-    @Override
     public void onDeclineUpgradeRequest(Context context) {
         InCallPresenter.getInstance().declineUpgradeRequest(context);
     }
 
-    @Override
     public void onText() {
         getPresenter().onText();
     }
@@ -400,4 +288,20 @@
             }
         }
     }
+
+    public void onShowAnswerUi(boolean shown) {
+        // Do Nothing
+    }
+
+    public void showTargets(int targetSet) {
+        // Do Nothing
+    }
+
+    public void showTargets(int targetSet, int videoState) {
+        // Do Nothing
+    }
+
+    protected void onMessageDialogCancel() {
+        // Do nothing.
+    }
 }
diff --git a/InCallUI/src/com/android/incallui/GlowPadAnswerFragment.java b/InCallUI/src/com/android/incallui/GlowPadAnswerFragment.java
new file mode 100644
index 0000000..62a8e78
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/GlowPadAnswerFragment.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.incallui;
+
+import android.os.Bundle;
+import android.telecom.VideoProfile;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.dialer.R;
+
+public class GlowPadAnswerFragment extends AnswerFragment {
+
+    private GlowPadWrapper mGlowpad;
+
+    public GlowPadAnswerFragment() {
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        mGlowpad = (GlowPadWrapper) inflater.inflate(R.layout.answer_fragment,
+                container, false);
+
+        Log.d(this, "Creating view for answer fragment ", this);
+        Log.d(this, "Created from activity", getActivity());
+        mGlowpad.setAnswerFragment(this);
+
+        return mGlowpad;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mGlowpad.requestFocus();
+    }
+
+    @Override
+    public void onDestroyView() {
+        Log.d(this, "onDestroyView");
+        if (mGlowpad != null) {
+            mGlowpad.stopPing();
+            mGlowpad = null;
+        }
+        super.onDestroyView();
+    }
+
+    @Override
+    public void onShowAnswerUi(boolean shown) {
+        Log.d(this, "Show answer UI: " + shown);
+        if (shown) {
+            mGlowpad.startPing();
+        } else {
+            mGlowpad.stopPing();
+        }
+    }
+
+    /**
+     * Sets targets on the glowpad according to target set identified by the parameter.
+     *
+     * @param targetSet Integer identifying the set of targets to use.
+     */
+    public void showTargets(int targetSet) {
+        showTargets(targetSet, VideoProfile.STATE_BIDIRECTIONAL);
+    }
+
+    /**
+     * Sets targets on the glowpad according to target set identified by the parameter.
+     *
+     * @param targetSet Integer identifying the set of targets to use.
+     */
+    @Override
+    public void showTargets(int targetSet, int videoState) {
+        final int targetResourceId;
+        final int targetDescriptionsResourceId;
+        final int directionDescriptionsResourceId;
+        final int handleDrawableResourceId;
+        mGlowpad.setVideoState(videoState);
+
+        switch (targetSet) {
+            case TARGET_SET_FOR_AUDIO_WITH_SMS:
+                targetResourceId = R.array.incoming_call_widget_audio_with_sms_targets;
+                targetDescriptionsResourceId =
+                        R.array.incoming_call_widget_audio_with_sms_target_descriptions;
+                directionDescriptionsResourceId =
+                        R.array.incoming_call_widget_audio_with_sms_direction_descriptions;
+                handleDrawableResourceId = R.drawable.ic_incall_audio_handle;
+                break;
+            case TARGET_SET_FOR_VIDEO_WITHOUT_SMS:
+                targetResourceId = R.array.incoming_call_widget_video_without_sms_targets;
+                targetDescriptionsResourceId =
+                        R.array.incoming_call_widget_video_without_sms_target_descriptions;
+                directionDescriptionsResourceId =
+                        R.array.incoming_call_widget_video_without_sms_direction_descriptions;
+                handleDrawableResourceId = R.drawable.ic_incall_video_handle;
+                break;
+            case TARGET_SET_FOR_VIDEO_WITH_SMS:
+                targetResourceId = R.array.incoming_call_widget_video_with_sms_targets;
+                targetDescriptionsResourceId =
+                        R.array.incoming_call_widget_video_with_sms_target_descriptions;
+                directionDescriptionsResourceId =
+                        R.array.incoming_call_widget_video_with_sms_direction_descriptions;
+                handleDrawableResourceId = R.drawable.ic_incall_video_handle;
+                break;
+            case TARGET_SET_FOR_VIDEO_ACCEPT_REJECT_REQUEST:
+                targetResourceId =
+                        R.array.incoming_call_widget_video_request_targets;
+                targetDescriptionsResourceId =
+                        R.array.incoming_call_widget_video_request_target_descriptions;
+                directionDescriptionsResourceId = R.array
+                        .incoming_call_widget_video_request_target_direction_descriptions;
+                handleDrawableResourceId = R.drawable.ic_incall_video_handle;
+                break;
+            case TARGET_SET_FOR_AUDIO_WITHOUT_SMS:
+            default:
+                targetResourceId = R.array.incoming_call_widget_audio_without_sms_targets;
+                targetDescriptionsResourceId =
+                        R.array.incoming_call_widget_audio_without_sms_target_descriptions;
+                directionDescriptionsResourceId =
+                        R.array.incoming_call_widget_audio_without_sms_direction_descriptions;
+                handleDrawableResourceId = R.drawable.ic_incall_audio_handle;
+                break;
+        }
+
+        if (targetResourceId != mGlowpad.getTargetResourceId()) {
+            mGlowpad.setTargetResources(targetResourceId);
+            mGlowpad.setTargetDescriptionsResourceId(targetDescriptionsResourceId);
+            mGlowpad.setDirectionDescriptionsResourceId(directionDescriptionsResourceId);
+            mGlowpad.setHandleDrawable(handleDrawableResourceId);
+            mGlowpad.reset(false);
+        }
+    }
+
+    @Override
+    protected void onMessageDialogCancel() {
+        if (mGlowpad != null) {
+            mGlowpad.startPing();
+        }
+    }
+}
diff --git a/InCallUI/src/com/android/incallui/GlowPadWrapper.java b/InCallUI/src/com/android/incallui/GlowPadWrapper.java
index ea5fc92..1bd6d39 100644
--- a/InCallUI/src/com/android/incallui/GlowPadWrapper.java
+++ b/InCallUI/src/com/android/incallui/GlowPadWrapper.java
@@ -46,7 +46,7 @@
         }
     };
 
-    private AnswerListener mAnswerListener;
+    private AnswerFragment mAnswerFragment;
     private boolean mPingEnabled = true;
     private boolean mTargetTriggered = false;
     private int mVideoState = VideoProfile.STATE_BIDIRECTIONAL;
@@ -113,24 +113,24 @@
         final int resId = getResourceIdForTarget(target);
         switch (resId) {
             case R.drawable.ic_lockscreen_answer:
-                mAnswerListener.onAnswer(VideoProfile.STATE_AUDIO_ONLY, getContext());
+                mAnswerFragment.onAnswer(VideoProfile.STATE_AUDIO_ONLY, getContext());
                 mTargetTriggered = true;
                 break;
             case R.drawable.ic_lockscreen_decline:
-                mAnswerListener.onDecline(getContext());
+                mAnswerFragment.onDecline(getContext());
                 mTargetTriggered = true;
                 break;
             case R.drawable.ic_lockscreen_text:
-                mAnswerListener.onText();
+                mAnswerFragment.onText();
                 mTargetTriggered = true;
                 break;
             case R.drawable.ic_videocam:
             case R.drawable.ic_lockscreen_answer_video:
-                mAnswerListener.onAnswer(mVideoState, getContext());
+                mAnswerFragment.onAnswer(mVideoState, getContext());
                 mTargetTriggered = true;
                 break;
             case R.drawable.ic_lockscreen_decline_video:
-                mAnswerListener.onDeclineUpgradeRequest(getContext());
+                mAnswerFragment.onDeclineUpgradeRequest(getContext());
                 mTargetTriggered = true;
                 break;
             default:
@@ -149,8 +149,8 @@
 
     }
 
-    public void setAnswerListener(AnswerListener listener) {
-        mAnswerListener = listener;
+    public void setAnswerFragment(AnswerFragment fragment) {
+        mAnswerFragment = fragment;
     }
 
     /**
@@ -161,11 +161,4 @@
     public void setVideoState(int videoState) {
         mVideoState = videoState;
     }
-
-    public interface AnswerListener {
-        void onAnswer(int videoState, Context context);
-        void onDecline(Context context);
-        void onDeclineUpgradeRequest(Context context);
-        void onText();
-    }
 }
diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java
index 7b53ed7..cbcf50c 100644
--- a/InCallUI/src/com/android/incallui/InCallActivity.java
+++ b/InCallUI/src/com/android/incallui/InCallActivity.java
@@ -26,8 +26,8 @@
 import android.app.FragmentTransaction;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
 import android.content.DialogInterface.OnCancelListener;
+import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Point;
@@ -37,20 +37,19 @@
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccountHandle;
 import android.text.TextUtils;
-import android.view.Display;
+import android.view.KeyEvent;
 import android.view.MenuItem;
+import android.view.MotionEvent;
 import android.view.OrientationEventListener;
 import android.view.Surface;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.view.KeyEvent;
 import android.view.View;
+import android.view.View.OnTouchListener;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
 
-import com.android.phone.common.animation.AnimUtils;
-import com.android.phone.common.animation.AnimationListenerAdapter;
 import com.android.contacts.common.activity.TransactionSafeActivity;
 import com.android.contacts.common.interactions.TouchPointManager;
 import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
@@ -58,6 +57,9 @@
 import com.android.dialer.logging.Logger;
 import com.android.dialer.logging.ScreenEvent;
 import com.android.incallui.Call.State;
+import com.android.incallui.util.AccessibilityUtil;
+import com.android.phone.common.animation.AnimUtils;
+import com.android.phone.common.animation.AnimationListenerAdapter;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -123,6 +125,8 @@
         }
     };
 
+    private OnTouchListener mDispatchTouchEventListener;
+
     private SelectPhoneAccountListener mSelectAcctListener = new SelectPhoneAccountListener() {
         @Override
         public void onPhoneAccountSelected(PhoneAccountHandle selectedAccountHandle,
@@ -461,6 +465,17 @@
     }
 
     @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (mDispatchTouchEventListener != null) {
+            boolean handled = mDispatchTouchEventListener.onTouch(null, ev);
+            if (handled) {
+                return true;
+            }
+        }
+        return super.dispatchTouchEvent(ev);
+    }
+
+    @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         switch (keyCode) {
             case KeyEvent.KEYCODE_CALL:
@@ -513,7 +528,6 @@
         if (event.getRepeatCount() == 0 && handleDialerKeyDown(keyCode, event)) {
             return true;
         }
-
         return super.onKeyDown(keyCode, event);
     }
 
@@ -714,7 +728,11 @@
             mDialpadFragment = new DialpadFragment();
             return mDialpadFragment;
         } else if (TAG_ANSWER_FRAGMENT.equals(tag)) {
-            mAnswerFragment = new AnswerFragment();
+            if (AccessibilityUtil.isTalkBackEnabled(this)) {
+                mAnswerFragment = new AccessibleAnswerFragment();
+            } else {
+                mAnswerFragment = new GlowPadAnswerFragment();
+            }
             return mAnswerFragment;
         } else if (TAG_CONFERENCE_FRAGMENT.equals(tag)) {
             mConferenceManagerFragment = new ConferenceManagerFragment();
@@ -914,4 +932,13 @@
             }
         }
     }
+
+
+    public OnTouchListener getDispatchTouchEventListener() {
+        return mDispatchTouchEventListener;
+    }
+
+    public void setDispatchTouchEventListener(OnTouchListener mDispatchTouchEventListener) {
+        this.mDispatchTouchEventListener = mDispatchTouchEventListener;
+    }
 }
diff --git a/InCallUI/src/com/android/incallui/util/AccessibilityUtil.java b/InCallUI/src/com/android/incallui/util/AccessibilityUtil.java
new file mode 100644
index 0000000..1fdd2ba
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/util/AccessibilityUtil.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.incallui.util;
+
+import android.content.Context;
+import android.view.accessibility.AccessibilityManager;
+
+public class AccessibilityUtil {
+    public static boolean isTalkBackEnabled(Context context) {
+        AccessibilityManager accessibilityManager = (AccessibilityManager) context
+                .getSystemService(Context.ACCESSIBILITY_SERVICE);
+        return accessibilityManager != null
+                && accessibilityManager.isEnabled()
+                && accessibilityManager.isTouchExplorationEnabled();
+    }
+}