summaryrefslogtreecommitdiff
path: root/java/com/android/contacts/common/dialog/CallSubjectDialog.java
diff options
context:
space:
mode:
authorEric Erfanian <erfanian@google.com>2017-02-22 16:32:36 -0800
committerEric Erfanian <erfanian@google.com>2017-03-01 09:56:52 -0800
commitccca31529c07970e89419fb85a9e8153a5396838 (patch)
treea7034c0a01672b97728c13282a2672771cd28baa /java/com/android/contacts/common/dialog/CallSubjectDialog.java
parente7ae4624ba6f25cb8e648db74e0d64c0113a16ba (diff)
Update dialer sources.
Test: Built package and system image. This change clobbers the old source, and is an export from an internal Google repository. The internal repository was forked form Android in March, and this change includes modifications since then, to near the v8 release. Since the fork, we've moved code from monolithic to independent modules. In addition, we've switched to Blaze/Bazel as the build sysetm. This export, however, still uses make. New dependencies have been added: - Dagger - Auto-Value - Glide - Libshortcutbadger Going forward, development will still be in Google3, and the Gerrit release will become an automated export, with the next drop happening in ~ two weeks. Android.mk includes local modifications from ToT. Abridged changelog: Bug fixes ● Not able to mute, add a call when using Phone app in multiwindow mode ● Double tap on keypad triggering multiple key and tones ● Reported spam numbers not showing as spam in the call log ● Crash when user tries to block number while Phone app is not set as default ● Crash when user picks a number from search auto-complete list Visual Voicemail (VVM) improvements ● Share Voicemail audio via standard exporting mechanisms that support file attachment (email, MMS, etc.) ● Make phone number, email and web sites in VVM transcript clickable ● Set PIN before declining VVM Terms of Service {Carrier} ● Set client type for outbound visual voicemail SMS {Carrier} New incoming call and incall UI on older devices (Android M) ● Updated Phone app icon ● New incall UI (large buttons, button labels) ● New and animated Answer/Reject gestures Accessibility ● Add custom answer/decline call buttons on answer screen for touch exploration accessibility services ● Increase size of touch target ● Add verbal feedback when a Voicemail fails to load ● Fix pressing of Phone buttons while in a phone call using Switch Access ● Fix selecting and opening contacts in talkback mode ● Split focus for ‘Learn More’ link in caller id & spam to help distinguish similar text Other ● Backup & Restore for App Preferences ● Prompt user to enable Wi-Fi calling if the call ends due to out of service and Wi-Fi is connected ● Rename “Dialpad” to “Keypad” ● Show "Private number" for restricted calls ● Delete unused items (vcard, add contact, call history) from Phone menu Change-Id: I2a7e53532a24c21bf308bf0a6d178d7ddbca4958
Diffstat (limited to 'java/com/android/contacts/common/dialog/CallSubjectDialog.java')
-rw-r--r--java/com/android/contacts/common/dialog/CallSubjectDialog.java607
1 files changed, 607 insertions, 0 deletions
diff --git a/java/com/android/contacts/common/dialog/CallSubjectDialog.java b/java/com/android/contacts/common/dialog/CallSubjectDialog.java
new file mode 100644
index 000000000..d2e3a2357
--- /dev/null
+++ b/java/com/android/contacts/common/dialog/CallSubjectDialog.java
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.contacts.common.dialog;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.text.Editable;
+import android.text.InputFilter;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.QuickContactBadge;
+import android.widget.TextView;
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.telecom.TelecomManagerCompat;
+import com.android.contacts.common.util.UriUtils;
+import com.android.dialer.animation.AnimUtils;
+import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.callintent.nano.CallInitiationType;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.compat.CompatUtils;
+import com.android.dialer.util.ViewUtil;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implements a dialog which prompts for a call subject for an outgoing call. The dialog includes a
+ * pop up list of historical call subjects.
+ */
+public class CallSubjectDialog extends Activity {
+
+ public static final String PREF_KEY_SUBJECT_HISTORY_COUNT = "subject_history_count";
+ public static final String PREF_KEY_SUBJECT_HISTORY_ITEM = "subject_history_item";
+ /** Activity intent argument bundle keys: */
+ public static final String ARG_PHOTO_ID = "PHOTO_ID";
+
+ public static final String ARG_PHOTO_URI = "PHOTO_URI";
+ public static final String ARG_CONTACT_URI = "CONTACT_URI";
+ public static final String ARG_NAME_OR_NUMBER = "NAME_OR_NUMBER";
+ public static final String ARG_IS_BUSINESS = "IS_BUSINESS";
+ public static final String ARG_NUMBER = "NUMBER";
+ public static final String ARG_DISPLAY_NUMBER = "DISPLAY_NUMBER";
+ public static final String ARG_NUMBER_LABEL = "NUMBER_LABEL";
+ public static final String ARG_PHONE_ACCOUNT_HANDLE = "PHONE_ACCOUNT_HANDLE";
+ private static final int CALL_SUBJECT_LIMIT = 16;
+ private static final int CALL_SUBJECT_HISTORY_SIZE = 5;
+ private int mAnimationDuration;
+ private Charset mMessageEncoding;
+ private View mBackgroundView;
+ private View mDialogView;
+ private QuickContactBadge mContactPhoto;
+ private TextView mNameView;
+ private TextView mNumberView;
+ private EditText mCallSubjectView;
+ private TextView mCharacterLimitView;
+ private View mHistoryButton;
+ private View mSendAndCallButton;
+ private ListView mSubjectList;
+
+ private int mLimit = CALL_SUBJECT_LIMIT;
+ /** Handles changes to the text in the subject box. Ensures the character limit is updated. */
+ private final TextWatcher mTextWatcher =
+ new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ // no-op
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ updateCharacterLimit();
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ // no-op
+ }
+ };
+
+ private int mPhotoSize;
+ private SharedPreferences mPrefs;
+ private List<String> mSubjectHistory;
+ /** Handles displaying the list of past call subjects. */
+ private final View.OnClickListener mHistoryOnClickListener =
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ hideSoftKeyboard(CallSubjectDialog.this, mCallSubjectView);
+ showCallHistory(mSubjectList.getVisibility() == View.GONE);
+ }
+ };
+ /**
+ * Handles auto-hiding the call history when user clicks in the call subject field to give it
+ * focus.
+ */
+ private final View.OnClickListener mCallSubjectClickListener =
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mSubjectList.getVisibility() == View.VISIBLE) {
+ showCallHistory(false);
+ }
+ }
+ };
+
+ private long mPhotoID;
+ private Uri mPhotoUri;
+ private Uri mContactUri;
+ private String mNameOrNumber;
+ private boolean mIsBusiness;
+ private String mNumber;
+ private String mDisplayNumber;
+ private String mNumberLabel;
+ private PhoneAccountHandle mPhoneAccountHandle;
+ /** Handles starting a call with a call subject specified. */
+ private final View.OnClickListener mSendAndCallOnClickListener =
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ String subject = mCallSubjectView.getText().toString();
+ Intent intent =
+ new CallIntentBuilder(mNumber, CallInitiationType.Type.CALL_SUBJECT_DIALOG)
+ .setPhoneAccountHandle(mPhoneAccountHandle)
+ .setCallSubject(subject)
+ .build();
+
+ TelecomManagerCompat.placeCall(
+ CallSubjectDialog.this,
+ (TelecomManager) getSystemService(Context.TELECOM_SERVICE),
+ intent);
+
+ mSubjectHistory.add(subject);
+ saveSubjectHistory(mSubjectHistory);
+ finish();
+ }
+ };
+ /** Click listener which handles user clicks outside of the dialog. */
+ private View.OnClickListener mBackgroundListener =
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ finish();
+ }
+ };
+ /**
+ * Item click listener which handles user clicks on the items in the list view. Dismisses the
+ * activity, returning the subject to the caller and closing the activity with the {@link
+ * Activity#RESULT_OK} result code.
+ */
+ private AdapterView.OnItemClickListener mItemClickListener =
+ new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
+ mCallSubjectView.setText(mSubjectHistory.get(position));
+ showCallHistory(false);
+ }
+ };
+
+ /**
+ * Show the call subject dialog given a phone number to dial (e.g. from the dialpad).
+ *
+ * @param activity The activity.
+ * @param number The number to dial.
+ */
+ public static void start(Activity activity, String number) {
+ start(
+ activity,
+ -1 /* photoId */,
+ null /* photoUri */,
+ null /* contactUri */,
+ number /* nameOrNumber */,
+ false /* isBusiness */,
+ number /* number */,
+ null /* displayNumber */,
+ null /* numberLabel */,
+ null /* phoneAccountHandle */);
+ }
+
+ /**
+ * Creates a call subject dialog.
+ *
+ * @param activity The current activity.
+ * @param photoId The photo ID (used to populate contact photo).
+ * @param photoUri The photo Uri (used to populate contact photo).
+ * @param contactUri The Contact URI (used so quick contact can be invoked from contact photo).
+ * @param nameOrNumber The name or number of the callee.
+ * @param isBusiness {@code true} if a business is being called (used for contact photo).
+ * @param number The raw number to dial.
+ * @param displayNumber The number to dial, formatted for display.
+ * @param numberLabel The label for the number (if from a contact).
+ * @param phoneAccountHandle The phone account handle.
+ */
+ public static void start(
+ Activity activity,
+ long photoId,
+ Uri photoUri,
+ Uri contactUri,
+ String nameOrNumber,
+ boolean isBusiness,
+ String number,
+ String displayNumber,
+ String numberLabel,
+ PhoneAccountHandle phoneAccountHandle) {
+ Bundle arguments = new Bundle();
+ arguments.putLong(ARG_PHOTO_ID, photoId);
+ arguments.putParcelable(ARG_PHOTO_URI, photoUri);
+ arguments.putParcelable(ARG_CONTACT_URI, contactUri);
+ arguments.putString(ARG_NAME_OR_NUMBER, nameOrNumber);
+ arguments.putBoolean(ARG_IS_BUSINESS, isBusiness);
+ arguments.putString(ARG_NUMBER, number);
+ arguments.putString(ARG_DISPLAY_NUMBER, displayNumber);
+ arguments.putString(ARG_NUMBER_LABEL, numberLabel);
+ arguments.putParcelable(ARG_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
+ start(activity, arguments);
+ }
+
+ /**
+ * Shows the call subject dialog given a Bundle containing all the arguments required to display
+ * the dialog (e.g. from Quick Contacts).
+ *
+ * @param activity The activity.
+ * @param arguments The arguments bundle.
+ */
+ public static void start(Activity activity, Bundle arguments) {
+ Intent intent = new Intent(activity, CallSubjectDialog.class);
+ intent.putExtras(arguments);
+ activity.startActivity(intent);
+ }
+
+ /**
+ * Loads the subject history from shared preferences.
+ *
+ * @param prefs Shared preferences.
+ * @return List of subject history strings.
+ */
+ public static List<String> loadSubjectHistory(SharedPreferences prefs) {
+ int historySize = prefs.getInt(PREF_KEY_SUBJECT_HISTORY_COUNT, 0);
+ List<String> subjects = new ArrayList(historySize);
+
+ for (int ix = 0; ix < historySize; ix++) {
+ String historyItem = prefs.getString(PREF_KEY_SUBJECT_HISTORY_ITEM + ix, null);
+ if (!TextUtils.isEmpty(historyItem)) {
+ subjects.add(historyItem);
+ }
+ }
+
+ return subjects;
+ }
+
+ /**
+ * Creates the dialog, inflating the layout and populating it with the name and phone number.
+ *
+ * @param savedInstanceState The last saved instance state of the Fragment, or null if this is a
+ * freshly created Fragment.
+ * @return Dialog instance.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mAnimationDuration = getResources().getInteger(R.integer.call_subject_animation_duration);
+ mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ mPhotoSize =
+ getResources().getDimensionPixelSize(R.dimen.call_subject_dialog_contact_photo_size);
+ readArguments();
+ loadConfiguration();
+ mSubjectHistory = loadSubjectHistory(mPrefs);
+
+ setContentView(R.layout.dialog_call_subject);
+ getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ mBackgroundView = findViewById(R.id.call_subject_dialog);
+ mBackgroundView.setOnClickListener(mBackgroundListener);
+ mDialogView = findViewById(R.id.dialog_view);
+ mContactPhoto = (QuickContactBadge) findViewById(R.id.contact_photo);
+ mNameView = (TextView) findViewById(R.id.name);
+ mNumberView = (TextView) findViewById(R.id.number);
+ mCallSubjectView = (EditText) findViewById(R.id.call_subject);
+ mCallSubjectView.addTextChangedListener(mTextWatcher);
+ mCallSubjectView.setOnClickListener(mCallSubjectClickListener);
+ InputFilter[] filters = new InputFilter[1];
+ filters[0] = new InputFilter.LengthFilter(mLimit);
+ mCallSubjectView.setFilters(filters);
+ mCharacterLimitView = (TextView) findViewById(R.id.character_limit);
+ mHistoryButton = findViewById(R.id.history_button);
+ mHistoryButton.setOnClickListener(mHistoryOnClickListener);
+ mHistoryButton.setVisibility(mSubjectHistory.isEmpty() ? View.GONE : View.VISIBLE);
+ mSendAndCallButton = findViewById(R.id.send_and_call_button);
+ mSendAndCallButton.setOnClickListener(mSendAndCallOnClickListener);
+ mSubjectList = (ListView) findViewById(R.id.subject_list);
+ mSubjectList.setOnItemClickListener(mItemClickListener);
+ mSubjectList.setVisibility(View.GONE);
+
+ updateContactInfo();
+ updateCharacterLimit();
+ }
+
+ /** Populates the contact info fields based on the current contact information. */
+ private void updateContactInfo() {
+ if (mContactUri != null) {
+ setPhoto(mPhotoID, mPhotoUri, mContactUri, mNameOrNumber, mIsBusiness);
+ } else {
+ mContactPhoto.setVisibility(View.GONE);
+ }
+ mNameView.setText(mNameOrNumber);
+ if (!TextUtils.isEmpty(mNumberLabel) && !TextUtils.isEmpty(mDisplayNumber)) {
+ mNumberView.setVisibility(View.VISIBLE);
+ mNumberView.setText(
+ getString(R.string.call_subject_type_and_number, mNumberLabel, mDisplayNumber));
+ } else {
+ mNumberView.setVisibility(View.GONE);
+ mNumberView.setText(null);
+ }
+ }
+
+ /** Reads arguments from the fragment arguments and populates the necessary instance variables. */
+ private void readArguments() {
+ Bundle arguments = getIntent().getExtras();
+ if (arguments == null) {
+ LogUtil.e("CallSubjectDialog.readArguments", "arguments cannot be null");
+ return;
+ }
+ mPhotoID = arguments.getLong(ARG_PHOTO_ID);
+ mPhotoUri = arguments.getParcelable(ARG_PHOTO_URI);
+ mContactUri = arguments.getParcelable(ARG_CONTACT_URI);
+ mNameOrNumber = arguments.getString(ARG_NAME_OR_NUMBER);
+ mIsBusiness = arguments.getBoolean(ARG_IS_BUSINESS);
+ mNumber = arguments.getString(ARG_NUMBER);
+ mDisplayNumber = arguments.getString(ARG_DISPLAY_NUMBER);
+ mNumberLabel = arguments.getString(ARG_NUMBER_LABEL);
+ mPhoneAccountHandle = arguments.getParcelable(ARG_PHONE_ACCOUNT_HANDLE);
+ }
+
+ /**
+ * Updates the character limit display, coloring the text RED when the limit is reached or
+ * exceeded.
+ */
+ private void updateCharacterLimit() {
+ String subjectText = mCallSubjectView.getText().toString();
+ final int length;
+
+ // If a message encoding is specified, use that to count bytes in the message.
+ if (mMessageEncoding != null) {
+ length = subjectText.getBytes(mMessageEncoding).length;
+ } else {
+ // No message encoding specified, so just count characters entered.
+ length = subjectText.length();
+ }
+
+ mCharacterLimitView.setText(getString(R.string.call_subject_limit, length, mLimit));
+ if (length >= mLimit) {
+ mCharacterLimitView.setTextColor(
+ getResources().getColor(R.color.call_subject_limit_exceeded));
+ } else {
+ mCharacterLimitView.setTextColor(
+ getResources().getColor(R.color.dialer_secondary_text_color));
+ }
+ }
+
+ /** Sets the photo on the quick contact photo. */
+ private void setPhoto(
+ long photoId, Uri photoUri, Uri contactUri, String displayName, boolean isBusiness) {
+ mContactPhoto.assignContactUri(contactUri);
+ if (CompatUtils.isLollipopCompatible()) {
+ mContactPhoto.setOverlay(null);
+ }
+
+ int contactType;
+ if (isBusiness) {
+ contactType = ContactPhotoManager.TYPE_BUSINESS;
+ } else {
+ contactType = ContactPhotoManager.TYPE_DEFAULT;
+ }
+
+ String lookupKey = null;
+ if (contactUri != null) {
+ lookupKey = UriUtils.getLookupKeyFromUri(contactUri);
+ }
+
+ ContactPhotoManager.DefaultImageRequest request =
+ new ContactPhotoManager.DefaultImageRequest(
+ displayName, lookupKey, contactType, true /* isCircular */);
+
+ if (photoId == 0 && photoUri != null) {
+ ContactPhotoManager.getInstance(this)
+ .loadPhoto(
+ mContactPhoto,
+ photoUri,
+ mPhotoSize,
+ false /* darkTheme */,
+ true /* isCircular */,
+ request);
+ } else {
+ ContactPhotoManager.getInstance(this)
+ .loadThumbnail(
+ mContactPhoto, photoId, false /* darkTheme */, true /* isCircular */, request);
+ }
+ }
+
+ /**
+ * Saves the subject history list to shared prefs, removing older items so that there are only
+ * {@link #CALL_SUBJECT_HISTORY_SIZE} items at most.
+ *
+ * @param history The history.
+ */
+ private void saveSubjectHistory(List<String> history) {
+ // Remove oldest subject(s).
+ while (history.size() > CALL_SUBJECT_HISTORY_SIZE) {
+ history.remove(0);
+ }
+
+ SharedPreferences.Editor editor = mPrefs.edit();
+ int historyCount = 0;
+ for (String subject : history) {
+ if (!TextUtils.isEmpty(subject)) {
+ editor.putString(PREF_KEY_SUBJECT_HISTORY_ITEM + historyCount, subject);
+ historyCount++;
+ }
+ }
+ editor.putInt(PREF_KEY_SUBJECT_HISTORY_COUNT, historyCount);
+ editor.apply();
+ }
+
+ /** Hide software keyboard for the given {@link View}. */
+ public void hideSoftKeyboard(Context context, View view) {
+ InputMethodManager imm =
+ (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+ }
+ }
+
+ /**
+ * Hides or shows the call history list.
+ *
+ * @param show {@code true} if the call history should be shown, {@code false} otherwise.
+ */
+ private void showCallHistory(final boolean show) {
+ // Bail early if the visibility has not changed.
+ if ((show && mSubjectList.getVisibility() == View.VISIBLE)
+ || (!show && mSubjectList.getVisibility() == View.GONE)) {
+ return;
+ }
+
+ final int dialogStartingBottom = mDialogView.getBottom();
+ if (show) {
+ // Showing the subject list; bind the list of history items to the list and show it.
+ ArrayAdapter<String> adapter =
+ new ArrayAdapter<String>(
+ CallSubjectDialog.this, R.layout.call_subject_history_list_item, mSubjectHistory);
+ mSubjectList.setAdapter(adapter);
+ mSubjectList.setVisibility(View.VISIBLE);
+ } else {
+ // Hiding the subject list.
+ mSubjectList.setVisibility(View.GONE);
+ }
+
+ // Use a ViewTreeObserver so that we can animate between the pre-layout and post-layout
+ // states.
+ ViewUtil.doOnPreDraw(
+ mBackgroundView,
+ true,
+ new Runnable() {
+ @Override
+ public void run() {
+ // Determine the amount the dialog has shifted due to the relayout.
+ int shiftAmount = dialogStartingBottom - mDialogView.getBottom();
+
+ // If the dialog needs to be shifted, do that now.
+ if (shiftAmount != 0) {
+ // Start animation in translated state and animate to translationY 0.
+ mDialogView.setTranslationY(shiftAmount);
+ mDialogView
+ .animate()
+ .translationY(0)
+ .setInterpolator(AnimUtils.EASE_OUT_EASE_IN)
+ .setDuration(mAnimationDuration)
+ .start();
+ }
+
+ if (show) {
+ // Show the subject list.
+ mSubjectList.setTranslationY(mSubjectList.getHeight());
+
+ mSubjectList
+ .animate()
+ .translationY(0)
+ .setInterpolator(AnimUtils.EASE_OUT_EASE_IN)
+ .setDuration(mAnimationDuration)
+ .setListener(
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mSubjectList.setVisibility(View.VISIBLE);
+ }
+ })
+ .start();
+ } else {
+ // Hide the subject list.
+ mSubjectList.setTranslationY(0);
+
+ mSubjectList
+ .animate()
+ .translationY(mSubjectList.getHeight())
+ .setInterpolator(AnimUtils.EASE_OUT_EASE_IN)
+ .setDuration(mAnimationDuration)
+ .setListener(
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mSubjectList.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ }
+ })
+ .start();
+ }
+ }
+ });
+ }
+
+ /**
+ * Loads the message encoding and maximum message length from the phone account extras for the
+ * current phone account.
+ */
+ private void loadConfiguration() {
+ // Only attempt to load configuration from the phone account extras if the SDK is N or
+ // later. If we've got a prior SDK the default encoding and message length will suffice.
+ if (VERSION.SDK_INT < VERSION_CODES.N) {
+ return;
+ }
+
+ if (mPhoneAccountHandle == null) {
+ return;
+ }
+
+ TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
+ final PhoneAccount account = telecomManager.getPhoneAccount(mPhoneAccountHandle);
+
+ Bundle phoneAccountExtras = account.getExtras();
+ if (phoneAccountExtras == null) {
+ return;
+ }
+
+ // Get limit, if provided; otherwise default to existing value.
+ mLimit = phoneAccountExtras.getInt(PhoneAccount.EXTRA_CALL_SUBJECT_MAX_LENGTH, mLimit);
+
+ // Get charset; default to none (e.g. count characters 1:1).
+ String charsetName =
+ phoneAccountExtras.getString(PhoneAccount.EXTRA_CALL_SUBJECT_CHARACTER_ENCODING);
+
+ if (!TextUtils.isEmpty(charsetName)) {
+ try {
+ mMessageEncoding = Charset.forName(charsetName);
+ } catch (java.nio.charset.UnsupportedCharsetException uce) {
+ // Character set was invalid; log warning and fallback to none.
+ LogUtil.e("CallSubjectDialog.loadConfiguration", "invalid charset: " + charsetName);
+ mMessageEncoding = null;
+ }
+ } else {
+ // No character set specified, so count characters 1:1.
+ mMessageEncoding = null;
+ }
+ }
+}