diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2017-09-07 17:44:03 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2017-09-07 17:44:03 +0000 |
commit | 2cb0136378f1e2930b81399da1bd606dc478e0b3 (patch) | |
tree | 2e633f463df6dbddf97914a6073c8fa39a706241 /java | |
parent | dc6e00fac8ff2e288e42094c77d66a61987b0cd2 (diff) | |
parent | af3cc176cdc652a05645cab9ad213696970c6e4d (diff) |
Merge changes I2f94d863,Id7f5ce4b,I1c0b5b42,I4d8d8de8,I3765a9ae, ...
* changes:
Added search actions to the end of the dialpad search results.
Disable action on bubble when hiding, and reable it when showing.
Improved behavior of back button in search ui.
Fix crash when Context is null in InCallPresenter
Bump version code and name to Dialer v12.1 and Dialer v13 (again).
Adding dialer specific transcription error codes
Removes the unused dialer/app/filterednumber package.
Ignore invalid action for LegacyVociemailNotificationReceiver
Diffstat (limited to 'java')
27 files changed, 399 insertions, 1297 deletions
diff --git a/java/com/android/dialer/app/AndroidManifest.xml b/java/com/android/dialer/app/AndroidManifest.xml index 4200082a6..1c04b764c 100644 --- a/java/com/android/dialer/app/AndroidManifest.xml +++ b/java/com/android/dialer/app/AndroidManifest.xml @@ -61,18 +61,6 @@ <application android:theme="@style/Theme.AppCompat"> <activity - android:exported="false" - android:label="@string/manage_blocked_numbers_label" - android:name="com.android.dialer.app.filterednumber.BlockedNumbersSettingsActivity" - android:parentActivityName="com.android.dialer.app.settings.DialerSettingsActivity" - android:theme="@style/ManageBlockedNumbersStyle"> - <intent-filter> - <action android:name="com.android.dialer.action.BLOCKED_NUMBERS_SETTINGS"/> - <category android:name="android.intent.category.DEFAULT"/> - </intent-filter> - </activity> - - <activity android:label="@string/call_log_activity_title" android:name="com.android.dialer.app.calllog.CallLogActivity" android:theme="@style/DialtactsThemeWithoutActionBarOverlay"> diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java index 74bc8cc33..7f5a9b94a 100644 --- a/java/com/android/dialer/app/DialtactsActivity.java +++ b/java/com/android/dialer/app/DialtactsActivity.java @@ -49,7 +49,6 @@ import android.text.TextUtils; import android.text.TextWatcher; import android.view.DragEvent; import android.view.Gravity; -import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; @@ -169,6 +168,7 @@ public class DialtactsActivity extends TransactionSafeActivity private static final String TAG = "DialtactsActivity"; private static final String KEY_IN_REGULAR_SEARCH_UI = "in_regular_search_ui"; private static final String KEY_IN_DIALPAD_SEARCH_UI = "in_dialpad_search_ui"; + private static final String KEY_IN_NEW_SEARCH_UI = "in_new_search_ui"; private static final String KEY_SEARCH_QUERY = "search_query"; private static final String KEY_FIRST_LAUNCH = "first_launch"; private static final String KEY_WAS_CONFIGURATION_CHANGE = "was_configuration_change"; @@ -213,6 +213,8 @@ public class DialtactsActivity extends TransactionSafeActivity */ private boolean mStateSaved; + private boolean mIsKeyboardOpen; + private boolean mInNewSearch; private boolean mIsRestarting; private boolean mInDialpadSearch; private boolean mInRegularSearch; @@ -307,10 +309,7 @@ public class DialtactsActivity extends TransactionSafeActivity } else if (mRegularSearchFragment != null && mRegularSearchFragment.isVisible()) { mRegularSearchFragment.setQueryString(mSearchQuery); } else if (mNewSearchFragment != null && mNewSearchFragment.isVisible()) { - mNewSearchFragment.setQuery(mSearchQuery); - // When the user switches between dialpad and the serachbar, we need to reset the - // call initiation type. - mNewSearchFragment.setCallInitiationType(getCallInitiationType()); + mNewSearchFragment.setQuery(mSearchQuery, getCallInitiationType()); } } @@ -333,27 +332,6 @@ public class DialtactsActivity extends TransactionSafeActivity private int mActionBarHeight; private int mPreviouslySelectedTabIndex; - /** Handles the user closing the soft keyboard. */ - private final View.OnKeyListener mSearchEditTextLayoutListener = - new View.OnKeyListener() { - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) { - if (TextUtils.isEmpty(mSearchView.getText().toString())) { - // If the search term is empty, close the search UI. - PerformanceReport.recordClick(UiAction.Type.CLOSE_SEARCH_WITH_HIDE_BUTTON); - maybeExitSearchUi(); - } else { - // If the search term is not empty, show the dialpad fab. - if (!mFloatingActionButtonController.isVisible()) { - PerformanceReport.recordClick(UiAction.Type.HIDE_KEYBOARD_IN_SEARCH); - } - showFabInSearchUi(); - } - } - return false; - } - }; /** * The text returned from a voice search query. Set in {@link #onActivityResult} and used in @@ -413,30 +391,20 @@ public class DialtactsActivity extends TransactionSafeActivity SearchEditTextLayout searchEditTextLayout = actionBar.getCustomView().findViewById(R.id.search_view_container); - searchEditTextLayout.setPreImeKeyListener(mSearchEditTextLayoutListener); mActionBarController = new ActionBarController(this, searchEditTextLayout); mSearchView = searchEditTextLayout.findViewById(R.id.search_view); mSearchView.addTextChangedListener(mPhoneSearchQueryTextListener); mSearchView.setHint(getSearchBoxHint()); + mVoiceSearchButton = searchEditTextLayout.findViewById(R.id.voice_search_button); searchEditTextLayout .findViewById(R.id.search_box_collapsed) .setOnClickListener(mSearchViewOnClickListener); - searchEditTextLayout.setCallback( - new SearchEditTextLayout.Callback() { - @Override - public void onBackButtonClicked() { - onBackPressed(); - } - - @Override - public void onSearchViewClicked() { - // Hide FAB, as the keyboard is shown. - mFloatingActionButtonController.scaleOut(); - } - }); + searchEditTextLayout + .findViewById(R.id.search_back_button) + .setOnClickListener(v -> exitSearchUi()); mIsLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; @@ -463,6 +431,7 @@ public class DialtactsActivity extends TransactionSafeActivity mSearchQuery = savedInstanceState.getString(KEY_SEARCH_QUERY); mInRegularSearch = savedInstanceState.getBoolean(KEY_IN_REGULAR_SEARCH_UI); mInDialpadSearch = savedInstanceState.getBoolean(KEY_IN_DIALPAD_SEARCH_UI); + mInNewSearch = savedInstanceState.getBoolean(KEY_IN_NEW_SEARCH_UI); mFirstLaunch = savedInstanceState.getBoolean(KEY_FIRST_LAUNCH); mWasConfigurationChange = savedInstanceState.getBoolean(KEY_WAS_CONFIGURATION_CHANGE); mShowDialpadOnResume = savedInstanceState.getBoolean(KEY_IS_DIALPAD_SHOWN); @@ -657,6 +626,7 @@ public class DialtactsActivity extends TransactionSafeActivity outState.putString(KEY_SEARCH_QUERY, mSearchQuery); outState.putBoolean(KEY_IN_REGULAR_SEARCH_UI, mInRegularSearch); outState.putBoolean(KEY_IN_DIALPAD_SEARCH_UI, mInDialpadSearch); + outState.putBoolean(KEY_IN_NEW_SEARCH_UI, mInNewSearch); outState.putBoolean(KEY_FIRST_LAUNCH, mFirstLaunch); outState.putBoolean(KEY_IS_DIALPAD_SHOWN, mIsDialpadShown); outState.putBoolean(KEY_WAS_CONFIGURATION_CHANGE, isChangingConfigurations()); @@ -896,14 +866,19 @@ public class DialtactsActivity extends TransactionSafeActivity updateSearchFragmentPosition(); } + @Override + public void onCallPlacedFromDialpad() { + hideDialpadFragment(false /* animate */, true /*clearDialpad */); + exitSearchUi(); + } + /** * Initiates animations and other visual updates to hide the dialpad. The fragment is hidden in a * callback after the hide animation ends. * * @see #commitDialpadFragmentHide */ - @Override - public void hideDialpadFragment(boolean animate, boolean clearDialpad) { + private void hideDialpadFragment(boolean animate, boolean clearDialpad) { LogUtil.enterBlock("DialtactsActivity.hideDialpadFragment"); if (mDialpadFragment == null || mDialpadFragment.getView() == null) { return; @@ -938,11 +913,6 @@ public class DialtactsActivity extends TransactionSafeActivity mActionBarController.onDialpadDown(); - if (isInSearchUi()) { - if (TextUtils.isEmpty(mSearchQuery)) { - exitSearchUi(); - } - } // reset the title to normal. setTitle(R.string.launcherActivityLabel); } @@ -990,7 +960,7 @@ public class DialtactsActivity extends TransactionSafeActivity @Override public boolean isInSearchUi() { - return mInDialpadSearch || mInRegularSearch; + return mInDialpadSearch || mInRegularSearch || mInNewSearch; } @Override @@ -1001,6 +971,7 @@ public class DialtactsActivity extends TransactionSafeActivity private void setNotInSearchUi() { mInDialpadSearch = false; mInRegularSearch = false; + mInNewSearch = false; } private void hideDialpadAndSearchUi() { @@ -1174,17 +1145,21 @@ public class DialtactsActivity extends TransactionSafeActivity } final String tag; + mInDialpadSearch = false; + mInRegularSearch = false; + mInNewSearch = false; boolean useNewSearch = ConfigProviderBindings.get(this).getBoolean("enable_new_search_fragment", false); if (useNewSearch) { tag = TAG_NEW_SEARCH_FRAGMENT; + mInNewSearch = true; } else if (smartDialSearch) { tag = TAG_SMARTDIAL_SEARCH_FRAGMENT; + mInDialpadSearch = true; } else { tag = TAG_REGULAR_SEARCH_FRAGMENT; + mInRegularSearch = true; } - mInDialpadSearch = smartDialSearch; - mInRegularSearch = !smartDialSearch; mFloatingActionButtonController.scaleOut(); @@ -1233,8 +1208,7 @@ public class DialtactsActivity extends TransactionSafeActivity if (!smartDialSearch && !useNewSearch) { ((SearchFragment) fragment).setQueryString(query); } else if (useNewSearch) { - ((NewSearchFragment) fragment).setQuery(query); - ((NewSearchFragment) fragment).setCallInitiationType(getCallInitiationType()); + ((NewSearchFragment) fragment).setQuery(query, getCallInitiationType()); } transaction.commit(); @@ -1308,43 +1282,34 @@ public class DialtactsActivity extends TransactionSafeActivity return; } if (mIsDialpadShown) { - if (TextUtils.isEmpty(mSearchQuery) - || (mSmartDialSearchFragment != null - && mSmartDialSearchFragment.isVisible() - && mSmartDialSearchFragment.getAdapter().getCount() == 0)) { - exitSearchUi(); - } hideDialpadFragment(true, false); } else if (isInSearchUi()) { - exitSearchUi(); - DialerUtils.hideInputMethod(mParentLayout); + if (mIsKeyboardOpen) { + DialerUtils.hideInputMethod(mParentLayout); + PerformanceReport.recordClick(UiAction.Type.HIDE_KEYBOARD_IN_SEARCH); + } else { + exitSearchUi(); + } } else { super.onBackPressed(); } } - private void maybeEnterSearchUi() { - if (!isInSearchUi()) { - enterSearchUi(true /* isSmartDial */, mSearchQuery, false); + @Override + public void onConfigurationChanged(Configuration configuration) { + super.onConfigurationChanged(configuration); + // Checks whether a hardware keyboard is available + if (configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) { + mIsKeyboardOpen = true; + } else if (configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { + mIsKeyboardOpen = false; } } - /** @return True if the search UI was exited, false otherwise */ - private boolean maybeExitSearchUi() { - if (isInSearchUi() && TextUtils.isEmpty(mSearchQuery)) { - exitSearchUi(); - DialerUtils.hideInputMethod(mParentLayout); - return true; + private void maybeEnterSearchUi() { + if (!isInSearchUi()) { + enterSearchUi(true /* isSmartDial */, mSearchQuery, false); } - return false; - } - - private void showFabInSearchUi() { - mFloatingActionButtonController.changeIcon( - getResources().getDrawable(R.drawable.quantum_ic_dialpad_white_24, null), - getResources().getString(R.string.action_menu_dialpad_button)); - mFloatingActionButtonController.align(getFabAlignment(), false /* animate */); - mFloatingActionButtonController.scaleIn(FAB_SCALE_IN_DELAY_MS); } @Override diff --git a/java/com/android/dialer/app/calllog/CallLogAdapter.java b/java/com/android/dialer/app/calllog/CallLogAdapter.java index 61129a7ce..6540b6f95 100644 --- a/java/com/android/dialer/app/calllog/CallLogAdapter.java +++ b/java/com/android/dialer/app/calllog/CallLogAdapter.java @@ -70,6 +70,7 @@ import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.AsyncTaskExecutor; import com.android.dialer.common.concurrent.AsyncTaskExecutors; +import com.android.dialer.compat.android.provider.VoicemailCompat; import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.enrichedcall.EnrichedCallCapabilities; import com.android.dialer.enrichedcall.EnrichedCallComponent; @@ -907,7 +908,7 @@ public class CallLogAdapter extends GroupingListAdapter final int transcriptionState = (VERSION.SDK_INT >= VERSION_CODES.O) ? cursor.getInt(CallLogQuery.TRANSCRIPTION_STATE) - : PhoneCallDetailsHelper.TRANSCRIPTION_NOT_STARTED; + : VoicemailCompat.TRANSCRIPTION_NOT_STARTED; final PhoneCallDetails details = new PhoneCallDetails(number, numberPresentation, postDialDigits); details.viaNumber = viaNumber; diff --git a/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java b/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java index c1a00e58d..a6e8f10f0 100644 --- a/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java +++ b/java/com/android/dialer/app/calllog/PhoneCallDetailsHelper.java @@ -31,6 +31,7 @@ import android.widget.TextView; import com.android.dialer.app.R; import com.android.dialer.app.calllog.calllogcache.CallLogCache; import com.android.dialer.calllogutils.PhoneCallDetails; +import com.android.dialer.compat.android.provider.VoicemailCompat; import com.android.dialer.logging.ContactSource; import com.android.dialer.oem.MotorolaUtils; import com.android.dialer.phonenumberutil.PhoneNumberHelper; @@ -45,13 +46,6 @@ public class PhoneCallDetailsHelper { /** The maximum number of icons will be shown to represent the call types in a group. */ private static final int MAX_CALL_TYPE_ICONS = 3; - // TODO(mdooley): remove when these api's become public - // Copied from android.provider.VoicemailContract - static final int TRANSCRIPTION_NOT_STARTED = 0; - static final int TRANSCRIPTION_IN_PROGRESS = 1; - static final int TRANSCRIPTION_FAILED = 2; - static final int TRANSCRIPTION_AVAILABLE = 3; - private final Context mContext; private final Resources mResources; private final CallLogCache mCallLogCache; @@ -159,12 +153,13 @@ public class PhoneCallDetailsHelper { // Set the branding text if the voicemail was transcribed by google // TODO(mdooley): the transcription state is only set by the google transcription code, // but a better solution would be to check the SOURCE_PACKAGE - showTranscriptBranding = details.transcriptionState == TRANSCRIPTION_AVAILABLE; + showTranscriptBranding = + details.transcriptionState == VoicemailCompat.TRANSCRIPTION_AVAILABLE; } else { - if (details.transcriptionState == TRANSCRIPTION_IN_PROGRESS) { + if (details.transcriptionState == VoicemailCompat.TRANSCRIPTION_IN_PROGRESS) { views.voicemailTranscriptionView.setText( mResources.getString(R.string.voicemail_transcription_in_progress)); - } else if (details.transcriptionState == TRANSCRIPTION_FAILED) { + } else if (details.transcriptionState == VoicemailCompat.TRANSCRIPTION_FAILED) { views.voicemailTranscriptionView.setText( mResources.getString(R.string.voicemail_transcription_failed)); } diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java deleted file mode 100644 index ca12e4351..000000000 --- a/java/com/android/dialer/app/filterednumber/BlockedNumbersAdapter.java +++ /dev/null @@ -1,95 +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.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; -import com.android.dialer.contactphoto.ContactPhotoManager; -import com.android.dialer.database.FilteredNumberContract.FilteredNumberColumns; -import com.android.dialer.location.GeoUtil; -import com.android.dialer.logging.InteractionEvent; -import com.android.dialer.logging.Logger; -import com.android.dialer.phonenumbercache.ContactInfoHelper; - -public class BlockedNumbersAdapter extends NumbersAdapter { - - private BlockedNumbersAdapter( - Context context, - FragmentManager fragmentManager, - ContactInfoHelper contactInfoHelper, - ContactPhotoManager contactPhotoManager) { - super(context, fragmentManager, contactInfoHelper, contactPhotoManager); - } - - public static BlockedNumbersAdapter newBlockedNumbersAdapter( - Context context, FragmentManager fragmentManager) { - return new BlockedNumbersAdapter( - context, - fragmentManager, - new ContactInfoHelper(context, GeoUtil.getCurrentCountryIso(context)), - ContactPhotoManager.getInstance(context)); - } - - @Override - public void bindView(View view, final Context context, Cursor cursor) { - super.bindView(view, context, cursor); - final Integer id = cursor.getInt(cursor.getColumnIndex(FilteredNumberColumns._ID)); - final String countryIso = - cursor.getString(cursor.getColumnIndex(FilteredNumberColumns.COUNTRY_ISO)); - final String number = cursor.getString(cursor.getColumnIndex(FilteredNumberColumns.NUMBER)); - - final View deleteButton = view.findViewById(R.id.delete_button); - deleteButton.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View view) { - BlockNumberDialogFragment.show( - id, - number, - countryIso, - PhoneNumberUtils.formatNumber(number, countryIso), - R.id.blocked_numbers_activity_container, - getFragmentManager(), - new BlockNumberDialogFragment.Callback() { - @Override - public void onFilterNumberSuccess() {} - - @Override - public void onUnfilterNumberSuccess() { - Logger.get(context) - .logInteraction(InteractionEvent.Type.UNBLOCK_NUMBER_MANAGEMENT_SCREEN); - } - - @Override - public void onChangeFilteredNumberUndo() {} - }); - } - }); - - updateView(view, number, countryIso); - } - - @Override - public boolean isEmpty() { - // Always return false, so that the header with blocking-related options always shows. - return false; - } -} diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java deleted file mode 100644 index db119ab77..000000000 --- a/java/com/android/dialer/app/filterednumber/BlockedNumbersFragment.java +++ /dev/null @@ -1,271 +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.dialer.app.filterednumber; - -import android.app.ListFragment; -import android.app.LoaderManager; -import android.content.Context; -import android.content.CursorLoader; -import android.content.Loader; -import android.database.Cursor; -import android.graphics.drawable.ColorDrawable; -import android.os.Bundle; -import android.support.v4.app.ActivityCompat; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import com.android.dialer.app.R; -import com.android.dialer.blocking.BlockedNumbersMigrator; -import com.android.dialer.blocking.BlockedNumbersMigrator.Listener; -import com.android.dialer.blocking.FilteredNumberCompat; -import com.android.dialer.blocking.FilteredNumbersUtil; -import com.android.dialer.blocking.FilteredNumbersUtil.CheckForSendToVoicemailContactListener; -import com.android.dialer.blocking.FilteredNumbersUtil.ImportSendToVoicemailContactsListener; -import com.android.dialer.database.FilteredNumberContract; -import com.android.dialer.lettertile.LetterTileDrawable; -import com.android.dialer.voicemailstatus.VisualVoicemailEnabledChecker; - -public class BlockedNumbersFragment extends ListFragment - implements LoaderManager.LoaderCallbacks<Cursor>, - View.OnClickListener, - VisualVoicemailEnabledChecker.Callback { - - private static final char ADD_BLOCKED_NUMBER_ICON_LETTER = '+'; - protected View migratePromoView; - private BlockedNumbersMigrator blockedNumbersMigratorForTest; - private TextView blockedNumbersText; - private TextView footerText; - private BlockedNumbersAdapter mAdapter; - private VisualVoicemailEnabledChecker mVoicemailEnabledChecker; - private View mImportSettings; - private View mBlockedNumbersDisabledForEmergency; - private View mBlockedNumberListDivider; - - @Override - public Context getContext() { - return getActivity(); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - LayoutInflater inflater = - (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - getListView().addHeaderView(inflater.inflate(R.layout.blocked_number_header, null)); - getListView().addFooterView(inflater.inflate(R.layout.blocked_number_footer, null)); - //replace the icon for add number with LetterTileDrawable(), so it will have identical style - ImageView addNumberIcon = (ImageView) getActivity().findViewById(R.id.add_number_icon); - LetterTileDrawable drawable = new LetterTileDrawable(getResources()); - drawable.setLetter(ADD_BLOCKED_NUMBER_ICON_LETTER); - drawable.setColor( - ActivityCompat.getColor(getActivity(), R.color.add_blocked_number_icon_color)); - drawable.setIsCircular(true); - addNumberIcon.setImageDrawable(drawable); - - if (mAdapter == null) { - mAdapter = - BlockedNumbersAdapter.newBlockedNumbersAdapter( - getContext(), getActivity().getFragmentManager()); - } - setListAdapter(mAdapter); - - blockedNumbersText = (TextView) getListView().findViewById(R.id.blocked_number_text_view); - migratePromoView = getListView().findViewById(R.id.migrate_promo); - getListView().findViewById(R.id.migrate_promo_allow_button).setOnClickListener(this); - mImportSettings = getListView().findViewById(R.id.import_settings); - mBlockedNumbersDisabledForEmergency = - getListView().findViewById(R.id.blocked_numbers_disabled_for_emergency); - mBlockedNumberListDivider = getActivity().findViewById(R.id.blocked_number_list_divider); - getListView().findViewById(R.id.import_button).setOnClickListener(this); - getListView().findViewById(R.id.view_numbers_button).setOnClickListener(this); - getListView().findViewById(R.id.add_number_linear_layout).setOnClickListener(this); - - footerText = (TextView) getActivity().findViewById(R.id.blocked_number_footer_textview); - mVoicemailEnabledChecker = new VisualVoicemailEnabledChecker(getContext(), this); - mVoicemailEnabledChecker.asyncUpdate(); - updateActiveVoicemailProvider(); - } - - @Override - public void onDestroy() { - setListAdapter(null); - super.onDestroy(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getLoaderManager().initLoader(0, null, this); - } - - @Override - public void onResume() { - super.onResume(); - - ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar(); - ColorDrawable backgroundDrawable = - new ColorDrawable(ActivityCompat.getColor(getActivity(), R.color.dialer_theme_color)); - actionBar.setBackgroundDrawable(backgroundDrawable); - actionBar.setDisplayShowCustomEnabled(false); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setTitle(R.string.manage_blocked_numbers_label); - - // If the device can use the framework blocking solution, users should not be able to add - // new blocked numbers from the Blocked Management UI. They will be shown a promo card - // asking them to migrate to new blocking instead. - if (FilteredNumberCompat.canUseNewFiltering()) { - migratePromoView.setVisibility(View.VISIBLE); - blockedNumbersText.setVisibility(View.GONE); - getListView().findViewById(R.id.add_number_linear_layout).setVisibility(View.GONE); - getListView().findViewById(R.id.add_number_linear_layout).setOnClickListener(null); - mBlockedNumberListDivider.setVisibility(View.GONE); - mImportSettings.setVisibility(View.GONE); - getListView().findViewById(R.id.import_button).setOnClickListener(null); - getListView().findViewById(R.id.view_numbers_button).setOnClickListener(null); - mBlockedNumbersDisabledForEmergency.setVisibility(View.GONE); - footerText.setVisibility(View.GONE); - } else { - FilteredNumbersUtil.checkForSendToVoicemailContact( - getActivity(), - new CheckForSendToVoicemailContactListener() { - @Override - public void onComplete(boolean hasSendToVoicemailContact) { - final int visibility = hasSendToVoicemailContact ? View.VISIBLE : View.GONE; - mImportSettings.setVisibility(visibility); - } - }); - } - - // All views except migrate and the block list are hidden when new filtering is available - if (!FilteredNumberCompat.canUseNewFiltering() - && FilteredNumbersUtil.hasRecentEmergencyCall(getContext())) { - mBlockedNumbersDisabledForEmergency.setVisibility(View.VISIBLE); - } else { - mBlockedNumbersDisabledForEmergency.setVisibility(View.GONE); - } - - mVoicemailEnabledChecker.asyncUpdate(); - } - - @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.blocked_number_fragment, container, false); - } - - @Override - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - final String[] projection = { - FilteredNumberContract.FilteredNumberColumns._ID, - FilteredNumberContract.FilteredNumberColumns.COUNTRY_ISO, - FilteredNumberContract.FilteredNumberColumns.NUMBER, - FilteredNumberContract.FilteredNumberColumns.NORMALIZED_NUMBER - }; - final String selection = - FilteredNumberContract.FilteredNumberColumns.TYPE - + "=" - + FilteredNumberContract.FilteredNumberTypes.BLOCKED_NUMBER; - return new CursorLoader( - getContext(), - FilteredNumberContract.FilteredNumber.CONTENT_URI, - projection, - selection, - null, - null); - } - - @Override - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - mAdapter.swapCursor(data); - if (FilteredNumberCompat.canUseNewFiltering() || data.getCount() == 0) { - mBlockedNumberListDivider.setVisibility(View.INVISIBLE); - } else { - mBlockedNumberListDivider.setVisibility(View.VISIBLE); - } - } - - @Override - public void onLoaderReset(Loader<Cursor> loader) { - mAdapter.swapCursor(null); - } - - @Override - public void onClick(final View view) { - final BlockedNumbersSettingsActivity activity = (BlockedNumbersSettingsActivity) getActivity(); - if (activity == null) { - return; - } - - int resId = view.getId(); - if (resId == R.id.add_number_linear_layout) { - activity.showSearchUi(); - } else if (resId == R.id.view_numbers_button) { - activity.showNumbersToImportPreviewUi(); - } else if (resId == R.id.import_button) { - FilteredNumbersUtil.importSendToVoicemailContacts( - activity, - new ImportSendToVoicemailContactsListener() { - @Override - public void onImportComplete() { - mImportSettings.setVisibility(View.GONE); - } - }); - } else if (resId == R.id.migrate_promo_allow_button) { - view.setEnabled(false); - (blockedNumbersMigratorForTest != null - ? blockedNumbersMigratorForTest - : new BlockedNumbersMigrator(getContext())) - .migrate( - new Listener() { - @Override - public void onComplete() { - getContext() - .startActivity( - FilteredNumberCompat.createManageBlockedNumbersIntent(getContext())); - // Remove this activity from the backstack - activity.finish(); - } - }); - } - } - - @Override - public void onVisualVoicemailEnabledStatusChanged(boolean newStatus) { - updateActiveVoicemailProvider(); - } - - private void updateActiveVoicemailProvider() { - if (getActivity() == null || getActivity().isFinishing()) { - return; - } - if (mVoicemailEnabledChecker.isVisualVoicemailEnabled()) { - footerText.setText(R.string.block_number_footer_message_vvm); - } else { - footerText.setText(R.string.block_number_footer_message_no_vvm); - } - } - - void setBlockedNumbersMigratorForTest(BlockedNumbersMigrator blockedNumbersMigrator) { - blockedNumbersMigratorForTest = blockedNumbersMigrator; - } -} diff --git a/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java b/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java deleted file mode 100644 index 9310fcb22..000000000 --- a/java/com/android/dialer/app/filterednumber/BlockedNumbersSettingsActivity.java +++ /dev/null @@ -1,141 +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.dialer.app.filterednumber; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.view.MenuItem; -import com.android.dialer.app.R; -import com.android.dialer.app.list.BlockedListSearchFragment; -import com.android.dialer.app.list.SearchFragment; -import com.android.dialer.logging.Logger; -import com.android.dialer.logging.ScreenEvent; - -public class BlockedNumbersSettingsActivity extends AppCompatActivity - implements SearchFragment.HostInterface { - - private static final String TAG_BLOCKED_MANAGEMENT_FRAGMENT = "blocked_management"; - private static final String TAG_BLOCKED_SEARCH_FRAGMENT = "blocked_search"; - private static final String TAG_VIEW_NUMBERS_TO_IMPORT_FRAGMENT = "view_numbers_to_import"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.blocked_numbers_activity); - - // If savedInstanceState != null, the Activity will automatically restore the last fragment. - if (savedInstanceState == null) { - showManagementUi(); - } - } - - /** Shows fragment with the list of currently blocked numbers and settings related to blocking. */ - public void showManagementUi() { - BlockedNumbersFragment fragment = - (BlockedNumbersFragment) - getFragmentManager().findFragmentByTag(TAG_BLOCKED_MANAGEMENT_FRAGMENT); - if (fragment == null) { - fragment = new BlockedNumbersFragment(); - } - - getFragmentManager() - .beginTransaction() - .replace(R.id.blocked_numbers_activity_container, fragment, TAG_BLOCKED_MANAGEMENT_FRAGMENT) - .commit(); - - Logger.get(this).logScreenView(ScreenEvent.Type.BLOCKED_NUMBER_MANAGEMENT, this); - } - - /** Shows fragment with search UI for browsing/finding numbers to block. */ - public void showSearchUi() { - BlockedListSearchFragment fragment = - (BlockedListSearchFragment) - getFragmentManager().findFragmentByTag(TAG_BLOCKED_SEARCH_FRAGMENT); - if (fragment == null) { - fragment = new BlockedListSearchFragment(); - fragment.setHasOptionsMenu(false); - fragment.setShowEmptyListForNullQuery(true); - fragment.setDirectorySearchEnabled(false); - } - - getFragmentManager() - .beginTransaction() - .replace(R.id.blocked_numbers_activity_container, fragment, TAG_BLOCKED_SEARCH_FRAGMENT) - .addToBackStack(null) - .commit(); - - Logger.get(this).logScreenView(ScreenEvent.Type.BLOCKED_NUMBER_ADD_NUMBER, this); - } - - /** - * Shows fragment with UI to preview the numbers of contacts currently marked as send-to-voicemail - * in Contacts. These numbers can be imported into Dialer's blocked number list. - */ - public void showNumbersToImportPreviewUi() { - ViewNumbersToImportFragment fragment = - (ViewNumbersToImportFragment) - getFragmentManager().findFragmentByTag(TAG_VIEW_NUMBERS_TO_IMPORT_FRAGMENT); - if (fragment == null) { - fragment = new ViewNumbersToImportFragment(); - } - - getFragmentManager() - .beginTransaction() - .replace( - R.id.blocked_numbers_activity_container, fragment, TAG_VIEW_NUMBERS_TO_IMPORT_FRAGMENT) - .addToBackStack(null) - .commit(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - onBackPressed(); - return true; - } - return false; - } - - @Override - public void onBackPressed() { - // TODO: Achieve back navigation without overriding onBackPressed. - if (getFragmentManager().getBackStackEntryCount() > 0) { - getFragmentManager().popBackStack(); - } else { - super.onBackPressed(); - } - } - - @Override - public boolean isActionBarShowing() { - return false; - } - - @Override - public boolean isDialpadShown() { - return false; - } - - @Override - public int getDialpadHeight() { - return 0; - } - - @Override - public int getActionBarHeight() { - return 0; - } -} diff --git a/java/com/android/dialer/app/filterednumber/NumbersAdapter.java b/java/com/android/dialer/app/filterednumber/NumbersAdapter.java deleted file mode 100644 index 6e1d1a5a6..000000000 --- a/java/com/android/dialer/app/filterednumber/NumbersAdapter.java +++ /dev/null @@ -1,139 +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.dialer.app.filterednumber; - -import android.app.FragmentManager; -import android.content.Context; -import android.provider.ContactsContract; -import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.text.BidiFormatter; -import android.text.TextDirectionHeuristics; -import android.text.TextUtils; -import android.view.View; -import android.widget.QuickContactBadge; -import android.widget.SimpleCursorAdapter; -import android.widget.TextView; -import com.android.dialer.app.R; -import com.android.dialer.compat.CompatUtils; -import com.android.dialer.contactphoto.ContactPhotoManager; -import com.android.dialer.contactphoto.ContactPhotoManager.DefaultImageRequest; -import com.android.dialer.lettertile.LetterTileDrawable; -import com.android.dialer.phonenumbercache.ContactInfo; -import com.android.dialer.phonenumbercache.ContactInfoHelper; -import com.android.dialer.phonenumberutil.PhoneNumberHelper; -import com.android.dialer.util.UriUtils; - -public class NumbersAdapter extends SimpleCursorAdapter { - - private Context mContext; - private FragmentManager mFragmentManager; - private ContactInfoHelper mContactInfoHelper; - private BidiFormatter mBidiFormatter = BidiFormatter.getInstance(); - private ContactPhotoManager mContactPhotoManager; - - public NumbersAdapter( - Context context, - FragmentManager fragmentManager, - ContactInfoHelper contactInfoHelper, - ContactPhotoManager contactPhotoManager) { - super(context, R.layout.blocked_number_item, null, new String[] {}, new int[] {}, 0); - mContext = context; - mFragmentManager = fragmentManager; - mContactInfoHelper = contactInfoHelper; - mContactPhotoManager = contactPhotoManager; - } - - public void updateView(View view, String number, String countryIso) { - final TextView callerName = (TextView) view.findViewById(R.id.caller_name); - final TextView callerNumber = (TextView) view.findViewById(R.id.caller_number); - final QuickContactBadge quickContactBadge = - (QuickContactBadge) view.findViewById(R.id.quick_contact_photo); - quickContactBadge.setOverlay(null); - if (CompatUtils.hasPrioritizedMimeType()) { - quickContactBadge.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE); - } - - ContactInfo info = mContactInfoHelper.lookupNumber(number, countryIso); - if (info == null) { - info = new ContactInfo(); - info.number = number; - } - final CharSequence locationOrType = getNumberTypeOrLocation(info); - final String displayNumber = getDisplayNumber(info); - final String displayNumberStr = - mBidiFormatter.unicodeWrap(displayNumber, TextDirectionHeuristics.LTR); - - String nameForDefaultImage; - if (!TextUtils.isEmpty(info.name)) { - nameForDefaultImage = info.name; - callerName.setText(info.name); - callerNumber.setText(locationOrType + " " + displayNumberStr); - } else { - nameForDefaultImage = displayNumber; - callerName.setText(displayNumberStr); - if (!TextUtils.isEmpty(locationOrType)) { - callerNumber.setText(locationOrType); - callerNumber.setVisibility(View.VISIBLE); - } else { - callerNumber.setVisibility(View.GONE); - } - } - loadContactPhoto(info, nameForDefaultImage, quickContactBadge); - } - - private void loadContactPhoto(ContactInfo info, String displayName, QuickContactBadge badge) { - final String lookupKey = - info.lookupUri == null ? null : UriUtils.getLookupKeyFromUri(info.lookupUri); - final int contactType = - mContactInfoHelper.isBusiness(info.sourceType) - ? LetterTileDrawable.TYPE_BUSINESS - : LetterTileDrawable.TYPE_DEFAULT; - final DefaultImageRequest request = - new DefaultImageRequest(displayName, lookupKey, contactType, true /* isCircular */); - badge.assignContactUri(info.lookupUri); - badge.setContentDescription( - mContext.getResources().getString(R.string.description_contact_details, displayName)); - mContactPhotoManager.loadDirectoryPhoto( - badge, info.photoUri, false /* darkTheme */, true /* isCircular */, request); - } - - private String getDisplayNumber(ContactInfo info) { - if (!TextUtils.isEmpty(info.formattedNumber)) { - return info.formattedNumber; - } else if (!TextUtils.isEmpty(info.number)) { - return info.number; - } else { - return ""; - } - } - - private CharSequence getNumberTypeOrLocation(ContactInfo info) { - if (!TextUtils.isEmpty(info.name)) { - return ContactsContract.CommonDataKinds.Phone.getTypeLabel( - mContext.getResources(), info.type, info.label); - } else { - return PhoneNumberHelper.getGeoDescription(mContext, info.number); - } - } - - protected Context getContext() { - return mContext; - } - - protected FragmentManager getFragmentManager() { - return mFragmentManager; - } -} diff --git a/java/com/android/dialer/app/filterednumber/ViewNumbersToImportAdapter.java b/java/com/android/dialer/app/filterednumber/ViewNumbersToImportAdapter.java deleted file mode 100644 index 1e90eecb6..000000000 --- a/java/com/android/dialer/app/filterednumber/ViewNumbersToImportAdapter.java +++ /dev/null @@ -1,56 +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.dialer.app.filterednumber; - -import android.app.FragmentManager; -import android.content.Context; -import android.database.Cursor; -import android.view.View; -import com.android.dialer.app.R; -import com.android.dialer.blocking.FilteredNumbersUtil; -import com.android.dialer.contactphoto.ContactPhotoManager; -import com.android.dialer.location.GeoUtil; -import com.android.dialer.phonenumbercache.ContactInfoHelper; - -public class ViewNumbersToImportAdapter extends NumbersAdapter { - - private ViewNumbersToImportAdapter( - Context context, - FragmentManager fragmentManager, - ContactInfoHelper contactInfoHelper, - ContactPhotoManager contactPhotoManager) { - super(context, fragmentManager, contactInfoHelper, contactPhotoManager); - } - - public static ViewNumbersToImportAdapter newViewNumbersToImportAdapter( - Context context, FragmentManager fragmentManager) { - return new ViewNumbersToImportAdapter( - context, - fragmentManager, - new ContactInfoHelper(context, GeoUtil.getCurrentCountryIso(context)), - ContactPhotoManager.getInstance(context)); - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - super.bindView(view, context, cursor); - - final String number = cursor.getString(FilteredNumbersUtil.PhoneQuery.NUMBER_COLUMN_INDEX); - - view.findViewById(R.id.delete_button).setVisibility(View.GONE); - updateView(view, number, null /* countryIso */); - } -} diff --git a/java/com/android/dialer/app/filterednumber/ViewNumbersToImportFragment.java b/java/com/android/dialer/app/filterednumber/ViewNumbersToImportFragment.java deleted file mode 100644 index d45f61ed7..000000000 --- a/java/com/android/dialer/app/filterednumber/ViewNumbersToImportFragment.java +++ /dev/null @@ -1,130 +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.dialer.app.filterednumber; - -import android.app.ListFragment; -import android.app.LoaderManager; -import android.content.Context; -import android.content.CursorLoader; -import android.content.Loader; -import android.database.Cursor; -import android.os.Bundle; -import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import com.android.dialer.app.R; -import com.android.dialer.blocking.FilteredNumbersUtil; -import com.android.dialer.blocking.FilteredNumbersUtil.ImportSendToVoicemailContactsListener; - -public class ViewNumbersToImportFragment extends ListFragment - implements LoaderManager.LoaderCallbacks<Cursor>, View.OnClickListener { - - private ViewNumbersToImportAdapter mAdapter; - - @Override - public Context getContext() { - return getActivity(); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - if (mAdapter == null) { - mAdapter = - ViewNumbersToImportAdapter.newViewNumbersToImportAdapter( - getContext(), getActivity().getFragmentManager()); - } - setListAdapter(mAdapter); - } - - @Override - public void onDestroy() { - setListAdapter(null); - super.onDestroy(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getLoaderManager().initLoader(0, null, this); - } - - @Override - public void onResume() { - super.onResume(); - - ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar(); - actionBar.setTitle(R.string.import_send_to_voicemail_numbers_label); - actionBar.setDisplayShowCustomEnabled(false); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - actionBar.setDisplayShowTitleEnabled(true); - - getActivity().findViewById(R.id.cancel_button).setOnClickListener(this); - getActivity().findViewById(R.id.import_button).setOnClickListener(this); - } - - @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.view_numbers_to_import_fragment, container, false); - } - - @Override - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - final CursorLoader cursorLoader = - new CursorLoader( - getContext(), - Phone.CONTENT_URI, - FilteredNumbersUtil.PhoneQuery.PROJECTION, - FilteredNumbersUtil.PhoneQuery.SELECT_SEND_TO_VOICEMAIL_TRUE, - null, - null); - return cursorLoader; - } - - @Override - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - mAdapter.swapCursor(data); - } - - @Override - public void onLoaderReset(Loader<Cursor> loader) { - mAdapter.swapCursor(null); - } - - @Override - public void onClick(final View view) { - if (view.getId() == R.id.import_button) { - FilteredNumbersUtil.importSendToVoicemailContacts( - getContext(), - new ImportSendToVoicemailContactsListener() { - @Override - public void onImportComplete() { - if (getActivity() != null) { - getActivity().onBackPressed(); - } - } - }); - } else if (view.getId() == R.id.cancel_button) { - getActivity().onBackPressed(); - } - } -} diff --git a/java/com/android/dialer/app/list/BlockedListSearchFragment.java b/java/com/android/dialer/app/list/BlockedListSearchFragment.java deleted file mode 100644 index 8d42221c0..000000000 --- a/java/com/android/dialer/app/list/BlockedListSearchFragment.java +++ /dev/null @@ -1,247 +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.dialer.app.list; - -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; -import android.util.TypedValue; -import android.view.View; -import android.widget.AdapterView; -import android.widget.EditText; -import android.widget.Toast; -import com.android.contacts.common.list.ContactEntryListAdapter; -import com.android.contacts.common.util.ContactDisplayUtils; -import com.android.dialer.app.R; -import com.android.dialer.app.widget.SearchEditTextLayout; -import com.android.dialer.blocking.BlockNumberDialogFragment; -import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler; -import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler.OnCheckBlockedListener; -import com.android.dialer.common.LogUtil; -import com.android.dialer.location.GeoUtil; -import com.android.dialer.logging.InteractionEvent; -import com.android.dialer.logging.Logger; - -public class BlockedListSearchFragment extends RegularSearchFragment - implements BlockNumberDialogFragment.Callback { - - private final TextWatcher mPhoneSearchQueryTextListener = - new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - setQueryString(s.toString()); - } - - @Override - public void afterTextChanged(Editable s) {} - }; - private final SearchEditTextLayout.Callback mSearchLayoutCallback = - new SearchEditTextLayout.Callback() { - @Override - public void onBackButtonClicked() { - getActivity().onBackPressed(); - } - - @Override - public void onSearchViewClicked() {} - }; - private FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler; - private EditText mSearchView; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setShowEmptyListForNullQuery(true); - /* - * Pass in the empty string here so ContactEntryListFragment#setQueryString interprets it as - * an empty search query, rather than as an uninitalized value. In the latter case, the - * adapter returned by #createListAdapter is used, which populates the view with contacts. - * Passing in the empty string forces ContactEntryListFragment to interpret it as an empty - * query, which results in showing an empty view - */ - setQueryString(getQueryString() == null ? "" : getQueryString()); - mFilteredNumberAsyncQueryHandler = new FilteredNumberAsyncQueryHandler(getContext()); - } - - @Override - public void onResume() { - super.onResume(); - - ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar(); - actionBar.setCustomView(R.layout.search_edittext); - actionBar.setDisplayShowCustomEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(false); - actionBar.setDisplayShowHomeEnabled(false); - - final SearchEditTextLayout searchEditTextLayout = - (SearchEditTextLayout) actionBar.getCustomView().findViewById(R.id.search_view_container); - searchEditTextLayout.expand(false, true); - searchEditTextLayout.setCallback(mSearchLayoutCallback); - searchEditTextLayout.setBackgroundDrawable(null); - - mSearchView = (EditText) searchEditTextLayout.findViewById(R.id.search_view); - mSearchView.addTextChangedListener(mPhoneSearchQueryTextListener); - mSearchView.setHint(R.string.block_number_search_hint); - - searchEditTextLayout - .findViewById(R.id.search_box_expanded) - .setBackgroundColor(getContext().getResources().getColor(android.R.color.white)); - - if (!TextUtils.isEmpty(getQueryString())) { - mSearchView.setText(getQueryString()); - } - - // TODO: Don't set custom text size; use default search text size. - mSearchView.setTextSize( - TypedValue.COMPLEX_UNIT_PX, - getResources().getDimension(R.dimen.blocked_number_search_text_size)); - } - - @Override - protected ContactEntryListAdapter createListAdapter() { - BlockedListSearchAdapter adapter = new BlockedListSearchAdapter(getActivity()); - adapter.setDisplayPhotos(true); - // Don't show SIP addresses. - adapter.setUseCallableUri(false); - // Keep in sync with the queryString set in #onCreate - adapter.setQueryString(getQueryString() == null ? "" : getQueryString()); - return adapter; - } - - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - super.onItemClick(parent, view, position, id); - final int adapterPosition = position - getListView().getHeaderViewsCount(); - final BlockedListSearchAdapter adapter = (BlockedListSearchAdapter) getAdapter(); - final int shortcutType = adapter.getShortcutTypeFromPosition(adapterPosition); - final Integer blockId = (Integer) view.getTag(R.id.block_id); - final String number; - switch (shortcutType) { - case DialerPhoneNumberListAdapter.SHORTCUT_INVALID: - // Handles click on a search result, either contact or nearby places result. - number = adapter.getPhoneNumber(adapterPosition); - blockContactNumber(number, blockId); - break; - case DialerPhoneNumberListAdapter.SHORTCUT_BLOCK_NUMBER: - // Handles click on 'Block number' shortcut to add the user query as a number. - number = adapter.getQueryString(); - blockNumber(number); - break; - default: - LogUtil.w( - "BlockedListSearchFragment.onItemClick", - "ignoring unsupported shortcut type: " + shortcutType); - break; - } - } - - @Override - protected void onItemClick(int position, long id) { - // Prevent SearchFragment.onItemClicked from being called. - } - - private void blockNumber(final String number) { - final String countryIso = GeoUtil.getCurrentCountryIso(getContext()); - final OnCheckBlockedListener onCheckListener = - new OnCheckBlockedListener() { - @Override - public void onCheckComplete(Integer id) { - if (id == null) { - BlockNumberDialogFragment.show( - id, - number, - countryIso, - PhoneNumberUtils.formatNumber(number, countryIso), - R.id.blocked_numbers_activity_container, - getFragmentManager(), - BlockedListSearchFragment.this); - } else if (id == FilteredNumberAsyncQueryHandler.INVALID_ID) { - Toast.makeText( - getContext(), - ContactDisplayUtils.getTtsSpannedPhoneNumber( - getResources(), R.string.invalidNumber, number), - Toast.LENGTH_SHORT) - .show(); - } else { - Toast.makeText( - getContext(), - ContactDisplayUtils.getTtsSpannedPhoneNumber( - getResources(), R.string.alreadyBlocked, number), - Toast.LENGTH_SHORT) - .show(); - } - } - }; - mFilteredNumberAsyncQueryHandler.isBlockedNumber(onCheckListener, number, countryIso); - } - - @Override - public void onFilterNumberSuccess() { - Logger.get(getContext()).logInteraction(InteractionEvent.Type.BLOCK_NUMBER_MANAGEMENT_SCREEN); - goBack(); - } - - @Override - public void onUnfilterNumberSuccess() { - LogUtil.e( - "BlockedListSearchFragment.onUnfilterNumberSuccess", - "unblocked a number from the BlockedListSearchFragment"); - goBack(); - } - - private void goBack() { - Activity activity = getActivity(); - if (activity == null) { - return; - } - activity.onBackPressed(); - } - - @Override - public void onChangeFilteredNumberUndo() { - getAdapter().notifyDataSetChanged(); - } - - private void blockContactNumber(final String number, final Integer blockId) { - if (blockId != null) { - Toast.makeText( - getContext(), - ContactDisplayUtils.getTtsSpannedPhoneNumber( - getResources(), R.string.alreadyBlocked, number), - Toast.LENGTH_SHORT) - .show(); - return; - } - - BlockNumberDialogFragment.show( - blockId, - number, - GeoUtil.getCurrentCountryIso(getContext()), - number, - R.id.blocked_numbers_activity_container, - getFragmentManager(), - this); - } -} diff --git a/java/com/android/dialer/app/voicemail/LegacyVoicemailNotificationReceiver.java b/java/com/android/dialer/app/voicemail/LegacyVoicemailNotificationReceiver.java index d681df205..4e43704f1 100644 --- a/java/com/android/dialer/app/voicemail/LegacyVoicemailNotificationReceiver.java +++ b/java/com/android/dialer/app/voicemail/LegacyVoicemailNotificationReceiver.java @@ -55,6 +55,12 @@ public class LegacyVoicemailNotificationReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { + + if (!TelephonyManager.ACTION_SHOW_VOICEMAIL_NOTIFICATION.equals(intent.getAction()) + && !VoicemailClient.ACTION_SHOW_LEGACY_VOICEMAIL.equals(intent.getAction())) { + return; + } + LogUtil.i( "LegacyVoicemailNotificationReceiver.onReceive", "received legacy voicemail notification"); if (!BuildCompat.isAtLeastO()) { diff --git a/java/com/android/dialer/app/widget/ActionBarController.java b/java/com/android/dialer/app/widget/ActionBarController.java index c1b4cc2b4..3daa0e2d4 100644 --- a/java/com/android/dialer/app/widget/ActionBarController.java +++ b/java/com/android/dialer/app/widget/ActionBarController.java @@ -49,18 +49,6 @@ public class ActionBarController { } }; - private final AnimationCallback mFadeInCallback = - new AnimationCallback() { - @Override - public void onAnimationEnd() { - slideActionBar(false /* slideUp */, false /* animate */); - } - - @Override - public void onAnimationCancel() { - slideActionBar(false /* slideUp */, false /* animate */); - } - }; private ValueAnimator mAnimator; public ActionBarController(ActivityUi activityUi, SearchEditTextLayout searchBox) { @@ -112,17 +100,13 @@ public class ActionBarController { mSearchBox.isFadedOut(), mSearchBox.isExpanded()); if (mActivityUi.isInSearchUi()) { - if (mActivityUi.hasSearchQuery()) { - if (mSearchBox.isFadedOut()) { - mSearchBox.setVisible(true); - } - if (!mSearchBox.isExpanded()) { - mSearchBox.expand(false /* animate */, false /* requestFocus */); - } - slideActionBar(false /* slideUp */, true /* animate */); - } else { - mSearchBox.fadeIn(mFadeInCallback); + if (mSearchBox.isFadedOut()) { + mSearchBox.setVisible(true); + } + if (!mSearchBox.isExpanded()) { + mSearchBox.expand(false /* animate */, false /* requestFocus */); } + slideActionBar(false /* slideUp */, true /* animate */); } } diff --git a/java/com/android/dialer/app/widget/SearchEditTextLayout.java b/java/com/android/dialer/app/widget/SearchEditTextLayout.java index 95bd12aa1..2051b65f2 100644 --- a/java/com/android/dialer/app/widget/SearchEditTextLayout.java +++ b/java/com/android/dialer/app/widget/SearchEditTextLayout.java @@ -23,7 +23,6 @@ import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.AttributeSet; -import android.view.KeyEvent; import android.view.View; import android.widget.EditText; import android.widget.FrameLayout; @@ -38,7 +37,6 @@ public class SearchEditTextLayout extends FrameLayout { /* Subclass-visible for testing */ protected boolean mIsExpanded = false; protected boolean mIsFadedOut = false; - private OnKeyListener mPreImeKeyListener; private int mTopMargin; private int mBottomMargin; private int mLeftMargin; @@ -56,20 +54,10 @@ public class SearchEditTextLayout extends FrameLayout { private ValueAnimator mAnimator; - private Callback mCallback; - public SearchEditTextLayout(Context context, AttributeSet attrs) { super(context, attrs); } - public void setPreImeKeyListener(OnKeyListener listener) { - mPreImeKeyListener = listener; - } - - public void setCallback(Callback listener) { - mCallback = listener; - } - @Override protected void onFinishInflate() { MarginLayoutParams params = (MarginLayoutParams) getLayoutParams(); @@ -82,7 +70,7 @@ public class SearchEditTextLayout extends FrameLayout { mCollapsed = findViewById(R.id.search_box_collapsed); mExpanded = findViewById(R.id.search_box_expanded); - mSearchView = (EditText) mExpanded.findViewById(R.id.search_view); + mSearchView = mExpanded.findViewById(R.id.search_view); mSearchIcon = findViewById(R.id.search_magnifying_glass); mCollapsedSearchBox = findViewById(R.id.search_box_start_search); @@ -123,16 +111,6 @@ public class SearchEditTextLayout extends FrameLayout { } }); - mSearchView.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mCallback != null) { - mCallback.onSearchViewClicked(); - } - } - }); - mSearchView.addTextChangedListener( new TextWatcher() { @Override @@ -147,43 +125,10 @@ public class SearchEditTextLayout extends FrameLayout { public void afterTextChanged(Editable s) {} }); - findViewById(R.id.search_close_button) - .setOnClickListener( - new OnClickListener() { - @Override - public void onClick(View v) { - mSearchView.setText(null); - } - }); - - findViewById(R.id.search_back_button) - .setOnClickListener( - new OnClickListener() { - @Override - public void onClick(View v) { - if (mCallback != null) { - mCallback.onBackButtonClicked(); - } - } - }); - + mClearButtonView.setOnClickListener(v -> mSearchView.setText(null)); super.onFinishInflate(); } - @Override - public boolean dispatchKeyEventPreIme(KeyEvent event) { - if (mPreImeKeyListener != null) { - if (mPreImeKeyListener.onKey(this, event.getKeyCode(), event)) { - return true; - } - } - return super.dispatchKeyEventPreIme(event); - } - - public void fadeOut() { - fadeOut(null); - } - public void fadeOut(AnimUtils.AnimationCallback callback) { AnimUtils.fadeOut(this, ANIMATION_DURATION, callback); mIsFadedOut = true; @@ -324,12 +269,4 @@ public class SearchEditTextLayout extends FrameLayout { params.rightMargin = (int) (mRightMargin * fraction); requestLayout(); } - - /** Listener for the back button next to the search view being pressed */ - public interface Callback { - - void onBackButtonClicked(); - - void onSearchViewClicked(); - } } diff --git a/java/com/android/dialer/binary/google/AndroidManifest.xml b/java/com/android/dialer/binary/google/AndroidManifest.xml index 12abe82ac..663a05f5a 100644 --- a/java/com/android/dialer/binary/google/AndroidManifest.xml +++ b/java/com/android/dialer/binary/google/AndroidManifest.xml @@ -16,7 +16,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" coreApp="true" package="com.google.android.google_stub_dialer" - android:versionCode="170000" + android:versionCode="180000" android:versionName="13.0"> <uses-sdk diff --git a/java/com/android/voicemail/impl/transcribe/VoicemailCompat.java b/java/com/android/dialer/compat/android/provider/VoicemailCompat.java index c6e30c6de..175ea5d95 100644 --- a/java/com/android/voicemail/impl/transcribe/VoicemailCompat.java +++ b/java/com/android/dialer/compat/android/provider/VoicemailCompat.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License */ -package com.android.voicemail.impl.transcribe; +package com.android.dialer.compat.android.provider; /** * Provide access to new API constants before they're publicly available @@ -47,7 +47,7 @@ public class VoicemailCompat { /** * Value of {@link #TRANSCRIPTION_STATE} when the voicemail transcription has been attempted and - * failed. + * failed for an unspecified reason. */ public static final int TRANSCRIPTION_FAILED = 2; @@ -56,4 +56,20 @@ public class VoicemailCompat { * result has been stored in the {@link #TRANSCRIPTION} column. */ public static final int TRANSCRIPTION_AVAILABLE = 3; + + /** + * Value of {@link #TRANSCRIPTION_STATE} when the voicemail transcription has been attempted and + * failed because no speech was detected. + * + * <p>Internal dialer use only, not part of the public SDK. + */ + public static final int TRANSCRIPTION_FAILED_NO_SPEECH_DETECTED = -1; + + /** + * Value of {@link #TRANSCRIPTION_STATE} when the voicemail transcription has been attempted and + * failed because the language was not supported. + * + * <p>Internal dialer use only, not part of the public SDK. + */ + public static final int TRANSCRIPTION_FAILED_LANGUAGE_NOT_SUPPORTED = -2; } diff --git a/java/com/android/dialer/dialpadview/DialpadFragment.java b/java/com/android/dialer/dialpadview/DialpadFragment.java index 86a83796e..837c3af90 100644 --- a/java/com/android/dialer/dialpadview/DialpadFragment.java +++ b/java/com/android/dialer/dialpadview/DialpadFragment.java @@ -1001,12 +1001,12 @@ public class DialpadFragment extends Fragment DialerUtils.startActivityWithErrorToast( getActivity(), new CallIntentBuilder(CallUtil.getVoicemailUri(), CallInitiationType.Type.DIALPAD).build()); - hideAndClearDialpad(false); + hideAndClearDialpad(); } - private void hideAndClearDialpad(boolean animate) { + private void hideAndClearDialpad() { LogUtil.enterBlock("DialpadFragment.hideAndClearDialpad"); - FragmentUtils.getParentUnsafe(this, DialpadListener.class).hideDialpadFragment(animate, true); + FragmentUtils.getParentUnsafe(this, DialpadListener.class).onCallPlacedFromDialpad(); } /** @@ -1053,7 +1053,7 @@ public class DialpadFragment extends Fragment final Intent intent = new CallIntentBuilder(number, CallInitiationType.Type.DIALPAD).build(); DialerUtils.startActivityWithErrorToast(getActivity(), intent); - hideAndClearDialpad(false); + hideAndClearDialpad(); } } } @@ -1297,7 +1297,7 @@ public class DialpadFragment extends Fragment return true; } else if (resId == R.id.menu_call_with_note) { CallSubjectDialog.start(getActivity(), mDigits.getText().toString()); - hideAndClearDialpad(false); + hideAndClearDialpad(); return true; } else { return false; @@ -1710,7 +1710,7 @@ public class DialpadFragment extends Fragment void onDialpadShown(); - void hideDialpadFragment(boolean animate, boolean value); + void onCallPlacedFromDialpad(); } /** Callback for async lookup of the last number dialed. */ diff --git a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java index 5b3532cdb..0623d394a 100644 --- a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java +++ b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java @@ -28,6 +28,7 @@ import android.support.annotation.VisibleForTesting; import android.support.v13.app.FragmentCompat; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -44,16 +45,19 @@ import com.android.dialer.enrichedcall.EnrichedCallComponent; import com.android.dialer.enrichedcall.EnrichedCallManager.CapabilitiesListener; import com.android.dialer.searchfragment.common.SearchCursor; import com.android.dialer.searchfragment.cp2.SearchContactsCursorLoader; +import com.android.dialer.searchfragment.list.SearchActionViewHolder.Action; import com.android.dialer.searchfragment.nearbyplaces.NearbyPlacesCursorLoader; import com.android.dialer.searchfragment.remote.RemoteContactsCursorLoader; import com.android.dialer.searchfragment.remote.RemoteDirectoriesCursorLoader; import com.android.dialer.searchfragment.remote.RemoteDirectoriesCursorLoader.Directory; +import com.android.dialer.util.CallUtil; import com.android.dialer.util.PermissionsUtil; import com.android.dialer.util.ViewUtil; import com.android.dialer.widget.EmptyContentView; import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; /** Fragment used for searching contacts. */ @@ -99,6 +103,7 @@ public final class NewSearchFragment extends Fragment View view = inflater.inflate(R.layout.fragment_search, parent, false); adapter = new SearchAdapter(getActivity(), new SearchCursorManager()); adapter.setCallInitiationType(callInitiationType); + adapter.setSearchActions(getActions()); emptyContentView = view.findViewById(R.id.empty_view); recyclerView = view.findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); @@ -184,22 +189,18 @@ public final class NewSearchFragment extends Fragment recyclerView.setAdapter(null); } - public void setQuery(String query) { + public void setQuery(String query, CallInitiationType.Type callInitiationType) { this.query = query; + this.callInitiationType = callInitiationType; if (adapter != null) { adapter.setQuery(query); + adapter.setCallInitiationType(callInitiationType); + adapter.setSearchActions(getActions()); loadNearbyPlacesCursor(); loadRemoteContactsCursors(); } } - public void setCallInitiationType(CallInitiationType.Type callInitiationType) { - this.callInitiationType = callInitiationType; - if (adapter != null) { - adapter.setCallInitiationType(callInitiationType); - } - } - /** Translate the search fragment and resize it to fit on the screen. */ public void animatePosition(int start, int end, int duration) { // Called before the view is ready, prepare a runnable to run in onCreateView @@ -329,4 +330,27 @@ public final class NewSearchFragment extends Fragment public void setRemoteDirectoriesDisabled(boolean disabled) { remoteDirectoriesDisabledForTesting = disabled; } + + /** + * Returns a list of search actions to be shown in the search results. + * + * <p>List will be empty if query is 1 or 0 characters or the query isn't from the Dialpad. For + * the list of supported actions, see {@link SearchActionViewHolder.Action}. + */ + private List<Integer> getActions() { + if (TextUtils.isEmpty(query) + || query.length() == 1 + || callInitiationType == CallInitiationType.Type.REGULAR_SEARCH) { + return Collections.emptyList(); + } + + List<Integer> actions = new ArrayList<>(); + actions.add(Action.CREATE_NEW_CONTACT); + actions.add(Action.ADD_TO_CONTACT); + actions.add(Action.SEND_SMS); + if (CallUtil.isVideoEnabled(getContext())) { + actions.add(Action.MAKE_VILTE_CALL); + } + return actions; + } } diff --git a/java/com/android/dialer/searchfragment/list/SearchActionViewHolder.java b/java/com/android/dialer/searchfragment/list/SearchActionViewHolder.java new file mode 100644 index 000000000..62e5c72b0 --- /dev/null +++ b/java/com/android/dialer/searchfragment/list/SearchActionViewHolder.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2017 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.searchfragment.list; + +import android.content.Context; +import android.content.Intent; +import android.support.annotation.IntDef; +import android.support.annotation.StringRes; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageView; +import android.widget.TextView; +import com.android.dialer.callintent.CallInitiationType; +import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.callintent.CallSpecificAppData; +import com.android.dialer.common.Assert; +import com.android.dialer.logging.DialerImpression; +import com.android.dialer.logging.Logger; +import com.android.dialer.util.DialerUtils; +import com.android.dialer.util.IntentUtil; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * {@link RecyclerView.ViewHolder} for showing an {@link SearchActionViewHolder.Action} in a list. + */ +final class SearchActionViewHolder extends RecyclerView.ViewHolder implements OnClickListener { + + /** IntDef for the different types of actions that can be used. */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + Action.INVALID, + Action.CREATE_NEW_CONTACT, + Action.ADD_TO_CONTACT, + Action.SEND_SMS, + Action.MAKE_VILTE_CALL + }) + @interface Action { + int INVALID = 0; + /** Opens the prompt to create a new contact. */ + int CREATE_NEW_CONTACT = 1; + /** Opens a prompt to add to an existing contact. */ + int ADD_TO_CONTACT = 2; + /** Opens the SMS conversation with the default SMS app. */ + int SEND_SMS = 3; + /** Attempts to make a VILTE call to the number. */ + int MAKE_VILTE_CALL = 4; + } + + private final Context context; + private final ImageView actionImage; + private final TextView actionText; + + private @Action int action; + private int position; + private String query; + + SearchActionViewHolder(View view) { + super(view); + context = view.getContext(); + actionImage = view.findViewById(R.id.search_action_image); + actionText = view.findViewById(R.id.search_action_text); + view.setOnClickListener(this); + } + + void setAction(@Action int action, int position, String query) { + this.action = action; + this.position = position; + this.query = query; + switch (action) { + case Action.ADD_TO_CONTACT: + actionText.setText(R.string.search_shortcut_add_to_contact); + actionImage.setImageResource(R.drawable.quantum_ic_person_add_vd_theme_24); + break; + case Action.CREATE_NEW_CONTACT: + actionText.setText(R.string.search_shortcut_create_new_contact); + actionImage.setImageResource(R.drawable.quantum_ic_person_add_vd_theme_24); + break; + case Action.MAKE_VILTE_CALL: + actionText.setText(R.string.search_shortcut_make_video_call); + actionImage.setImageResource(R.drawable.quantum_ic_videocam_vd_theme_24); + break; + case Action.SEND_SMS: + actionText.setText(R.string.search_shortcut_send_sms_message); + actionImage.setImageResource(R.drawable.quantum_ic_message_vd_theme_24); + break; + case Action.INVALID: + default: + throw Assert.createIllegalStateFailException("Invalid action: " + action); + } + } + + @Override + public void onClick(View v) { + switch (action) { + case Action.ADD_TO_CONTACT: + Logger.get(context).logImpression(DialerImpression.Type.ADD_TO_A_CONTACT_FROM_DIALPAD); + Intent intent = IntentUtil.getAddToExistingContactIntent(query); + @StringRes int errorString = R.string.add_contact_not_available; + DialerUtils.startActivityWithErrorToast(context, intent, errorString); + break; + + case Action.CREATE_NEW_CONTACT: + Logger.get(context).logImpression(DialerImpression.Type.CREATE_NEW_CONTACT_FROM_DIALPAD); + intent = IntentUtil.getNewContactIntent(query); + DialerUtils.startActivityWithErrorToast(context, intent); + break; + + case Action.MAKE_VILTE_CALL: + CallSpecificAppData callSpecificAppData = + CallSpecificAppData.newBuilder() + .setCallInitiationType(CallInitiationType.Type.DIALPAD) + .setPositionOfSelectedSearchResult(position) + .setCharactersInSearchString(query.length()) + .build(); + intent = new CallIntentBuilder(query, callSpecificAppData).setIsVideoCall(true).build(); + DialerUtils.startActivityWithErrorToast(context, intent); + break; + + case Action.SEND_SMS: + intent = IntentUtil.getSendSmsIntent(query); + DialerUtils.startActivityWithErrorToast(context, intent); + break; + + case Action.INVALID: + default: + throw Assert.createIllegalStateFailException("Invalid action: " + action); + } + } +} diff --git a/java/com/android/dialer/searchfragment/list/SearchAdapter.java b/java/com/android/dialer/searchfragment/list/SearchAdapter.java index f08d60e09..61055a0c1 100644 --- a/java/com/android/dialer/searchfragment/list/SearchAdapter.java +++ b/java/com/android/dialer/searchfragment/list/SearchAdapter.java @@ -40,6 +40,7 @@ import com.android.dialer.searchfragment.list.SearchCursorManager.RowType; import com.android.dialer.searchfragment.nearbyplaces.NearbyPlaceViewHolder; import com.android.dialer.searchfragment.remote.RemoteContactViewHolder; import com.android.dialer.util.DialerUtils; +import java.util.List; /** RecyclerView adapter for {@link NewSearchFragment}. */ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) @@ -75,6 +76,9 @@ public final class SearchAdapter extends RecyclerView.Adapter<ViewHolder> case RowType.DIRECTORY_ROW: return new RemoteContactViewHolder( LayoutInflater.from(activity).inflate(R.layout.search_contact_row, root, false)); + case RowType.SEARCH_ACTION: + return new SearchActionViewHolder( + LayoutInflater.from(activity).inflate(R.layout.search_action_layout, root, false)); case RowType.INVALID: default: throw Assert.createIllegalStateFailException("Invalid RowType: " + rowType); @@ -98,6 +102,9 @@ public final class SearchAdapter extends RecyclerView.Adapter<ViewHolder> String header = searchCursorManager.getCursor(position).getString(SearchCursor.HEADER_TEXT_POSITION); ((HeaderViewHolder) holder).setHeader(header); + } else if (holder instanceof SearchActionViewHolder) { + ((SearchActionViewHolder) holder) + .setAction(searchCursorManager.getSearchAction(position), position, query); } else { throw Assert.createIllegalStateFailException("Invalid ViewHolder: " + holder); } @@ -124,6 +131,13 @@ public final class SearchAdapter extends RecyclerView.Adapter<ViewHolder> } } + /** Sets the actions to be shown at the bottom of the search results. */ + void setSearchActions(List<Integer> actions) { + if (searchCursorManager.setSearchActions(actions)) { + notifyDataSetChanged(); + } + } + void setCallInitiationType(CallInitiationType.Type callInitiationType) { this.callInitiationType = callInitiationType; } diff --git a/java/com/android/dialer/searchfragment/list/SearchCursorManager.java b/java/com/android/dialer/searchfragment/list/SearchCursorManager.java index a303425d3..95bede001 100644 --- a/java/com/android/dialer/searchfragment/list/SearchCursorManager.java +++ b/java/com/android/dialer/searchfragment/list/SearchCursorManager.java @@ -23,16 +23,19 @@ import com.android.dialer.common.Assert; import com.android.dialer.searchfragment.common.SearchCursor; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; /** * Manages all of the cursors needed for {@link SearchAdapter}. * - * <p>This class accepts three cursors: + * <p>This class accepts four data sources: * * <ul> * <li>A contacts cursor {@link #setContactsCursor(SearchCursor)} * <li>A google search results cursor {@link #setNearbyPlacesCursor(SearchCursor)} * <li>A work directory cursor {@link #setCorpDirectoryCursor(SearchCursor)} + * <li>A list of action to be performed on a number {@link #setSearchActions(List)} * </ul> * * <p>The key purpose of this class is to compose three aforementioned cursors together to function @@ -56,7 +59,8 @@ public final class SearchCursorManager { SearchCursorManager.RowType.NEARBY_PLACES_HEADER, SearchCursorManager.RowType.NEARBY_PLACES_ROW, SearchCursorManager.RowType.DIRECTORY_HEADER, - SearchCursorManager.RowType.DIRECTORY_ROW + SearchCursorManager.RowType.DIRECTORY_ROW, + SearchCursorManager.RowType.SEARCH_ACTION }) @interface RowType { int INVALID = 0; @@ -73,11 +77,14 @@ public final class SearchCursorManager { int DIRECTORY_HEADER = 5; /** A row containing contact information for contacts stored externally in corp directories. */ int DIRECTORY_ROW = 6; + /** A row containing a search action */ + int SEARCH_ACTION = 7; } private SearchCursor contactsCursor = null; private SearchCursor nearbyPlacesCursor = null; private SearchCursor corpDirectoryCursor = null; + private List<Integer> searchActions = new ArrayList<>(); /** Returns true if the cursor changed. */ boolean setContactsCursor(@Nullable SearchCursor cursor) { @@ -149,6 +156,20 @@ public final class SearchCursorManager { return updated; } + /** Sets search actions, returning true if different from existing actions. */ + boolean setSearchActions(List<Integer> searchActions) { + if (!this.searchActions.equals(searchActions)) { + this.searchActions = searchActions; + return true; + } + return false; + } + + /** Returns {@link SearchActionViewHolder.Action}. */ + int getSearchAction(int position) { + return searchActions.get(position - getCount() + searchActions.size()); + } + /** Returns the sum of counts of all cursors, including headers. */ int getCount() { int count = 0; @@ -164,11 +185,19 @@ public final class SearchCursorManager { count += corpDirectoryCursor.getCount(); } - return count; + return count + searchActions.size(); } @RowType int getRowType(int position) { + int cursorCount = getCount(); + if (position >= cursorCount) { + throw Assert.createIllegalStateFailException( + String.format("Invalid position: %d, cursor count: %d", position, cursorCount)); + } else if (position >= cursorCount - searchActions.size()) { + return RowType.SEARCH_ACTION; + } + SearchCursor cursor = getCursor(position); if (cursor == contactsCursor) { return cursor.isHeader() ? RowType.CONTACT_HEADER : RowType.CONTACT_ROW; diff --git a/java/com/android/dialer/searchfragment/list/res/layout/search_action_layout.xml b/java/com/android/dialer/searchfragment/list/res/layout/search_action_layout.xml new file mode 100644 index 000000000..99d0fbf0c --- /dev/null +++ b/java/com/android/dialer/searchfragment/list/res/layout/search_action_layout.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp"> + + <ImageView + android:id="@+id/search_action_image" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_marginStart="8dp" + android:layout_gravity="center_vertical" + android:padding="12dp" + android:tint="@color/dialer_theme_color"/> + + <TextView + android:id="@+id/search_action_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="72dp" + android:layout_marginEnd="16dp" + android:layout_gravity="center_vertical" + style="@style/PrimaryText"/> +</FrameLayout>
\ No newline at end of file diff --git a/java/com/android/dialer/searchfragment/list/res/values/strings.xml b/java/com/android/dialer/searchfragment/list/res/values/strings.xml index 0d25b8c7a..ea238fc92 100644 --- a/java/com/android/dialer/searchfragment/list/res/values/strings.xml +++ b/java/com/android/dialer/searchfragment/list/res/values/strings.xml @@ -17,4 +17,18 @@ <resources> <!-- Shown as a prompt to turn on contacts permissions to allow contact search [CHAR LIMIT=NONE]. See 2424710404207193826 for current translation. --> <string name="new_permission_no_search">To search your contacts, turn on the Contacts permissions.</string> + + <!-- Shortcut item used to add a number directly to a new contact from search. + [CHAR LIMIT=25] --> + <string name="search_shortcut_create_new_contact">Create new contact</string> + + <!-- Shortcut item used to add a number to an existing contact directly from search. + [CHAR LIMIT=25] --> + <string name="search_shortcut_add_to_contact">Add to a contact</string> + + <!-- Shortcut item used to send a text message directly from search. [CHAR LIMIT=25] --> + <string name="search_shortcut_send_sms_message">Send SMS</string> + + <!-- Shortcut item used to make a video call directly from search. [CHAR LIMIT=25] --> + <string name="search_shortcut_make_video_call">Make video call</string> </resources> diff --git a/java/com/android/dialershared/bubble/Bubble.java b/java/com/android/dialershared/bubble/Bubble.java index cd2c9fc57..d24552245 100644 --- a/java/com/android/dialershared/bubble/Bubble.java +++ b/java/com/android/dialershared/bubble/Bubble.java @@ -241,6 +241,7 @@ public class Bubble { viewHolder.getPrimaryButton().setScaleY(0); } + viewHolder.setChildClickable(true); visibility = Visibility.ENTERING; viewHolder .getPrimaryButton() @@ -495,6 +496,9 @@ public class Bubble { return; } + // Make bubble non clickable to prevent further buggy actions + viewHolder.setChildClickable(false); + if (textShowing) { hideAfterText = true; return; @@ -822,6 +826,14 @@ public class Bubble { moveHandler = new MoveHandler(primaryButton, Bubble.this); } + private void setChildClickable(boolean clickable) { + firstButton.setClickable(clickable); + secondButton.setClickable(clickable); + thirdButton.setClickable(clickable); + + primaryButton.setOnTouchListener(clickable ? moveHandler : null); + } + public ViewGroup getRoot() { return root; } diff --git a/java/com/android/incallui/InCallPresenter.java b/java/com/android/incallui/InCallPresenter.java index 3f87a592d..4cc03f3dd 100644 --- a/java/com/android/incallui/InCallPresenter.java +++ b/java/com/android/incallui/InCallPresenter.java @@ -1682,18 +1682,23 @@ public class InCallPresenter implements CallList.Listener { VideoSurfaceTexture getLocalVideoSurfaceTexture() { if (mLocalVideoSurfaceTexture == null) { - mLocalVideoSurfaceTexture = - VideoSurfaceBindings.createLocalVideoSurfaceTexture( - mContext.getPackageManager().hasSystemFeature(PIXEL2017_SYSTEM_FEATURE)); + boolean isPixel2017 = false; + if (mContext != null) { + isPixel2017 = mContext.getPackageManager().hasSystemFeature(PIXEL2017_SYSTEM_FEATURE); + } + mLocalVideoSurfaceTexture = VideoSurfaceBindings.createLocalVideoSurfaceTexture(isPixel2017); } return mLocalVideoSurfaceTexture; } VideoSurfaceTexture getRemoteVideoSurfaceTexture() { if (mRemoteVideoSurfaceTexture == null) { + boolean isPixel2017 = false; + if (mContext != null) { + isPixel2017 = mContext.getPackageManager().hasSystemFeature(PIXEL2017_SYSTEM_FEATURE); + } mRemoteVideoSurfaceTexture = - VideoSurfaceBindings.createRemoteVideoSurfaceTexture( - mContext.getPackageManager().hasSystemFeature(PIXEL2017_SYSTEM_FEATURE)); + VideoSurfaceBindings.createRemoteVideoSurfaceTexture(isPixel2017); } return mRemoteVideoSurfaceTexture; } diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java b/java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java index 9d3c2e4a7..a9a37225b 100644 --- a/java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java +++ b/java/com/android/voicemail/impl/transcribe/TranscriptionDbHelper.java @@ -30,6 +30,7 @@ import android.support.v4.os.BuildCompat; import android.util.Pair; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; +import com.android.dialer.compat.android.provider.VoicemailCompat; import java.util.ArrayList; import java.util.List; diff --git a/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java b/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java index b5f29da00..fbab07655 100644 --- a/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java +++ b/java/com/android/voicemail/impl/transcribe/TranscriptionTask.java @@ -22,6 +22,7 @@ import android.net.Uri; import android.text.TextUtils; import android.util.Pair; import com.android.dialer.common.concurrent.ThreadUtil; +import com.android.dialer.compat.android.provider.VoicemailCompat; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; import com.android.voicemail.impl.VvmLog; @@ -124,24 +125,29 @@ public abstract class TranscriptionTask implements Runnable { } else { VvmLog.i(TAG, "transcribeVoicemail, transcription unsuccessful, " + status); switch (status) { + case FAILED_NO_SPEECH_DETECTED: + updateTranscriptionAndState( + transcript, VoicemailCompat.TRANSCRIPTION_FAILED_NO_SPEECH_DETECTED); + Logger.get(context) + .logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_NO_SPEECH_DETECTED); + break; case FAILED_LANGUAGE_NOT_SUPPORTED: + updateTranscriptionAndState( + transcript, VoicemailCompat.TRANSCRIPTION_FAILED_LANGUAGE_NOT_SUPPORTED); Logger.get(context) .logImpression( DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_LANGUAGE_NOT_SUPPORTED); break; - case FAILED_NO_SPEECH_DETECTED: - Logger.get(context) - .logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_NO_SPEECH_DETECTED); - break; case EXPIRED: + updateTranscriptionAndState(transcript, VoicemailCompat.TRANSCRIPTION_FAILED); Logger.get(context) .logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_EXPIRED); break; default: + updateTranscriptionAndState(transcript, VoicemailCompat.TRANSCRIPTION_FAILED); Logger.get(context).logImpression(DialerImpression.Type.VVM_TRANSCRIPTION_RESPONSE_EMPTY); break; } - updateTranscriptionAndState(transcript, VoicemailCompat.TRANSCRIPTION_FAILED); } } |