blob: 036a0f3e7154548c24e55c50bcc6fb9b556b277f [file] [log] [blame]
Tyler Gunn9e0c14e2015-08-04 13:33:49 -07001/*
2 * Copyright (C) 2015 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
Gary Mai69c182a2016-12-05 13:07:03 -080017package com.android.contacts.dialog;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070018
Tyler Gunn96a121e2015-08-12 14:34:45 -070019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070021import android.app.Activity;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070022import android.content.Context;
23import android.content.Intent;
Tyler Gunna05f1532015-08-06 15:01:44 -070024import android.content.SharedPreferences;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070025import android.net.Uri;
26import android.os.Bundle;
Tyler Gunna05f1532015-08-06 15:01:44 -070027import android.preference.PreferenceManager;
Tyler Gunn9467b382015-11-09 14:08:18 -080028import android.telecom.PhoneAccount;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070029import android.telecom.PhoneAccountHandle;
30import android.telecom.TelecomManager;
31import android.text.Editable;
Tyler Gunna05f1532015-08-06 15:01:44 -070032import android.text.InputFilter;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070033import android.text.TextUtils;
34import android.text.TextWatcher;
35import android.util.Log;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070036import android.view.View;
37import android.view.ViewGroup;
Tyler Gunn96a121e2015-08-12 14:34:45 -070038import android.view.ViewTreeObserver;
Tyler Gunna05f1532015-08-06 15:01:44 -070039import android.view.inputmethod.InputMethodManager;
Tyler Gunn96a121e2015-08-12 14:34:45 -070040import android.widget.AdapterView;
41import android.widget.ArrayAdapter;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070042import android.widget.EditText;
Tyler Gunn96a121e2015-08-12 14:34:45 -070043import android.widget.ListView;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070044import android.widget.QuickContactBadge;
45import android.widget.TextView;
46
Gary Mai0a49afa2016-12-05 15:53:58 -080047import com.android.contacts.CallUtil;
48import com.android.contacts.ContactPhotoManager;
Arthur Wang3f6a2442016-12-05 14:51:59 -080049import com.android.contacts.R;
Gary Mai69c182a2016-12-05 13:07:03 -080050import com.android.contacts.compat.CompatUtils;
51import com.android.contacts.compat.PhoneAccountSdkCompat;
52import com.android.contacts.compat.telecom.TelecomManagerCompat;
53import com.android.contacts.util.UriUtils;
Tyler Gunn96a121e2015-08-12 14:34:45 -070054import com.android.phone.common.animation.AnimUtils;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070055
Tyler Gunn9467b382015-11-09 14:08:18 -080056import java.nio.charset.Charset;
Tyler Gunna05f1532015-08-06 15:01:44 -070057import java.util.ArrayList;
58import java.util.List;
59
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070060/**
Tyler Gunn96a121e2015-08-12 14:34:45 -070061 * Implements a dialog which prompts for a call subject for an outgoing call. The dialog includes
62 * a pop up list of historical call subjects.
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070063 */
Tyler Gunn96a121e2015-08-12 14:34:45 -070064public class CallSubjectDialog extends Activity {
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070065 private static final String TAG = "CallSubjectDialog";
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070066 private static final int CALL_SUBJECT_LIMIT = 16;
Tyler Gunna05f1532015-08-06 15:01:44 -070067 private static final int CALL_SUBJECT_HISTORY_SIZE = 5;
68
69 private static final int REQUEST_SUBJECT = 1001;
70
71 public static final String PREF_KEY_SUBJECT_HISTORY_COUNT = "subject_history_count";
72 public static final String PREF_KEY_SUBJECT_HISTORY_ITEM = "subject_history_item";
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070073
74 /**
Tyler Gunn96a121e2015-08-12 14:34:45 -070075 * Activity intent argument bundle keys:
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070076 */
Tyler Gunna05f1532015-08-06 15:01:44 -070077 public static final String ARG_PHOTO_ID = "PHOTO_ID";
78 public static final String ARG_PHOTO_URI = "PHOTO_URI";
79 public static final String ARG_CONTACT_URI = "CONTACT_URI";
80 public static final String ARG_NAME_OR_NUMBER = "NAME_OR_NUMBER";
81 public static final String ARG_IS_BUSINESS = "IS_BUSINESS";
82 public static final String ARG_NUMBER = "NUMBER";
83 public static final String ARG_DISPLAY_NUMBER = "DISPLAY_NUMBER";
84 public static final String ARG_NUMBER_LABEL = "NUMBER_LABEL";
85 public static final String ARG_PHONE_ACCOUNT_HANDLE = "PHONE_ACCOUNT_HANDLE";
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070086
Tyler Gunn96a121e2015-08-12 14:34:45 -070087 private int mAnimationDuration;
Tyler Gunn9467b382015-11-09 14:08:18 -080088 private Charset mMessageEncoding;
Tyler Gunn96a121e2015-08-12 14:34:45 -070089 private View mBackgroundView;
90 private View mDialogView;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070091 private QuickContactBadge mContactPhoto;
92 private TextView mNameView;
93 private TextView mNumberView;
94 private EditText mCallSubjectView;
95 private TextView mCharacterLimitView;
96 private View mHistoryButton;
97 private View mSendAndCallButton;
Tyler Gunn96a121e2015-08-12 14:34:45 -070098 private ListView mSubjectList;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -070099
100 private int mLimit = CALL_SUBJECT_LIMIT;
101 private int mPhotoSize;
Tyler Gunna05f1532015-08-06 15:01:44 -0700102 private SharedPreferences mPrefs;
103 private List<String> mSubjectHistory;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700104
105 private long mPhotoID;
106 private Uri mPhotoUri;
107 private Uri mContactUri;
108 private String mNameOrNumber;
109 private boolean mIsBusiness;
110 private String mNumber;
111 private String mDisplayNumber;
112 private String mNumberLabel;
113 private PhoneAccountHandle mPhoneAccountHandle;
114
115 /**
116 * Handles changes to the text in the subject box. Ensures the character limit is updated.
117 */
118 private final TextWatcher mTextWatcher = new TextWatcher() {
119 @Override
120 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
121 // no-op
122 }
123
124 @Override
125 public void onTextChanged(CharSequence s, int start, int before, int count) {
126 updateCharacterLimit();
127 }
128
129 @Override
130 public void afterTextChanged(Editable s) {
131 // no-op
132 }
133 };
134
135 /**
Tyler Gunn96a121e2015-08-12 14:34:45 -0700136 * Click listener which handles user clicks outside of the dialog.
137 */
138 private View.OnClickListener mBackgroundListener = new View.OnClickListener() {
139 @Override
140 public void onClick(View v) {
141 finish();
142 }
143 };
144
145 /**
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700146 * Handles displaying the list of past call subjects.
147 */
148 private final View.OnClickListener mHistoryOnClickListener = new View.OnClickListener() {
149 @Override
150 public void onClick(View v) {
Tyler Gunn96a121e2015-08-12 14:34:45 -0700151 hideSoftKeyboard(CallSubjectDialog.this, mCallSubjectView);
152 showCallHistory(mSubjectList.getVisibility() == View.GONE);
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700153 }
154 };
155
156 /**
157 * Handles starting a call with a call subject specified.
158 */
159 private final View.OnClickListener mSendAndCallOnClickListener = new View.OnClickListener() {
160 @Override
161 public void onClick(View v) {
Tyler Gunna05f1532015-08-06 15:01:44 -0700162 String subject = mCallSubjectView.getText().toString();
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700163 Intent intent = CallUtil.getCallWithSubjectIntent(mNumber, mPhoneAccountHandle,
Tyler Gunna05f1532015-08-06 15:01:44 -0700164 subject);
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700165
Nancy Chen78384182015-12-22 17:21:13 -0800166 TelecomManagerCompat.placeCall(
167 CallSubjectDialog.this,
168 (TelecomManager) getSystemService(Context.TELECOM_SERVICE),
169 intent);
Tyler Gunna05f1532015-08-06 15:01:44 -0700170
171 mSubjectHistory.add(subject);
172 saveSubjectHistory(mSubjectHistory);
Tyler Gunn96a121e2015-08-12 14:34:45 -0700173 finish();
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700174 }
175 };
176
177 /**
Tyler Gunn96a121e2015-08-12 14:34:45 -0700178 * Handles auto-hiding the call history when user clicks in the call subject field to give it
179 * focus.
180 */
181 private final View.OnClickListener mCallSubjectClickListener = new View.OnClickListener() {
182 @Override
183 public void onClick(View v) {
184 if (mSubjectList.getVisibility() == View.VISIBLE) {
185 showCallHistory(false);
186 }
187 }
188 };
189
190 /**
191 * Item click listener which handles user clicks on the items in the list view. Dismisses
192 * the activity, returning the subject to the caller and closing the activity with the
193 * {@link Activity#RESULT_OK} result code.
194 */
195 private AdapterView.OnItemClickListener mItemClickListener =
196 new AdapterView.OnItemClickListener() {
197 @Override
198 public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
199 mCallSubjectView.setText(mSubjectHistory.get(position));
200 showCallHistory(false);
201 }
202 };
203
204 /**
Nancy Chen04538af2015-12-15 11:58:36 -0800205 * Show the call subject dialog given a phone number to dial (e.g. from the dialpad).
Tyler Gunna05f1532015-08-06 15:01:44 -0700206 *
207 * @param activity The activity.
208 * @param number The number to dial.
209 */
210 public static void start(Activity activity, String number) {
211 start(activity,
212 -1 /* photoId */,
213 null /* photoUri */,
214 null /* contactUri */,
215 number /* nameOrNumber */,
216 false /* isBusiness */,
217 number /* number */,
218 null /* displayNumber */,
219 null /* numberLabel */,
220 null /* phoneAccountHandle */);
221 }
222
223 /**
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700224 * Creates a call subject dialog.
225 *
226 * @param activity The current activity.
227 * @param photoId The photo ID (used to populate contact photo).
228 * @param photoUri The photo Uri (used to populate contact photo).
229 * @param contactUri The Contact URI (used so quick contact can be invoked from contact photo).
230 * @param nameOrNumber The name or number of the callee.
231 * @param isBusiness {@code true} if a business is being called (used for contact photo).
232 * @param number The raw number to dial.
233 * @param displayNumber The number to dial, formatted for display.
234 * @param numberLabel The label for the number (if from a contact).
235 * @param phoneAccountHandle The phone account handle.
236 */
237 public static void start(Activity activity, long photoId, Uri photoUri, Uri contactUri,
238 String nameOrNumber, boolean isBusiness, String number, String displayNumber,
239 String numberLabel, PhoneAccountHandle phoneAccountHandle) {
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700240 Bundle arguments = new Bundle();
241 arguments.putLong(ARG_PHOTO_ID, photoId);
242 arguments.putParcelable(ARG_PHOTO_URI, photoUri);
243 arguments.putParcelable(ARG_CONTACT_URI, contactUri);
244 arguments.putString(ARG_NAME_OR_NUMBER, nameOrNumber);
245 arguments.putBoolean(ARG_IS_BUSINESS, isBusiness);
246 arguments.putString(ARG_NUMBER, number);
247 arguments.putString(ARG_DISPLAY_NUMBER, displayNumber);
248 arguments.putString(ARG_NUMBER_LABEL, numberLabel);
249 arguments.putParcelable(ARG_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
Tyler Gunna05f1532015-08-06 15:01:44 -0700250 start(activity, arguments);
251 }
252
253 /**
254 * Shows the call subject dialog given a Bundle containing all the arguments required to
255 * display the dialog (e.g. from Quick Contacts).
256 *
257 * @param activity The activity.
258 * @param arguments The arguments bundle.
259 */
260 public static void start(Activity activity, Bundle arguments) {
Tyler Gunn96a121e2015-08-12 14:34:45 -0700261 Intent intent = new Intent(activity, CallSubjectDialog.class);
262 intent.putExtras(arguments);
263 activity.startActivity(intent);
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700264 }
265
266 /**
267 * Creates the dialog, inflating the layout and populating it with the name and phone number.
268 *
269 * @param savedInstanceState The last saved instance state of the Fragment,
270 * or null if this is a freshly created Fragment.
271 *
272 * @return Dialog instance.
273 */
274 @Override
Tyler Gunn96a121e2015-08-12 14:34:45 -0700275 public void onCreate(Bundle savedInstanceState) {
276 super.onCreate(savedInstanceState);
277 mAnimationDuration = getResources().getInteger(R.integer.call_subject_animation_duration);
278 mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
279 mPhotoSize = getResources().getDimensionPixelSize(
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700280 R.dimen.call_subject_dialog_contact_photo_size);
281 readArguments();
Tyler Gunn9467b382015-11-09 14:08:18 -0800282 loadConfiguration();
Tyler Gunna05f1532015-08-06 15:01:44 -0700283 mSubjectHistory = loadSubjectHistory(mPrefs);
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700284
Tyler Gunn96a121e2015-08-12 14:34:45 -0700285 setContentView(R.layout.dialog_call_subject);
286 getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
287 ViewGroup.LayoutParams.MATCH_PARENT);
288 mBackgroundView = findViewById(R.id.call_subject_dialog);
289 mBackgroundView.setOnClickListener(mBackgroundListener);
290 mDialogView = findViewById(R.id.dialog_view);
291 mContactPhoto = (QuickContactBadge) findViewById(R.id.contact_photo);
292 mNameView = (TextView) findViewById(R.id.name);
293 mNumberView = (TextView) findViewById(R.id.number);
294 mCallSubjectView = (EditText) findViewById(R.id.call_subject);
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700295 mCallSubjectView.addTextChangedListener(mTextWatcher);
Tyler Gunn96a121e2015-08-12 14:34:45 -0700296 mCallSubjectView.setOnClickListener(mCallSubjectClickListener);
Tyler Gunna05f1532015-08-06 15:01:44 -0700297 InputFilter[] filters = new InputFilter[1];
298 filters[0] = new InputFilter.LengthFilter(mLimit);
299 mCallSubjectView.setFilters(filters);
Tyler Gunn96a121e2015-08-12 14:34:45 -0700300 mCharacterLimitView = (TextView) findViewById(R.id.character_limit);
301 mHistoryButton = findViewById(R.id.history_button);
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700302 mHistoryButton.setOnClickListener(mHistoryOnClickListener);
Tyler Gunna05f1532015-08-06 15:01:44 -0700303 mHistoryButton.setVisibility(mSubjectHistory.isEmpty() ? View.GONE : View.VISIBLE);
Tyler Gunn96a121e2015-08-12 14:34:45 -0700304 mSendAndCallButton = findViewById(R.id.send_and_call_button);
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700305 mSendAndCallButton.setOnClickListener(mSendAndCallOnClickListener);
Tyler Gunn96a121e2015-08-12 14:34:45 -0700306 mSubjectList = (ListView) findViewById(R.id.subject_list);
307 mSubjectList.setOnItemClickListener(mItemClickListener);
308 mSubjectList.setVisibility(View.GONE);
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700309
310 updateContactInfo();
311 updateCharacterLimit();
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700312 }
313
314 /**
315 * Populates the contact info fields based on the current contact information.
316 */
317 private void updateContactInfo() {
Tyler Gunna05f1532015-08-06 15:01:44 -0700318 if (mContactUri != null) {
319 setPhoto(mPhotoID, mPhotoUri, mContactUri, mNameOrNumber, mIsBusiness);
320 } else {
321 mContactPhoto.setVisibility(View.GONE);
322 }
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700323 mNameView.setText(mNameOrNumber);
324 if (!TextUtils.isEmpty(mNumberLabel) && !TextUtils.isEmpty(mDisplayNumber)) {
325 mNumberView.setVisibility(View.VISIBLE);
Tyler Gunn96a121e2015-08-12 14:34:45 -0700326 mNumberView.setText(getString(R.string.call_subject_type_and_number,
327 mNumberLabel, mDisplayNumber));
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700328 } else {
329 mNumberView.setVisibility(View.GONE);
330 mNumberView.setText(null);
331 }
332 }
333
334 /**
335 * Reads arguments from the fragment arguments and populates the necessary instance variables.
336 */
337 private void readArguments() {
Tyler Gunn96a121e2015-08-12 14:34:45 -0700338 Bundle arguments = getIntent().getExtras();
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700339 if (arguments == null) {
340 Log.e(TAG, "Arguments cannot be null.");
Tyler Gunna05f1532015-08-06 15:01:44 -0700341 return;
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700342 }
343 mPhotoID = arguments.getLong(ARG_PHOTO_ID);
344 mPhotoUri = arguments.getParcelable(ARG_PHOTO_URI);
345 mContactUri = arguments.getParcelable(ARG_CONTACT_URI);
346 mNameOrNumber = arguments.getString(ARG_NAME_OR_NUMBER);
347 mIsBusiness = arguments.getBoolean(ARG_IS_BUSINESS);
348 mNumber = arguments.getString(ARG_NUMBER);
349 mDisplayNumber = arguments.getString(ARG_DISPLAY_NUMBER);
350 mNumberLabel = arguments.getString(ARG_NUMBER_LABEL);
351 mPhoneAccountHandle = arguments.getParcelable(ARG_PHONE_ACCOUNT_HANDLE);
352 }
353
354 /**
355 * Updates the character limit display, coloring the text RED when the limit is reached or
356 * exceeded.
357 */
358 private void updateCharacterLimit() {
Tyler Gunn9467b382015-11-09 14:08:18 -0800359 String subjectText = mCallSubjectView.getText().toString();
360 final int length;
361
362 // If a message encoding is specified, use that to count bytes in the message.
363 if (mMessageEncoding != null) {
364 length = subjectText.getBytes(mMessageEncoding).length;
365 } else {
366 // No message encoding specified, so just count characters entered.
367 length = subjectText.length();
368 }
369
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700370 mCharacterLimitView.setText(
Tyler Gunn96a121e2015-08-12 14:34:45 -0700371 getString(R.string.call_subject_limit, length, mLimit));
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700372 if (length >= mLimit) {
Tyler Gunn96a121e2015-08-12 14:34:45 -0700373 mCharacterLimitView.setTextColor(getResources().getColor(
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700374 R.color.call_subject_limit_exceeded));
375 } else {
Tyler Gunn96a121e2015-08-12 14:34:45 -0700376 mCharacterLimitView.setTextColor(getResources().getColor(
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700377 R.color.dialtacts_secondary_text_color));
378 }
379 }
380
381 /**
382 * Sets the photo on the quick contact photo.
383 *
384 * @param photoId
385 * @param photoUri
386 * @param contactUri
387 * @param displayName
388 * @param isBusiness
389 */
390 private void setPhoto(long photoId, Uri photoUri, Uri contactUri, String displayName,
391 boolean isBusiness) {
392 mContactPhoto.assignContactUri(contactUri);
Wenyi Wang54ea4b12015-12-16 14:18:59 -0800393 if (CompatUtils.isLollipopCompatible()) {
394 mContactPhoto.setOverlay(null);
395 }
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700396
397 int contactType;
398 if (isBusiness) {
399 contactType = ContactPhotoManager.TYPE_BUSINESS;
400 } else {
401 contactType = ContactPhotoManager.TYPE_DEFAULT;
402 }
403
404 String lookupKey = null;
405 if (contactUri != null) {
406 lookupKey = UriUtils.getLookupKeyFromUri(contactUri);
407 }
408
409 ContactPhotoManager.DefaultImageRequest
410 request = new ContactPhotoManager.DefaultImageRequest(
411 displayName, lookupKey, contactType, true /* isCircular */);
412
413 if (photoId == 0 && photoUri != null) {
Tyler Gunn96a121e2015-08-12 14:34:45 -0700414 ContactPhotoManager.getInstance(this).loadPhoto(mContactPhoto, photoUri,
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700415 mPhotoSize, false /* darkTheme */, true /* isCircular */, request);
416 } else {
Tyler Gunn96a121e2015-08-12 14:34:45 -0700417 ContactPhotoManager.getInstance(this).loadThumbnail(mContactPhoto, photoId,
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700418 false /* darkTheme */, true /* isCircular */, request);
419 }
420 }
Tyler Gunna05f1532015-08-06 15:01:44 -0700421
422 /**
423 * Loads the subject history from shared preferences.
424 *
425 * @param prefs Shared preferences.
426 * @return List of subject history strings.
427 */
428 public static List<String> loadSubjectHistory(SharedPreferences prefs) {
429 int historySize = prefs.getInt(PREF_KEY_SUBJECT_HISTORY_COUNT, 0);
430 List<String> subjects = new ArrayList(historySize);
431
432 for (int ix = 0 ; ix < historySize; ix++) {
433 String historyItem = prefs.getString(PREF_KEY_SUBJECT_HISTORY_ITEM + ix, null);
434 if (!TextUtils.isEmpty(historyItem)) {
435 subjects.add(historyItem);
436 }
437 }
438
439 return subjects;
440 }
441
442 /**
443 * Saves the subject history list to shared prefs, removing older items so that there are only
444 * {@link #CALL_SUBJECT_HISTORY_SIZE} items at most.
445 *
446 * @param history The history.
447 */
448 private void saveSubjectHistory(List<String> history) {
449 // Remove oldest subject(s).
450 while (history.size() > CALL_SUBJECT_HISTORY_SIZE) {
451 history.remove(0);
452 }
453
454 SharedPreferences.Editor editor = mPrefs.edit();
455 int historyCount = 0;
456 for (String subject : history) {
457 if (!TextUtils.isEmpty(subject)) {
458 editor.putString(PREF_KEY_SUBJECT_HISTORY_ITEM + historyCount,
459 subject);
460 historyCount++;
461 }
462 }
463 editor.putInt(PREF_KEY_SUBJECT_HISTORY_COUNT, historyCount);
464 editor.apply();
465 }
466
467 /**
Tyler Gunna05f1532015-08-06 15:01:44 -0700468 * Hide software keyboard for the given {@link View}.
469 */
470 public void hideSoftKeyboard(Context context, View view) {
471 InputMethodManager imm = (InputMethodManager) context.getSystemService(
472 Context.INPUT_METHOD_SERVICE);
473 if (imm != null) {
Tyler Gunn96a121e2015-08-12 14:34:45 -0700474 imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
Tyler Gunna05f1532015-08-06 15:01:44 -0700475 }
476 }
477
478 /**
Tyler Gunn96a121e2015-08-12 14:34:45 -0700479 * Hides or shows the call history list.
480 *
481 * @param show {@code true} if the call history should be shown, {@code false} otherwise.
Tyler Gunna05f1532015-08-06 15:01:44 -0700482 */
Tyler Gunn96a121e2015-08-12 14:34:45 -0700483 private void showCallHistory(final boolean show) {
484 // Bail early if the visibility has not changed.
485 if ((show && mSubjectList.getVisibility() == View.VISIBLE) ||
486 (!show && mSubjectList.getVisibility() == View.GONE)) {
487 return;
Tyler Gunna05f1532015-08-06 15:01:44 -0700488 }
Tyler Gunn96a121e2015-08-12 14:34:45 -0700489
490 final int dialogStartingBottom = mDialogView.getBottom();
491 if (show) {
492 // Showing the subject list; bind the list of history items to the list and show it.
493 ArrayAdapter<String> adapter = new ArrayAdapter<String>(CallSubjectDialog.this,
494 R.layout.call_subject_history_list_item, mSubjectHistory);
495 mSubjectList.setAdapter(adapter);
496 mSubjectList.setVisibility(View.VISIBLE);
497 } else {
498 // Hiding the subject list.
499 mSubjectList.setVisibility(View.GONE);
500 }
501
502 // Use a ViewTreeObserver so that we can animate between the pre-layout and post-layout
503 // states.
504 final ViewTreeObserver observer = mBackgroundView.getViewTreeObserver();
505 observer.addOnPreDrawListener(
506 new ViewTreeObserver.OnPreDrawListener() {
507 @Override
508 public boolean onPreDraw() {
509 // We don't want to continue getting called.
510 if (observer.isAlive()) {
511 observer.removeOnPreDrawListener(this);
512 }
513
514 // Determine the amount the dialog has shifted due to the relayout.
515 int shiftAmount = dialogStartingBottom - mDialogView.getBottom();
516
517 // If the dialog needs to be shifted, do that now.
518 if (shiftAmount != 0) {
519 // Start animation in translated state and animate to translationY 0.
520 mDialogView.setTranslationY(shiftAmount);
521 mDialogView.animate()
522 .translationY(0)
523 .setInterpolator(AnimUtils.EASE_OUT_EASE_IN)
524 .setDuration(mAnimationDuration)
525 .start();
526 }
527
528 if (show) {
529 // Show the subhect list.
530 mSubjectList.setTranslationY(mSubjectList.getHeight());
531
532 mSubjectList.animate()
533 .translationY(0)
534 .setInterpolator(AnimUtils.EASE_OUT_EASE_IN)
535 .setDuration(mAnimationDuration)
536 .setListener(new AnimatorListenerAdapter() {
537 @Override
538 public void onAnimationEnd(Animator animation) {
539 super.onAnimationEnd(animation);
540 }
541
542 @Override
543 public void onAnimationStart(Animator animation) {
544 super.onAnimationStart(animation);
545 mSubjectList.setVisibility(View.VISIBLE);
546 }
547 })
548 .start();
549 } else {
550 // Hide the subject list.
551 mSubjectList.setTranslationY(0);
552
553 mSubjectList.animate()
554 .translationY(mSubjectList.getHeight())
555 .setInterpolator(AnimUtils.EASE_OUT_EASE_IN)
556 .setDuration(mAnimationDuration)
557 .setListener(new AnimatorListenerAdapter() {
558 @Override
559 public void onAnimationEnd(Animator animation) {
560 super.onAnimationEnd(animation);
561 mSubjectList.setVisibility(View.GONE);
562 }
563
564 @Override
565 public void onAnimationStart(Animator animation) {
566 super.onAnimationStart(animation);
567 }
568 })
569 .start();
570 }
571 return true;
572 }
573 }
574 );
Tyler Gunna05f1532015-08-06 15:01:44 -0700575 }
Tyler Gunn9467b382015-11-09 14:08:18 -0800576
577 /**
578 * Loads the message encoding and maximum message length from the phone account extras for the
579 * current phone account.
580 */
581 private void loadConfiguration() {
582 // Only attempt to load configuration from the phone account extras if the SDK is N or
583 // later. If we've got a prior SDK the default encoding and message length will suffice.
584 int sdk = android.os.Build.VERSION.SDK_INT;
585 if(sdk <= android.os.Build.VERSION_CODES.M) {
586 return;
587 }
588
589 if (mPhoneAccountHandle == null) {
590 return;
591 }
592
593 TelecomManager telecomManager =
594 (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
595 final PhoneAccount account = telecomManager.getPhoneAccount(mPhoneAccountHandle);
596
Ta-wei Yen59023c22016-01-08 15:46:27 -0800597 Bundle phoneAccountExtras = PhoneAccountSdkCompat.getExtras(account);
Tyler Gunn9467b382015-11-09 14:08:18 -0800598 if (phoneAccountExtras == null) {
599 return;
600 }
601
602 // Get limit, if provided; otherwise default to existing value.
Ta-wei Yen59023c22016-01-08 15:46:27 -0800603 mLimit = phoneAccountExtras
604 .getInt(PhoneAccountSdkCompat.EXTRA_CALL_SUBJECT_MAX_LENGTH, mLimit);
Tyler Gunn9467b382015-11-09 14:08:18 -0800605
606 // Get charset; default to none (e.g. count characters 1:1).
607 String charsetName = phoneAccountExtras.getString(
Ta-wei Yen59023c22016-01-08 15:46:27 -0800608 PhoneAccountSdkCompat.EXTRA_CALL_SUBJECT_CHARACTER_ENCODING);
Tyler Gunn9467b382015-11-09 14:08:18 -0800609
610 if (!TextUtils.isEmpty(charsetName)) {
611 try {
612 mMessageEncoding = Charset.forName(charsetName);
613 } catch (java.nio.charset.UnsupportedCharsetException uce) {
614 // Character set was invalid; log warning and fallback to none.
615 Log.w(TAG, "Invalid charset: " + charsetName);
616 mMessageEncoding = null;
617 }
618 } else {
619 // No character set specified, so count characters 1:1.
620 mMessageEncoding = null;
621 }
622 }
Tyler Gunn9e0c14e2015-08-04 13:33:49 -0700623}