diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2018-03-04 08:25:29 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2018-03-04 08:25:29 +0000 |
commit | 63d59d1fe094623021de9d890500b6d4d13599d1 (patch) | |
tree | 0b1fb8ccda7b6077f0ae8a7a0a3cf733e103ceea /java | |
parent | 511786627ba3e4ad121b23219d1e4ce6daee6ca1 (diff) | |
parent | f2874ff76230a05421c653e1aed6e288062d82cf (diff) |
Snap for 4632767 from f2874ff76230a05421c653e1aed6e288062d82cf to pi-release
Change-Id: I0f473726a9ab6e894c265e50224ac64bde8bcabe
Diffstat (limited to 'java')
72 files changed, 1076 insertions, 578 deletions
diff --git a/java/com/android/contacts/common/compat/PhoneNumberUtilsCompat.java b/java/com/android/contacts/common/compat/PhoneNumberUtilsCompat.java deleted file mode 100644 index a6cfe07cd..000000000 --- a/java/com/android/contacts/common/compat/PhoneNumberUtilsCompat.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.compat; - -import android.telephony.PhoneNumberUtils; -import android.text.style.TtsSpan; - -/** - * This class contains static utility methods extracted from PhoneNumberUtils, and the methods were - * added in API level 23. In this way, we could enable the corresponding functionality for pre-M - * devices. We need maintain this class and keep it synced with PhoneNumberUtils. Another thing to - * keep in mind is that we use com.google.i18n rather than com.android.i18n in here, so we need make - * sure the application behavior is preserved. - */ -public class PhoneNumberUtilsCompat { - - /** Not instantiable. */ - private PhoneNumberUtilsCompat() {} - - public static String formatNumber( - String phoneNumber, String phoneNumberE164, String defaultCountryIso) { - return PhoneNumberUtils.formatNumber(phoneNumber, phoneNumberE164, defaultCountryIso); - } - - public static CharSequence createTtsSpannable(CharSequence phoneNumber) { - return PhoneNumberUtils.createTtsSpannable(phoneNumber); - } - - public static TtsSpan createTtsSpan(String phoneNumber) { - return PhoneNumberUtils.createTtsSpan(phoneNumber); - } -} diff --git a/java/com/android/contacts/common/list/ContactListItemView.java b/java/com/android/contacts/common/list/ContactListItemView.java index 0a5bf094b..409aa1b9e 100644 --- a/java/com/android/contacts/common/list/ContactListItemView.java +++ b/java/com/android/contacts/common/list/ContactListItemView.java @@ -32,6 +32,7 @@ import android.provider.ContactsContract.SearchSnippets; import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; +import android.telephony.PhoneNumberUtils; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; @@ -50,7 +51,6 @@ import android.widget.TextView; import com.android.contacts.common.ContactPresenceIconUtil; import com.android.contacts.common.ContactStatusUtil; import com.android.contacts.common.R; -import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.contacts.common.format.TextHighlighter; import com.android.contacts.common.list.PhoneNumberListAdapter.Listener; import com.android.contacts.common.util.ContactDisplayUtils; @@ -1111,7 +1111,7 @@ public class ContactListItemView extends ViewGroup implements SelectionBoundsAdj mSnippetView.setVisibility(VISIBLE); if (ContactDisplayUtils.isPossiblePhoneNumber(text)) { // Give the text-to-speech engine a hint that it's a phone number - mSnippetView.setContentDescription(PhoneNumberUtilsCompat.createTtsSpannable(text)); + mSnippetView.setContentDescription(PhoneNumberUtils.createTtsSpannable(text)); } else { mSnippetView.setContentDescription(null); } @@ -1232,8 +1232,7 @@ public class ContactListItemView extends ViewGroup implements SelectionBoundsAdj if (ContactDisplayUtils.isPossiblePhoneNumber(name)) { // Give the text-to-speech engine a hint that it's a phone number mNameTextView.setTextDirection(View.TEXT_DIRECTION_LTR); - mNameTextView.setContentDescription( - PhoneNumberUtilsCompat.createTtsSpannable(name.toString())); + mNameTextView.setContentDescription(PhoneNumberUtils.createTtsSpannable(name.toString())); } else { // Remove span tags of highlighting for talkback to avoid reading highlighting and rest // of the name into two separate parts. diff --git a/java/com/android/contacts/common/model/ContactLoader.java b/java/com/android/contacts/common/model/ContactLoader.java index 51b8e3efc..12cca4f13 100644 --- a/java/com/android/contacts/common/model/ContactLoader.java +++ b/java/com/android/contacts/common/model/ContactLoader.java @@ -669,7 +669,7 @@ public class ContactLoader extends AsyncTaskLoader<Contact> { final DataItem dataItem = dataItems.get(dataIndex); if (dataItem instanceof PhoneDataItem) { final PhoneDataItem phoneDataItem = (PhoneDataItem) dataItem; - phoneDataItem.computeFormattedPhoneNumber(countryIso); + phoneDataItem.computeFormattedPhoneNumber(getContext(), countryIso); } } } diff --git a/java/com/android/contacts/common/model/dataitem/PhoneDataItem.java b/java/com/android/contacts/common/model/dataitem/PhoneDataItem.java index e1f56456a..ed3212490 100644 --- a/java/com/android/contacts/common/model/dataitem/PhoneDataItem.java +++ b/java/com/android/contacts/common/model/dataitem/PhoneDataItem.java @@ -19,15 +19,15 @@ package com.android.contacts.common.model.dataitem; import android.content.ContentValues; import android.content.Context; import android.provider.ContactsContract.CommonDataKinds.Phone; -import com.android.contacts.common.compat.PhoneNumberUtilsCompat; +import com.android.dialer.phonenumberutil.PhoneNumberHelper; /** * Represents a phone data item, wrapping the columns in {@link - * ContactsContract.CommonDataKinds.Phone}. + * android.provider.ContactsContract.CommonDataKinds.Phone}. */ public class PhoneDataItem extends DataItem { - public static final String KEY_FORMATTED_PHONE_NUMBER = "formattedPhoneNumber"; + private static final String KEY_FORMATTED_PHONE_NUMBER = "formattedPhoneNumber"; /* package */ PhoneDataItem(ContentValues values) { super(values); @@ -50,12 +50,12 @@ public class PhoneDataItem extends DataItem { return getContentValues().getAsString(Phone.LABEL); } - public void computeFormattedPhoneNumber(String defaultCountryIso) { + public void computeFormattedPhoneNumber(Context context, String defaultCountryIso) { final String phoneNumber = getNumber(); if (phoneNumber != null) { final String formattedPhoneNumber = - PhoneNumberUtilsCompat.formatNumber( - phoneNumber, getNormalizedNumber(), defaultCountryIso); + PhoneNumberHelper.formatNumber( + context, phoneNumber, getNormalizedNumber(), defaultCountryIso); getContentValues().put(KEY_FORMATTED_PHONE_NUMBER, formattedPhoneNumber); } } diff --git a/java/com/android/contacts/common/util/ContactDisplayUtils.java b/java/com/android/contacts/common/util/ContactDisplayUtils.java index a45394f50..7d428e102 100644 --- a/java/com/android/contacts/common/util/ContactDisplayUtils.java +++ b/java/com/android/contacts/common/util/ContactDisplayUtils.java @@ -21,13 +21,13 @@ import android.content.res.Resources; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.telephony.PhoneNumberUtils; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; import android.text.style.TtsSpan; import android.util.Patterns; import com.android.contacts.common.R; -import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.contacts.common.preference.ContactsPreferences; import com.android.dialer.common.LogUtil; import java.util.Objects; @@ -219,7 +219,7 @@ public class ContactDisplayUtils { int start = TextUtils.isEmpty(phoneNumber) ? -1 : message.indexOf(phoneNumber); while (start >= 0) { final int end = start + phoneNumber.length(); - final TtsSpan ttsSpan = PhoneNumberUtilsCompat.createTtsSpan(phoneNumber); + final TtsSpan ttsSpan = PhoneNumberUtils.createTtsSpan(phoneNumber); spannable.setSpan( ttsSpan, start, diff --git a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java index 07891a069..295aa963a 100644 --- a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java +++ b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java @@ -325,6 +325,7 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment { holder.numberTextView.setVisibility(View.VISIBLE); holder.numberTextView.setText( PhoneNumberHelper.formatNumberForDisplay( + getContext(), account.getAddress().getSchemeSpecificPart(), getCountryIso(getContext(), accountHandle))); } diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java index baca590b5..4b860fea1 100644 --- a/java/com/android/dialer/app/calllog/CallLogAdapter.java +++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java @@ -52,7 +52,6 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import com.android.contacts.common.ContactsUtils; -import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.contacts.common.preference.ContactsPreferences; import com.android.dialer.app.DialtactsActivity; import com.android.dialer.app.R; @@ -1057,7 +1056,7 @@ public class CallLogAdapter extends GroupingListAdapter CharSequence formattedNumber = info.formattedNumber == null ? null - : PhoneNumberUtilsCompat.createTtsSpannable(info.formattedNumber); + : PhoneNumberUtils.createTtsSpannable(info.formattedNumber); details.updateDisplayNumber(activity, formattedNumber, isVoicemailNumber); views.displayNumber = details.displayNumber; diff --git a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java index 5c9411180..4c187faed 100644 --- a/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java +++ b/java/com/android/dialer/app/calllog/CallLogListItemViewHolder.java @@ -52,7 +52,6 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; -import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.contacts.common.dialog.CallSubjectDialog; import com.android.dialer.app.DialtactsActivity; import com.android.dialer.app.R; @@ -1222,7 +1221,7 @@ public final class CallLogListItemViewHolder extends RecyclerView.ViewHolder menu.setHeaderTitle(context.getResources().getText(R.string.voicemail)); } else { menu.setHeaderTitle( - PhoneNumberUtilsCompat.createTtsSpannable( + PhoneNumberUtils.createTtsSpannable( BidiFormatter.getInstance().unicodeWrap(number, TextDirectionHeuristics.LTR))); } diff --git a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java index d20ddd0e5..3afb6bb87 100644 --- a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java +++ b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java @@ -43,6 +43,7 @@ import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.location.GeoUtil; import com.android.dialer.phonenumbercache.ContactInfo; import com.android.dialer.phonenumbercache.ContactInfoHelper; +import com.android.dialer.phonenumberutil.PhoneNumberHelper; import com.android.dialer.util.PermissionsUtil; import java.util.ArrayList; import java.util.Arrays; @@ -199,7 +200,7 @@ public class CallLogNotificationsQueryHelper { number = (number == null) ? "" : number; ContactInfo contactInfo = new ContactInfo(); contactInfo.number = number; - contactInfo.formattedNumber = PhoneNumberUtils.formatNumber(number, countryIso); + contactInfo.formattedNumber = PhoneNumberHelper.formatNumber(context, number, countryIso); // contactInfo.normalizedNumber is not PhoneNumberUtils.normalizeNumber. Read ContactInfo. contactInfo.normalizedNumber = PhoneNumberUtils.formatNumberToE164(number, countryIso); diff --git a/java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java b/java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java index 0ddfb9f3b..7b1536b37 100644 --- a/java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java +++ b/java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java @@ -27,14 +27,15 @@ import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; -import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; import android.text.TextUtils; import com.android.dialer.app.R; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; +import com.android.dialer.location.GeoUtil; import com.android.dialer.notification.DialerNotificationManager; import com.android.dialer.notification.NotificationChannelManager; +import com.android.dialer.phonenumberutil.PhoneNumberHelper; import com.android.dialer.telecom.TelecomUtil; /** Shows a notification in the status bar for legacy vociemail. */ @@ -144,7 +145,8 @@ public final class LegacyVoicemailNotifier { } else { return String.format( context.getString(R.string.notification_voicemail_text_format), - PhoneNumberUtils.formatNumber(voicemailNumber)); + PhoneNumberHelper.formatNumber( + context, voicemailNumber, GeoUtil.getCurrentCountryIso(context))); } } diff --git a/java/com/android/dialer/app/calllog/MissedCallNotifier.java b/java/com/android/dialer/app/calllog/MissedCallNotifier.java index 14bbdfa56..80901ce88 100644 --- a/java/com/android/dialer/app/calllog/MissedCallNotifier.java +++ b/java/com/android/dialer/app/calllog/MissedCallNotifier.java @@ -36,12 +36,12 @@ import android.support.v4.util.Pair; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; +import android.telephony.PhoneNumberUtils; import android.text.BidiFormatter; import android.text.TextDirectionHeuristics; import android.text.TextUtils; import android.util.ArraySet; import com.android.contacts.common.ContactsUtils; -import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.dialer.app.DialtactsActivity; import com.android.dialer.app.MainComponent; import com.android.dialer.app.R; @@ -171,7 +171,7 @@ public class MissedCallNotifier implements Worker<Pair<Integer, String>, Void> { if (TextUtils.equals(contactInfo.name, contactInfo.formattedNumber) || TextUtils.equals(contactInfo.name, contactInfo.number)) { expandedText = - PhoneNumberUtilsCompat.createTtsSpannable( + PhoneNumberUtils.createTtsSpannable( BidiFormatter.getInstance() .unicodeWrap(contactInfo.name, TextDirectionHeuristics.LTR)); } else { @@ -328,7 +328,7 @@ public class MissedCallNotifier implements Worker<Pair<Integer, String>, Void> { if (TextUtils.equals(contactInfo.name, contactInfo.formattedNumber) || TextUtils.equals(contactInfo.name, contactInfo.number)) { expandedText = - PhoneNumberUtilsCompat.createTtsSpannable( + PhoneNumberUtils.createTtsSpannable( BidiFormatter.getInstance() .unicodeWrap(contactInfo.name, TextDirectionHeuristics.LTR)); } else { diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java index 4f8bc66a9..603c06fd3 100644 --- a/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java +++ b/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java @@ -18,7 +18,6 @@ package com.android.dialer.app.filterednumber; import android.app.FragmentManager; import android.content.Context; import android.database.Cursor; -import android.telephony.PhoneNumberUtils; import android.view.View; import com.android.dialer.app.R; import com.android.dialer.blocking.BlockNumberDialogFragment; @@ -28,6 +27,7 @@ import com.android.dialer.location.GeoUtil; import com.android.dialer.logging.InteractionEvent; import com.android.dialer.logging.Logger; import com.android.dialer.phonenumbercache.ContactInfoHelper; +import com.android.dialer.phonenumberutil.PhoneNumberHelper; /** TODO(calderwoodra): documentation */ public class BlockedNumbersAdapter extends NumbersAdapter { @@ -66,7 +66,7 @@ public class BlockedNumbersAdapter extends NumbersAdapter { id, number, countryIso, - PhoneNumberUtils.formatNumber(number, countryIso), + PhoneNumberHelper.formatNumber(getContext(), number, countryIso), R.id.blocked_numbers_activity_container, getFragmentManager(), new BlockNumberDialogFragment.Callback() { diff --git a/java/com/android/dialer/app/list/BlockedListSearchFragment.java b/java/com/android/dialer/app/list/BlockedListSearchFragment.java index de9dbaee6..ce812af6e 100644 --- a/java/com/android/dialer/app/list/BlockedListSearchFragment.java +++ b/java/com/android/dialer/app/list/BlockedListSearchFragment.java @@ -19,7 +19,6 @@ import android.app.Activity; import android.os.Bundle; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; -import android.telephony.PhoneNumberUtils; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; @@ -39,6 +38,7 @@ import com.android.dialer.common.LogUtil; import com.android.dialer.location.GeoUtil; import com.android.dialer.logging.InteractionEvent; import com.android.dialer.logging.Logger; +import com.android.dialer.phonenumberutil.PhoneNumberHelper; /** TODO(calderwoodra): documentation */ public class BlockedListSearchFragment extends RegularSearchFragment @@ -174,7 +174,7 @@ public class BlockedListSearchFragment extends RegularSearchFragment id, number, countryIso, - PhoneNumberUtils.formatNumber(number, countryIso), + PhoneNumberHelper.formatNumber(getContext(), number, countryIso), R.id.blocked_numbers_activity_container, getFragmentManager(), BlockedListSearchFragment.this); diff --git a/java/com/android/dialer/app/list/DialerPhoneNumberListAdapter.java b/java/com/android/dialer/app/list/DialerPhoneNumberListAdapter.java index 3711e6e75..d5609b856 100644 --- a/java/com/android/dialer/app/list/DialerPhoneNumberListAdapter.java +++ b/java/com/android/dialer/app/list/DialerPhoneNumberListAdapter.java @@ -31,6 +31,7 @@ import com.android.contacts.common.list.PhoneNumberListAdapter; import com.android.contacts.common.util.ContactDisplayUtils; import com.android.dialer.app.R; import com.android.dialer.location.GeoUtil; +import com.android.dialer.phonenumberutil.PhoneNumberHelper; /** * {@link PhoneNumberListAdapter} with the following added shortcuts, that are displayed as list @@ -228,7 +229,8 @@ public class DialerPhoneNumberListAdapter extends PhoneNumberListAdapter { @Override public void setQueryString(String queryString) { formattedQueryString = - PhoneNumberUtils.formatNumber(PhoneNumberUtils.normalizeNumber(queryString), countryIso); + PhoneNumberHelper.formatNumber( + getContext(), PhoneNumberUtils.normalizeNumber(queryString), countryIso); super.setQueryString(queryString); } } diff --git a/java/com/android/dialer/app/list/PhoneFavoriteTileView.java b/java/com/android/dialer/app/list/PhoneFavoriteTileView.java index 3739588ea..30b8464ed 100644 --- a/java/com/android/dialer/app/list/PhoneFavoriteTileView.java +++ b/java/com/android/dialer/app/list/PhoneFavoriteTileView.java @@ -199,9 +199,12 @@ public abstract class PhoneFavoriteTileView extends ContactTileView { */ private void sendViewNotification(Context context, Uri contactUri) { if (loader != null) { - loader.cancelLoad(); + // Cancels the current load if it's running and clears up any memory if it's using any. + loader.reset(); } loader = new ContactLoader(context, contactUri, true /* postViewNotification */); + // Immediately release anything we're holding in memory + loader.registerListener(0, (loader1, contact) -> loader.reset()); loader.startLoading(); } } diff --git a/java/com/android/dialer/app/settings/DialerSettingsActivity.java b/java/com/android/dialer/app/settings/DialerSettingsActivity.java index cbd9e7950..24e5fe8aa 100644 --- a/java/com/android/dialer/app/settings/DialerSettingsActivity.java +++ b/java/com/android/dialer/app/settings/DialerSettingsActivity.java @@ -102,7 +102,6 @@ public class DialerSettingsActivity extends AppCompatPreferenceActivity { Header soundSettingsHeader = new Header(); soundSettingsHeader.titleRes = R.string.sounds_and_vibration_title; - soundSettingsHeader.fragment = SoundSettingsFragment.class.getName(); soundSettingsHeader.id = R.id.settings_header_sounds_and_vibration; target.add(soundSettingsHeader); @@ -271,22 +270,32 @@ public class DialerSettingsActivity extends AppCompatPreferenceActivity { && getResources().getBoolean(R.bool.config_sort_order_user_changeable); } + /** + * For the "sounds and vibration" setting, we go directly to the system sound settings fragment. + * This helps since: + * <li>We don't need a separate Dialer sounds and vibrations fragment, as everything we need is + * present in the system sounds fragment. + * <li>OEM's e.g Moto that support dual sim ring-tones no longer need to update the dialer sound + * and settings fragment. + * + * <p>For all other settings, we launch our our preferences fragment. + */ @Override public void onHeaderClick(Header header, int position) { if (header.id == R.id.settings_header_sounds_and_vibration) { - // If we don't have the permission to write to system settings, go to system sound - // settings instead. Otherwise, perform the super implementation (which launches our - // own preference fragment. + if (!Settings.System.canWrite(this)) { Toast.makeText( this, getResources().getString(R.string.toast_cannot_write_system_settings), Toast.LENGTH_SHORT) .show(); - startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS)); - return; } + + startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS)); + return; } + super.onHeaderClick(header, position); } diff --git a/java/com/android/dialer/app/settings/SoundSettingsFragment.java b/java/com/android/dialer/app/settings/SoundSettingsFragment.java deleted file mode 100644 index 19cddbc4f..000000000 --- a/java/com/android/dialer/app/settings/SoundSettingsFragment.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2014 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.dialer.app.settings; - -import android.content.Context; -import android.media.RingtoneManager; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Vibrator; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceFragment; -import android.preference.PreferenceScreen; -import android.preference.SwitchPreference; -import android.provider.Settings; -import android.telephony.CarrierConfigManager; -import android.telephony.TelephonyManager; -import android.widget.Toast; -import com.android.dialer.app.R; -import com.android.dialer.compat.SdkVersionOverride; -import com.android.dialer.util.SettingsUtil; - -public class SoundSettingsFragment extends PreferenceFragment - implements Preference.OnPreferenceChangeListener { - - private static final int NO_DTMF_TONE = 0; - private static final int PLAY_DTMF_TONE = 1; - - private static final int NO_VIBRATION_FOR_CALLS = 0; - private static final int DO_VIBRATION_FOR_CALLS = 1; - - private static final int DTMF_TONE_TYPE_NORMAL = 0; - - private static final int MSG_UPDATE_RINGTONE_SUMMARY = 1; - - private Preference ringtonePreference; - private final Handler ringtoneLookupComplete = - new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_UPDATE_RINGTONE_SUMMARY: - ringtonePreference.setSummary((CharSequence) msg.obj); - break; - } - } - }; - private final Runnable ringtoneLookupRunnable = - new Runnable() { - @Override - public void run() { - updateRingtonePreferenceSummary(); - } - }; - private SwitchPreference vibrateWhenRinging; - private SwitchPreference playDtmfTone; - private ListPreference dtmfToneLength; - - @Override - public Context getContext() { - return getActivity(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - addPreferencesFromResource(R.xml.sound_settings); - - Context context = getActivity(); - - ringtonePreference = findPreference(context.getString(R.string.ringtone_preference_key)); - vibrateWhenRinging = - (SwitchPreference) findPreference(context.getString(R.string.vibrate_on_preference_key)); - playDtmfTone = - (SwitchPreference) findPreference(context.getString(R.string.play_dtmf_preference_key)); - dtmfToneLength = - (ListPreference) - findPreference(context.getString(R.string.dtmf_tone_length_preference_key)); - - if (hasVibrator()) { - vibrateWhenRinging.setOnPreferenceChangeListener(this); - } else { - getPreferenceScreen().removePreference(vibrateWhenRinging); - vibrateWhenRinging = null; - } - - playDtmfTone.setOnPreferenceChangeListener(this); - playDtmfTone.setChecked(shouldPlayDtmfTone()); - - TelephonyManager telephonyManager = - (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE); - if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M - && telephonyManager.canChangeDtmfToneLength() - && (telephonyManager.isWorldPhone() || !shouldHideCarrierSettings())) { - dtmfToneLength.setOnPreferenceChangeListener(this); - dtmfToneLength.setValueIndex( - Settings.System.getInt( - context.getContentResolver(), - Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, - DTMF_TONE_TYPE_NORMAL)); - } else { - getPreferenceScreen().removePreference(dtmfToneLength); - dtmfToneLength = null; - } - } - - @Override - public void onResume() { - super.onResume(); - - if (!Settings.System.canWrite(getContext())) { - // If the user launches this setting fragment, then toggles the WRITE_SYSTEM_SETTINGS - // AppOp, then close the fragment since there is nothing useful to do. - getActivity().onBackPressed(); - return; - } - - if (vibrateWhenRinging != null) { - vibrateWhenRinging.setChecked(shouldVibrateWhenRinging()); - } - - // Lookup the ringtone name asynchronously. - new Thread(ringtoneLookupRunnable).start(); - } - - /** - * Supports onPreferenceChangeListener to look for preference changes. - * - * @param preference The preference to be changed - * @param objValue The value of the selection, NOT its localized display value. - */ - @Override - public boolean onPreferenceChange(Preference preference, Object objValue) { - if (!Settings.System.canWrite(getContext())) { - // A user shouldn't be able to get here, but this protects against monkey crashes. - Toast.makeText( - getContext(), - getResources().getString(R.string.toast_cannot_write_system_settings), - Toast.LENGTH_SHORT) - .show(); - return true; - } - if (preference == vibrateWhenRinging) { - boolean doVibrate = (Boolean) objValue; - Settings.System.putInt( - getActivity().getContentResolver(), - Settings.System.VIBRATE_WHEN_RINGING, - doVibrate ? DO_VIBRATION_FOR_CALLS : NO_VIBRATION_FOR_CALLS); - } else if (preference == dtmfToneLength) { - int index = dtmfToneLength.findIndexOfValue((String) objValue); - Settings.System.putInt( - getActivity().getContentResolver(), Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, index); - } - return true; - } - - /** Click listener for toggle events. */ - @Override - public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { - if (!Settings.System.canWrite(getContext())) { - Toast.makeText( - getContext(), - getResources().getString(R.string.toast_cannot_write_system_settings), - Toast.LENGTH_SHORT) - .show(); - return true; - } - if (preference == playDtmfTone) { - Settings.System.putInt( - getActivity().getContentResolver(), - Settings.System.DTMF_TONE_WHEN_DIALING, - playDtmfTone.isChecked() ? PLAY_DTMF_TONE : NO_DTMF_TONE); - } - return true; - } - - /** Updates the summary text on the ringtone preference with the name of the ringtone. */ - private void updateRingtonePreferenceSummary() { - SettingsUtil.updateRingtoneName( - getActivity(), - ringtoneLookupComplete, - RingtoneManager.TYPE_RINGTONE, - ringtonePreference.getKey(), - MSG_UPDATE_RINGTONE_SUMMARY); - } - - /** - * Obtain the value for "vibrate when ringing" setting. The default value is false. - * - * <p>Watch out: if the setting is missing in the device, this will try obtaining the old "vibrate - * on ring" setting from AudioManager, and save the previous setting to the new one. - */ - private boolean shouldVibrateWhenRinging() { - int vibrateWhenRingingSetting = - Settings.System.getInt( - getActivity().getContentResolver(), - Settings.System.VIBRATE_WHEN_RINGING, - NO_VIBRATION_FOR_CALLS); - return hasVibrator() && (vibrateWhenRingingSetting == DO_VIBRATION_FOR_CALLS); - } - - /** Obtains the value for dialpad/DTMF tones. The default value is true. */ - private boolean shouldPlayDtmfTone() { - int dtmfToneSetting = - Settings.System.getInt( - getActivity().getContentResolver(), - Settings.System.DTMF_TONE_WHEN_DIALING, - PLAY_DTMF_TONE); - return dtmfToneSetting == PLAY_DTMF_TONE; - } - - /** Whether the device hardware has a vibrator. */ - private boolean hasVibrator() { - Vibrator vibrator = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE); - return vibrator != null && vibrator.hasVibrator(); - } - - private boolean shouldHideCarrierSettings() { - CarrierConfigManager configManager = - (CarrierConfigManager) getActivity().getSystemService(Context.CARRIER_CONFIG_SERVICE); - return configManager - .getConfig() - .getBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL); - } -} diff --git a/java/com/android/dialer/assisteddialing/ConcreteCreator.java b/java/com/android/dialer/assisteddialing/ConcreteCreator.java index 2561e28cd..dfd28a661 100644 --- a/java/com/android/dialer/assisteddialing/ConcreteCreator.java +++ b/java/com/android/dialer/assisteddialing/ConcreteCreator.java @@ -23,7 +23,6 @@ import android.os.Build.VERSION_CODES; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; -import android.support.v4.os.BuildCompat; import android.support.v4.os.UserManagerCompat; import android.telephony.TelephonyManager; import com.android.dialer.common.LogUtil; @@ -42,8 +41,8 @@ public final class ConcreteCreator { // Floor set at N due to use of Optional. @VisibleForTesting public static final int BUILD_CODE_FLOOR = Build.VERSION_CODES.N; - // Ceiling set at O_MR1 because this feature will ship as part of the framework in P. - @VisibleForTesting public static final int BUILD_CODE_CEILING = Build.VERSION_CODES.O_MR1; + // Ceiling set at P because this feature will ship as part of the framework in Q. + @VisibleForTesting public static final int BUILD_CODE_CEILING = 28; /** * Creates a new AssistedDialingMediator @@ -107,8 +106,7 @@ public final class ConcreteCreator { } return (Build.VERSION.SDK_INT >= BUILD_CODE_FLOOR - && Build.VERSION.SDK_INT <= BUILD_CODE_CEILING - && !BuildCompat.isAtLeastP()) + && Build.VERSION.SDK_INT <= BUILD_CODE_CEILING) && configProvider.getBoolean("assisted_dialing_enabled", false); } diff --git a/java/com/android/dialer/calldetails/CallDetailsActivity.java b/java/com/android/dialer/calldetails/CallDetailsActivity.java index 26b38ed82..ec124df9e 100644 --- a/java/com/android/dialer/calldetails/CallDetailsActivity.java +++ b/java/com/android/dialer/calldetails/CallDetailsActivity.java @@ -32,7 +32,6 @@ import android.provider.CallLog.Calls; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.RequiresPermission; -import android.support.v4.os.BuildCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -52,7 +51,6 @@ import com.android.dialer.common.concurrent.DialerExecutor.FailureListener; import com.android.dialer.common.concurrent.DialerExecutor.SuccessListener; import com.android.dialer.common.concurrent.DialerExecutor.Worker; import com.android.dialer.common.concurrent.DialerExecutorComponent; -import com.android.dialer.compat.telephony.TelephonyManagerCompat; import com.android.dialer.constants.ActivityRequestCodes; import com.android.dialer.dialercontact.DialerContact; import com.android.dialer.duo.Duo; @@ -409,14 +407,8 @@ public class CallDetailsActivity extends AppCompatActivity { @Override public void openAssistedDialingSettings(View unused) { - if (BuildCompat.isAtLeastP()) { - Intent callSettingsIntent = - new Intent(TelephonyManagerCompat.ACTION_SHOW_ASSISTED_DIALING_SETTINGS); - getActivity().startActivity(callSettingsIntent); - } else { Intent intent = new Intent(getActivity(), AssistedDialingSettingActivity.class); getActivity().startActivity(intent); - } } @Override diff --git a/java/com/android/dialer/calllog/RefreshAnnotatedCallLogReceiver.java b/java/com/android/dialer/calllog/RefreshAnnotatedCallLogReceiver.java index e0bfcd8a3..4a7ce0bac 100644 --- a/java/com/android/dialer/calllog/RefreshAnnotatedCallLogReceiver.java +++ b/java/com/android/dialer/calllog/RefreshAnnotatedCallLogReceiver.java @@ -21,10 +21,18 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.support.annotation.Nullable; +import com.android.dialer.calllog.RefreshAnnotatedCallLogWorker.RefreshResult; import com.android.dialer.calllog.constants.IntentNames; import com.android.dialer.common.LogUtil; -import com.android.dialer.common.concurrent.DefaultFutureCallback; import com.android.dialer.common.concurrent.ThreadUtil; +import com.android.dialer.logging.DialerImpression; +import com.android.dialer.logging.Logger; +import com.android.dialer.logging.LoggingBindings; +import com.android.dialer.metrics.FutureTimer; +import com.android.dialer.metrics.Metrics; +import com.android.dialer.metrics.MetricsComponent; +import com.google.common.base.Function; +import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -43,6 +51,8 @@ public final class RefreshAnnotatedCallLogReceiver extends BroadcastReceiver { private static final long REFRESH_ANNOTATED_CALL_LOG_WAIT_MILLIS = 100L; private final RefreshAnnotatedCallLogWorker refreshAnnotatedCallLogWorker; + private final FutureTimer futureTimer; + private final LoggingBindings logger; @Nullable private Runnable refreshAnnotatedCallLogRunnable; @@ -57,6 +67,8 @@ public final class RefreshAnnotatedCallLogReceiver extends BroadcastReceiver { public RefreshAnnotatedCallLogReceiver(Context context) { refreshAnnotatedCallLogWorker = CallLogComponent.get(context).getRefreshAnnotatedCallLogWorker(); + futureTimer = MetricsComponent.get(context).futureTimer(); + logger = Logger.get(context); } @Override @@ -97,12 +109,29 @@ public final class RefreshAnnotatedCallLogReceiver extends BroadcastReceiver { refreshAnnotatedCallLogRunnable = () -> { - ListenableFuture<Void> future = + ListenableFuture<RefreshResult> future = checkDirty ? refreshAnnotatedCallLogWorker.refreshWithDirtyCheck() : refreshAnnotatedCallLogWorker.refreshWithoutDirtyCheck(); Futures.addCallback( - future, new DefaultFutureCallback<>(), MoreExecutors.directExecutor()); + future, + new FutureCallback<RefreshResult>() { + @Override + public void onSuccess(RefreshResult refreshResult) { + logger.logImpression(getImpressionType(checkDirty, refreshResult)); + } + + @Override + public void onFailure(Throwable throwable) { + ThreadUtil.getUiThreadHandler() + .post( + () -> { + throw new RuntimeException(throwable); + }); + } + }, + MoreExecutors.directExecutor()); + futureTimer.applyTiming(future, new EventNameFromResultFunction(checkDirty)); }; ThreadUtil.getUiThreadHandler() @@ -118,4 +147,49 @@ public final class RefreshAnnotatedCallLogReceiver extends BroadcastReceiver { ThreadUtil.getUiThreadHandler().removeCallbacks(refreshAnnotatedCallLogRunnable); } + + private static class EventNameFromResultFunction implements Function<RefreshResult, String> { + + private final boolean checkDirty; + + private EventNameFromResultFunction(boolean checkDirty) { + this.checkDirty = checkDirty; + } + + @Override + public String apply(RefreshResult refreshResult) { + switch (refreshResult) { + case NOT_DIRTY: + return Metrics.ANNOTATED_CALL_LOG_NOT_DIRTY; // NOT_DIRTY implies forceRefresh is false + case REBUILT_BUT_NO_CHANGES_NEEDED: + return checkDirty + ? Metrics.ANNOTATED_LOG_NO_CHANGES_NEEDED + : Metrics.NEW_CALL_LOG_FORCE_REFRESH_NO_CHANGES_NEEDED; + case REBUILT_AND_CHANGES_NEEDED: + return checkDirty + ? Metrics.ANNOTATED_CALL_LOG_CHANGES_NEEDED + : Metrics.ANNOTATED_CALL_LOG_FORCE_REFRESH_CHANGES_NEEDED; + default: + throw new IllegalStateException("Unsupported result: " + refreshResult); + } + } + } + + private static DialerImpression.Type getImpressionType( + boolean checkDirty, RefreshResult refreshResult) { + switch (refreshResult) { + case NOT_DIRTY: + return DialerImpression.Type.ANNOTATED_CALL_LOG_NOT_DIRTY; + case REBUILT_BUT_NO_CHANGES_NEEDED: + return checkDirty + ? DialerImpression.Type.ANNOTATED_CALL_LOG_NO_CHANGES_NEEDED + : DialerImpression.Type.ANNOTATED_CALL_LOG_FORCE_REFRESH_NO_CHANGES_NEEDED; + case REBUILT_AND_CHANGES_NEEDED: + return checkDirty + ? DialerImpression.Type.ANNOTATED_CALL_LOG_CHANGES_NEEDED + : DialerImpression.Type.ANNOTATED_CALL_LOG_FORCE_REFRESH_CHANGES_NEEDED; + default: + throw new IllegalStateException("Unsupported result: " + refreshResult); + } + } } diff --git a/java/com/android/dialer/calllog/RefreshAnnotatedCallLogWorker.java b/java/com/android/dialer/calllog/RefreshAnnotatedCallLogWorker.java index e05b77268..c399b05ea 100644 --- a/java/com/android/dialer/calllog/RefreshAnnotatedCallLogWorker.java +++ b/java/com/android/dialer/calllog/RefreshAnnotatedCallLogWorker.java @@ -79,23 +79,30 @@ public class RefreshAnnotatedCallLogWorker { this.lightweightExecutorService = lightweightExecutorService; } + /** Result of refreshing the annotated call log. */ + public enum RefreshResult { + NOT_DIRTY, + REBUILT_BUT_NO_CHANGES_NEEDED, + REBUILT_AND_CHANGES_NEEDED + } + /** Checks if the annotated call log is dirty and refreshes it if necessary. */ - ListenableFuture<Void> refreshWithDirtyCheck() { + ListenableFuture<RefreshResult> refreshWithDirtyCheck() { return refresh(true); } /** Refreshes the annotated call log, bypassing dirty checks. */ - ListenableFuture<Void> refreshWithoutDirtyCheck() { + ListenableFuture<RefreshResult> refreshWithoutDirtyCheck() { return refresh(false); } - private ListenableFuture<Void> refresh(boolean checkDirty) { + private ListenableFuture<RefreshResult> refresh(boolean checkDirty) { LogUtil.i("RefreshAnnotatedCallLogWorker.refresh", "submitting serialized refresh request"); return dialerFutureSerializer.submitAsync( () -> checkDirtyAndRebuildIfNecessary(checkDirty), lightweightExecutorService); } - private ListenableFuture<Void> checkDirtyAndRebuildIfNecessary(boolean checkDirty) { + private ListenableFuture<RefreshResult> checkDirtyAndRebuildIfNecessary(boolean checkDirty) { ListenableFuture<Boolean> forceRebuildFuture = backgroundExecutorService.submit( () -> { @@ -139,7 +146,7 @@ public class RefreshAnnotatedCallLogWorker { return Futures.transformAsync( callLogState.isBuilt(), this::rebuild, MoreExecutors.directExecutor()); } - return Futures.immediateFuture(null); + return Futures.immediateFuture(RefreshResult.NOT_DIRTY); }, lightweightExecutorService); } @@ -160,7 +167,7 @@ public class RefreshAnnotatedCallLogWorker { return isDirtyFuture; } - private ListenableFuture<Void> rebuild(boolean isBuilt) { + private ListenableFuture<RefreshResult> rebuild(boolean isBuilt) { CallLogMutations mutations = new CallLogMutations(); // Start by filling the data sources--the system call log data source must go first! @@ -225,7 +232,9 @@ public class RefreshAnnotatedCallLogWorker { unused -> { sharedPreferences.edit().putBoolean(SharedPrefKeys.FORCE_REBUILD, false).apply(); callLogState.markBuilt(); - return null; + return mutations.isEmpty() + ? RefreshResult.REBUILT_BUT_NO_CHANGES_NEEDED + : RefreshResult.REBUILT_AND_CHANGES_NEEDED; }, backgroundExecutorService); } diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java index 77de62ea4..69722731e 100644 --- a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java +++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java @@ -37,6 +37,8 @@ import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.Ann import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; +import com.android.dialer.metrics.Metrics; +import com.android.dialer.metrics.MetricsComponent; import java.util.ArrayList; import java.util.Arrays; @@ -153,6 +155,7 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { Assert.checkArgument( selectionArgs == null, "selection args not supported for coalesced call log"); Assert.checkArgument(sortOrder == null, "sort order not supported for coalesced call log"); + MetricsComponent.get(getContext()).metrics().startTimer(Metrics.NEW_CALL_LOG_COALESCE); try (Cursor allAnnotatedCallLogRows = queryBuilder.query( db, @@ -168,6 +171,7 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { .coalesce(allAnnotatedCallLogRows); coalescedRows.setNotificationUri( getContext().getContentResolver(), CoalescedAnnotatedCallLog.CONTENT_URI); + MetricsComponent.get(getContext()).metrics().stopTimer(Metrics.NEW_CALL_LOG_COALESCE); return coalescedRows; } default: diff --git a/java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java b/java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java index f0f696396..6fe3a82c8 100644 --- a/java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java +++ b/java/com/android/dialer/calllogutils/PhoneNumberDisplayUtil.java @@ -18,10 +18,10 @@ package com.android.dialer.calllogutils; import android.content.Context; import android.provider.CallLog.Calls; +import android.telephony.PhoneNumberUtils; import android.text.BidiFormatter; import android.text.TextDirectionHeuristics; import android.text.TextUtils; -import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.dialer.phonenumberutil.PhoneNumberHelper; import com.google.common.base.Optional; @@ -86,8 +86,8 @@ public class PhoneNumberDisplayUtil { } /** Returns number annotated as phone number in LTR direction. */ - public static CharSequence getTtsSpannableLtrNumber(CharSequence number) { - return PhoneNumberUtilsCompat.createTtsSpannable( + private static CharSequence getTtsSpannableLtrNumber(CharSequence number) { + return PhoneNumberUtils.createTtsSpannable( BidiFormatter.getInstance().unicodeWrap(number.toString(), TextDirectionHeuristics.LTR)); } } diff --git a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java index 669cba7a9..236f77972 100644 --- a/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java +++ b/java/com/android/dialer/compat/telephony/TelephonyManagerCompat.java @@ -65,9 +65,6 @@ public class TelephonyManagerCompat { public static final String ASSISTED_DIALING_EXTRAS = "android.telecom.extra.ASSISTED_DIALING_EXTRAS"; - public static final String EXTRA_ASSISTED_DIALING_TRANSFORMATION_INFO = - "android.telecom.extra.ASSISTED_DIALING_TRANSFORMATION_INFO"; - /** Indicates the Connection/Call used assisted dialing. */ public static final int PROPERTY_ASSISTED_DIALING_USED = 1 << 9; @@ -80,10 +77,6 @@ public class TelephonyManagerCompat { */ public static final Integer FEATURES_ASSISTED_DIALING = 1 << 4; - /** The {@link android.content.Intent} action used to show the assisted dialing settings. */ - public static final String ACTION_SHOW_ASSISTED_DIALING_SETTINGS = - "android.telecom.action.SHOW_ASSISTED_DIALING_SETTINGS"; - /** * Returns the number of phones available. Returns 1 for Single standby mode (Single SIM * functionality) Returns 2 for Dual standby mode.(Dual SIM functionality) diff --git a/java/com/android/dialer/dialpadview/DialpadFragment.java b/java/com/android/dialer/dialpadview/DialpadFragment.java index f09333280..eeab6c428 100644 --- a/java/com/android/dialer/dialpadview/DialpadFragment.java +++ b/java/com/android/dialer/dialpadview/DialpadFragment.java @@ -88,6 +88,7 @@ import com.android.dialer.location.GeoUtil; import com.android.dialer.logging.UiAction; import com.android.dialer.oem.MotorolaUtils; import com.android.dialer.performancereport.PerformanceReport; +import com.android.dialer.phonenumberutil.PhoneNumberHelper; import com.android.dialer.precall.PreCall; import com.android.dialer.proguard.UsedByReflection; import com.android.dialer.telecom.TelecomUtil; @@ -220,8 +221,7 @@ public class DialpadFragment extends Fragment * @return the provided string of digits as a formatted phone number, retaining any post-dial * portion of the string. */ - @VisibleForTesting - static String getFormattedDigits(String dialString, String normalizedNumber, String countryIso) { + String getFormattedDigits(String dialString, String normalizedNumber, String countryIso) { String number = PhoneNumberUtils.extractNetworkPortion(dialString); // Also retrieve the post dial portion of the provided data, so that the entire dial // string can be reconstituted later. @@ -231,7 +231,7 @@ public class DialpadFragment extends Fragment return postDial; } - number = PhoneNumberUtils.formatNumber(number, normalizedNumber, countryIso); + number = PhoneNumberHelper.formatNumber(getContext(), number, normalizedNumber, countryIso); if (TextUtils.isEmpty(postDial)) { return number; diff --git a/java/com/android/dialer/logging/dialer_impression.proto b/java/com/android/dialer/logging/dialer_impression.proto index 635d8fd02..80249f464 100644 --- a/java/com/android/dialer/logging/dialer_impression.proto +++ b/java/com/android/dialer/logging/dialer_impression.proto @@ -12,7 +12,7 @@ message DialerImpression { // Event enums to be used for Impression Logging in Dialer. // It's perfectly acceptable for this enum to be large // Values should be from 1000 to 100000. - // Next Tag: 1341 + // Next Tag: 1346 enum Type { UNKNOWN_AOSP_EVENT_TYPE = 1000; @@ -659,21 +659,32 @@ message DialerImpression { DUO_CALL_LOG_INVITE_SHOWN = 1326; // NUI bottom navigation bar - NUI_SWITCH_TAB_TO_FAVORITE = 1327; - NUI_SWITCH_TAB_TO_CALL_LOG = 1328; - NUI_SWITCH_TAB_TO_CONTACTS = 1329; - NUI_SWITCH_TAB_TO_VOICEMAIL = 1330; + MAIN_SWITCH_TAB_TO_FAVORITE = 1327; + MAIN_SWITCH_TAB_TO_CALL_LOG = 1328; + MAIN_SWITCH_TAB_TO_CONTACTS = 1329; + MAIN_SWITCH_TAB_TO_VOICEMAIL = 1330; // NUI search - NUI_TOUCH_DIALPAD_SEARCH_LIST_TO_CLOSE_SEARCH_AND_DIALPAD = 1331; - NUI_TOUCH_DIALPAD_SEARCH_LIST_TO_HIDE_DIALPAD = 1332; - NUI_TOUCH_SEARCH_LIST_TO_CLOSE_SEARCH = 1333; - NUI_TOUCH_SEARCH_LIST_TO_HIDE_KEYBOARD = 1334; - NUI_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH = 1335; - NUI_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH_AND_DIALPAD = 1336; - NUI_PRESS_BACK_BUTTON_TO_HIDE_DIALPAD = 1337; - NUI_CLICK_SEARCH_BAR = 1338; - NUI_CLICK_SEARCH_BAR_VOICE_BUTTON = 1339; + MAIN_TOUCH_DIALPAD_SEARCH_LIST_TO_CLOSE_SEARCH_AND_DIALPAD = 1331; + MAIN_TOUCH_DIALPAD_SEARCH_LIST_TO_HIDE_DIALPAD = 1332; + MAIN_TOUCH_SEARCH_LIST_TO_CLOSE_SEARCH = 1333; + MAIN_TOUCH_SEARCH_LIST_TO_HIDE_KEYBOARD = 1334; + MAIN_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH = 1335; + MAIN_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH_AND_DIALPAD = 1336; + MAIN_PRESS_BACK_BUTTON_TO_HIDE_DIALPAD = 1337; + MAIN_CLICK_SEARCH_BAR = 1338; + MAIN_CLICK_SEARCH_BAR_VOICE_BUTTON = 1339; // NUI FAB - NUI_CLICK_FAB_TO_OPEN_DIALPAD = 1340; + MAIN_CLICK_FAB_TO_OPEN_DIALPAD = 1340; + + // The call log was not dirty. + ANNOTATED_CALL_LOG_NOT_DIRTY = 1341; + // The call log was dirty but no changes were needed. + ANNOTATED_CALL_LOG_NO_CHANGES_NEEDED = 1342; + // The call log was force refreshed but no changes were needed. + ANNOTATED_CALL_LOG_FORCE_REFRESH_NO_CHANGES_NEEDED = 1343; + // The call log was dirty and changes were needed. + ANNOTATED_CALL_LOG_CHANGES_NEEDED = 1344; + // The call log was force refreshed and changes were needed. + ANNOTATED_CALL_LOG_FORCE_REFRESH_CHANGES_NEEDED = 1345; } } diff --git a/java/com/android/dialer/main/impl/MainSearchController.java b/java/com/android/dialer/main/impl/MainSearchController.java index 7d380d75d..993ed3d8c 100644 --- a/java/com/android/dialer/main/impl/MainSearchController.java +++ b/java/com/android/dialer/main/impl/MainSearchController.java @@ -136,6 +136,11 @@ public class MainSearchController implements SearchBarListener { } searchFragment.setQuery("", CallInitiationType.Type.DIALPAD); + // Split the transactions so that the dialpad fragment isn't popped off the stack when we exit + // search. We do this so that the dialpad actually animates down instead of just disappearing. + transaction.commit(); + transaction = mainActivity.getFragmentManager().beginTransaction(); + // Show Dialpad if (getDialpadFragment() == null) { DialpadFragment dialpadFragment = new DialpadFragment(); @@ -228,21 +233,21 @@ public class MainSearchController implements SearchBarListener { if (TextUtils.isEmpty(getDialpadFragment().getQuery())) { Logger.get(mainActivity) .logImpression( - DialerImpression.Type.NUI_TOUCH_DIALPAD_SEARCH_LIST_TO_CLOSE_SEARCH_AND_DIALPAD); + DialerImpression.Type.MAIN_TOUCH_DIALPAD_SEARCH_LIST_TO_CLOSE_SEARCH_AND_DIALPAD); closeSearch(true); } else { Logger.get(mainActivity) - .logImpression(DialerImpression.Type.NUI_TOUCH_DIALPAD_SEARCH_LIST_TO_HIDE_DIALPAD); + .logImpression(DialerImpression.Type.MAIN_TOUCH_DIALPAD_SEARCH_LIST_TO_HIDE_DIALPAD); hideDialpad(/* animate=*/ true, /* bottomNavVisible=*/ false); } } else if (isSearchVisible()) { if (TextUtils.isEmpty(toolbar.getQuery())) { Logger.get(mainActivity) - .logImpression(DialerImpression.Type.NUI_TOUCH_SEARCH_LIST_TO_CLOSE_SEARCH); + .logImpression(DialerImpression.Type.MAIN_TOUCH_SEARCH_LIST_TO_CLOSE_SEARCH); closeSearch(true); } else { Logger.get(mainActivity) - .logImpression(DialerImpression.Type.NUI_TOUCH_SEARCH_LIST_TO_HIDE_KEYBOARD); + .logImpression(DialerImpression.Type.MAIN_TOUCH_SEARCH_LIST_TO_HIDE_KEYBOARD); toolbar.hideKeyboard(); } } @@ -257,7 +262,7 @@ public class MainSearchController implements SearchBarListener { if (isDialpadVisible() && !TextUtils.isEmpty(getDialpadFragment().getQuery())) { LogUtil.i("MainSearchController.onBackPressed", "Dialpad visible with query"); Logger.get(mainActivity) - .logImpression(DialerImpression.Type.NUI_PRESS_BACK_BUTTON_TO_HIDE_DIALPAD); + .logImpression(DialerImpression.Type.MAIN_PRESS_BACK_BUTTON_TO_HIDE_DIALPAD); hideDialpad(/* animate=*/ true, /* bottomNavVisible=*/ false); return true; } else if (isSearchVisible()) { @@ -265,8 +270,8 @@ public class MainSearchController implements SearchBarListener { Logger.get(mainActivity) .logImpression( isDialpadVisible() - ? DialerImpression.Type.NUI_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH_AND_DIALPAD - : DialerImpression.Type.NUI_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH); + ? DialerImpression.Type.MAIN_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH_AND_DIALPAD + : DialerImpression.Type.MAIN_PRESS_BACK_BUTTON_TO_CLOSE_SEARCH); closeSearch(true); return true; } else { @@ -346,7 +351,7 @@ public class MainSearchController implements SearchBarListener { @Override public void onSearchBarClicked() { LogUtil.enterBlock("MainSearchController.onSearchBarClicked"); - Logger.get(mainActivity).logImpression(DialerImpression.Type.NUI_CLICK_SEARCH_BAR); + Logger.get(mainActivity).logImpression(DialerImpression.Type.MAIN_CLICK_SEARCH_BAR); openSearch(Optional.absent()); } @@ -406,7 +411,8 @@ public class MainSearchController implements SearchBarListener { @Override public void onVoiceButtonClicked(VoiceSearchResultCallback voiceSearchResultCallback) { - Logger.get(mainActivity).logImpression(DialerImpression.Type.NUI_CLICK_SEARCH_BAR_VOICE_BUTTON); + Logger.get(mainActivity) + .logImpression(DialerImpression.Type.MAIN_CLICK_SEARCH_BAR_VOICE_BUTTON); try { Intent voiceIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); mainActivity.startActivityForResult(voiceIntent, ActivityRequestCodes.DIALTACTS_VOICE_SEARCH); diff --git a/java/com/android/dialer/main/impl/OldMainActivityPeer.java b/java/com/android/dialer/main/impl/OldMainActivityPeer.java index 293ec9563..e87fb0eca 100644 --- a/java/com/android/dialer/main/impl/OldMainActivityPeer.java +++ b/java/com/android/dialer/main/impl/OldMainActivityPeer.java @@ -65,6 +65,7 @@ import com.android.dialer.callintent.CallSpecificAppData; import com.android.dialer.common.FragmentUtils.FragmentUtilListener; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.DialerExecutorComponent; +import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.common.concurrent.UiListener; import com.android.dialer.compat.CompatUtils; import com.android.dialer.configprovider.ConfigProviderBindings; @@ -87,6 +88,8 @@ import com.android.dialer.main.impl.bottomnav.BottomNavBar; import com.android.dialer.main.impl.bottomnav.BottomNavBar.OnBottomNavTabSelectedListener; import com.android.dialer.main.impl.bottomnav.BottomNavBar.TabIndex; import com.android.dialer.main.impl.toolbar.MainToolbar; +import com.android.dialer.metrics.Metrics; +import com.android.dialer.metrics.MetricsComponent; import com.android.dialer.postcall.PostCall; import com.android.dialer.precall.PreCall; import com.android.dialer.searchfragment.list.NewSearchFragment.SearchFragmentListener; @@ -200,7 +203,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen fab.setOnClickListener( v -> { Logger.get(mainActivity) - .logImpression(DialerImpression.Type.NUI_CLICK_FAB_TO_OPEN_DIALPAD); + .logImpression(DialerImpression.Type.MAIN_CLICK_FAB_TO_OPEN_DIALPAD); searchController.showDialpad(true); }); @@ -404,6 +407,14 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen } else { bottomNav.setVisibility(View.VISIBLE); } + + // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume. + ThreadUtil.postDelayedOnUiThread( + () -> + MetricsComponent.get(mainActivity) + .metrics() + .recordMemory(Metrics.OLD_MAIN_ACTIVITY_PEER_ON_RESUME_MEMORY_EVENT_NAME), + 1000); } @Override @@ -1095,7 +1106,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen public void onSpeedDialSelected() { LogUtil.enterBlock("MainBottomNavBarBottomNavTabListener.onSpeedDialSelected"); if (selectedTab != TabIndex.SPEED_DIAL) { - Logger.get(context).logImpression(DialerImpression.Type.NUI_SWITCH_TAB_TO_FAVORITE); + Logger.get(context).logImpression(DialerImpression.Type.MAIN_SWITCH_TAB_TO_FAVORITE); selectedTab = TabIndex.SPEED_DIAL; } hideAllFragments(); @@ -1115,7 +1126,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen public void onCallLogSelected() { LogUtil.enterBlock("MainBottomNavBarBottomNavTabListener.onCallLogSelected"); if (selectedTab != TabIndex.CALL_LOG) { - Logger.get(context).logImpression(DialerImpression.Type.NUI_SWITCH_TAB_TO_CALL_LOG); + Logger.get(context).logImpression(DialerImpression.Type.MAIN_SWITCH_TAB_TO_CALL_LOG); selectedTab = TabIndex.CALL_LOG; } hideAllFragments(); @@ -1135,7 +1146,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen public void onContactsSelected() { LogUtil.enterBlock("MainBottomNavBarBottomNavTabListener.onContactsSelected"); if (selectedTab != TabIndex.CONTACTS) { - Logger.get(context).logImpression(DialerImpression.Type.NUI_SWITCH_TAB_TO_CONTACTS); + Logger.get(context).logImpression(DialerImpression.Type.MAIN_SWITCH_TAB_TO_CONTACTS); selectedTab = TabIndex.CONTACTS; } hideAllFragments(); @@ -1159,7 +1170,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen public void onVoicemailSelected() { LogUtil.enterBlock("MainBottomNavBarBottomNavTabListener.onVoicemailSelected"); if (selectedTab != TabIndex.VOICEMAIL) { - Logger.get(context).logImpression(DialerImpression.Type.NUI_SWITCH_TAB_TO_VOICEMAIL); + Logger.get(context).logImpression(DialerImpression.Type.MAIN_SWITCH_TAB_TO_VOICEMAIL); selectedTab = TabIndex.VOICEMAIL; } hideAllFragments(); diff --git a/java/com/android/dialer/main/impl/res/layout/main_activity.xml b/java/com/android/dialer/main/impl/res/layout/main_activity.xml index b69625e63..0883acebc 100644 --- a/java/com/android/dialer/main/impl/res/layout/main_activity.xml +++ b/java/com/android/dialer/main/impl/res/layout/main_activity.xml @@ -37,7 +37,7 @@ android:layout_height="match_parent" android:layout_above="@+id/bottom_nav_bar"/> - <android.support.design.widget.FloatingActionButton + <com.android.dialer.widget.DialerFloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/java/com/android/dialer/metrics/FutureTimer.java b/java/com/android/dialer/metrics/FutureTimer.java index f7ba3feef..a45fb3835 100644 --- a/java/com/android/dialer/metrics/FutureTimer.java +++ b/java/com/android/dialer/metrics/FutureTimer.java @@ -21,6 +21,7 @@ import android.support.annotation.IntDef; import android.support.annotation.VisibleForTesting; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.Annotations.LightweightExecutor; +import com.google.common.base.Function; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -72,7 +73,7 @@ public final class FutureTimer { * of tracking heavyweight operations (which is what this method is intended for). */ public <T> void applyTiming(ListenableFuture<T> future, String eventName) { - applyTiming(future, eventName, LogCatMode.DONT_LOG_VALUES); + applyTiming(future, unused -> eventName, LogCatMode.DONT_LOG_VALUES); } /** @@ -81,14 +82,35 @@ public final class FutureTimer { */ public <T> void applyTiming( ListenableFuture<T> future, String eventName, @LogCatMode int logCatMode) { + applyTiming(future, unused -> eventName, logCatMode); + } + + /** + * Overload of {@link #applyTiming(ListenableFuture, String)} that accepts a function which + * specifies how to compute an event name from the result of the future. + * + * <p>This is useful when the event name depends on the result of the future. + */ + public <T> void applyTiming( + ListenableFuture<T> future, Function<T, String> eventNameFromResultFunction) { + applyTiming(future, eventNameFromResultFunction, LogCatMode.DONT_LOG_VALUES); + } + + private <T> void applyTiming( + ListenableFuture<T> future, + Function<T, String> eventNameFromResultFunction, + @LogCatMode int logCatMode) { long startTime = SystemClock.elapsedRealtime(); - metrics.startTimer(eventName); + Integer timerId = metrics.startUnnamedTimer(); Futures.addCallback( future, new FutureCallback<T>() { @Override public void onSuccess(T result) { - metrics.stopTimer(eventName); + String eventName = eventNameFromResultFunction.apply(result); + if (timerId != null) { + metrics.stopUnnamedTimer(timerId, eventName); + } long operationTime = SystemClock.elapsedRealtime() - startTime; // If the operation took a long time, do some WARNING logging. diff --git a/java/com/android/dialer/metrics/Metrics.java b/java/com/android/dialer/metrics/Metrics.java index 383b3a3f3..55726586a 100644 --- a/java/com/android/dialer/metrics/Metrics.java +++ b/java/com/android/dialer/metrics/Metrics.java @@ -17,23 +17,35 @@ package com.android.dialer.metrics; import android.app.Application; +import android.support.annotation.Nullable; /** Logs metrics. */ public interface Metrics { String APPLICATION_ON_CREATE_EVENT_NAME = "Application.onCreate"; String DIALTACTS_ON_CREATE_EVENT_NAME = "GoogleDialtactsActivity.onCreate"; + String MAIN_ACTIVITY_ON_CREATE_EVENT_NAME = "GoogleMainActivity.onCreate"; String ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_INCOMING = "CallList.onCallAdded_To_InCallActivity.onCreate_Incoming"; String ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING = "CallList.onCallAdded_To_InCallActivity.onCreate_Outgoing"; String DIALTACTS_ON_RESUME_MEMORY_EVENT_NAME = "GoogleDialtactsActivity.onResume"; + String OLD_MAIN_ACTIVITY_PEER_ON_RESUME_MEMORY_EVENT_NAME = "OldMainActivityPeer.onResume"; String INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME = "IncallActivity.OnResume"; String INCALL_ACTIVITY_ON_STOP_MEMORY_EVENT_NAME = "IncallActivity.OnStop"; String OLD_CALL_LOG_JANK_EVENT_NAME = "OldCallLog.Jank"; String NEW_CALL_LOG_JANK_EVENT_NAME = "NewCallLog.Jank"; // Events related to refreshing the annotated call log. + String NEW_CALL_LOG_COALESCE = "NewCallLog.Coalesce"; + String ANNOTATED_CALL_LOG_NOT_DIRTY = "RefreshAnnotatedCallLogReceiver.NotDirty"; + String ANNOTATED_CALL_LOG_CHANGES_NEEDED = "RefreshAnnotatedCallLogReceiver.ChangesNeeded"; + String ANNOTATED_LOG_NO_CHANGES_NEEDED = "RefreshAnnotatedCallLogReceiver.NoChangesNeeded"; + String ANNOTATED_CALL_LOG_FORCE_REFRESH_CHANGES_NEEDED = + "RefreshAnnotatedCallLogReceiver.ForceRefreshChangesNeeded"; + String NEW_CALL_LOG_FORCE_REFRESH_NO_CHANGES_NEEDED = + "RefreshAnnotatedCallLogReceiver.ForceRefreshNoChangesNeeded"; + String INITIAL_FILL_EVENT_NAME = "RefreshAnnotatedCallLog.Initial.Fill"; String INITIAL_ON_SUCCESSFUL_FILL_EVENT_NAME = "RefreshAnnotatedCallLog.Initial.OnSuccessfulFill"; String INITIAL_APPLY_MUTATIONS_EVENT_NAME = "RefreshAnnotatedCallLog.Initial.ApplyMutations"; @@ -59,6 +71,23 @@ public interface Metrics { /** Start a timer. */ void startTimer(String timerEventName); + /** + * Starts a timer for which the name is not yet known. + * + * @return opaque identifier for the event which should be provided back to {@link + * #stopUnnamedTimer(int, String)} to stop the timer. Null if the timer cannot be started, for + * example because the user is locked. + */ + @Nullable + Integer startUnnamedTimer(); + + /** + * Stop a timer which was started with {@link #startUnnamedTimer()}. + * + * @param timerId the value returned in the corresponding call to {@link #startUnnamedTimer()} + */ + void stopUnnamedTimer(int timerId, String timerEventName); + /** Stop a timer. */ void stopTimer(String timerEventName); diff --git a/java/com/android/dialer/metrics/MetricsComponent.java b/java/com/android/dialer/metrics/MetricsComponent.java index f37129791..a3570db10 100644 --- a/java/com/android/dialer/metrics/MetricsComponent.java +++ b/java/com/android/dialer/metrics/MetricsComponent.java @@ -28,6 +28,8 @@ public abstract class MetricsComponent { public abstract Metrics.Initializer metricsInitializer(); + public abstract FutureTimer futureTimer(); + public static MetricsComponent get(Context context) { return ((MetricsComponent.HasComponent) ((HasRootComponent) context.getApplicationContext()).component()) diff --git a/java/com/android/dialer/metrics/StubMetrics.java b/java/com/android/dialer/metrics/StubMetrics.java index 99c3d7691..ecd2382b9 100644 --- a/java/com/android/dialer/metrics/StubMetrics.java +++ b/java/com/android/dialer/metrics/StubMetrics.java @@ -16,26 +16,91 @@ package com.android.dialer.metrics; +import android.os.SystemClock; +import com.android.dialer.common.Assert; +import com.android.dialer.common.LogUtil; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import javax.annotation.concurrent.ThreadSafe; import javax.inject.Inject; +import javax.inject.Singleton; -/** Stub {@link Metrics}. */ +/** Stub {@link Metrics} which simply logs debug messages to logcat. */ +@ThreadSafe +@Singleton public final class StubMetrics implements Metrics { + private final ConcurrentMap<String, StubTimerEvent> namedEvents = new ConcurrentHashMap<>(); + private final ConcurrentMap<Integer, StubTimerEvent> unnamedEvents = new ConcurrentHashMap<>(); + @Inject StubMetrics() {} @Override - public void startTimer(String timerEventName) {} + public void startTimer(String timerEventName) { + namedEvents.put(timerEventName, new StubTimerEvent()); + } @Override - public void stopTimer(String timerEventName) {} + public Integer startUnnamedTimer() { + StubTimerEvent stubTimerEvent = new StubTimerEvent(); + int id = stubTimerEvent.hashCode(); + LogUtil.d("StubMetrics.startUnnamedTimer", "started timer for id: %d", id); + unnamedEvents.put(id, stubTimerEvent); + return id; + } @Override - public void startJankRecorder(String eventName) {} + public void stopTimer(String timerEventName) { + StubTimerEvent stubTimerEvent = namedEvents.remove(timerEventName); + if (stubTimerEvent == null) { + return; + } + + LogUtil.d( + "StubMetrics.stopTimer", + "%s took %dms", + timerEventName, + SystemClock.elapsedRealtime() - stubTimerEvent.startTime); + } + + @Override + public void stopUnnamedTimer(int timerId, String timerEventName) { + long startTime = + Assert.isNotNull( + unnamedEvents.remove(timerId), + "no timer found for id: %d (%s)", + timerId, + timerEventName) + .startTime; + + LogUtil.d( + "StubMetrics.stopUnnamedTimer", + "%s took %dms", + timerEventName, + SystemClock.elapsedRealtime() - startTime); + } @Override - public void stopJankRecorder(String eventName) {} + public void startJankRecorder(String eventName) { + LogUtil.d("StubMetrics.startJankRecorder", "started jank recorder for %s", eventName); + } @Override - public void recordMemory(String memoryEventName) {} + public void stopJankRecorder(String eventName) { + LogUtil.d("StubMetrics.startJankRecorder", "stopped jank recorder for %s", eventName); + } + + @Override + public void recordMemory(String memoryEventName) { + LogUtil.d("StubMetrics.startJankRecorder", "recorded memory for %s", memoryEventName); + } + + private static class StubTimerEvent { + final long startTime; + + StubTimerEvent() { + this.startTime = SystemClock.elapsedRealtime(); + } + } } diff --git a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java index f094be8a5..01f9669cb 100644 --- a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java +++ b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java @@ -475,7 +475,7 @@ public class ContactInfoHelper { if (TextUtils.isEmpty(countryIso)) { countryIso = currentCountryIso; } - return PhoneNumberUtils.formatNumber(number, normalizedNumber, countryIso); + return PhoneNumberHelper.formatNumber(context, number, normalizedNumber, countryIso); } /** diff --git a/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java b/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java index b58739d94..f5e634670 100644 --- a/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java +++ b/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java @@ -35,6 +35,7 @@ import com.android.dialer.compat.CompatUtils; import com.android.dialer.compat.telephony.TelephonyManagerCompat; import com.android.dialer.phonenumbergeoutil.PhoneNumberGeoUtilComponent; import com.android.dialer.telecom.TelecomUtil; +import com.google.common.base.Ascii; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -224,28 +225,50 @@ public class PhoneNumberHelper { } /** - * @return Formatted phone number. e.g. 1-123-456-7890. Returns the original number if formatting - * failed. + * An enhanced version of {@link PhoneNumberUtils#formatNumber(String, String, String)}. + * + * <p>The {@link Context} parameter allows us to tweak formatting according to device properties. + * + * <p>Returns the formatted phone number (e.g, 1-123-456-7890) or the original number if + * formatting fails or is intentionally ignored. */ - public static String formatNumber(@Nullable String number, String countryIso) { + public static String formatNumber( + Context context, @Nullable String number, @Nullable String numberE164, String countryIso) { // The number can be null e.g. schema is voicemail and uri content is empty. if (number == null) { return null; } - String formattedNumber = PhoneNumberUtils.formatNumber(number, countryIso); + + // Argentina phone number formats are complex and PhoneNumberUtils doesn't format all Argentina + // numbers correctly. + // To ensure consistent user experience, we disable phone number formatting for all numbers + // (not just Argentinian ones) for devices with Argentinian SIMs. + TelephonyManager telephonyManager = + (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + if (telephonyManager != null + && "AR".equals(Ascii.toUpperCase(telephonyManager.getSimCountryIso()))) { + return number; + } + + String formattedNumber = PhoneNumberUtils.formatNumber(number, numberE164, countryIso); return formattedNumber != null ? formattedNumber : number; } + /** @see #formatNumber(Context, String, String, String). */ + public static String formatNumber(Context context, @Nullable String number, String countryIso) { + return formatNumber(context, number, /* numberE164 = */ null, countryIso); + } + @Nullable public static CharSequence formatNumberForDisplay( - @Nullable String number, @NonNull String countryIso) { + Context context, @Nullable String number, @NonNull String countryIso) { if (number == null) { return null; } return PhoneNumberUtils.createTtsSpannable( BidiFormatter.getInstance() - .unicodeWrap(formatNumber(number, countryIso), TextDirectionHeuristics.LTR)); + .unicodeWrap(formatNumber(context, number, countryIso), TextDirectionHeuristics.LTR)); } /** diff --git a/java/com/android/dialer/precall/impl/AssistedDialAction.java b/java/com/android/dialer/precall/impl/AssistedDialAction.java index 15a889e74..9ed37ac8c 100644 --- a/java/com/android/dialer/precall/impl/AssistedDialAction.java +++ b/java/com/android/dialer/precall/impl/AssistedDialAction.java @@ -20,7 +20,6 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.os.Bundle; -import android.support.v4.os.BuildCompat; import android.telecom.PhoneAccount; import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; @@ -58,9 +57,7 @@ public class AssistedDialAction implements PreCallAction { AssistedDialingMediator assistedDialingMediator = ConcreteCreator.createNewAssistedDialingMediator( getAssistedDialingTelephonyManager(context, builder), context); - if (BuildCompat.isAtLeastP()) { - builder.getOutgoingCallExtras().putBoolean(TelephonyManagerCompat.USE_ASSISTED_DIALING, true); - } + // Checks the platform is N+ and meets other pre-flight checks. if (!assistedDialingMediator.isPlatformEligible()) { return; diff --git a/java/com/android/dialer/speeddial/SuggestionViewHolder.java b/java/com/android/dialer/speeddial/SuggestionViewHolder.java index 70df30706..68c0ce4c3 100644 --- a/java/com/android/dialer/speeddial/SuggestionViewHolder.java +++ b/java/com/android/dialer/speeddial/SuggestionViewHolder.java @@ -23,7 +23,6 @@ import android.net.Uri; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Contacts; import android.support.v7.widget.RecyclerView; -import android.telephony.PhoneNumberUtils; import android.text.TextUtils; import android.view.View; import android.view.View.OnClickListener; @@ -32,6 +31,7 @@ import android.widget.TextView; import com.android.dialer.contactphoto.ContactPhotoManager; import com.android.dialer.lettertile.LetterTileDrawable; import com.android.dialer.location.GeoUtil; +import com.android.dialer.phonenumberutil.PhoneNumberHelper; /** ViewHolder for displaying suggested contacts in {@link SpeedDialFragment}. */ public class SuggestionViewHolder extends RecyclerView.ViewHolder implements OnClickListener { @@ -56,7 +56,7 @@ public class SuggestionViewHolder extends RecyclerView.ViewHolder implements OnC public void bind(Context context, Cursor cursor) { number = cursor.getString(StrequentContactsCursorLoader.PHONE_NUMBER); - number = PhoneNumberUtils.formatNumber(number, GeoUtil.getCurrentCountryIso(context)); + number = PhoneNumberHelper.formatNumber(context, number, GeoUtil.getCurrentCountryIso(context)); String name = cursor.getString(StrequentContactsCursorLoader.PHONE_DISPLAY_NAME); String label = getLabel(context.getResources(), cursor); diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java index 6d71dade9..3a5e72b6b 100644 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java @@ -210,7 +210,8 @@ public final class NewVoicemailFragment extends Fragment implements LoaderCallba showView(emptyContentView); emptyContentView.setDescription((R.string.empty_voicemail_tab_text)); - emptyContentView.setImage(R.drawable.quantum_ic_schedule_vd_theme_24); + emptyContentView.setImage(R.drawable.quantum_ic_voicemail_vd_theme_24); + emptyContentView.setImageTint(R.color.empty_voicemail_icon_tint_color, null); } private void showView(View view) { diff --git a/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java b/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java index 7f5bb796a..5ae26f5f7 100644 --- a/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java +++ b/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java @@ -32,14 +32,12 @@ import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; -import android.text.Html; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; import com.android.dialer.notification.NotificationChannelManager; import com.android.dialer.telecom.TelecomUtil; -import com.android.dialer.widget.TextViewPreference; import com.android.voicemail.VoicemailClient; import com.android.voicemail.VoicemailClient.ActivationStateListener; import com.android.voicemail.VoicemailComponent; @@ -75,7 +73,6 @@ public class VoicemailSettingsFragment extends PreferenceFragment private SwitchPreference donateVoicemailSwitchPreference; private Preference voicemailChangePinPreference; private PreferenceScreen advancedSettings; - private TextViewPreference voicemailTranscriptionInstructionText; @Override public void onCreate(Bundle icicle) { @@ -212,10 +209,6 @@ public class VoicemailSettingsFragment extends PreferenceFragment return false; } }); - - voicemailTranscriptionInstructionText = - (TextViewPreference) findPreference(getString(R.string.voicemail_transcription_text_key)); - voicemailTranscriptionInstructionText.setTitle(getVoicemailTranscriptionInstructionsText()); } @Override @@ -355,20 +348,4 @@ public class VoicemailSettingsFragment extends PreferenceFragment builder.setCancelable(true); builder.show(); } - - /** - * Builds a spannable string containing the voicemail transcription instructions text containing - * the appropriate "Learn More" urls. - * - * @return The voicemail transcription instructions text. - */ - private CharSequence getVoicemailTranscriptionInstructionsText() { - String settingText = - getString( - R.string.voicemail_transcription_instruction_text, - getString(R.string.transcription_learn_more_url), - getString(R.string.donation_learn_more_url)); - CharSequence settingSeq = Html.fromHtml(settingText); - return settingSeq; - } } diff --git a/java/com/android/dialer/voicemail/settings/res/values/strings.xml b/java/com/android/dialer/voicemail/settings/res/values/strings.xml index 3056ef6b2..1d2c104a3 100644 --- a/java/com/android/dialer/voicemail/settings/res/values/strings.xml +++ b/java/com/android/dialer/voicemail/settings/res/values/strings.xml @@ -125,17 +125,6 @@ <!-- The label for the confirm-disable-voicemail button [CHAR LIMIT=16] --> <string name="confirm_disable_voicemail_accept_dialog_label">TURN OFF</string> - <!-- Internal preferences key for static instruction text. --> - <string name="voicemail_transcription_text_key" translatable="false">voicemail_transcription_text_key</string> - - <!-- Additional information text and links for visual voicemail and voicemail donation setting page - [CHAR LIMIT=NONE] --> - <string name="voicemail_transcription_instruction_text"> - Visual voicemail allows you to check voicemail messages without having to call voicemail. Transcripts provided by Google. <a href="<xliff:g example="http://www.google.com" id="url1">%1$s</xliff:g>">Learn more</a> - <br><br> - For voicemail transcription analysis, your voicemail messages are stored anonymously. <a href="<xliff:g example="http://www.google.com" id="url2">%2$s</xliff:g>">Learn more</a> - </string> - <string translatable="false" name="transcription_learn_more_url">https://support.google.com/phoneapp/answer/2811844?hl=en%26ref_topic=7539039</string> <string translatable="false" name="donation_learn_more_url">https://support.google.com/phoneapp/answer/2811844#voicemail_transcript</string> diff --git a/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml b/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml index 75c8cfe2b..e558985a4 100644 --- a/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml +++ b/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml @@ -44,7 +44,4 @@ android:title="@string/voicemail_advanced_settings_title"> </PreferenceScreen> - <com.android.dialer.widget.TextViewPreference - android:key="@string/voicemail_transcription_text_key"/> - </PreferenceScreen> diff --git a/java/com/android/dialer/widget/DialerFloatingActionButton.java b/java/com/android/dialer/widget/DialerFloatingActionButton.java new file mode 100644 index 000000000..17ad90736 --- /dev/null +++ b/java/com/android/dialer/widget/DialerFloatingActionButton.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 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.dialer.widget; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.support.design.widget.FloatingActionButton; +import android.util.AttributeSet; +import com.android.dialer.common.Assert; + +/** + * Since {@link FloatingActionButton} is possibly the worst widget supported by the framework, we + * need this class to work around several of it's bugs. + * + * <p>Current fixes: + * + * <ul> + * <li>Being able to trigger click events twice. + * <li>Banning setVisibility since 9 times out of 10, it just causes bad state. + * </ul> + * + * Planned fixes: + * + * <ul> + * <li>Animating on first show/hide + * <li>Being able to call show/hide rapidly and being in the proper state + * <li>Having a proper 48x48 touch target in mini mode + * </ul> + */ +public class DialerFloatingActionButton extends FloatingActionButton { + + public DialerFloatingActionButton(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + } + + @Override + public void show() { + super.show(); + setClickable(true); + } + + @Override + public void show(@Nullable OnVisibilityChangedListener onVisibilityChangedListener) { + super.show(onVisibilityChangedListener); + setClickable(true); + } + + @Override + public void hide() { + super.hide(); + setClickable(false); + } + + @Override + public void hide(@Nullable OnVisibilityChangedListener onVisibilityChangedListener) { + super.hide(onVisibilityChangedListener); + setClickable(false); + } + + @Override + public void setVisibility(int i) { + throw Assert.createUnsupportedOperationFailException( + "Do not call setVisibility, call show/hide instead"); + } +} diff --git a/java/com/android/dialer/widget/EmptyContentView.java b/java/com/android/dialer/widget/EmptyContentView.java index 5c2e4d501..b99657a10 100644 --- a/java/com/android/dialer/widget/EmptyContentView.java +++ b/java/com/android/dialer/widget/EmptyContentView.java @@ -17,6 +17,10 @@ package com.android.dialer.widget; import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.Resources.Theme; +import android.support.annotation.ColorRes; +import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.util.AttributeSet; import android.view.LayoutInflater; @@ -86,6 +90,11 @@ public class EmptyContentView extends LinearLayout implements View.OnClickListen } } + public void setImageTint(@ColorRes int color, @Nullable Theme theme) { + imageView.setImageTintList( + (ColorStateList.valueOf(getContext().getResources().getColor(color, theme)))); + } + public void setActionLabel(@StringRes int resourceId) { actionLabel = resourceId; if (resourceId == NO_LABEL) { diff --git a/java/com/android/dialer/widget/res/layout-land/empty_content_view.xml b/java/com/android/dialer/widget/res/layout-land/empty_content_view.xml index 00344bf44..3a7574f53 100644 --- a/java/com/android/dialer/widget/res/layout-land/empty_content_view.xml +++ b/java/com/android/dialer/widget/res/layout-land/empty_content_view.xml @@ -18,7 +18,7 @@ <ImageView android:id="@+id/empty_list_view_image" android:layout_width="match_parent" - android:layout_height="0dp" + android:layout_height="108dp" android:layout_weight="1" android:maxHeight="126dp" android:gravity="center_horizontal"/> diff --git a/java/com/android/dialer/widget/res/values/colors.xml b/java/com/android/dialer/widget/res/values/colors.xml index c974609ef..12a5cb999 100644 --- a/java/com/android/dialer/widget/res/values/colors.xml +++ b/java/com/android/dialer/widget/res/values/colors.xml @@ -1,4 +1,20 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2018 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 + --> <resources> <color name="empty_list_text_color">#b2b2b2</color> + <color name="empty_voicemail_icon_tint_color">#E1E1E1</color> </resources>
\ No newline at end of file diff --git a/java/com/android/incallui/CallCardPresenter.java b/java/com/android/incallui/CallCardPresenter.java index ad92f57c9..8eb07c579 100644 --- a/java/com/android/incallui/CallCardPresenter.java +++ b/java/com/android/incallui/CallCardPresenter.java @@ -483,7 +483,7 @@ public class CallCardPresenter .setCallSubject(shouldShowCallSubject(primary) ? primary.getCallSubject() : null) .setCallbackNumber( PhoneNumberHelper.formatNumber( - primary.getCallbackNumber(), primary.getSimCountryIso())) + context, primary.getCallbackNumber(), primary.getSimCountryIso())) .setIsWifi(primary.hasProperty(Details.PROPERTY_WIFI)) .setIsConference( primary.isConferenceCall() @@ -907,7 +907,7 @@ public class CallCardPresenter if (secondary == null) { // Clear the secondary display info. - inCallScreen.setSecondary(SecondaryInfo.createEmptySecondaryInfo(isFullscreen)); + inCallScreen.setSecondary(SecondaryInfo.builder().setIsFullscreen(isFullscreen).build()); return; } @@ -915,39 +915,39 @@ public class CallCardPresenter LogUtil.i( "CallCardPresenter.updateSecondaryDisplayInfo", "secondary call is merge in process, clearing info"); - inCallScreen.setSecondary(SecondaryInfo.createEmptySecondaryInfo(isFullscreen)); + inCallScreen.setSecondary(SecondaryInfo.builder().setIsFullscreen(isFullscreen).build()); return; } if (secondary.isConferenceCall()) { inCallScreen.setSecondary( - new SecondaryInfo( - true /* show */, - CallerInfoUtils.getConferenceString( - context, secondary.hasProperty(Details.PROPERTY_GENERIC_CONFERENCE)), - false /* nameIsNumber */, - null /* label */, - secondary.getCallProviderLabel(), - true /* isConference */, - secondary.isVideoCall(), - isFullscreen)); + SecondaryInfo.builder() + .setShouldShow(true) + .setName( + CallerInfoUtils.getConferenceString( + context, secondary.hasProperty(Details.PROPERTY_GENERIC_CONFERENCE))) + .setProviderLabel(secondary.getCallProviderLabel()) + .setIsConference(true) + .setIsVideoCall(secondary.isVideoCall()) + .setIsFullscreen(isFullscreen) + .build()); } else if (secondaryContactInfo != null) { LogUtil.v("CallCardPresenter.updateSecondaryDisplayInfo", "" + secondaryContactInfo); String name = getNameForCall(secondaryContactInfo); boolean nameIsNumber = name != null && name.equals(secondaryContactInfo.number); inCallScreen.setSecondary( - new SecondaryInfo( - true /* show */, - secondary.updateNameIfRestricted(name), - nameIsNumber, - secondaryContactInfo.label, - secondary.getCallProviderLabel(), - false /* isConference */, - secondary.isVideoCall(), - isFullscreen)); + SecondaryInfo.builder() + .setShouldShow(true) + .setName(secondary.updateNameIfRestricted(name)) + .setNameIsNumber(nameIsNumber) + .setLabel(secondaryContactInfo.label) + .setProviderLabel(secondary.getCallProviderLabel()) + .setIsVideoCall(secondary.isVideoCall()) + .setIsFullscreen(isFullscreen) + .build()); } else { // Clear the secondary display info. - inCallScreen.setSecondary(SecondaryInfo.createEmptySecondaryInfo(isFullscreen)); + inCallScreen.setSecondary(SecondaryInfo.builder().setIsFullscreen(isFullscreen).build()); } } diff --git a/java/com/android/incallui/ConferenceParticipantListAdapter.java b/java/com/android/incallui/ConferenceParticipantListAdapter.java index d4579b1ed..4780974ef 100644 --- a/java/com/android/incallui/ConferenceParticipantListAdapter.java +++ b/java/com/android/incallui/ConferenceParticipantListAdapter.java @@ -20,6 +20,7 @@ import android.content.Context; import android.net.Uri; import android.support.annotation.Nullable; import android.support.v4.util.ArrayMap; +import android.telephony.PhoneNumberUtils; import android.text.BidiFormatter; import android.text.TextDirectionHeuristics; import android.text.TextUtils; @@ -32,7 +33,6 @@ import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; -import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.contacts.common.preference.ContactsPreferences; import com.android.contacts.common.util.ContactDisplayUtils; import com.android.dialer.common.LogUtil; @@ -341,7 +341,7 @@ public class ConferenceParticipantListAdapter extends BaseAdapter { } else { numberTextView.setVisibility(View.VISIBLE); numberTextView.setText( - PhoneNumberUtilsCompat.createTtsSpannable( + PhoneNumberUtils.createTtsSpannable( BidiFormatter.getInstance().unicodeWrap(callerNumber, TextDirectionHeuristics.LTR))); } } diff --git a/java/com/android/incallui/ContactInfoCache.java b/java/com/android/incallui/ContactInfoCache.java index d2ae70939..90513381e 100644 --- a/java/com/android/incallui/ContactInfoCache.java +++ b/java/com/android/incallui/ContactInfoCache.java @@ -214,7 +214,7 @@ public class ContactInfoCache implements OnImageLoadCompleteListener { // No name, but we do have a valid CNAP name, so use that. displayName = info.cnapName; info.name = info.cnapName; - displayNumber = PhoneNumberHelper.formatNumber(number, info.countryIso); + displayNumber = PhoneNumberHelper.formatNumber(context, number, info.countryIso); Log.d( TAG, " ==> cnapName available: displayName '" @@ -227,7 +227,7 @@ public class ContactInfoCache implements OnImageLoadCompleteListener { // case when an incoming call doesn't match any contact, // or if you manually dial an outgoing number using the // dialpad. - displayNumber = PhoneNumberHelper.formatNumber(number, info.countryIso); + displayNumber = PhoneNumberHelper.formatNumber(context, number, info.countryIso); Log.d( TAG, @@ -252,7 +252,7 @@ public class ContactInfoCache implements OnImageLoadCompleteListener { // later determine whether to use the name or nameAlternative when presenting displayName = info.name; cce.nameAlternative = info.nameAlternative; - displayNumber = PhoneNumberHelper.formatNumber(number, info.countryIso); + displayNumber = PhoneNumberHelper.formatNumber(context, number, info.countryIso); label = info.phoneLabel; Log.d( TAG, diff --git a/java/com/android/incallui/DialpadFragment.java b/java/com/android/incallui/DialpadFragment.java index c5b9d785f..44eaf212a 100644 --- a/java/com/android/incallui/DialpadFragment.java +++ b/java/com/android/incallui/DialpadFragment.java @@ -18,6 +18,7 @@ package com.android.incallui; import android.content.Context; import android.os.Bundle; +import android.telephony.PhoneNumberUtils; import android.util.ArrayMap; import android.util.AttributeSet; import android.view.KeyEvent; @@ -29,7 +30,6 @@ import android.view.ViewGroup; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; -import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.dialer.common.LogUtil; import com.android.dialer.dialpadview.DialpadKeyButton; import com.android.dialer.dialpadview.DialpadKeyButton.OnPressedListener; @@ -199,7 +199,7 @@ public class DialpadFragment extends BaseFragment<DialpadPresenter, DialpadUi> * @param text Text to set Dialpad EditText to. */ public void setDtmfText(String text) { - dtmfDialerField.setText(PhoneNumberUtilsCompat.createTtsSpannable(text)); + dtmfDialerField.setText(PhoneNumberUtils.createTtsSpannable(text)); } /** Starts the slide up animation for the Dialpad keys when the Dialpad is revealed. */ diff --git a/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java b/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java index b5dbc0c20..2eeecc341 100644 --- a/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java +++ b/java/com/android/incallui/answer/impl/answermethod/FlingUpDownMethod.java @@ -336,7 +336,7 @@ public class FlingUpDownMethod extends AnswerMethod implements OnProgressChanged if (getParent().isVideoCall() || getParent().isVideoUpgradeRequest()) { contactPuckIcon.setImageResource(R.drawable.quantum_ic_videocam_white_24); } else if (getParent().isRttCall()) { - contactPuckIcon.setImageResource(R.drawable.quantum_ic_call_white_24); + contactPuckIcon.setImageResource(R.drawable.quantum_ic_rtt_vd_theme_24); } else { contactPuckIcon.setImageResource(R.drawable.quantum_ic_call_white_24); } diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java index 50bc691b7..d36b00d91 100644 --- a/java/com/android/incallui/call/DialerCall.java +++ b/java/com/android/incallui/call/DialerCall.java @@ -1136,7 +1136,7 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa */ public boolean isAssistedDialed() { if (getIntentExtras() != null) { - // O_MR1 and below uses the existence of USE_ASSISTED_DIALING to indicate assisted dialing + // P and below uses the existence of USE_ASSISTED_DIALING to indicate assisted dialing // was used. The Dialer client is responsible for performing assisted dialing before // placing the outgoing call. // @@ -1148,13 +1148,6 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa } } - // Starting in P+ USE_ASSISTED_DIALING indicates that the client requested the platform - // perform assisted dialing. PROPERTY_ASSISTED_DIALING_USED indicates assisted dialing took - // place. - if (hasProperty(TelephonyManagerCompat.PROPERTY_ASSISTED_DIALING_USED) - && BuildCompat.isAtLeastP()) { - return true; - } return false; } @@ -1164,21 +1157,6 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa return null; } - if (BuildCompat.isAtLeastP()) { - if (getExtras() == null) { - return null; - } - - if (getExtras() - .getParcelable(TelephonyManagerCompat.EXTRA_ASSISTED_DIALING_TRANSFORMATION_INFO) - == null) { - return null; - } - - // TODO(erfanian): Use the framework transformation info when we can link against it - return null; - } - if (getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS) == null) { return null; } diff --git a/java/com/android/incallui/contactgrid/ContactGridManager.java b/java/com/android/incallui/contactgrid/ContactGridManager.java index 1b76958dc..327eaf2b8 100644 --- a/java/com/android/incallui/contactgrid/ContactGridManager.java +++ b/java/com/android/incallui/contactgrid/ContactGridManager.java @@ -22,6 +22,7 @@ import android.graphics.drawable.Drawable; import android.os.SystemClock; import android.support.annotation.Nullable; import android.support.v4.view.ViewCompat; +import android.telephony.PhoneNumberUtils; import android.text.TextUtils; import android.view.View; import android.view.accessibility.AccessibilityEvent; @@ -30,7 +31,6 @@ import android.widget.ImageView; import android.widget.Space; import android.widget.TextView; import android.widget.ViewAnimator; -import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.lettertile.LetterTileDrawable; @@ -276,7 +276,7 @@ public class ContactGridManager { } else { contactNameTextView.setText( primaryInfo.nameIsNumber() - ? PhoneNumberUtilsCompat.createTtsSpannable(primaryInfo.name()) + ? PhoneNumberUtils.createTtsSpannable(primaryInfo.name()) : primaryInfo.name()); // Set direction of the name field diff --git a/java/com/android/incallui/hold/OnHoldFragment.java b/java/com/android/incallui/hold/OnHoldFragment.java index 33ca158d3..bddb9bafb 100644 --- a/java/com/android/incallui/hold/OnHoldFragment.java +++ b/java/com/android/incallui/hold/OnHoldFragment.java @@ -59,14 +59,14 @@ public class OnHoldFragment extends Fragment { ((TextView) view.findViewById(R.id.hold_contact_name)) .setText( - secondaryInfo.nameIsNumber + secondaryInfo.nameIsNumber() ? PhoneNumberUtils.createTtsSpannable( BidiFormatter.getInstance() - .unicodeWrap(secondaryInfo.name, TextDirectionHeuristics.LTR)) - : secondaryInfo.name); + .unicodeWrap(secondaryInfo.name(), TextDirectionHeuristics.LTR)) + : secondaryInfo.name()); ((ImageView) view.findViewById(R.id.hold_phone_icon)) .setImageResource( - secondaryInfo.isVideoCall + secondaryInfo.isVideoCall() ? R.drawable.quantum_ic_videocam_white_18 : R.drawable.quantum_ic_phone_paused_vd_theme_24); view.addOnAttachStateChangeListener( diff --git a/java/com/android/incallui/incall/impl/InCallFragment.java b/java/com/android/incallui/incall/impl/InCallFragment.java index 29160abef..5f558a4ce 100644 --- a/java/com/android/incallui/incall/impl/InCallFragment.java +++ b/java/com/android/incallui/incall/impl/InCallFragment.java @@ -305,7 +305,7 @@ public class InCallFragment extends Fragment savedSecondaryInfo = null; FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); Fragment oldBanner = getChildFragmentManager().findFragmentById(R.id.incall_on_hold_banner); - if (secondaryInfo.shouldShow) { + if (secondaryInfo.shouldShow()) { transaction.replace(R.id.incall_on_hold_banner, OnHoldFragment.newInstance(secondaryInfo)); } else { if (oldBanner != null) { diff --git a/java/com/android/incallui/incall/protocol/SecondaryInfo.java b/java/com/android/incallui/incall/protocol/SecondaryInfo.java index cadfca6bf..2dfd220a4 100644 --- a/java/com/android/incallui/incall/protocol/SecondaryInfo.java +++ b/java/com/android/incallui/incall/protocol/SecondaryInfo.java @@ -18,41 +18,62 @@ package com.android.incallui.incall.protocol; import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.Nullable; import com.android.dialer.common.LogUtil; +import com.google.auto.value.AutoValue; import java.util.Locale; /** Information about the secondary call. */ -public class SecondaryInfo implements Parcelable { - public final boolean shouldShow; - public final String name; - public final boolean nameIsNumber; - public final String label; - public final String providerLabel; - public final boolean isConference; - public final boolean isVideoCall; - public final boolean isFullscreen; - - public static SecondaryInfo createEmptySecondaryInfo(boolean isFullScreen) { - return new SecondaryInfo(false, null, false, null, null, false, false, isFullScreen); +@AutoValue +public abstract class SecondaryInfo implements Parcelable { + public abstract boolean shouldShow(); + + @Nullable + public abstract String name(); + + public abstract boolean nameIsNumber(); + + @Nullable + public abstract String label(); + + @Nullable + public abstract String providerLabel(); + + public abstract boolean isConference(); + + public abstract boolean isVideoCall(); + + public abstract boolean isFullscreen(); + + public static Builder builder() { + return new AutoValue_SecondaryInfo.Builder() + .setShouldShow(false) + .setNameIsNumber(false) + .setIsConference(false) + .setIsVideoCall(false) + .setIsFullscreen(false); } - public SecondaryInfo( - boolean shouldShow, - String name, - boolean nameIsNumber, - String label, - String providerLabel, - boolean isConference, - boolean isVideoCall, - boolean isFullscreen) { - this.shouldShow = shouldShow; - this.name = name; - this.nameIsNumber = nameIsNumber; - this.label = label; - this.providerLabel = providerLabel; - this.isConference = isConference; - this.isVideoCall = isVideoCall; - this.isFullscreen = isFullscreen; + /** Builder class for secondary info. */ + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder setShouldShow(boolean shouldShow); + + public abstract Builder setName(String name); + + public abstract Builder setNameIsNumber(boolean nameIsNumber); + + public abstract Builder setLabel(String label); + + public abstract Builder setProviderLabel(String providerLabel); + + public abstract Builder setIsConference(boolean isConference); + + public abstract Builder setIsVideoCall(boolean isVideoCall); + + public abstract Builder setIsFullscreen(boolean isFullscreen); + + public abstract SecondaryInfo build(); } @Override @@ -60,28 +81,26 @@ public class SecondaryInfo implements Parcelable { return String.format( Locale.US, "SecondaryInfo, show: %b, name: %s, label: %s, " + "providerLabel: %s", - shouldShow, - LogUtil.sanitizePii(name), - label, - providerLabel); - } - - protected SecondaryInfo(Parcel in) { - shouldShow = in.readByte() != 0; - name = in.readString(); - nameIsNumber = in.readByte() != 0; - label = in.readString(); - providerLabel = in.readString(); - isConference = in.readByte() != 0; - isVideoCall = in.readByte() != 0; - isFullscreen = in.readByte() != 0; + shouldShow(), + LogUtil.sanitizePii(name()), + label(), + providerLabel()); } public static final Creator<SecondaryInfo> CREATOR = new Creator<SecondaryInfo>() { @Override public SecondaryInfo createFromParcel(Parcel in) { - return new SecondaryInfo(in); + return builder() + .setShouldShow(in.readByte() != 0) + .setName(in.readString()) + .setNameIsNumber(in.readByte() != 0) + .setLabel(in.readString()) + .setProviderLabel(in.readString()) + .setIsConference(in.readByte() != 0) + .setIsVideoCall(in.readByte() != 0) + .setIsFullscreen(in.readByte() != 0) + .build(); } @Override @@ -97,13 +116,13 @@ public class SecondaryInfo implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeByte((byte) (shouldShow ? 1 : 0)); - dest.writeString(name); - dest.writeByte((byte) (nameIsNumber ? 1 : 0)); - dest.writeString(label); - dest.writeString(providerLabel); - dest.writeByte((byte) (isConference ? 1 : 0)); - dest.writeByte((byte) (isVideoCall ? 1 : 0)); - dest.writeByte((byte) (isFullscreen ? 1 : 0)); + dest.writeByte((byte) (shouldShow() ? 1 : 0)); + dest.writeString(name()); + dest.writeByte((byte) (nameIsNumber() ? 1 : 0)); + dest.writeString(label()); + dest.writeString(providerLabel()); + dest.writeByte((byte) (isConference() ? 1 : 0)); + dest.writeByte((byte) (isVideoCall() ? 1 : 0)); + dest.writeByte((byte) (isFullscreen() ? 1 : 0)); } } diff --git a/java/com/android/incallui/rtt/impl/RttChatFragment.java b/java/com/android/incallui/rtt/impl/RttChatFragment.java index deb205ce6..396b89e75 100644 --- a/java/com/android/incallui/rtt/impl/RttChatFragment.java +++ b/java/com/android/incallui/rtt/impl/RttChatFragment.java @@ -29,6 +29,7 @@ import android.telecom.CallAudioState; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; +import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -45,6 +46,8 @@ import android.widget.TextView.OnEditorActionListener; import com.android.dialer.common.Assert; import com.android.dialer.common.FragmentUtils; import com.android.dialer.common.LogUtil; +import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment; +import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment.AudioRouteSelectorPresenter; import com.android.incallui.call.DialerCall.State; import com.android.incallui.incall.protocol.InCallButtonUi; import com.android.incallui.incall.protocol.InCallButtonUiDelegate; @@ -68,7 +71,8 @@ public class RttChatFragment extends Fragment MessageListener, RttCallScreen, InCallScreen, - InCallButtonUi { + InCallButtonUi, + AudioRouteSelectorPresenter { private static final String ARG_CALL_ID = "call_id"; @@ -94,6 +98,7 @@ public class RttChatFragment extends Fragment private TextView nameTextView; private Chronometer chronometer; private boolean isTimerStarted; + private RttOverflowMenu overflowMenu; /** * Create a new instance of RttChatFragment. @@ -173,6 +178,10 @@ public class RttChatFragment extends Fragment inCallButtonUiDelegate.onEndCallClicked(); }); + overflowMenu = new RttOverflowMenu(getContext(), inCallButtonUiDelegate); + view.findViewById(R.id.rtt_overflow_button) + .setOnClickListener(v -> overflowMenu.showAtLocation(v, Gravity.TOP | Gravity.RIGHT, 0, 0)); + nameTextView = view.findViewById(R.id.rtt_name_or_number); chronometer = view.findViewById(R.id.rtt_timer); return view; @@ -240,6 +249,9 @@ public class RttChatFragment extends Fragment public void onStop() { LogUtil.enterBlock("RttChatFragment.onStop"); super.onStop(); + if (overflowMenu.isShowing()) { + overflowMenu.dismiss(); + } onRttScreenStop(); } @@ -360,7 +372,11 @@ public class RttChatFragment extends Fragment public void setVideoPaused(boolean isPaused) {} @Override - public void setAudioState(CallAudioState audioState) {} + public void setAudioState(CallAudioState audioState) { + LogUtil.i("RttChatFragment.setAudioState", "audioState: " + audioState); + overflowMenu.setMuteButtonChecked(audioState.isMuted()); + overflowMenu.setAudioState(audioState); + } @Override public void updateButtonStates() {} @@ -374,5 +390,16 @@ public class RttChatFragment extends Fragment } @Override - public void showAudioRouteSelector() {} + public void showAudioRouteSelector() { + AudioRouteSelectorDialogFragment.newInstance(inCallButtonUiDelegate.getCurrentAudioState()) + .show(getChildFragmentManager(), null); + } + + @Override + public void onAudioRouteSelected(int audioRoute) { + inCallButtonUiDelegate.setAudioRoute(audioRoute); + } + + @Override + public void onAudioRouteSelectorDismiss() {} } diff --git a/java/com/android/incallui/rtt/impl/RttCheckableButton.java b/java/com/android/incallui/rtt/impl/RttCheckableButton.java new file mode 100644 index 000000000..c0c8599a4 --- /dev/null +++ b/java/com/android/incallui/rtt/impl/RttCheckableButton.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.incallui.rtt.impl; + +import android.content.Context; +import android.content.res.TypedArray; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.view.SoundEffectConstants; +import android.widget.Button; +import android.widget.Checkable; + +/** Image button that maintains a checked state. */ +public class RttCheckableButton extends Button implements Checkable { + + private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked}; + + /** Callback interface to notify when the button's checked state has changed */ + public interface OnCheckedChangeListener { + + void onCheckedChanged(RttCheckableButton button, boolean isChecked); + } + + private boolean broadcasting; + private boolean isChecked; + private OnCheckedChangeListener onCheckedChangeListener; + private CharSequence contentDescriptionChecked; + private CharSequence contentDescriptionUnchecked; + + public RttCheckableButton(Context context) { + this(context, null); + } + + public RttCheckableButton(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.imageButtonStyle); + } + + public RttCheckableButton(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public RttCheckableButton( + Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) { + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RttCheckableButton); + setChecked(typedArray.getBoolean(R.styleable.RttCheckableButton_android_checked, false)); + contentDescriptionChecked = + typedArray.getText(R.styleable.RttCheckableButton_contentDescriptionChecked); + contentDescriptionUnchecked = + typedArray.getText(R.styleable.RttCheckableButton_contentDescriptionUnchecked); + typedArray.recycle(); + + updateContentDescription(); + setClickable(true); + setFocusable(true); + } + + @Override + public void setChecked(boolean checked) { + performSetChecked(checked); + } + + /** + * Called when the state of the button should be updated, this should not be the result of user + * interaction. + * + * @param checked {@code true} if the button should be in the checked state, {@code false} + * otherwise. + */ + private void performSetChecked(boolean checked) { + if (isChecked() == checked) { + return; + } + isChecked = checked; + CharSequence contentDescription = updateContentDescription(); + announceForAccessibility(contentDescription); + refreshDrawableState(); + } + + private CharSequence updateContentDescription() { + CharSequence contentDescription = + isChecked ? contentDescriptionChecked : contentDescriptionUnchecked; + setContentDescription(contentDescription); + return contentDescription; + } + + /** + * Called when the user interacts with a button. This should not result in the button updating + * state, rather the request should be propagated to the associated listener. + * + * @param checked {@code true} if the button should be in the checked state, {@code false} + * otherwise. + */ + private void userRequestedSetChecked(boolean checked) { + if (isChecked() == checked) { + return; + } + if (broadcasting) { + return; + } + broadcasting = true; + if (onCheckedChangeListener != null) { + onCheckedChangeListener.onCheckedChanged(this, checked); + } + broadcasting = false; + } + + @Override + public boolean isChecked() { + return isChecked; + } + + @Override + public void toggle() { + userRequestedSetChecked(!isChecked()); + } + + @Override + public int[] onCreateDrawableState(int extraSpace) { + final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); + if (isChecked()) { + mergeDrawableStates(drawableState, CHECKED_STATE_SET); + } + return drawableState; + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + invalidate(); + } + + public void setOnCheckedChangeListener(OnCheckedChangeListener listener) { + this.onCheckedChangeListener = listener; + } + + @Override + public boolean performClick() { + if (!isCheckable()) { + return super.performClick(); + } + + toggle(); + final boolean handled = super.performClick(); + if (!handled) { + // View only makes a sound effect if the onClickListener was + // called, so we'll need to make one here instead. + playSoundEffect(SoundEffectConstants.CLICK); + } + return handled; + } + + private boolean isCheckable() { + return onCheckedChangeListener != null; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + SavedState savedState = (SavedState) state; + super.onRestoreInstanceState(savedState.getSuperState()); + performSetChecked(savedState.isChecked); + requestLayout(); + } + + @Override + public Parcelable onSaveInstanceState() { + return new SavedState(isChecked(), super.onSaveInstanceState()); + } + + private static class SavedState extends BaseSavedState { + + public final boolean isChecked; + + private SavedState(boolean isChecked, Parcelable superState) { + super(superState); + this.isChecked = isChecked; + } + + protected SavedState(Parcel in) { + super(in); + isChecked = in.readByte() != 0; + } + + public static final Creator<SavedState> CREATOR = + new Creator<SavedState>() { + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeByte((byte) (isChecked ? 1 : 0)); + } + } +} diff --git a/java/com/android/incallui/rtt/impl/RttOverflowMenu.java b/java/com/android/incallui/rtt/impl/RttOverflowMenu.java new file mode 100644 index 000000000..e0916bedf --- /dev/null +++ b/java/com/android/incallui/rtt/impl/RttOverflowMenu.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.incallui.rtt.impl; + +import android.content.Context; +import android.telecom.CallAudioState; +import android.view.View; +import android.widget.PopupWindow; +import com.android.incallui.incall.protocol.InCallButtonUiDelegate; +import com.android.incallui.rtt.impl.RttCheckableButton.OnCheckedChangeListener; +import com.android.incallui.speakerbuttonlogic.SpeakerButtonInfo; +import com.android.incallui.speakerbuttonlogic.SpeakerButtonInfo.IconSize; + +/** Overflow menu for RTT call. */ +public class RttOverflowMenu extends PopupWindow implements OnCheckedChangeListener { + + private final RttCheckableButton muteButton; + private final RttCheckableButton speakerButton; + private final RttCheckableButton dialpadButton; + private final RttCheckableButton addCallButton; + private final InCallButtonUiDelegate inCallButtonUiDelegate; + + RttOverflowMenu(Context context, InCallButtonUiDelegate inCallButtonUiDelegate) { + super(context); + this.inCallButtonUiDelegate = inCallButtonUiDelegate; + View view = View.inflate(context, R.layout.overflow_menu, null); + setContentView(view); + setOnDismissListener(this::dismiss); + setFocusable(true); + setWidth(context.getResources().getDimensionPixelSize(R.dimen.rtt_overflow_menu_width)); + muteButton = view.findViewById(R.id.menu_mute); + muteButton.setOnCheckedChangeListener(this); + speakerButton = view.findViewById(R.id.menu_speaker); + speakerButton.setOnCheckedChangeListener(this); + dialpadButton = view.findViewById(R.id.menu_keypad); + dialpadButton.setOnCheckedChangeListener(this); + addCallButton = view.findViewById(R.id.menu_add_call); + addCallButton.setOnCheckedChangeListener(this); + } + + @Override + public void onCheckedChanged(RttCheckableButton button, boolean isChecked) { + if (button == muteButton) { + inCallButtonUiDelegate.muteClicked(isChecked, true); + } else if (button == speakerButton) { + inCallButtonUiDelegate.toggleSpeakerphone(); + } else if (button == dialpadButton) { + inCallButtonUiDelegate.showDialpadClicked(isChecked); + } else if (button == addCallButton) { + inCallButtonUiDelegate.addCallClicked(); + } + } + + void setMuteButtonChecked(boolean isChecked) { + muteButton.setChecked(isChecked); + } + + void setAudioState(CallAudioState audioState) { + SpeakerButtonInfo info = new SpeakerButtonInfo(audioState, IconSize.SIZE_24_DP); + if (info.checkable) { + speakerButton.setChecked(info.isChecked); + } + } +} diff --git a/java/com/android/incallui/rtt/impl/res/color/rtt_checkable_button_color.xml b/java/com/android/incallui/rtt/impl/res/color/rtt_checkable_button_color.xml new file mode 100644 index 000000000..cb3a4522f --- /dev/null +++ b/java/com/android/incallui/rtt/impl/res/color/rtt_checkable_button_color.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2018 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 + --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_checked="true" + android:color="@color/rtt_button_selected_color" /> + <item android:color="@color/rtt_button_unselected_color" /> +</selector>
\ No newline at end of file diff --git a/java/com/android/incallui/rtt/impl/res/drawable/overflow_menu_background.xml b/java/com/android/incallui/rtt/impl/res/drawable/overflow_menu_background.xml new file mode 100644 index 000000000..614298679 --- /dev/null +++ b/java/com/android/incallui/rtt/impl/res/drawable/overflow_menu_background.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2018 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 + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@android:color/white"/> + <corners android:radius="2dp"/> +</shape>
\ No newline at end of file diff --git a/java/com/android/incallui/rtt/impl/res/layout/overflow_menu.xml b/java/com/android/incallui/rtt/impl/res/layout/overflow_menu.xml new file mode 100644 index 000000000..a29fad5f1 --- /dev/null +++ b/java/com/android/incallui/rtt/impl/res/layout/overflow_menu.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2018 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 + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="180dp" + android:layout_height="wrap_content" + android:paddingTop="8dp" + android:paddingBottom="8dp" + android:background="@drawable/overflow_menu_background" + android:orientation="vertical"> + <com.android.incallui.rtt.impl.RttCheckableButton + android:id="@+id/menu_mute" + style="@style/RttButton" + android:drawableStart="@drawable/quantum_ic_mic_off_vd_theme_24" + android:text="@string/incall_label_mute" + app:contentDescriptionChecked="@string/incall_content_description_muted" + app:contentDescriptionUnchecked="@string/incall_content_description_unmuted"/> + <com.android.incallui.rtt.impl.RttCheckableButton + android:id="@+id/menu_speaker" + style="@style/RttButton" + android:drawableStart="@drawable/quantum_ic_volume_up_vd_theme_24" + android:text="@string/incall_label_speaker" + app:contentDescriptionChecked="@string/incall_content_description_speaker" + app:contentDescriptionUnchecked="@string/incall_content_description_earpiece"/> + <com.android.incallui.rtt.impl.RttCheckableButton + android:id="@+id/menu_keypad" + style="@style/RttButton" + android:drawableStart="@drawable/quantum_ic_dialpad_vd_theme_24" + android:text="@string/incall_label_dialpad"/> + <com.android.incallui.rtt.impl.RttCheckableButton + android:id="@+id/menu_add_call" + style="@style/RttButton" + android:drawableStart="@drawable/quantum_ic_add_call_vd_theme_24" + android:text="@string/incall_label_add_call"/> +</LinearLayout>
\ No newline at end of file diff --git a/java/com/android/incallui/rtt/impl/res/values/attrs.xml b/java/com/android/incallui/rtt/impl/res/values/attrs.xml new file mode 100644 index 000000000..2e7d899bb --- /dev/null +++ b/java/com/android/incallui/rtt/impl/res/values/attrs.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2018 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 + --> +<resources> + <declare-styleable name="RttCheckableButton"> + <attr name="android:checked"/> + <attr name="contentDescriptionChecked" format="reference|string"/> + <attr name="contentDescriptionUnchecked" format="reference|string"/> + </declare-styleable> +</resources> diff --git a/java/com/android/incallui/rtt/impl/res/values/colors.xml b/java/com/android/incallui/rtt/impl/res/values/colors.xml index c25ad21f2..e1702ccdf 100644 --- a/java/com/android/incallui/rtt/impl/res/values/colors.xml +++ b/java/com/android/incallui/rtt/impl/res/values/colors.xml @@ -17,4 +17,6 @@ <resources> <color name="rtt_status_bar_color">#03165C</color> <color name="rtt_navigation_bar_color">#FAFAFA</color> + <color name="rtt_button_unselected_color">#757575</color> + <color name="rtt_button_selected_color">#2A56C6</color> </resources>
\ No newline at end of file diff --git a/java/com/android/incallui/rtt/impl/res/values/dimens.xml b/java/com/android/incallui/rtt/impl/res/values/dimens.xml index a3f230c08..4c3fe02d2 100644 --- a/java/com/android/incallui/rtt/impl/res/values/dimens.xml +++ b/java/com/android/incallui/rtt/impl/res/values/dimens.xml @@ -17,4 +17,5 @@ <resources> <dimen name="rtt_message_margin_top">16dp</dimen> <dimen name="rtt_same_group_message_margin_top">2dp</dimen> + <dimen name="rtt_overflow_menu_width">180dp</dimen> </resources>
\ No newline at end of file diff --git a/java/com/android/incallui/rtt/impl/res/values/styles.xml b/java/com/android/incallui/rtt/impl/res/values/styles.xml index 55207a3cc..bbacde813 100644 --- a/java/com/android/incallui/rtt/impl/res/values/styles.xml +++ b/java/com/android/incallui/rtt/impl/res/values/styles.xml @@ -15,9 +15,29 @@ ~ limitations under the License --> <resources> + <style name="Dialer.Incall.TextAppearance.RttMessage" parent="Dialer.Incall.TextAppearance"> <item name="android:fontFamily">sans-serif</item> <item name="android:textColor">#DD000000</item> <item name="android:textSize">16sp</item> </style> + + <style name="ButtonTheme"> + <item name="android:colorControlHighlight">#33000000</item> + </style> + + <style name="RttButton"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:drawablePadding">16dp</item> + <item name="android:paddingLeft">16dp</item> + <item name="android:paddingRight">16dp</item> + <item name="android:paddingTop">8dp</item> + <item name="android:paddingBottom">8dp</item> + <item name="android:drawableTint">@color/rtt_checkable_button_color</item> + <item name="android:textSize">16sp</item> + <item name="android:textColor">@color/rtt_checkable_button_color</item> + <item name="android:theme">@style/ButtonTheme</item> + <item name="android:background">?attr/selectableItemBackground</item> + </style> </resources>
\ No newline at end of file diff --git a/java/com/android/incallui/spam/SpamCallListListener.java b/java/com/android/incallui/spam/SpamCallListListener.java index c7fa498e1..22b383332 100644 --- a/java/com/android/incallui/spam/SpamCallListListener.java +++ b/java/com/android/incallui/spam/SpamCallListListener.java @@ -34,7 +34,6 @@ import android.support.v4.os.BuildCompat; import android.telecom.DisconnectCause; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; -import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.dialer.blocking.FilteredNumberCompat; import com.android.dialer.blocking.FilteredNumbersUtil; import com.android.dialer.common.Assert; @@ -47,6 +46,7 @@ import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; import com.android.dialer.notification.DialerNotificationManager; import com.android.dialer.notification.NotificationChannelId; +import com.android.dialer.phonenumberutil.PhoneNumberHelper; import com.android.dialer.spam.SpamComponent; import com.android.dialer.telecom.TelecomUtil; import com.android.dialer.util.PermissionsUtil; @@ -267,8 +267,9 @@ public class SpamCallListListener implements CallList.Listener { private CharSequence getDisplayNumber(DialerCall call) { String formattedNumber = - PhoneNumberUtils.formatNumber(call.getNumber(), GeoUtil.getCurrentCountryIso(context)); - return PhoneNumberUtilsCompat.createTtsSpannable(formattedNumber); + PhoneNumberHelper.formatNumber( + context, call.getNumber(), GeoUtil.getCurrentCountryIso(context)); + return PhoneNumberUtils.createTtsSpannable(formattedNumber); } /** Display a notification with two actions: "add contact" and "report spam". */ diff --git a/java/com/android/incallui/spam/SpamNotificationActivity.java b/java/com/android/incallui/spam/SpamNotificationActivity.java index 6ba7c30f8..8919dc713 100644 --- a/java/com/android/incallui/spam/SpamNotificationActivity.java +++ b/java/com/android/incallui/spam/SpamNotificationActivity.java @@ -27,7 +27,6 @@ import android.provider.CallLog; import android.provider.ContactsContract; import android.support.v4.app.FragmentActivity; import android.telephony.PhoneNumberUtils; -import com.android.contacts.common.compat.PhoneNumberUtilsCompat; import com.android.dialer.blocking.BlockedNumbersMigrator; import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler; import com.android.dialer.blocking.FilteredNumberCompat; @@ -39,6 +38,7 @@ import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; import com.android.dialer.logging.ReportingLocation; import com.android.dialer.notification.DialerNotificationManager; +import com.android.dialer.phonenumberutil.PhoneNumberHelper; import com.android.dialer.spam.SpamComponent; import com.android.incallui.call.DialerCall; @@ -109,8 +109,8 @@ public class SpamNotificationActivity extends FragmentActivity { /** Returns the formatted version of the given number. */ private static String getFormattedNumber(String number, Context context) { String formattedNumber = - PhoneNumberUtils.formatNumber(number, GeoUtil.getCurrentCountryIso(context)); - return PhoneNumberUtilsCompat.createTtsSpannable(formattedNumber).toString(); + PhoneNumberHelper.formatNumber(context, number, GeoUtil.getCurrentCountryIso(context)); + return PhoneNumberUtils.createTtsSpannable(formattedNumber).toString(); } private void logCallImpression(DialerImpression.Type impression) { diff --git a/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java b/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java index 4fe894a38..f2721da7d 100644 --- a/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java +++ b/java/com/android/incallui/speakeasy/SpeakEasyCallManager.java @@ -16,8 +16,8 @@ package com.android.incallui.speakeasy; -import android.app.Fragment; import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; import com.android.incallui.call.DialerCall; import com.google.common.base.Optional; diff --git a/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java b/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java index e84766c71..9e58ce18f 100644 --- a/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java +++ b/java/com/android/incallui/speakeasy/SpeakEasyCallManagerStub.java @@ -16,8 +16,8 @@ package com.android.incallui.speakeasy; -import android.app.Fragment; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import com.android.incallui.call.DialerCall; import com.google.common.base.Optional; import javax.inject.Inject; diff --git a/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java b/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java index 631cc1d68..28ee774ba 100644 --- a/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java +++ b/java/com/android/incallui/video/impl/SurfaceViewVideoCallFragment.java @@ -846,7 +846,7 @@ public class SurfaceViewVideoCallFragment extends Fragment updateButtonStates(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); Fragment oldBanner = getChildFragmentManager().findFragmentById(R.id.videocall_on_hold_banner); - if (secondaryInfo.shouldShow) { + if (secondaryInfo.shouldShow()) { OnHoldFragment onHoldFragment = OnHoldFragment.newInstance(secondaryInfo); onHoldFragment.setPadTopInset(!isInFullscreenMode); transaction.replace(R.id.videocall_on_hold_banner, onHoldFragment); diff --git a/java/com/android/incallui/video/impl/SwitchOnHoldCallController.java b/java/com/android/incallui/video/impl/SwitchOnHoldCallController.java index 372b56b4e..3efdfd7fa 100644 --- a/java/com/android/incallui/video/impl/SwitchOnHoldCallController.java +++ b/java/com/android/incallui/video/impl/SwitchOnHoldCallController.java @@ -74,7 +74,7 @@ public class SwitchOnHoldCallController implements OnClickListener { } private boolean hasSecondaryInfo() { - return secondaryInfo != null && secondaryInfo.shouldShow; + return secondaryInfo != null && secondaryInfo.shouldShow(); } public void updateButtonState() { diff --git a/java/com/android/incallui/video/impl/VideoCallFragment.java b/java/com/android/incallui/video/impl/VideoCallFragment.java index 0793d1830..6b5a9797f 100644 --- a/java/com/android/incallui/video/impl/VideoCallFragment.java +++ b/java/com/android/incallui/video/impl/VideoCallFragment.java @@ -887,7 +887,7 @@ public class VideoCallFragment extends Fragment updateButtonStates(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); Fragment oldBanner = getChildFragmentManager().findFragmentById(R.id.videocall_on_hold_banner); - if (secondaryInfo.shouldShow) { + if (secondaryInfo.shouldShow()) { OnHoldFragment onHoldFragment = OnHoldFragment.newInstance(secondaryInfo); onHoldFragment.setPadTopInset(!isInFullscreenMode); transaction.replace(R.id.videocall_on_hold_banner, onHoldFragment); |