14d910f9df60b820d3461995c1d85d0581041b531David Brown/* 24d910f9df60b820d3461995c1d85d0581041b531David Brown * Copyright (C) 2009 The Android Open Source Project 34d910f9df60b820d3461995c1d85d0581041b531David Brown * 44d910f9df60b820d3461995c1d85d0581041b531David Brown * Licensed under the Apache License, Version 2.0 (the "License"); 54d910f9df60b820d3461995c1d85d0581041b531David Brown * you may not use this file except in compliance with the License. 64d910f9df60b820d3461995c1d85d0581041b531David Brown * You may obtain a copy of the License at 74d910f9df60b820d3461995c1d85d0581041b531David Brown * 84d910f9df60b820d3461995c1d85d0581041b531David Brown * http://www.apache.org/licenses/LICENSE-2.0 94d910f9df60b820d3461995c1d85d0581041b531David Brown * 104d910f9df60b820d3461995c1d85d0581041b531David Brown * Unless required by applicable law or agreed to in writing, software 114d910f9df60b820d3461995c1d85d0581041b531David Brown * distributed under the License is distributed on an "AS IS" BASIS, 124d910f9df60b820d3461995c1d85d0581041b531David Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134d910f9df60b820d3461995c1d85d0581041b531David Brown * See the License for the specific language governing permissions and 144d910f9df60b820d3461995c1d85d0581041b531David Brown * limitations under the License. 154d910f9df60b820d3461995c1d85d0581041b531David Brown */ 164d910f9df60b820d3461995c1d85d0581041b531David Brown 174d910f9df60b820d3461995c1d85d0581041b531David Brownpackage com.android.phone; 184d910f9df60b820d3461995c1d85d0581041b531David Brown 194d910f9df60b820d3461995c1d85d0581041b531David Brownimport android.content.Context; 20c0005b83ea6ff24b5136fc93d807553922f00458David Brownimport android.graphics.drawable.Drawable; 214d910f9df60b820d3461995c1d85d0581041b531David Brownimport android.os.SystemClock; 224d910f9df60b820d3461995c1d85d0581041b531David Brownimport android.util.AttributeSet; 234d910f9df60b820d3461995c1d85d0581041b531David Brownimport android.util.Log; 244d910f9df60b820d3461995c1d85d0581041b531David Brownimport android.view.LayoutInflater; 25825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brownimport android.view.MotionEvent; 264d910f9df60b820d3461995c1d85d0581041b531David Brownimport android.view.View; 2709337da1891f61ed2a821782f58f1b7d98770682Jim Millerimport android.view.animation.AlphaAnimation; 2809337da1891f61ed2a821782f58f1b7d98770682Jim Millerimport android.view.animation.Animation; 2909337da1891f61ed2a821782f58f1b7d98770682Jim Millerimport android.view.animation.Animation.AnimationListener; 3047e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brownimport android.widget.Button; 314d910f9df60b820d3461995c1d85d0581041b531David Brownimport android.widget.FrameLayout; 32c0005b83ea6ff24b5136fc93d807553922f00458David Brownimport android.widget.ImageButton; 33284c588c8d9a1089ba7f22725c8f52a83f267435David Brownimport android.widget.TextView; 3447e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brownimport android.widget.ToggleButton; 354d910f9df60b820d3461995c1d85d0581041b531David Brown 36a1bfb5406fa20be8351e272a089c582946e86fc4David Brownimport com.android.internal.telephony.Call; 374d910f9df60b820d3461995c1d85d0581041b531David Brownimport com.android.internal.telephony.Phone; 383948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Millerimport com.android.internal.widget.SlidingTab; 394d910f9df60b820d3461995c1d85d0581041b531David Brown 404d910f9df60b820d3461995c1d85d0581041b531David Brown 414d910f9df60b820d3461995c1d85d0581041b531David Brown/** 424d910f9df60b820d3461995c1d85d0581041b531David Brown * In-call onscreen touch UI elements, used on some platforms. 434d910f9df60b820d3461995c1d85d0581041b531David Brown * 444d910f9df60b820d3461995c1d85d0581041b531David Brown * This widget is a fullscreen overlay, drawn on top of the 454d910f9df60b820d3461995c1d85d0581041b531David Brown * non-touch-sensitive parts of the in-call UI (i.e. the call card). 464d910f9df60b820d3461995c1d85d0581041b531David Brown */ 474d910f9df60b820d3461995c1d85d0581041b531David Brownpublic class InCallTouchUi extends FrameLayout 483948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller implements View.OnClickListener, SlidingTab.OnTriggerListener { 4909337da1891f61ed2a821782f58f1b7d98770682Jim Miller private static final int IN_CALL_WIDGET_TRANSITION_TIME = 250; // in ms 504d910f9df60b820d3461995c1d85d0581041b531David Brown private static final String LOG_TAG = "InCallTouchUi"; 511e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2); 524d910f9df60b820d3461995c1d85d0581041b531David Brown 534d910f9df60b820d3461995c1d85d0581041b531David Brown /** 544d910f9df60b820d3461995c1d85d0581041b531David Brown * Reference to the InCallScreen activity that owns us. This may be 554d910f9df60b820d3461995c1d85d0581041b531David Brown * null if we haven't been initialized yet *or* after the InCallScreen 564d910f9df60b820d3461995c1d85d0581041b531David Brown * activity has been destroyed. 574d910f9df60b820d3461995c1d85d0581041b531David Brown */ 584d910f9df60b820d3461995c1d85d0581041b531David Brown private InCallScreen mInCallScreen; 594d910f9df60b820d3461995c1d85d0581041b531David Brown 604d910f9df60b820d3461995c1d85d0581041b531David Brown // Phone app instance 614d910f9df60b820d3461995c1d85d0581041b531David Brown private PhoneApp mApplication; 624d910f9df60b820d3461995c1d85d0581041b531David Brown 632b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown // UI containers / elements 643948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller private SlidingTab mIncomingCallWidget; // UI used for an incoming call 654d910f9df60b820d3461995c1d85d0581041b531David Brown private View mInCallControls; // UI elements while on a regular call 6647e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // 67284c588c8d9a1089ba7f22725c8f52a83f267435David Brown private Button mAddButton; 68284c588c8d9a1089ba7f22725c8f52a83f267435David Brown private Button mMergeButton; 69284c588c8d9a1089ba7f22725c8f52a83f267435David Brown private Button mEndButton; 7047e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown private Button mDialpadButton; 7147e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown private ToggleButton mBluetoothButton; 7247e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown private ToggleButton mMuteButton; 7347e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown private ToggleButton mSpeakerButton; 74c0005b83ea6ff24b5136fc93d807553922f00458David Brown // 75284c588c8d9a1089ba7f22725c8f52a83f267435David Brown private View mHoldButtonContainer; 76284c588c8d9a1089ba7f22725c8f52a83f267435David Brown private ImageButton mHoldButton; 77284c588c8d9a1089ba7f22725c8f52a83f267435David Brown private TextView mHoldButtonLabel; 78284c588c8d9a1089ba7f22725c8f52a83f267435David Brown private View mSwapButtonContainer; 79284c588c8d9a1089ba7f22725c8f52a83f267435David Brown private ImageButton mSwapButton; 8039a84144262f12df44861d746788b9de92259e4fAbhishek Pillai private TextView mSwapButtonLabel; 8139a84144262f12df44861d746788b9de92259e4fAbhishek Pillai private View mCdmaMergeButtonContainer; 8239a84144262f12df44861d746788b9de92259e4fAbhishek Pillai private ImageButton mCdmaMergeButton; 83c0005b83ea6ff24b5136fc93d807553922f00458David Brown // 84c0005b83ea6ff24b5136fc93d807553922f00458David Brown private Drawable mHoldIcon; 85c0005b83ea6ff24b5136fc93d807553922f00458David Brown private Drawable mUnholdIcon; 86c0005b83ea6ff24b5136fc93d807553922f00458David Brown private Drawable mShowDialpadIcon; 87c0005b83ea6ff24b5136fc93d807553922f00458David Brown private Drawable mHideDialpadIcon; 884d910f9df60b820d3461995c1d85d0581041b531David Brown 89a1bfb5406fa20be8351e272a089c582946e86fc4David Brown // Time of the most recent "answer" or "reject" action (see updateState()) 90a1bfb5406fa20be8351e272a089c582946e86fc4David Brown private long mLastIncomingCallActionTime; // in SystemClock.uptimeMillis() time base 914d910f9df60b820d3461995c1d85d0581041b531David Brown 924d910f9df60b820d3461995c1d85d0581041b531David Brown // Overall enabledness of the "touch UI" features 934d910f9df60b820d3461995c1d85d0581041b531David Brown private boolean mAllowIncomingCallTouchUi; 944d910f9df60b820d3461995c1d85d0581041b531David Brown private boolean mAllowInCallTouchUi; 954d910f9df60b820d3461995c1d85d0581041b531David Brown 964d910f9df60b820d3461995c1d85d0581041b531David Brown public InCallTouchUi(Context context, AttributeSet attrs) { 974d910f9df60b820d3461995c1d85d0581041b531David Brown super(context, attrs); 984d910f9df60b820d3461995c1d85d0581041b531David Brown 994d910f9df60b820d3461995c1d85d0581041b531David Brown if (DBG) log("InCallTouchUi constructor..."); 1004d910f9df60b820d3461995c1d85d0581041b531David Brown if (DBG) log("- this = " + this); 1014d910f9df60b820d3461995c1d85d0581041b531David Brown if (DBG) log("- context " + context + ", attrs " + attrs); 1024d910f9df60b820d3461995c1d85d0581041b531David Brown 1034d910f9df60b820d3461995c1d85d0581041b531David Brown // Inflate our contents, and add it (to ourself) as a child. 1044d910f9df60b820d3461995c1d85d0581041b531David Brown LayoutInflater inflater = LayoutInflater.from(context); 1054d910f9df60b820d3461995c1d85d0581041b531David Brown inflater.inflate( 1064d910f9df60b820d3461995c1d85d0581041b531David Brown R.layout.incall_touch_ui, // resource 1074d910f9df60b820d3461995c1d85d0581041b531David Brown this, // root 1084d910f9df60b820d3461995c1d85d0581041b531David Brown true); 1094d910f9df60b820d3461995c1d85d0581041b531David Brown 1104d910f9df60b820d3461995c1d85d0581041b531David Brown mApplication = PhoneApp.getInstance(); 1114d910f9df60b820d3461995c1d85d0581041b531David Brown 1124d910f9df60b820d3461995c1d85d0581041b531David Brown // The various touch UI features are enabled on a per-product 1134d910f9df60b820d3461995c1d85d0581041b531David Brown // basis. (These flags in config.xml may be overridden by 1144d910f9df60b820d3461995c1d85d0581041b531David Brown // product-specific overlay files.) 1154d910f9df60b820d3461995c1d85d0581041b531David Brown 1164d910f9df60b820d3461995c1d85d0581041b531David Brown mAllowIncomingCallTouchUi = getResources().getBoolean(R.bool.allow_incoming_call_touch_ui); 1174d910f9df60b820d3461995c1d85d0581041b531David Brown if (DBG) log("- incoming call touch UI: " 1184d910f9df60b820d3461995c1d85d0581041b531David Brown + (mAllowIncomingCallTouchUi ? "ENABLED" : "DISABLED")); 1194d910f9df60b820d3461995c1d85d0581041b531David Brown mAllowInCallTouchUi = getResources().getBoolean(R.bool.allow_in_call_touch_ui); 1204d910f9df60b820d3461995c1d85d0581041b531David Brown if (DBG) log("- regular in-call touch UI: " 1214d910f9df60b820d3461995c1d85d0581041b531David Brown + (mAllowInCallTouchUi ? "ENABLED" : "DISABLED")); 1224d910f9df60b820d3461995c1d85d0581041b531David Brown } 1234d910f9df60b820d3461995c1d85d0581041b531David Brown 1244d910f9df60b820d3461995c1d85d0581041b531David Brown void setInCallScreenInstance(InCallScreen inCallScreen) { 1254d910f9df60b820d3461995c1d85d0581041b531David Brown mInCallScreen = inCallScreen; 1264d910f9df60b820d3461995c1d85d0581041b531David Brown } 1274d910f9df60b820d3461995c1d85d0581041b531David Brown 1284d910f9df60b820d3461995c1d85d0581041b531David Brown @Override 1294d910f9df60b820d3461995c1d85d0581041b531David Brown protected void onFinishInflate() { 1304d910f9df60b820d3461995c1d85d0581041b531David Brown super.onFinishInflate(); 1314d910f9df60b820d3461995c1d85d0581041b531David Brown if (DBG) log("InCallTouchUi onFinishInflate(this = " + this + ")..."); 1324d910f9df60b820d3461995c1d85d0581041b531David Brown 1334d910f9df60b820d3461995c1d85d0581041b531David Brown // Look up the various UI elements. 13420d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown 13520d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown // "Dial-to-answer" widget for incoming calls. 1363948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller mIncomingCallWidget = (SlidingTab) findViewById(R.id.incomingCallWidget); 1373948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller mIncomingCallWidget.setLeftTabResources( 1383948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller R.drawable.ic_jog_dial_answer, 1393948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller com.android.internal.R.drawable.jog_tab_target_green, 1403948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller com.android.internal.R.drawable.jog_tab_bar_left_answer, 1413948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller com.android.internal.R.drawable.jog_tab_left_answer 1423948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller ); 1433948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller mIncomingCallWidget.setRightTabResources( 1443948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller R.drawable.ic_jog_dial_decline, 1453948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller com.android.internal.R.drawable.jog_tab_target_red, 1463948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller com.android.internal.R.drawable.jog_tab_bar_right_decline, 1473948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller com.android.internal.R.drawable.jog_tab_right_decline 1483948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller ); 1493948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller 150b7ea5aff1b9f1dc965a9b9f6882b8ea951a3d8aeJim Miller // For now, we only need to show two states: answer and decline. 1513948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller mIncomingCallWidget.setLeftHintText(R.string.slide_to_answer_hint); 1523948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller mIncomingCallWidget.setRightHintText(R.string.slide_to_decline_hint); 1533948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller 1543948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller mIncomingCallWidget.setOnTriggerListener(this); 15520d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown 15620d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown // Container for the UI elements shown while on a regular call. 1574d910f9df60b820d3461995c1d85d0581041b531David Brown mInCallControls = findViewById(R.id.inCallControls); 1584d910f9df60b820d3461995c1d85d0581041b531David Brown 1592b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown // Regular (single-tap) buttons, where we listen for click events: 16047e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // Main cluster of buttons: 161284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mAddButton = (Button) mInCallControls.findViewById(R.id.addButton); 162284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mAddButton.setOnClickListener(this); 163284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mMergeButton = (Button) mInCallControls.findViewById(R.id.mergeButton); 164284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mMergeButton.setOnClickListener(this); 165284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mEndButton = (Button) mInCallControls.findViewById(R.id.endButton); 166284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mEndButton.setOnClickListener(this); 16747e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mDialpadButton = (Button) mInCallControls.findViewById(R.id.dialpadButton); 16847e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mDialpadButton.setOnClickListener(this); 16947e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mBluetoothButton = (ToggleButton) mInCallControls.findViewById(R.id.bluetoothButton); 17047e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mBluetoothButton.setOnClickListener(this); 17147e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mMuteButton = (ToggleButton) mInCallControls.findViewById(R.id.muteButton); 17247e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mMuteButton.setOnClickListener(this); 17347e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mSpeakerButton = (ToggleButton) mInCallControls.findViewById(R.id.speakerButton); 17447e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mSpeakerButton.setOnClickListener(this); 175c0005b83ea6ff24b5136fc93d807553922f00458David Brown 17647e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // Upper corner buttons: 177284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mHoldButtonContainer = mInCallControls.findViewById(R.id.holdButtonContainer); 178284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mHoldButton = (ImageButton) mInCallControls.findViewById(R.id.holdButton); 179284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mHoldButton.setOnClickListener(this); 180284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mHoldButtonLabel = (TextView) mInCallControls.findViewById(R.id.holdButtonLabel); 181c0005b83ea6ff24b5136fc93d807553922f00458David Brown // 182284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mSwapButtonContainer = mInCallControls.findViewById(R.id.swapButtonContainer); 183284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mSwapButton = (ImageButton) mInCallControls.findViewById(R.id.swapButton); 184284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mSwapButton.setOnClickListener(this); 18539a84144262f12df44861d746788b9de92259e4fAbhishek Pillai mSwapButtonLabel = (TextView) mInCallControls.findViewById(R.id.swapButtonLabel); 18639a84144262f12df44861d746788b9de92259e4fAbhishek Pillai if (PhoneApp.getInstance().phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { 18739a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // In CDMA we use a generalized text - "Manage call", as behavior on selecting 18839a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // this option depends entirely on what the current call state is. 18939a84144262f12df44861d746788b9de92259e4fAbhishek Pillai mSwapButtonLabel.setText(R.string.onscreenManageCallsText); 19039a84144262f12df44861d746788b9de92259e4fAbhishek Pillai } else { 19139a84144262f12df44861d746788b9de92259e4fAbhishek Pillai mSwapButtonLabel.setText(R.string.onscreenSwapCallsText); 19239a84144262f12df44861d746788b9de92259e4fAbhishek Pillai } 19339a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // 19439a84144262f12df44861d746788b9de92259e4fAbhishek Pillai mCdmaMergeButtonContainer = mInCallControls.findViewById(R.id.cdmaMergeButtonContainer); 19539a84144262f12df44861d746788b9de92259e4fAbhishek Pillai mCdmaMergeButton = (ImageButton) mInCallControls.findViewById(R.id.cdmaMergeButton); 19639a84144262f12df44861d746788b9de92259e4fAbhishek Pillai mCdmaMergeButton.setOnClickListener(this); 197c0005b83ea6ff24b5136fc93d807553922f00458David Brown 198825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // Add a custom OnTouchListener to manually shrink the "hit 199825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // target" of some buttons. 200825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // (We do this for a few specific buttons which are vulnerable to 201825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // "false touches" because either (1) they're near the edge of the 202825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // screen and might be unintentionally touched while holding the 203825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // device in your hand, or (2) they're in the upper corners and might 204825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // be touched by the user's ear before the prox sensor has a chance to 205825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // kick in.) 206825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown View.OnTouchListener smallerHitTargetTouchListener = new SmallerHitTargetTouchListener(); 207825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown mAddButton.setOnTouchListener(smallerHitTargetTouchListener); 208825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown mMergeButton.setOnTouchListener(smallerHitTargetTouchListener); 209825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown mDialpadButton.setOnTouchListener(smallerHitTargetTouchListener); 210825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown mBluetoothButton.setOnTouchListener(smallerHitTargetTouchListener); 211825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown mSpeakerButton.setOnTouchListener(smallerHitTargetTouchListener); 212825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown mHoldButton.setOnTouchListener(smallerHitTargetTouchListener); 213825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown mSwapButton.setOnTouchListener(smallerHitTargetTouchListener); 214825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown mCdmaMergeButton.setOnTouchListener(smallerHitTargetTouchListener); 215825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown mSpeakerButton.setOnTouchListener(smallerHitTargetTouchListener); 216825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown 217284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // Icons we need to change dynamically. (Most other icons are specified 218284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // directly in incall_touch_ui.xml.) 219284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mHoldIcon = getResources().getDrawable(R.drawable.ic_in_call_touch_round_hold); 220284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mUnholdIcon = getResources().getDrawable(R.drawable.ic_in_call_touch_round_unhold); 221c0005b83ea6ff24b5136fc93d807553922f00458David Brown mShowDialpadIcon = getResources().getDrawable(R.drawable.ic_in_call_touch_dialpad); 222c0005b83ea6ff24b5136fc93d807553922f00458David Brown mHideDialpadIcon = getResources().getDrawable(R.drawable.ic_in_call_touch_dialpad_close); 2234d910f9df60b820d3461995c1d85d0581041b531David Brown } 2244d910f9df60b820d3461995c1d85d0581041b531David Brown 2254d910f9df60b820d3461995c1d85d0581041b531David Brown /** 2264d910f9df60b820d3461995c1d85d0581041b531David Brown * Updates the visibility and/or state of our UI elements, based on 2274d910f9df60b820d3461995c1d85d0581041b531David Brown * the current state of the phone. 2284d910f9df60b820d3461995c1d85d0581041b531David Brown */ 2294d910f9df60b820d3461995c1d85d0581041b531David Brown void updateState(Phone phone) { 2304d910f9df60b820d3461995c1d85d0581041b531David Brown if (DBG) log("updateState(" + phone + ")..."); 2314d910f9df60b820d3461995c1d85d0581041b531David Brown 2321f3361d1fd6f0ee60362cecf686b7cf997ed485bDavid Brown if (mInCallScreen == null) { 2331f3361d1fd6f0ee60362cecf686b7cf997ed485bDavid Brown log("- updateState: mInCallScreen has been destroyed; bailing out..."); 2341f3361d1fd6f0ee60362cecf686b7cf997ed485bDavid Brown return; 2351f3361d1fd6f0ee60362cecf686b7cf997ed485bDavid Brown } 2361f3361d1fd6f0ee60362cecf686b7cf997ed485bDavid Brown 2374d910f9df60b820d3461995c1d85d0581041b531David Brown Phone.State state = phone.getState(); // IDLE, RINGING, or OFFHOOK 238a1bfb5406fa20be8351e272a089c582946e86fc4David Brown if (DBG) log("- updateState: phone state is " + state); 2394d910f9df60b820d3461995c1d85d0581041b531David Brown 2404d910f9df60b820d3461995c1d85d0581041b531David Brown boolean showIncomingCallControls = false; 2414d910f9df60b820d3461995c1d85d0581041b531David Brown boolean showInCallControls = false; 2424d910f9df60b820d3461995c1d85d0581041b531David Brown 2434d910f9df60b820d3461995c1d85d0581041b531David Brown if (state == Phone.State.RINGING) { 2444d910f9df60b820d3461995c1d85d0581041b531David Brown // A phone call is ringing *or* call waiting. 2454d910f9df60b820d3461995c1d85d0581041b531David Brown if (mAllowIncomingCallTouchUi) { 246a1bfb5406fa20be8351e272a089c582946e86fc4David Brown // Watch out: even if the phone state is RINGING, it's 247a1bfb5406fa20be8351e272a089c582946e86fc4David Brown // possible for the ringing call to be in the DISCONNECTING 248a1bfb5406fa20be8351e272a089c582946e86fc4David Brown // state. (This typically happens immediately after the user 249a1bfb5406fa20be8351e272a089c582946e86fc4David Brown // rejects an incoming call, and in that case we *don't* show 250a1bfb5406fa20be8351e272a089c582946e86fc4David Brown // the incoming call controls.) 251a1bfb5406fa20be8351e272a089c582946e86fc4David Brown final Call ringingCall = phone.getRingingCall(); 252a1bfb5406fa20be8351e272a089c582946e86fc4David Brown if (ringingCall.getState().isAlive()) { 253a1bfb5406fa20be8351e272a089c582946e86fc4David Brown if (DBG) log("- updateState: RINGING! Showing incoming call controls..."); 254a1bfb5406fa20be8351e272a089c582946e86fc4David Brown showIncomingCallControls = true; 255a1bfb5406fa20be8351e272a089c582946e86fc4David Brown } 256a1bfb5406fa20be8351e272a089c582946e86fc4David Brown 257a1bfb5406fa20be8351e272a089c582946e86fc4David Brown // Ugly hack to cover up slow response from the radio: 258a1bfb5406fa20be8351e272a089c582946e86fc4David Brown // if we attempted to answer or reject an incoming call 259a1bfb5406fa20be8351e272a089c582946e86fc4David Brown // within the last 500 msec, *don't* show the incoming call 260a1bfb5406fa20be8351e272a089c582946e86fc4David Brown // UI even if the phone is still in the RINGING state. 261a1bfb5406fa20be8351e272a089c582946e86fc4David Brown long now = SystemClock.uptimeMillis(); 262a1bfb5406fa20be8351e272a089c582946e86fc4David Brown if (now < mLastIncomingCallActionTime + 500) { 263a1bfb5406fa20be8351e272a089c582946e86fc4David Brown log("updateState: Too soon after last action; not drawing!"); 264a1bfb5406fa20be8351e272a089c582946e86fc4David Brown showIncomingCallControls = false; 265a1bfb5406fa20be8351e272a089c582946e86fc4David Brown } 2664d910f9df60b820d3461995c1d85d0581041b531David Brown 2674d910f9df60b820d3461995c1d85d0581041b531David Brown // TODO: UI design issue: if the device is NOT currently 2684d910f9df60b820d3461995c1d85d0581041b531David Brown // locked, we probably don't need to make the user 2694d910f9df60b820d3461995c1d85d0581041b531David Brown // double-tap the "incoming call" buttons. (The device 2704d910f9df60b820d3461995c1d85d0581041b531David Brown // presumably isn't in a pocket or purse, so we don't need 2714d910f9df60b820d3461995c1d85d0581041b531David Brown // to worry about false touches while it's ringing.) 2724d910f9df60b820d3461995c1d85d0581041b531David Brown // But OTOH having "inconsistent" buttons might just make 2734d910f9df60b820d3461995c1d85d0581041b531David Brown // it *more* confusing. 2744d910f9df60b820d3461995c1d85d0581041b531David Brown } 2754d910f9df60b820d3461995c1d85d0581041b531David Brown } else { 2764d910f9df60b820d3461995c1d85d0581041b531David Brown if (mAllowInCallTouchUi) { 2772b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown // Ok, the in-call touch UI is available on this platform, 2782b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown // so make it visible (with some exceptions): 2792b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown if (mInCallScreen.okToShowInCallTouchUi()) { 2802b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown showInCallControls = true; 2812b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown } else { 2822b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown if (DBG) log("- updateState: NOT OK to show touch UI; disabling..."); 2832b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown } 2844d910f9df60b820d3461995c1d85d0581041b531David Brown } 2854d910f9df60b820d3461995c1d85d0581041b531David Brown } 2864d910f9df60b820d3461995c1d85d0581041b531David Brown 2872b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown if (showInCallControls) { 2882b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown updateInCallControls(phone); 2892b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown } 2902b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown 2914d910f9df60b820d3461995c1d85d0581041b531David Brown if (showIncomingCallControls && showInCallControls) { 2924d910f9df60b820d3461995c1d85d0581041b531David Brown throw new IllegalStateException( 2934d910f9df60b820d3461995c1d85d0581041b531David Brown "'Incoming' and 'in-call' touch controls visible at the same time!"); 2944d910f9df60b820d3461995c1d85d0581041b531David Brown } 2953964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller 2963964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller if (showIncomingCallControls) { 2973964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller showIncomingCallWidget(); 2983964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller } else { 2993964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller hideIncomingCallWidget(); 3003964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller } 3013964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller 3024d910f9df60b820d3461995c1d85d0581041b531David Brown mInCallControls.setVisibility(showInCallControls ? View.VISIBLE : View.GONE); 3034d910f9df60b820d3461995c1d85d0581041b531David Brown 3044d910f9df60b820d3461995c1d85d0581041b531David Brown // TODO: As an optimization, also consider setting the visibility 30547e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // of the overall InCallTouchUi widget to GONE if *nothing at all* 3064d910f9df60b820d3461995c1d85d0581041b531David Brown // is visible right now. 3074d910f9df60b820d3461995c1d85d0581041b531David Brown } 3084d910f9df60b820d3461995c1d85d0581041b531David Brown 3094d910f9df60b820d3461995c1d85d0581041b531David Brown // View.OnClickListener implementation 3104d910f9df60b820d3461995c1d85d0581041b531David Brown public void onClick(View view) { 3114d910f9df60b820d3461995c1d85d0581041b531David Brown int id = view.getId(); 3124d910f9df60b820d3461995c1d85d0581041b531David Brown if (DBG) log("onClick(View " + view + ", id " + id + ")..."); 3134d910f9df60b820d3461995c1d85d0581041b531David Brown 3142b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown switch (id) { 315284c588c8d9a1089ba7f22725c8f52a83f267435David Brown case R.id.addButton: 316284c588c8d9a1089ba7f22725c8f52a83f267435David Brown case R.id.mergeButton: 317284c588c8d9a1089ba7f22725c8f52a83f267435David Brown case R.id.endButton: 3182b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown case R.id.dialpadButton: 3192b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown case R.id.bluetoothButton: 3202b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown case R.id.muteButton: 3212b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown case R.id.speakerButton: 322284c588c8d9a1089ba7f22725c8f52a83f267435David Brown case R.id.holdButton: 323284c588c8d9a1089ba7f22725c8f52a83f267435David Brown case R.id.swapButton: 32439a84144262f12df44861d746788b9de92259e4fAbhishek Pillai case R.id.cdmaMergeButton: 3252b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown // Clicks on the regular onscreen buttons get forwarded 3262b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown // straight to the InCallScreen. 3272b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown mInCallScreen.handleOnscreenButtonClick(id); 3282b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown break; 3292b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown 3302b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown default: 3311e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown Log.w(LOG_TAG, "onClick: unexpected click: View " + view + ", id " + id); 3321e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown break; 3332b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown } 3344d910f9df60b820d3461995c1d85d0581041b531David Brown } 3354d910f9df60b820d3461995c1d85d0581041b531David Brown 3362b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown /** 33747e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown * Updates the enabledness and "checked" state of the buttons on the 3382b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown * "inCallControls" panel, based on the current telephony state. 3392b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown */ 3402b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown void updateInCallControls(Phone phone) { 34139a84144262f12df44861d746788b9de92259e4fAbhishek Pillai int phoneType = phone.getPhoneType(); 34247e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // Note we do NOT need to worry here about cases where the entire 34347e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // in-call touch UI is disabled, like during an OTA call or if the 34447e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // dtmf dialpad is up. (That's handled by updateState(), which 34547e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // calls InCallScreen.okToShowInCallTouchUi().) 34647e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // 34747e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // If we get here, it *is* OK to show the in-call touch UI, so we 34847e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // now need to update the enabledness and/or "checked" state of 34947e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // each individual button. 35047e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // 35147e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown 35247e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // The InCallControlState object tells us the enabledness and/or 35347e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // state of the various onscreen buttons: 35447e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown InCallControlState inCallControlState = mInCallScreen.getUpdatedInCallControlState(); 35547e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown 356284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // "Add" or "Merge": 357284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // These two buttons occupy the same space onscreen, so only 358284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // one of them should be available at a given moment. 359284c588c8d9a1089ba7f22725c8f52a83f267435David Brown if (inCallControlState.canAddCall) { 360284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mAddButton.setVisibility(View.VISIBLE); 361284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mAddButton.setEnabled(true); 362284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mMergeButton.setVisibility(View.GONE); 363284c588c8d9a1089ba7f22725c8f52a83f267435David Brown } else if (inCallControlState.canMerge) { 36439a84144262f12df44861d746788b9de92259e4fAbhishek Pillai if (phoneType == Phone.PHONE_TYPE_CDMA) { 36539a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // In CDMA "Add" option is always given to the user and the 36639a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // "Merge" option is provided as a button on the top left corner of the screen, 36739a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // we always set the mMergeButton to GONE 36839a84144262f12df44861d746788b9de92259e4fAbhishek Pillai mMergeButton.setVisibility(View.GONE); 36939a84144262f12df44861d746788b9de92259e4fAbhishek Pillai } else if (phoneType == Phone.PHONE_TYPE_GSM) { 37039a84144262f12df44861d746788b9de92259e4fAbhishek Pillai mMergeButton.setVisibility(View.VISIBLE); 37139a84144262f12df44861d746788b9de92259e4fAbhishek Pillai mMergeButton.setEnabled(true); 37239a84144262f12df44861d746788b9de92259e4fAbhishek Pillai mAddButton.setVisibility(View.GONE); 37339a84144262f12df44861d746788b9de92259e4fAbhishek Pillai } else { 37439a84144262f12df44861d746788b9de92259e4fAbhishek Pillai throw new IllegalStateException("Unexpected phone type: " + phoneType); 37539a84144262f12df44861d746788b9de92259e4fAbhishek Pillai } 376c0005b83ea6ff24b5136fc93d807553922f00458David Brown } else { 377284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // Neither "Add" nor "Merge" is available. (This happens in 378284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // some transient states, like while dialing an outgoing call, 379284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // and in other rare cases like if you have both lines in use 380284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // *and* there are already 5 people on the conference call.) 381284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // Since the common case here is "while dialing", we show the 382284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // "Add" button in a disabled state so that there won't be any 383284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // jarring change in the UI when the call finally connects. 384284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mAddButton.setVisibility(View.VISIBLE); 385284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mAddButton.setEnabled(false); 386284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mMergeButton.setVisibility(View.GONE); 387c0005b83ea6ff24b5136fc93d807553922f00458David Brown } 388284c588c8d9a1089ba7f22725c8f52a83f267435David Brown if (inCallControlState.canAddCall && inCallControlState.canMerge) { 38939a84144262f12df44861d746788b9de92259e4fAbhishek Pillai if (phoneType == Phone.PHONE_TYPE_GSM) { 39039a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // Uh oh, the InCallControlState thinks that "Add" *and* "Merge" 39139a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // should both be available right now. This *should* never 39239a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // happen with GSM, but if it's possible on any 39339a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // future devices we may need to re-layout Add and Merge so 39439a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // they can both be visible at the same time... 39539a84144262f12df44861d746788b9de92259e4fAbhishek Pillai Log.w(LOG_TAG, "updateInCallControls: Add *and* Merge enabled," + 39639a84144262f12df44861d746788b9de92259e4fAbhishek Pillai " but can't show both!"); 39739a84144262f12df44861d746788b9de92259e4fAbhishek Pillai } else if (phoneType == Phone.PHONE_TYPE_CDMA) { 39839a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // In CDMA "Add" option is always given to the user and the hence 39939a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // in this case both "Add" and "Merge" options would be available to user 40039a84144262f12df44861d746788b9de92259e4fAbhishek Pillai if (DBG) log("updateInCallControls: CDMA: Add and Merge both enabled"); 40139a84144262f12df44861d746788b9de92259e4fAbhishek Pillai } else { 40239a84144262f12df44861d746788b9de92259e4fAbhishek Pillai throw new IllegalStateException("Unexpected phone type: " + phoneType); 40339a84144262f12df44861d746788b9de92259e4fAbhishek Pillai } 404c0005b83ea6ff24b5136fc93d807553922f00458David Brown } 40547e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown 40647e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // "End call": this button has no state and it's always enabled. 407284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mEndButton.setEnabled(true); 40847e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown 40947e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // "Dialpad": Enabled only when it's OK to use the dialpad in the 41047e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // first place. 41147e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mDialpadButton.setEnabled(inCallControlState.dialpadEnabled); 412c0005b83ea6ff24b5136fc93d807553922f00458David Brown // 4135aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown if (inCallControlState.dialpadVisible) { 4145aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown // Show the "hide dialpad" state. 4155aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown mDialpadButton.setText(R.string.onscreenHideDialpadText); 4165aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown mDialpadButton.setCompoundDrawablesWithIntrinsicBounds( 4175aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown null, mHideDialpadIcon, null, null); 4185aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown } else { 4195aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown // Show the "show dialpad" state. 4205aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown mDialpadButton.setText(R.string.onscreenShowDialpadText); 4215aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown mDialpadButton.setCompoundDrawablesWithIntrinsicBounds( 4225aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown null, mShowDialpadIcon, null, null); 4235aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown } 42447e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown 42547e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // "Bluetooth" 42647e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mBluetoothButton.setEnabled(inCallControlState.bluetoothEnabled); 42747e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mBluetoothButton.setChecked(inCallControlState.bluetoothIndicatorOn); 42847e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown 42947e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // "Mute" 43047e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mMuteButton.setEnabled(inCallControlState.canMute); 43147e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mMuteButton.setChecked(inCallControlState.muteIndicatorOn); 43247e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown 43347e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // "Speaker" 43447e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mSpeakerButton.setEnabled(inCallControlState.speakerEnabled); 43547e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown mSpeakerButton.setChecked(inCallControlState.speakerOn); 43647e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown 437284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // "Hold" 438284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // (Note "Hold" and "Swap" are never both available at 43947e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // the same time. That's why it's OK for them to both be in the 44047e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // same position onscreen.) 44147e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // This button is totally hidden (rather than just disabled) 44247e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // when the operation isn't available. 443284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mHoldButtonContainer.setVisibility( 444284c588c8d9a1089ba7f22725c8f52a83f267435David Brown inCallControlState.canHold ? View.VISIBLE : View.GONE); 445284c588c8d9a1089ba7f22725c8f52a83f267435David Brown if (inCallControlState.canHold) { 446284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // The Hold button icon and label (either "Hold" or "Unhold") 447284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // depend on the current Hold state. 448284c588c8d9a1089ba7f22725c8f52a83f267435David Brown if (inCallControlState.onHold) { 449284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mHoldButton.setImageDrawable(mUnholdIcon); 450284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mHoldButtonLabel.setText(R.string.onscreenUnholdText); 451284c588c8d9a1089ba7f22725c8f52a83f267435David Brown } else { 452284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mHoldButton.setImageDrawable(mHoldIcon); 453284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mHoldButtonLabel.setText(R.string.onscreenHoldText); 454284c588c8d9a1089ba7f22725c8f52a83f267435David Brown } 455284c588c8d9a1089ba7f22725c8f52a83f267435David Brown } 45647e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown 457284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // "Swap" 45847e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // This button is totally hidden (rather than just disabled) 45947e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown // when the operation isn't available. 460284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mSwapButtonContainer.setVisibility( 461284c588c8d9a1089ba7f22725c8f52a83f267435David Brown inCallControlState.canSwap ? View.VISIBLE : View.GONE); 462284c588c8d9a1089ba7f22725c8f52a83f267435David Brown 46339a84144262f12df44861d746788b9de92259e4fAbhishek Pillai if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) { 46439a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // "Merge" 46539a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // This button is totally hidden (rather than just disabled) 46639a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // when the operation isn't available. 46739a84144262f12df44861d746788b9de92259e4fAbhishek Pillai mCdmaMergeButtonContainer.setVisibility( 46839a84144262f12df44861d746788b9de92259e4fAbhishek Pillai inCallControlState.canMerge ? View.VISIBLE : View.GONE); 46939a84144262f12df44861d746788b9de92259e4fAbhishek Pillai } 47039a84144262f12df44861d746788b9de92259e4fAbhishek Pillai 471284c588c8d9a1089ba7f22725c8f52a83f267435David Brown if (inCallControlState.canSwap && inCallControlState.canHold) { 472284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // Uh oh, the InCallControlState thinks that Swap *and* Hold 473284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // should both be available. This *should* never happen with 474284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // either GSM or CDMA, but if it's possible on any future 475284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // devices we may need to re-layout Hold and Swap so they can 476284c588c8d9a1089ba7f22725c8f52a83f267435David Brown // both be visible at the same time... 477284c588c8d9a1089ba7f22725c8f52a83f267435David Brown Log.w(LOG_TAG, "updateInCallControls: Hold *and* Swap enabled, but can't show both!"); 478284c588c8d9a1089ba7f22725c8f52a83f267435David Brown } 47947e534e7b9f75d8ec85ba15f1fd681770ec4592eDavid Brown 48039a84144262f12df44861d746788b9de92259e4fAbhishek Pillai if (phoneType == Phone.PHONE_TYPE_CDMA) { 48139a84144262f12df44861d746788b9de92259e4fAbhishek Pillai if (inCallControlState.canSwap && inCallControlState.canMerge) { 48239a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // Uh oh, the InCallControlState thinks that Swap *and* Merge 48339a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // should both be available. This *should* never happen with 48439a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // CDMA, but if it's possible on any future 48539a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // devices we may need to re-layout Merge and Swap so they can 48639a84144262f12df44861d746788b9de92259e4fAbhishek Pillai // both be visible at the same time... 48739a84144262f12df44861d746788b9de92259e4fAbhishek Pillai Log.w(LOG_TAG, "updateInCallControls: Merge *and* Swap" + 48839a84144262f12df44861d746788b9de92259e4fAbhishek Pillai "enabled, but can't show both!"); 48939a84144262f12df44861d746788b9de92259e4fAbhishek Pillai } 49039a84144262f12df44861d746788b9de92259e4fAbhishek Pillai } 49139a84144262f12df44861d746788b9de92259e4fAbhishek Pillai 4925aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown // One final special case: if the dialpad is visible, that trumps 4935aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown // *any* of the upper corner buttons: 4945aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown if (inCallControlState.dialpadVisible) { 495284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mHoldButtonContainer.setVisibility(View.GONE); 496284c588c8d9a1089ba7f22725c8f52a83f267435David Brown mSwapButtonContainer.setVisibility(View.GONE); 497af7374137755158062fd65dffe762566ab154d49David Brown mCdmaMergeButtonContainer.setVisibility(View.GONE); 4985aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown } 4992b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown } 5002b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown 5012b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown // 5022b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown // InCallScreen API 5032b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown // 5042b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown 5052b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown /** 5062b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown * @return true if the onscreen touch UI is enabled (for regular 5072b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown * "ongoing call" states) on the current device. 5082b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown */ 5096d5544932495d81ff7ce53f4678c4beb25acc1b0David Brown /* package */ boolean isTouchUiEnabled() { 5102b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown return mAllowInCallTouchUi; 5112b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown } 5122b7613e21b0bea57cfa4e5ba5860a8ff1cfefbc1David Brown 5136d50f0fd38eb801c2d5304792fcf72e769cb8d72David Brown /** 5146d50f0fd38eb801c2d5304792fcf72e769cb8d72David Brown * @return true if the onscreen touch UI is enabled for 5156d50f0fd38eb801c2d5304792fcf72e769cb8d72David Brown * the "incoming call" state on the current device. 5166d50f0fd38eb801c2d5304792fcf72e769cb8d72David Brown */ 5176d50f0fd38eb801c2d5304792fcf72e769cb8d72David Brown /* package */ boolean isIncomingCallTouchUiEnabled() { 5186d50f0fd38eb801c2d5304792fcf72e769cb8d72David Brown return mAllowIncomingCallTouchUi; 5196d50f0fd38eb801c2d5304792fcf72e769cb8d72David Brown } 5206d50f0fd38eb801c2d5304792fcf72e769cb8d72David Brown 521a1bfb5406fa20be8351e272a089c582946e86fc4David Brown // 5223948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller // SlidingTab.OnTriggerListener implementation 523a1bfb5406fa20be8351e272a089c582946e86fc4David Brown // 524a1bfb5406fa20be8351e272a089c582946e86fc4David Brown 52520d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown /** 52620d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown * Handles "Answer" and "Reject" actions for an incoming call. 5273948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller * We get this callback from the SlidingTab 528a1bfb5406fa20be8351e272a089c582946e86fc4David Brown * when the user triggers an action. 529a1bfb5406fa20be8351e272a089c582946e86fc4David Brown * 530a1bfb5406fa20be8351e272a089c582946e86fc4David Brown * To answer or reject the incoming call, we call 531a1bfb5406fa20be8351e272a089c582946e86fc4David Brown * InCallScreen.handleOnscreenButtonClick() and pass one of the 532a1bfb5406fa20be8351e272a089c582946e86fc4David Brown * special "virtual button" IDs: 533a1bfb5406fa20be8351e272a089c582946e86fc4David Brown * - R.id.answerButton to answer the call 534a1bfb5406fa20be8351e272a089c582946e86fc4David Brown * or 535a1bfb5406fa20be8351e272a089c582946e86fc4David Brown * - R.id.rejectButton to reject the call. 536a1bfb5406fa20be8351e272a089c582946e86fc4David Brown */ 5373948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller public void onTrigger(View v, int whichHandle) { 5381e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown log("onDialTrigger(whichHandle = " + whichHandle + ")..."); 53920d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown 54020d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown switch (whichHandle) { 5413948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller case SlidingTab.OnTriggerListener.LEFT_HANDLE: 54220d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown if (DBG) log("LEFT_HANDLE: answer!"); 54320d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown 54409337da1891f61ed2a821782f58f1b7d98770682Jim Miller hideIncomingCallWidget(); 54509337da1891f61ed2a821782f58f1b7d98770682Jim Miller 54620d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown // ...and also prevent it from reappearing right away. 54720d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown // (This covers up a slow response from the radio; see updateState().) 54820d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown mLastIncomingCallActionTime = SystemClock.uptimeMillis(); 54920d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown 55020d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown // Do the appropriate action. 55120d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown if (mInCallScreen != null) { 55220d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown // Send this to the InCallScreen as a virtual "button click" event: 55320d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown mInCallScreen.handleOnscreenButtonClick(R.id.answerButton); 55420d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown } else { 55520d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown Log.e(LOG_TAG, "answer trigger: mInCallScreen is null"); 55620d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown } 55720d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown break; 558a1bfb5406fa20be8351e272a089c582946e86fc4David Brown 5593948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller case SlidingTab.OnTriggerListener.RIGHT_HANDLE: 56020d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown if (DBG) log("RIGHT_HANDLE: reject!"); 561a1bfb5406fa20be8351e272a089c582946e86fc4David Brown 56209337da1891f61ed2a821782f58f1b7d98770682Jim Miller hideIncomingCallWidget(); 56309337da1891f61ed2a821782f58f1b7d98770682Jim Miller 56420d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown // ...and also prevent it from reappearing right away. 56520d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown // (This covers up a slow response from the radio; see updateState().) 56620d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown mLastIncomingCallActionTime = SystemClock.uptimeMillis(); 567a1bfb5406fa20be8351e272a089c582946e86fc4David Brown 56820d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown // Do the appropriate action. 56920d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown if (mInCallScreen != null) { 57020d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown // Send this to the InCallScreen as a virtual "button click" event: 57120d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown mInCallScreen.handleOnscreenButtonClick(R.id.rejectButton); 57220d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown } else { 57320d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown Log.e(LOG_TAG, "reject trigger: mInCallScreen is null"); 57420d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown } 57520d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown break; 576a1bfb5406fa20be8351e272a089c582946e86fc4David Brown 57720d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown default: 57820d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown Log.e(LOG_TAG, "onDialTrigger: unexpected whichHandle value: " + whichHandle); 57920d7df041ea1a115de6e5f0b6e236ae6e17b2fccDavid Brown break; 580a1bfb5406fa20be8351e272a089c582946e86fc4David Brown } 5819688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown 5829688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown // Regardless of what action the user did, be sure to clear out 5839688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown // the hint text we were displaying while the user was dragging. 5843948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller mInCallScreen.updateSlidingTabHint(0, 0); 5859688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown } 5869688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown 5879688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown /** 58809337da1891f61ed2a821782f58f1b7d98770682Jim Miller * Apply an animation to hide the incoming call widget. 58909337da1891f61ed2a821782f58f1b7d98770682Jim Miller */ 59009337da1891f61ed2a821782f58f1b7d98770682Jim Miller private void hideIncomingCallWidget() { 5913964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller if (mIncomingCallWidget.getVisibility() != View.VISIBLE 5923964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller || mIncomingCallWidget.getAnimation() != null) { 5933964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller // Widget is already hidden or in the process of being hidden 5943964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller return; 5953964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller } 5963964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller // Hide the incoming call screen with a transition 59709337da1891f61ed2a821782f58f1b7d98770682Jim Miller AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f); 59809337da1891f61ed2a821782f58f1b7d98770682Jim Miller anim.setDuration(IN_CALL_WIDGET_TRANSITION_TIME); 59909337da1891f61ed2a821782f58f1b7d98770682Jim Miller anim.setAnimationListener(new AnimationListener() { 60009337da1891f61ed2a821782f58f1b7d98770682Jim Miller 60109337da1891f61ed2a821782f58f1b7d98770682Jim Miller public void onAnimationStart(Animation animation) { 60209337da1891f61ed2a821782f58f1b7d98770682Jim Miller 60309337da1891f61ed2a821782f58f1b7d98770682Jim Miller } 60409337da1891f61ed2a821782f58f1b7d98770682Jim Miller 60509337da1891f61ed2a821782f58f1b7d98770682Jim Miller public void onAnimationRepeat(Animation animation) { 60609337da1891f61ed2a821782f58f1b7d98770682Jim Miller 60709337da1891f61ed2a821782f58f1b7d98770682Jim Miller } 60809337da1891f61ed2a821782f58f1b7d98770682Jim Miller 60909337da1891f61ed2a821782f58f1b7d98770682Jim Miller public void onAnimationEnd(Animation animation) { 61009337da1891f61ed2a821782f58f1b7d98770682Jim Miller // hide the incoming call UI. 6113964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller mIncomingCallWidget.clearAnimation(); 61209337da1891f61ed2a821782f58f1b7d98770682Jim Miller mIncomingCallWidget.setVisibility(View.GONE); 61309337da1891f61ed2a821782f58f1b7d98770682Jim Miller } 61409337da1891f61ed2a821782f58f1b7d98770682Jim Miller }); 61509337da1891f61ed2a821782f58f1b7d98770682Jim Miller mIncomingCallWidget.startAnimation(anim); 61609337da1891f61ed2a821782f58f1b7d98770682Jim Miller } 61709337da1891f61ed2a821782f58f1b7d98770682Jim Miller 61809337da1891f61ed2a821782f58f1b7d98770682Jim Miller /** 6193964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller * Shows the incoming call widget and cancels any animation that may be fading it out. 6203964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller */ 6213964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller private void showIncomingCallWidget() { 6223964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller Animation anim = mIncomingCallWidget.getAnimation(); 6233964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller if (anim != null) { 6243964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller anim.reset(); 6253964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller mIncomingCallWidget.clearAnimation(); 6263964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller } 627b7ea5aff1b9f1dc965a9b9f6882b8ea951a3d8aeJim Miller mIncomingCallWidget.reset(false); 6283964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller mIncomingCallWidget.setVisibility(View.VISIBLE); 6293964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller } 6303964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller 6313964d23925df0ff41d532952f3fddbe81d68dbdfJim Miller /** 6323948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller * Handles state changes of the SlidingTabSelector widget. While the user 6339688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown * is dragging one of the handles, we display an onscreen hint; see 6349688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown * CallCard.getRotateWidgetHint(). 6359688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown */ 6369688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown public void onGrabbedStateChange(View v, int grabbedState) { 6379688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown if (mInCallScreen != null) { 6389688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown // Look up the hint based on which handle is currently grabbed. 6399688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown // (Note we don't simply pass grabbedState thru to the InCallScreen, 6409688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown // since *this* class is the only place that knows that the left 6419688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown // handle means "Answer" and the right handle means "Decline".) 6429688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown int hintTextResId, hintColorResId; 6439688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown switch (grabbedState) { 6443948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller case SlidingTab.OnTriggerListener.NO_HANDLE: 6459688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown hintTextResId = 0; 6469688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown hintColorResId = 0; 6479688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown break; 6483948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller case SlidingTab.OnTriggerListener.LEFT_HANDLE: 6493948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller // TODO: Use different variants of "Slide to answer" in some cases 6503948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller // depending on the phone state, like slide_to_answer_and_hold 6513948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller // for a call waiting call, or slide_to_answer_and_end_active or 6523948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller // slide_to_answer_and_end_onhold for the 2-lines-in-use case. 6539688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown // (Note these are GSM-only cases, though.) 6543948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller hintTextResId = R.string.slide_to_answer; 6559688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown hintColorResId = R.color.incall_textConnected; // green 6569688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown break; 6573948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller case SlidingTab.OnTriggerListener.RIGHT_HANDLE: 6583948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller hintTextResId = R.string.slide_to_decline; 6599688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown hintColorResId = R.color.incall_textEnded; // red 6609688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown break; 6619688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown default: 662825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown Log.e(LOG_TAG, "onGrabbedStateChange: unexpected grabbedState: " 663825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown + grabbedState); 6649688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown hintTextResId = 0; 6659688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown hintColorResId = 0; 6669688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown break; 6679688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown } 6689688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown 6699688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown // Tell the InCallScreen to update the CallCard and force the 6709688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown // screen to redraw. 6713948a2541dd196b361d4cd9d18db805dd8cb56f9Jim Miller mInCallScreen.updateSlidingTabHint(hintTextResId, hintColorResId); 6729688349b8750a9ac7282d83993e0112c5f51e7acDavid Brown } 673a1bfb5406fa20be8351e272a089c582946e86fc4David Brown } 674a1bfb5406fa20be8351e272a089c582946e86fc4David Brown 6754d910f9df60b820d3461995c1d85d0581041b531David Brown 676825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown /** 677825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * OnTouchListener used to shrink the "hit target" of some onscreen 678825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * buttons. 679825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown */ 680825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown class SmallerHitTargetTouchListener implements View.OnTouchListener { 681825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown /** 682825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * Width of the allowable "hit target" as a percentage of 683825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * the total width of this button. 684825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown */ 685825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown private static final int HIT_TARGET_PERCENT_X = 50; 686825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown 687825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown /** 688825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * Height of the allowable "hit target" as a percentage of 689825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * the total height of this button. 690825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * 691825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * This is larger than HIT_TARGET_PERCENT_X because some of 692825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * the onscreen buttons are wide but not very tall and we don't 693825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * want to make the vertical hit target *too* small. 694825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown */ 695825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown private static final int HIT_TARGET_PERCENT_Y = 80; 696825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown 697825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // Size (percentage-wise) of the "edge" area that's *not* touch-sensitive. 698825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown private static final int X_EDGE = (100 - HIT_TARGET_PERCENT_X) / 2; 699825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown private static final int Y_EDGE = (100 - HIT_TARGET_PERCENT_Y) / 2; 700825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // Min/max values (percentage-wise) of the touch-sensitive hit target. 701825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown private static final int X_HIT_MIN = X_EDGE; 702825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown private static final int X_HIT_MAX = 100 - X_EDGE; 703825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown private static final int Y_HIT_MIN = Y_EDGE; 704825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown private static final int Y_HIT_MAX = 100 - Y_EDGE; 705825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown 706825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // True if the most recent DOWN event was a "hit". 707825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown boolean mDownEventHit; 708825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown 709825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown /** 710825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * Called when a touch event is dispatched to a view. This allows listeners to 711825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * get a chance to respond before the target view. 712825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * 713825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * @return True if the listener has consumed the event, false otherwise. 714825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * (In other words, we return true when the touch is *outside* 715825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * the "smaller hit target", which will prevent the actual 716825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown * button from handling these events.) 717825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown */ 718825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown public boolean onTouch(View v, MotionEvent event) { 719825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // if (DBG) log("SmallerHitTargetTouchListener: " + v + ", event " + event); 720825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown 721825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown if (event.getAction() == MotionEvent.ACTION_DOWN) { 722825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // Note that event.getX() and event.getY() are already 723825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // translated into the View's coordinates. (In other words, 724825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // "0,0" is a touch on the upper-left-most corner of the view.) 725825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown int touchX = (int) event.getX(); 726825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown int touchY = (int) event.getY(); 727825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown 728825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown int viewWidth = v.getWidth(); 729825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown int viewHeight = v.getHeight(); 730825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown 731825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // Touch location as a percentage of the total button width or height. 732825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown int touchXPercent = (int) ((float) (touchX * 100) / (float) viewWidth); 733825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown int touchYPercent = (int) ((float) (touchY * 100) / (float) viewHeight); 734825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // if (DBG) log("- percentage: x = " + touchXPercent + ", y = " + touchYPercent); 735825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown 736825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // TODO: user research: add event logging here of the actual 737825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // hit location (and button ID), and enable it for dogfooders 738825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // for a few days. That'll give us a good idea of how close 739825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // to the center of the button(s) most touch events are, to 740825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // help us fine-tune the HIT_TARGET_PERCENT_* constants. 741825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown 742825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown if (touchXPercent < X_HIT_MIN || touchXPercent > X_HIT_MAX 743825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown || touchYPercent < Y_HIT_MIN || touchYPercent > Y_HIT_MAX) { 744825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // Missed! 745825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // if (DBG) log(" -> MISSED!"); 746825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown mDownEventHit = false; 747825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown return true; // Consume this event; don't let the button see it 748825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown } else { 749825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // Hit! 750825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // if (DBG) log(" -> HIT!"); 751825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown mDownEventHit = true; 752825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown return false; // Let this event through to the actual button 753825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown } 754825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown } else { 755825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // This is a MOVE, UP or CANCEL event. 756825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // 757825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // We only do the "smaller hit target" check on DOWN events. 758825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // For the subsequent MOVE/UP/CANCEL events, we let them 759825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // through to the actual button IFF the previous DOWN event 760825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown // got through to the actual button (i.e. it was a "hit".) 761825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown return !mDownEventHit; 762825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown } 763825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown } 764825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown } 765825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown 766825ccf147f31df0e00c22b6d66a63f2761533fdaDavid Brown 7674d910f9df60b820d3461995c1d85d0581041b531David Brown // Debugging / testing code 7684d910f9df60b820d3461995c1d85d0581041b531David Brown 7694d910f9df60b820d3461995c1d85d0581041b531David Brown private void log(String msg) { 7704d910f9df60b820d3461995c1d85d0581041b531David Brown Log.d(LOG_TAG, msg); 7714d910f9df60b820d3461995c1d85d0581041b531David Brown } 7724d910f9df60b820d3461995c1d85d0581041b531David Brown} 773