1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.incallui; 18 19 import android.app.AlertDialog; 20 import android.app.Dialog; 21 import android.content.DialogInterface; 22 import android.os.Bundle; 23 import android.text.Editable; 24 import android.text.TextWatcher; 25 import android.view.LayoutInflater; 26 import android.view.View; 27 import android.view.ViewGroup; 28 import android.view.WindowManager; 29 import android.widget.AdapterView; 30 import android.widget.ArrayAdapter; 31 import android.widget.Button; 32 import android.widget.EditText; 33 import android.widget.ListView; 34 35 import com.google.common.base.Preconditions; 36 37 import java.util.ArrayList; 38 39 /** 40 * 41 */ 42 public class AnswerFragment extends BaseFragment<AnswerPresenter, AnswerPresenter.AnswerUi> 43 implements GlowPadWrapper.AnswerListener, AnswerPresenter.AnswerUi { 44 45 /** 46 * The popup showing the list of canned responses. 47 * 48 * This is an AlertDialog containing a ListView showing the possible choices. This may be null 49 * if the InCallScreen hasn't ever called showRespondViaSmsPopup() yet, or if the popup was 50 * visible once but then got dismissed. 51 */ 52 private Dialog mCannedResponsePopup = null; 53 54 /** 55 * The popup showing a text field for users to type in their custom message. 56 */ 57 private AlertDialog mCustomMessagePopup = null; 58 59 private ArrayAdapter<String> mTextResponsesAdapter = null; 60 61 private GlowPadWrapper mGlowpad; 62 63 public AnswerFragment() { 64 } 65 66 @Override 67 public AnswerPresenter createPresenter() { 68 return new AnswerPresenter(); 69 } 70 71 @Override 72 AnswerPresenter.AnswerUi getUi() { 73 return this; 74 } 75 76 @Override 77 public View onCreateView(LayoutInflater inflater, ViewGroup container, 78 Bundle savedInstanceState) { 79 mGlowpad = (GlowPadWrapper) inflater.inflate(R.layout.answer_fragment, 80 container, false); 81 82 Log.d(this, "Creating view for answer fragment ", this); 83 Log.d(this, "Created from activity", getActivity()); 84 mGlowpad.setAnswerListener(this); 85 86 return mGlowpad; 87 } 88 89 @Override 90 public void onDestroyView() { 91 Log.d(this, "onDestroyView"); 92 if (mGlowpad != null) { 93 mGlowpad.stopPing(); 94 mGlowpad = null; 95 } 96 super.onDestroyView(); 97 } 98 99 @Override 100 public void showAnswerUi(boolean show) { 101 getView().setVisibility(show ? View.VISIBLE : View.GONE); 102 103 Log.d(this, "Show answer UI: " + show); 104 if (show) { 105 mGlowpad.startPing(); 106 } else { 107 mGlowpad.stopPing(); 108 } 109 } 110 111 @Override 112 public void showTextButton(boolean show) { 113 final int targetResourceId = show 114 ? R.array.incoming_call_widget_3way_targets 115 : R.array.incoming_call_widget_2way_targets; 116 117 if (targetResourceId != mGlowpad.getTargetResourceId()) { 118 if (show) { 119 // Answer, Decline, and Respond via SMS. 120 mGlowpad.setTargetResources(targetResourceId); 121 mGlowpad.setTargetDescriptionsResourceId( 122 R.array.incoming_call_widget_3way_target_descriptions); 123 mGlowpad.setDirectionDescriptionsResourceId( 124 R.array.incoming_call_widget_3way_direction_descriptions); 125 } else { 126 // Answer or Decline. 127 mGlowpad.setTargetResources(targetResourceId); 128 mGlowpad.setTargetDescriptionsResourceId( 129 R.array.incoming_call_widget_2way_target_descriptions); 130 mGlowpad.setDirectionDescriptionsResourceId( 131 R.array.incoming_call_widget_2way_direction_descriptions); 132 } 133 134 mGlowpad.reset(false); 135 } 136 } 137 138 @Override 139 public void showMessageDialog() { 140 final ListView lv = new ListView(getActivity()); 141 142 Preconditions.checkNotNull(mTextResponsesAdapter); 143 lv.setAdapter(mTextResponsesAdapter); 144 lv.setOnItemClickListener(new RespondViaSmsItemClickListener()); 145 146 final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()).setCancelable( 147 true).setView(lv); 148 builder.setOnCancelListener(new DialogInterface.OnCancelListener() { 149 @Override 150 public void onCancel(DialogInterface dialogInterface) { 151 if (mGlowpad != null) { 152 mGlowpad.startPing(); 153 } 154 dismissCannedResponsePopup(); 155 getPresenter().onDismissDialog(); 156 } 157 }); 158 mCannedResponsePopup = builder.create(); 159 mCannedResponsePopup.show(); 160 } 161 162 private boolean isCannedResponsePopupShowing() { 163 if (mCannedResponsePopup != null) { 164 return mCannedResponsePopup.isShowing(); 165 } 166 return false; 167 } 168 169 private boolean isCustomMessagePopupShowing() { 170 if (mCustomMessagePopup != null) { 171 return mCustomMessagePopup.isShowing(); 172 } 173 return false; 174 } 175 176 /** 177 * Dismiss the canned response list popup. 178 * 179 * This is safe to call even if the popup is already dismissed, and even if you never called 180 * showRespondViaSmsPopup() in the first place. 181 */ 182 private void dismissCannedResponsePopup() { 183 if (mCannedResponsePopup != null) { 184 mCannedResponsePopup.dismiss(); // safe even if already dismissed 185 mCannedResponsePopup = null; 186 } 187 } 188 189 /** 190 * Dismiss the custom compose message popup. 191 */ 192 private void dismissCustomMessagePopup() { 193 if (mCustomMessagePopup != null) { 194 mCustomMessagePopup.dismiss(); 195 mCustomMessagePopup = null; 196 } 197 } 198 199 public void dismissPendingDialogues() { 200 if (isCannedResponsePopupShowing()) { 201 dismissCannedResponsePopup(); 202 } 203 204 if (isCustomMessagePopupShowing()) { 205 dismissCustomMessagePopup(); 206 } 207 } 208 209 public boolean hasPendingDialogs() { 210 return !(mCannedResponsePopup == null && mCustomMessagePopup == null); 211 } 212 213 /** 214 * Shows the custom message entry dialog. 215 */ 216 public void showCustomMessageDialog() { 217 // Create an alert dialog containing an EditText 218 final EditText et = new EditText(getActivity()); 219 final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()).setCancelable( 220 true).setView(et) 221 .setPositiveButton(R.string.custom_message_send, 222 new DialogInterface.OnClickListener() { 223 @Override 224 public void onClick(DialogInterface dialog, int which) { 225 // The order is arranged in a way that the popup will be destroyed when the 226 // InCallActivity is about to finish. 227 final String textMessage = et.getText().toString().trim(); 228 dismissCustomMessagePopup(); 229 getPresenter().rejectCallWithMessage(textMessage); 230 } 231 }) 232 .setNegativeButton(R.string.custom_message_cancel, 233 new DialogInterface.OnClickListener() { 234 @Override 235 public void onClick(DialogInterface dialog, int which) { 236 dismissCustomMessagePopup(); 237 getPresenter().onDismissDialog(); 238 } 239 }) 240 .setTitle(R.string.respond_via_sms_custom_message); 241 mCustomMessagePopup = builder.create(); 242 243 // Enable/disable the send button based on whether there is a message in the EditText 244 et.addTextChangedListener(new TextWatcher() { 245 @Override 246 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 247 } 248 249 @Override 250 public void onTextChanged(CharSequence s, int start, int before, int count) { 251 } 252 253 @Override 254 public void afterTextChanged(Editable s) { 255 final Button sendButton = mCustomMessagePopup.getButton( 256 DialogInterface.BUTTON_POSITIVE); 257 sendButton.setEnabled(s != null && s.toString().trim().length() != 0); 258 } 259 }); 260 261 // Keyboard up, show the dialog 262 mCustomMessagePopup.getWindow().setSoftInputMode( 263 WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); 264 mCustomMessagePopup.show(); 265 266 // Send button starts out disabled 267 final Button sendButton = mCustomMessagePopup.getButton(DialogInterface.BUTTON_POSITIVE); 268 sendButton.setEnabled(false); 269 } 270 271 @Override 272 public void configureMessageDialog(ArrayList<String> textResponses) { 273 final ArrayList<String> textResponsesForDisplay = new ArrayList<String>(textResponses); 274 275 textResponsesForDisplay.add(getResources().getString( 276 R.string.respond_via_sms_custom_message)); 277 mTextResponsesAdapter = new ArrayAdapter<String>(getActivity(), 278 android.R.layout.simple_list_item_1, android.R.id.text1, textResponsesForDisplay); 279 } 280 281 @Override 282 public void onAnswer() { 283 getPresenter().onAnswer(); 284 } 285 286 @Override 287 public void onDecline() { 288 getPresenter().onDecline(); 289 } 290 291 @Override 292 public void onText() { 293 getPresenter().onText(); 294 } 295 296 /** 297 * OnItemClickListener for the "Respond via SMS" popup. 298 */ 299 public class RespondViaSmsItemClickListener implements AdapterView.OnItemClickListener { 300 301 /** 302 * Handles the user selecting an item from the popup. 303 */ 304 @Override 305 public void onItemClick(AdapterView<?> parent, // The ListView 306 View view, // The TextView that was clicked 307 int position, long id) { 308 Log.d(this, "RespondViaSmsItemClickListener.onItemClick(" + position + ")..."); 309 final String message = (String) parent.getItemAtPosition(position); 310 Log.v(this, "- message: '" + message + "'"); 311 dismissCannedResponsePopup(); 312 313 // The "Custom" choice is a special case. 314 // (For now, it's guaranteed to be the last item.) 315 if (position == (parent.getCount() - 1)) { 316 // Show the custom message dialog 317 showCustomMessageDialog(); 318 } else { 319 getPresenter().rejectCallWithMessage(message); 320 } 321 } 322 } 323 } 324