diff options
Diffstat (limited to 'java/com/android')
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); } } |