summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorblong <blong@codeaurora.org>2014-09-02 17:10:35 +0800
committerXiaojing Zhang <zhangx@codeaurora.org>2014-11-04 20:35:42 -0800
commit837b4965ab91525fe42d77c99fb81d178bb95c04 (patch)
tree3035a18322fc3aa1ac11a5f8f5e31cc18c23396d /src
parentbd3aefdf298ad570053c8c5fd9cf541386198c5e (diff)
downloadandroid_packages_apps_Dialer-837b4965ab91525fe42d77c99fb81d178bb95c04.tar.gz
android_packages_apps_Dialer-837b4965ab91525fe42d77c99fb81d178bb95c04.tar.bz2
android_packages_apps_Dialer-837b4965ab91525fe42d77c99fb81d178bb95c04.zip
Add call log search in dialer
- add a menu to support search call log by name and number in the calllog screen Change-Id: I80c85a9bdea962296ea39dab7ce689df06e8159e
Diffstat (limited to 'src')
-rw-r--r--src/com/android/dialer/PhoneCallDetailsHelper.java35
-rw-r--r--src/com/android/dialer/calllog/CallLogActivity.java264
-rw-r--r--src/com/android/dialer/calllog/CallLogAdapter.java6
-rw-r--r--src/com/android/dialer/calllog/CallLogQueryHandler.java15
-rw-r--r--src/com/android/dialer/calllog/CallLogSearchFragment.java90
5 files changed, 395 insertions, 15 deletions
diff --git a/src/com/android/dialer/PhoneCallDetailsHelper.java b/src/com/android/dialer/PhoneCallDetailsHelper.java
index c5f2fb675..57e2c88f5 100644
--- a/src/com/android/dialer/PhoneCallDetailsHelper.java
+++ b/src/com/android/dialer/PhoneCallDetailsHelper.java
@@ -20,8 +20,12 @@ import android.content.res.Resources;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.graphics.Typeface;
+import android.text.SpannableString;
+import android.text.Spanned;
import android.text.TextUtils;
import android.text.format.DateUtils;
+import android.text.style.StyleSpan;
import android.view.View;
import android.widget.TextView;
@@ -71,7 +75,13 @@ public class PhoneCallDetailsHelper {
}
/** Fills the call details views with content. */
- public void setPhoneCallDetails(PhoneCallDetailsViews views, PhoneCallDetails details) {
+ public void setPhoneCallDetails(PhoneCallDetailsViews views,
+ PhoneCallDetails details) {
+ setPhoneCallDetails(views, details, null);
+ }
+
+ public void setPhoneCallDetails(PhoneCallDetailsViews views,
+ PhoneCallDetails details, String filter) {
// Display up to a given number of icons.
views.callTypeIcons.clear();
int count = details.callTypes.length;
@@ -110,16 +120,35 @@ public class PhoneCallDetailsHelper {
views.callAccountIcon.setVisibility(View.GONE);
}
- final CharSequence nameText;
- final CharSequence displayNumber =
+ CharSequence nameText;
+ CharSequence displayNumber =
mPhoneNumberHelper.getDisplayNumber(details.number,
details.numberPresentation, details.formattedNumber);
+ String phoneNum = (String) details.number;
+ if (!TextUtils.isEmpty(filter) && phoneNum.contains(filter)) {
+ int start, end;
+ start = phoneNum.indexOf(filter);
+ end = start + filter.length();
+ SpannableString result = new SpannableString(phoneNum);
+ result.setSpan(new StyleSpan(Typeface.BOLD), start, end,
+ Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+ displayNumber = result;
+ }
if (TextUtils.isEmpty(details.name)) {
nameText = displayNumber;
// We have a real phone number as "nameView" so make it always LTR
views.nameView.setTextDirection(View.TEXT_DIRECTION_LTR);
} else {
nameText = details.name;
+ if (!TextUtils.isEmpty(filter) && nameText.toString().contains(filter)) {
+ int start,end;
+ start = nameText.toString().indexOf(filter);
+ end = start + filter.length();
+ SpannableString style = new SpannableString(nameText);
+ style.setSpan(new StyleSpan(Typeface.BOLD), start, end,
+ Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+ nameText = style;
+ }
}
views.nameView.setText(nameText);
diff --git a/src/com/android/dialer/calllog/CallLogActivity.java b/src/com/android/dialer/calllog/CallLogActivity.java
index a7a8c0549..ba522bcf9 100644
--- a/src/com/android/dialer/calllog/CallLogActivity.java
+++ b/src/com/android/dialer/calllog/CallLogActivity.java
@@ -16,8 +16,10 @@
package com.android.dialer.calllog;
import android.app.ActionBar;
+import android.app.ActionBar.LayoutParams;
import android.app.Fragment;
import android.app.FragmentManager;
+import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
@@ -28,10 +30,18 @@ import android.provider.CallLog.Calls;
import android.telephony.TelephonyManager;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.view.inputmethod.InputMethodManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
+import android.widget.SearchView;
+import android.widget.SearchView.OnCloseListener;
+import android.widget.SearchView.OnQueryTextListener;
+import android.util.Log;
import com.android.contacts.common.interactions.TouchPointManager;
import com.android.contacts.common.list.ViewPagerTabs;
@@ -55,7 +65,9 @@ public class CallLogActivity extends AnalyticsActivity implements CallLogQueryHa
private boolean mSwitchToVoicemailTab;
private MSimCallLogFragment mMSimCallsFragment;
-
+ private CallLogSearchFragment mSearchFragment;
+ private SearchView mSearchView;
+ private boolean mInSearchUi;
private String[] mTabTitles;
private static final int TAB_INDEX_ALL = 0;
@@ -147,6 +159,7 @@ public class CallLogActivity extends AnalyticsActivity implements CallLogQueryHa
if (getTelephonyManager().isMultiSimEnabled()) {
initMSimCallLog();
+ addSearchFragment();
return;
}
@@ -197,7 +210,7 @@ public class CallLogActivity extends AnalyticsActivity implements CallLogQueryHa
mViewPagerTabs.setViewPager(mViewPager);
mViewPager.setCurrentItem(startingTab);
}
-
+ addSearchFragment();
mVoicemailStatusHelper = new VoicemailStatusHelperImpl();
}
@@ -213,6 +226,13 @@ public class CallLogActivity extends AnalyticsActivity implements CallLogQueryHa
callLogQueryHandler.fetchVoicemailStatus();
}
+ @Override
+ public void onAttachFragment(Fragment fragment) {
+ if (fragment instanceof CallLogSearchFragment) {
+ mSearchFragment = (CallLogSearchFragment) fragment;
+ }
+ }
+
private TelephonyManager getTelephonyManager() {
return (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
}
@@ -243,7 +263,20 @@ public class CallLogActivity extends AnalyticsActivity implements CallLogQueryHa
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
final MenuItem itemDeleteAll = menu.findItem(R.id.delete_all);
-
+ final MenuItem itemSearchCallLog = menu.findItem(R.id.search_calllog);
+ if (mInSearchUi) {
+ if (itemDeleteAll != null) {
+ itemDeleteAll.setVisible(false);
+ }
+ if (itemSearchCallLog != null) {
+ itemSearchCallLog.setVisible(false);
+ }
+ } else {
+ if (mSearchFragment != null && itemSearchCallLog != null) {
+ final CallLogAdapter adapter = mSearchFragment.getAdapter();
+ itemSearchCallLog.setVisible(adapter != null
+ && !adapter.isEmpty());
+ }
// If onPrepareOptionsMenu is called before fragments loaded. Don't do anything.
if (mAllCallsFragment != null && itemDeleteAll != null) {
final CallLogAdapter adapter = mAllCallsFragment.getAdapter();
@@ -254,21 +287,25 @@ public class CallLogActivity extends AnalyticsActivity implements CallLogQueryHa
final CallLogAdapter adapter = mMSimCallsFragment.getAdapter();
itemDeleteAll.setVisible(adapter != null && !adapter.isEmpty());
}
-
+ }
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
- final Intent intent = new Intent(this, DialtactsActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- return true;
- case R.id.delete_all:
- onDelCallLog();
- return true;
+ case android.R.id.home:
+ final Intent intent = new Intent(this, DialtactsActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ return true;
+ case R.id.delete_all:
+ onDelCallLog();
+ return true;
+ case R.id.search_calllog:
+ enterSearchUi();
+ return true;
+
}
return super.onOptionsItemSelected(item);
}
@@ -278,6 +315,7 @@ public class CallLogActivity extends AnalyticsActivity implements CallLogQueryHa
"com.android.contacts.action.MULTI_PICK_CALL");
startActivity(intent);
}
+
@Override
public void onVoicemailStatusFetched(Cursor statusCursor) {
if (this.isFinishing()) {
@@ -306,4 +344,206 @@ public class CallLogActivity extends AnalyticsActivity implements CallLogQueryHa
// Return false; did not take ownership of cursor
return false;
}
+
+ private void enterSearchUi() {
+ if (mSearchFragment == null) {
+ return;
+ }
+ if (mSearchView == null) {
+ prepareSearchView();
+ }
+ final ActionBar actionBar = getActionBar();
+
+ mSearchView.setQuery(null, true);
+ mSearchView.requestFocus();
+
+ actionBar.setDisplayShowCustomEnabled(true);
+
+ for (int i = 0; i < mViewPagerAdapter.getCount(); i++) {
+ updateFragmentVisibility(i, false /* not visible */);
+ }
+
+ mSearchFragment.setUserVisibleHint(true);
+ final FragmentTransaction transaction = getFragmentManager()
+ .beginTransaction();
+ transaction.show(mSearchFragment);
+ transaction.commitAllowingStateLoss();
+ getFragmentManager().executePendingTransactions();
+ mViewPager.setVisibility(View.GONE);
+ mViewPagerTabs.setVisibility(View.GONE);
+ // We need to call this and onActionViewCollapsed() manually, since we
+ // are using a custom
+ // layout instead of asking the search menu item to take care of
+ // SearchView.
+ mSearchView.onActionViewExpanded();
+ mInSearchUi = true;
+ }
+
+ private void updateFragmentVisibility(int position, boolean visibility) {
+ if (position >= TAB_INDEX_ALL) {
+ final Fragment fragment = getFragmentAt(position);
+ if (fragment != null) {
+ fragment.setMenuVisibility(visibility);
+ fragment.setUserVisibleHint(visibility);
+ }
+ }
+ }
+
+ private Fragment getFragmentAt(int position) {
+ switch (position) {
+ case TAB_INDEX_ALL:
+ if (getTelephonyManager().isMultiSimEnabled()) {
+ return mMSimCallsFragment;
+ } else {
+ return mAllCallsFragment;
+ }
+ case TAB_INDEX_MISSED:
+ return mMissedCallsFragment;
+ case TAB_INDEX_VOICEMAIL:
+ return mVoicemailFragment;
+ default:
+ throw new IllegalStateException("Unknown fragment index: "
+ + position);
+ }
+ }
+
+ private void addSearchFragment() {
+ if (mSearchFragment != null) {
+ return;
+ }
+ final FragmentTransaction ft = getFragmentManager().beginTransaction();
+ final Fragment searchFragment = new CallLogSearchFragment();
+ searchFragment.setUserVisibleHint(false);
+ ft.add(R.id.calllog_frame, searchFragment);
+ ft.hide(searchFragment);
+ ft.commitAllowingStateLoss();
+ }
+
+ private void prepareSearchView() {
+ final View searchViewLayout = getLayoutInflater().inflate(
+ R.layout.custom_action_bar, null);
+ mSearchView = (SearchView) searchViewLayout
+ .findViewById(R.id.search_view);
+ mSearchView.setOnQueryTextListener(mPhoneSearchQueryTextListener);
+ mSearchView.setOnCloseListener(mPhoneSearchCloseListener);
+ mSearchView.setQueryHint(getString(R.string.calllog_search_hint));
+ mSearchView.setIconifiedByDefault(true);
+ mSearchView.setIconified(false);
+
+ mSearchView
+ .setOnQueryTextFocusChangeListener(new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View view, boolean hasFocus) {
+ if (hasFocus) {
+ showInputMethod(view.findFocus());
+ }
+ }
+ });
+
+ getActionBar().setCustomView(
+ searchViewLayout,
+ new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT));
+ }
+
+ private void showInputMethod(View view) {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ if (!imm.showSoftInput(view, 0)) {
+ }
+ }
+ }
+
+ private void hideInputMethod(View view) {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null && view != null) {
+ imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
+ }
+ }
+
+ /**
+ * Listener used to send search queries to the phone search fragment.
+ */
+ private final OnQueryTextListener mPhoneSearchQueryTextListener = new OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ View view = getCurrentFocus();
+ if (view != null) {
+ hideInputMethod(view);
+ view.clearFocus();
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String newText) {
+ // Show search result with non-empty text. Show a bare list
+ // otherwise.
+ if (mSearchFragment != null) {
+ mSearchFragment.setQueryString(newText);
+ }
+ return true;
+ }
+ };
+
+ /**
+ * Listener used to handle the "close" button on the right side of
+ * {@link SearchView}. If some text is in the search view, this will clean
+ * it up. Otherwise this will exit the search UI and let users go back to
+ * usual Phone UI.
+ *
+ * This does _not_ handle back button.
+ */
+ private final OnCloseListener mPhoneSearchCloseListener = new OnCloseListener() {
+ @Override
+ public boolean onClose() {
+ if (!TextUtils.isEmpty(mSearchView.getQuery())) {
+ mSearchView.setQuery(null, true);
+ }
+ return true;
+ }
+ };
+
+ @Override
+ public void onBackPressed() {
+ if (mInSearchUi) {
+ // We should let the user go back to usual screens with tabs.
+ exitSearchUi();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ private void exitSearchUi() {
+ final ActionBar actionBar = getActionBar();
+ if (mSearchFragment != null) {
+ mSearchFragment.setUserVisibleHint(false);
+
+ final FragmentTransaction transaction = getFragmentManager()
+ .beginTransaction();
+ transaction.hide(mSearchFragment);
+ transaction.commitAllowingStateLoss();
+
+ }
+
+ // We want to hide SearchView and show Tabs. Also focus on previously
+ // selected one.
+ actionBar.setDisplayShowCustomEnabled(false);
+
+ for (int i = 0; i < mViewPagerAdapter.getCount(); i++) {
+ updateFragmentVisibility(i, i == mViewPager.getCurrentItem());
+ }
+
+ mViewPager.setVisibility(View.VISIBLE);
+ mViewPagerTabs.setVisibility(View.VISIBLE);
+ hideInputMethod(getCurrentFocus());
+
+ // Request to update option menu.
+ invalidateOptionsMenu();
+
+ // See comments in onActionViewExpanded()
+ mSearchView.onActionViewCollapsed();
+ mSearchView.clearFocus();
+ mInSearchUi = false;
+ }
}
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 8e5fca7d7..589d80ec2 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -147,6 +147,8 @@ public class CallLogAdapter extends GroupingListAdapter
private final OnReportButtonClickListener mOnReportButtonClickListener;
private ViewTreeObserver mViewTreeObserver = null;
+ private String mFilterString;
+
/**
* A cache of the contact details for the phone numbers in the call log.
* <p>
@@ -1415,4 +1417,8 @@ public class CallLogAdapter extends GroupingListAdapter
}
}
}
+
+ public void setQueryString(String filter) {
+ mFilterString = filter;
+ }
}
diff --git a/src/com/android/dialer/calllog/CallLogQueryHandler.java b/src/com/android/dialer/calllog/CallLogQueryHandler.java
index b6f2e626a..77f83c1e9 100644
--- a/src/com/android/dialer/calllog/CallLogQueryHandler.java
+++ b/src/com/android/dialer/calllog/CallLogQueryHandler.java
@@ -138,6 +138,21 @@ public class CallLogQueryHandler extends NoNullCursorAsyncQueryHandler {
fetchCalls(callType, 0);
}
+ public void fetchCalls(String filter) {
+ cancelFetch();
+ int requestId = newCallsRequest();
+ fetchCalls(QUERY_CALLLOG_TOKEN ,requestId,filter);
+ }
+
+ public void fetchCalls(int token,int requestId,String filter) {
+ String selection = "(" + Calls.NUMBER + " like '%" + filter
+ + "%' or " + Calls.CACHED_NAME + " like '%" + filter + "%' )";
+
+ startQuery(token, requestId, Calls.CONTENT_URI_WITH_VOICEMAIL,
+ CallLogQuery._PROJECTION, selection, null,
+ Calls.DEFAULT_SORT_ORDER);
+ }
+
public void fetchVoicemailStatus() {
startQuery(QUERY_VOICEMAIL_STATUS_TOKEN, null, Status.CONTENT_URI,
VoicemailStatusHelperImpl.PROJECTION, null, null, null);
diff --git a/src/com/android/dialer/calllog/CallLogSearchFragment.java b/src/com/android/dialer/calllog/CallLogSearchFragment.java
new file mode 100644
index 000000000..1f04539e7
--- /dev/null
+++ b/src/com/android/dialer/calllog/CallLogSearchFragment.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation, Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.dialer.calllog;
+
+import android.app.ListFragment;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.net.Uri;
+import android.net.Uri.Builder;
+import android.provider.CallLog.Calls;
+
+import com.android.contacts.common.GeoUtil;
+import com.android.dialer.R;
+import com.android.dialerbind.ObjectFactory;
+
+
+public class CallLogSearchFragment extends CallLogFragment {
+
+ private String mQueryString;
+
+ private void updateCallList(int filterType) {
+ mCallLogQueryHandler.fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL);
+ }
+
+ public void fetchCalls() {
+ if (TextUtils.isEmpty(mQueryString)) {
+ mCallLogQueryHandler.fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL);
+ } else {
+ mCallLogQueryHandler.fetchCalls(mQueryString);
+ }
+ }
+
+ public void startCallsQuery() {
+ mAdapter.setLoading(true);
+ if (TextUtils.isEmpty(mQueryString)) {
+ mCallLogQueryHandler.fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL);
+ } else {
+ mCallLogQueryHandler.fetchCalls(mQueryString);
+ }
+ }
+
+ public void setQueryString(String queryString) {
+ if (!TextUtils.equals(mQueryString, queryString)) {
+ mQueryString = queryString;
+ if (mAdapter != null) {
+ mAdapter.setLoading(true);
+ mAdapter.setQueryString(mQueryString);
+ if (TextUtils.isEmpty(queryString)) {
+ mCallLogQueryHandler
+ .fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL);
+ } else {
+ mCallLogQueryHandler.fetchCalls(queryString);
+ }
+ }
+ }
+ }
+
+}