Simple search function for contacts

This commit is contained in:
Sylvain Berfini 2014-03-14 16:36:04 +01:00
parent 4774e9dd71
commit 63343b607e
5 changed files with 152 additions and 24 deletions

View file

@ -67,6 +67,36 @@
</LinearLayout> </LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:contentDescription="@string/content_description_cancel"
android:id="@+id/clearSearchField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/list_delete"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:paddingLeft="5dp"
android:paddingRight="5dp"/>
<EditText
android:textCursorDrawable="@null"
android:id="@+id/searchField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:background="@drawable/chat_fast_address_background"
android:gravity="center"
android:layout_toLeftOf="@id/clearSearchField"
android:paddingRight="5dp"
android:inputType="textPersonName"/>
</RelativeLayout>
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">

View file

@ -23,12 +23,15 @@ import org.linphone.compatibility.Compatibility;
import org.linphone.core.LinphoneFriend; import org.linphone.core.LinphoneFriend;
import org.linphone.core.PresenceActivityType; import org.linphone.core.PresenceActivityType;
import android.annotation.SuppressLint;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
@ -37,6 +40,7 @@ import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import android.widget.AlphabetIndexer; import android.widget.AlphabetIndexer;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ListView; import android.widget.ListView;
@ -46,6 +50,7 @@ import android.widget.TextView;
/** /**
* @author Sylvain Berfini * @author Sylvain Berfini
*/ */
@SuppressLint("DefaultLocale")
public class ContactsFragment extends Fragment implements OnClickListener, OnItemClickListener { public class ContactsFragment extends Fragment implements OnClickListener, OnItemClickListener {
private Handler mHandler = new Handler(); private Handler mHandler = new Handler();
@ -57,6 +62,9 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
private AlphabetIndexer indexer; private AlphabetIndexer indexer;
private boolean editOnClick = false, editConsumed = false, onlyDisplayChatAddress = false; private boolean editOnClick = false, editConsumed = false, onlyDisplayChatAddress = false;
private String sipAddressToAdd; private String sipAddressToAdd;
private ImageView clearSearchField;
private EditText searchField;
private Cursor searchCursor;
private static ContactsFragment instance; private static ContactsFragment instance;
@ -100,6 +108,29 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
allContacts.setEnabled(onlyDisplayLinphoneContacts); allContacts.setEnabled(onlyDisplayLinphoneContacts);
linphoneContacts.setEnabled(!allContacts.isEnabled()); linphoneContacts.setEnabled(!allContacts.isEnabled());
clearSearchField = (ImageView) view.findViewById(R.id.clearSearchField);
clearSearchField.setOnClickListener(this);
searchField = (EditText) view.findViewById(R.id.searchField);
searchField.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
searchContacts(searchField.getText().toString());
}
});
return view; return view;
} }
@ -109,22 +140,63 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
if (id == R.id.allContacts) { if (id == R.id.allContacts) {
onlyDisplayLinphoneContacts = false; onlyDisplayLinphoneContacts = false;
if (searchField.getText().toString().length() > 0) {
searchContacts();
} else {
changeContactsAdapter(); changeContactsAdapter();
} }
}
else if (id == R.id.linphoneContacts) { else if (id == R.id.linphoneContacts) {
onlyDisplayLinphoneContacts = true; onlyDisplayLinphoneContacts = true;
if (searchField.getText().toString().length() > 0) {
searchContacts();
} else {
changeContactsAdapter(); changeContactsAdapter();
}
} }
else if (id == R.id.newContact) { else if (id == R.id.newContact) {
editConsumed = true; editConsumed = true;
LinphoneActivity.instance().addContact(null, sipAddressToAdd); LinphoneActivity.instance().addContact(null, sipAddressToAdd);
} }
else if (id == R.id.clearSearchField) {
searchField.setText("");
}
}
private void searchContacts() {
searchContacts(searchField.getText().toString());
}
private void searchContacts(String search) {
if (search == null || search.length() == 0) {
changeContactsAdapter();
return;
}
changeContactsToggle();
if (searchCursor != null) {
searchCursor.close();
}
if (onlyDisplayLinphoneContacts) {
searchCursor = Compatibility.getSIPContactsCursor(getActivity().getContentResolver(), search);
indexer = new AlphabetIndexer(searchCursor, Compatibility.getCursorDisplayNameColumnIndex(searchCursor), " ABCDEFGHIJKLMNOPQRSTUVWXYZ");
contactsList.setAdapter(new ContactsListAdapter(null, searchCursor));
} else {
searchCursor = Compatibility.getContactsCursor(getActivity().getContentResolver(), search);
indexer = new AlphabetIndexer(searchCursor, Compatibility.getCursorDisplayNameColumnIndex(searchCursor), " ABCDEFGHIJKLMNOPQRSTUVWXYZ");
contactsList.setAdapter(new ContactsListAdapter(null, searchCursor));
}
} }
private void changeContactsAdapter() { private void changeContactsAdapter() {
changeContactsToggle(); changeContactsToggle();
if (searchCursor != null) {
searchCursor.close();
}
Cursor allContactsCursor = LinphoneActivity.instance().getAllContactsCursor(); Cursor allContactsCursor = LinphoneActivity.instance().getAllContactsCursor();
Cursor sipContactsCursor = LinphoneActivity.instance().getSIPContactsCursor(); Cursor sipContactsCursor = LinphoneActivity.instance().getSIPContactsCursor();
@ -199,6 +271,9 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
@Override @Override
public void onPause() { public void onPause() {
instance = null; instance = null;
if (searchCursor != null) {
searchCursor.close();
}
super.onPause(); super.onPause();
} }
@ -206,7 +281,11 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
if (searchField != null && searchField.getText().toString().length() > 0) {
searchContacts(searchField.getText().toString());
} else {
changeContactsAdapter(); changeContactsAdapter();
}
contactsList.setSelectionFromTop(lastKnownPosition, 0); contactsList.setSelectionFromTop(lastKnownPosition, 0);
} }
}); });
@ -231,7 +310,7 @@ public class ContactsFragment extends Fragment implements OnClickListener, OnIte
} }
public Object getItem(int position) { public Object getItem(int position) {
if (position >= contacts.size()) { if (contacts == null || position >= contacts.size()) {
return Compatibility.getContact(getActivity().getContentResolver(), cursor, position); return Compatibility.getContact(getActivity().getContentResolver(), cursor, position);
} else { } else {
return contacts.get(position); return contacts.get(position);

View file

@ -21,9 +21,6 @@ package org.linphone;
import static android.media.AudioManager.MODE_RINGTONE; import static android.media.AudioManager.MODE_RINGTONE;
import static android.media.AudioManager.STREAM_RING; import static android.media.AudioManager.STREAM_RING;
import static android.media.AudioManager.STREAM_VOICE_CALL; import static android.media.AudioManager.STREAM_VOICE_CALL;
import static org.linphone.core.LinphoneCall.State.CallEnd;
import static org.linphone.core.LinphoneCall.State.Error;
import static org.linphone.core.LinphoneCall.State.IncomingReceived;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -71,7 +68,6 @@ import org.linphone.core.PayloadType;
import org.linphone.core.PresenceActivityType; import org.linphone.core.PresenceActivityType;
import org.linphone.core.PresenceModel; import org.linphone.core.PresenceModel;
import org.linphone.core.PublishState; import org.linphone.core.PublishState;
import org.linphone.core.Reason;
import org.linphone.core.SubscriptionState; import org.linphone.core.SubscriptionState;
import org.linphone.mediastream.Log; import org.linphone.mediastream.Log;
import org.linphone.mediastream.Version; import org.linphone.mediastream.Version;
@ -184,7 +180,7 @@ public class LinphoneManager implements LinphoneCoreListener {
mRingbackSoundFile = basePath + "/ringback.wav"; mRingbackSoundFile = basePath + "/ringback.wav";
mPauseSoundFile = basePath + "/toy_mono.wav"; mPauseSoundFile = basePath + "/toy_mono.wav";
mChatDatabaseFile = basePath + "/linphone-history.db"; mChatDatabaseFile = basePath + "/linphone-history.db";
mErrorToneFile = basePath + "/error_tone.wav"; mErrorToneFile = basePath + "/error.wav";
mPrefs = LinphonePreferences.instance(); mPrefs = LinphonePreferences.instance();
mAudioManager = ((AudioManager) c.getSystemService(Context.AUDIO_SERVICE)); mAudioManager = ((AudioManager) c.getSystemService(Context.AUDIO_SERVICE));
@ -964,7 +960,7 @@ public class LinphoneManager implements LinphoneCoreListener {
@SuppressLint("Wakelock") @SuppressLint("Wakelock")
public void callState(final LinphoneCore lc,final LinphoneCall call, final State state, final String message) { public void callState(final LinphoneCore lc,final LinphoneCall call, final State state, final String message) {
Log.i("new state [",state,"]"); Log.i("new state [",state,"]");
if (state == IncomingReceived && !call.equals(lc.getCurrentCall())) { if (state == State.IncomingReceived && !call.equals(lc.getCurrentCall())) {
if (call.getReplacedCall()!=null){ if (call.getReplacedCall()!=null){
// attended transfer // attended transfer
// it will be accepted automatically. // it will be accepted automatically.
@ -972,14 +968,14 @@ public class LinphoneManager implements LinphoneCoreListener {
} }
} }
if (state == IncomingReceived && mR.getBoolean(R.bool.auto_answer_calls)) { if (state == State.IncomingReceived && mR.getBoolean(R.bool.auto_answer_calls)) {
try { try {
mLc.acceptCall(call); mLc.acceptCall(call);
} catch (LinphoneCoreException e) { } catch (LinphoneCoreException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
else if (state == IncomingReceived || (state == State.CallIncomingEarlyMedia && mR.getBoolean(R.bool.allow_ringing_while_early_media))) { else if (state == State.IncomingReceived || (state == State.CallIncomingEarlyMedia && mR.getBoolean(R.bool.allow_ringing_while_early_media))) {
// Brighten screen for at least 10 seconds // Brighten screen for at least 10 seconds
if (mLc.getCallsNb() == 1) { if (mLc.getCallsNb() == 1) {
ringingCall = call; ringingCall = call;
@ -991,7 +987,7 @@ public class LinphoneManager implements LinphoneCoreListener {
stopRinging(); stopRinging();
} }
if (state == LinphoneCall.State.Connected) { if (state == State.Connected) {
if (mLc.getCallsNb() == 1) { if (mLc.getCallsNb() == 1) {
requestAudioFocus(); requestAudioFocus();
Compatibility.setAudioManagerInCallMode(mAudioManager); Compatibility.setAudioManagerInCallMode(mAudioManager);
@ -1002,7 +998,7 @@ public class LinphoneManager implements LinphoneCoreListener {
} }
} }
if (state == CallEnd || state == Error) { if (state == State.CallReleased || state == State.Error) {
if (mLc.getCallsNb() == 0) { if (mLc.getCallsNb() == 0) {
if (mAudioFocused){ if (mAudioFocused){
int res=mAudioManager.abandonAudioFocus(null); int res=mAudioManager.abandonAudioFocus(null);
@ -1021,7 +1017,7 @@ public class LinphoneManager implements LinphoneCoreListener {
} }
} }
if (state == CallEnd) { if (state == State.CallEnd) {
if (mLc.getCallsNb() == 0) { if (mLc.getCallsNb() == 0) {
if (mIncallWakeLock != null && mIncallWakeLock.isHeld()) { if (mIncallWakeLock != null && mIncallWakeLock.isHeld()) {
mIncallWakeLock.release(); mIncallWakeLock.release();

View file

@ -128,21 +128,28 @@ public class ApiNinePlus {
return list; return list;
} }
public static Cursor getContactsCursor(ContentResolver cr) { public static Cursor getContactsCursor(ContentResolver cr, String search) {
String req = Data.MIMETYPE + " = '" + CommonDataKinds.Phone.CONTENT_ITEM_TYPE String req = "(" + Data.MIMETYPE + " = '" + CommonDataKinds.Phone.CONTENT_ITEM_TYPE
+ "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL"; + "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL OR ("
+ Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL))";
req += " OR (" + Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE if (search != null) {
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL)"; req += " AND " + Data.DISPLAY_NAME + " LIKE '%" + search + "%'";
}
return ApiFivePlus.getGeneralContactCursor(cr, req, true); return ApiFivePlus.getGeneralContactCursor(cr, req, true);
} }
public static Cursor getSIPContactsCursor(ContentResolver cr) { public static Cursor getSIPContactsCursor(ContentResolver cr, String search) {
String req = null; String req = null;
req = Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE req = Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL"; + "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL";
if (search != null) {
req += " AND " + Data.DISPLAY_NAME + " LIKE '%" + search + "%'";
}
return ApiFivePlus.getGeneralContactCursor(cr, req, true); return ApiFivePlus.getGeneralContactCursor(cr, req, true);
} }

View file

@ -82,7 +82,15 @@ public class Compatibility {
public static Cursor getContactsCursor(ContentResolver cr) { public static Cursor getContactsCursor(ContentResolver cr) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) { if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
return ApiNinePlus.getContactsCursor(cr); return ApiNinePlus.getContactsCursor(cr, null);
} else {
return ApiFivePlus.getContactsCursor(cr);
}
}
public static Cursor getContactsCursor(ContentResolver cr, String search) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
return ApiNinePlus.getContactsCursor(cr, search);
} else { } else {
return ApiFivePlus.getContactsCursor(cr); return ApiFivePlus.getContactsCursor(cr);
} }
@ -90,7 +98,15 @@ public class Compatibility {
public static Cursor getSIPContactsCursor(ContentResolver cr) { public static Cursor getSIPContactsCursor(ContentResolver cr) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) { if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
return ApiNinePlus.getSIPContactsCursor(cr); return ApiNinePlus.getSIPContactsCursor(cr, null);
} else {
return ApiFivePlus.getSIPContactsCursor(cr);
}
}
public static Cursor getSIPContactsCursor(ContentResolver cr, String search) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
return ApiNinePlus.getSIPContactsCursor(cr, search);
} else { } else {
return ApiFivePlus.getSIPContactsCursor(cr); return ApiFivePlus.getSIPContactsCursor(cr);
} }