Simple search function for contacts
This commit is contained in:
parent
4774e9dd71
commit
63343b607e
5 changed files with 152 additions and 24 deletions
|
@ -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">
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue