I'm developing an Android Auto like app, where I want to show the call log using recyclerview and cards.
This is working fine, but the call log is showing all the logs. Lets say that if I have received 3 calls from Peter, I don't want to see 3 entries showing this, with one entry enought. This will be like doing something like "most recent contacts" or something like that.
When using the recyclerview and cards, I've created 3 classes to hold the contacts info: The custom adapter, the contact info, and the custom view holder.
This is the ContactInfo class:
public class ContactInfo {
public int id;
public String name;
public String type;
public static final String ID_PREFIX = "ID_";
public static final String NAME_PREFIX = "Name_";
public static final String TYPE_PREFIX = "Type_";
}
Then, in the fragment where I show the call log, this is what I do to display the logs:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.phone_layout, container, false);
...
ContactAdapter contactAdapter = new ContactAdapter(DisplayCallLog());
...
return view;
}
private ArrayList<ContactInfo> DisplayCallLog() {
ArrayList<ContactInfo> data = new ArrayList<ContactInfo>();
int contactID = 0;
String contactNumber = null;
int logType = 0;
String contactName = null;
String contactType = null;
ContactInfo cI;
int resultLimit = 0;
//Check access to Call Log
if (ActivityCompat.checkSelfPermission(this.getActivity(), Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED) {
//Get phone numbers from call log
Cursor cursorCallLog = getActivity().getContentResolver().query(CallLog.Calls.CONTENT_URI,
null, null, null, CallLog.Calls.DATE + " DESC");
while (cursorCallLog.moveToNext() && resultLimit<6) {
contactNumber = cursorCallLog.getString(cursorCallLog.getColumnIndex(CallLog.Calls.NUMBER));
//We also get the call type: Incoming, Outgoing, missed
logType = cursorCallLog.getInt(cursorCallLog.getColumnIndex(CallLog.Calls.TYPE));
resultLimit++;
//With the phone number we search the ID
String number = Uri.encode(contactNumber);
Cursor cursorContactLookup = getActivity().getContentResolver().query(
Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
number),
new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME, ContactsContract.PhoneLookup._ID},
null, null, null);
while (cursorContactLookup.moveToNext()) {
contactID = cursorContactLookup
.getInt(cursorContactLookup
.getColumnIndexOrThrow(ContactsContract.PhoneLookup._ID));
//Get the contact name and phone type
Cursor cursorContactDetails = getActivity().getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[] {
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.TYPE,
},
ContactsContract.Data.CONTACT_ID + "=?",
new String[] {String.valueOf(contactID)}, null);
while (cursorContactDetails.moveToNext()) {
contactName = cursorContactDetails
.getString(cursorContactDetails
.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
int type = cursorContactDetails
.getInt(cursorContactDetails
.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.TYPE));
switch (type) {
case ContactsContract.CommonDataKinds.Phone.TYPE_HOME:
contactType = "Home";
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_WORK:
contactType = "Work";
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE:
contactType = "Mobile";
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_OTHER:
contactType = "Other";
break;
}
//Call contactinfo class and save into list
cI = new ContactInfo();
cI.id = contactID;
cI.name = contactName;
cI.type = contactType;
//cI.logType = logType;
//HERE: CHECK IF LIST DOES NOT CONTAIN CURRENT CONTACT
if (!data.contains(cI)) {
data.add(cI);
}
}
cursorContactDetails.close();
}
cursorContactLookup.close();
}
cursorCallLog.close();
}
return data;
}
The problem I'm having is that cI shows a string like this:
I/CONTACT_INFO: com.example_infodash.phone.ContactInfo#41c9e198
Where the last numbers are allways diferent even if the contact saved is the same. So it never finds the same contact in the list, even if is duplicated.
So my question is, how could I check if the contact saved is already in the list? I guess that the trouble in this case is because of the use of a custom class like ContactInfo.
The problem I'm having is that cI shows a string like this:
I/CONTACT_INFO: com.example_infodash.phone.ContactInfo#41c9e198
Solution for this problem: Override toString method in ContactInfo
public class ContactInfo {
public int id;
public String name;
public String type;
public static final String ID_PREFIX = "ID_";
public static final String NAME_PREFIX = "Name_";
public static final String TYPE_PREFIX = "Type_";
#Override
public String toString() {
return "{name: " + name + ", type: " + type + "}";
}
}
For ArrayList 'contains' problem, you have to override equals() in ContactInfo. Like this:
public class ContactModel {
public String name;
public String phone;
public ContactModel(String name, String phone) {
this.name = name;
this.phone = phone;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ContactModel that = (ContactModel) o;
if (name != null ? !name.equals(that.name) : that.name != null) return false;
return phone != null ? phone.equals(that.phone) : that.phone == null;
}
}
If you are in Android Studio you can create it automatically. Go to ContactInfo class, right click in it, choose:
Generate... -> equals() and hashCode()
Your equals() method:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ContactInfo that = (ContactInfo) o;
if (that.name.equals(name) && that.id == id) return true;
else return false;
}
Related
this is my service Interface
public interface ContactService {
void postPhoneContacts(#NonNull ContactServiceListener serviceListener, int id, List<UserProfileInfo> userInfo);
}
This is mybackground service from where i want to make a network call
How to intsantiate Contact Service Interface here? I am getting Null Pointer Exception. From Fragment I am starting this service. Please help me this out
public class UploadContactBgService extends Service {
private ContactService contactService;
private int userId;
#Override
public void onCreate() {
super.onCreate();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
List<UserProfileInfo> contactList = getContactsFromPhone();
EventBus.getDefault().post(new PostContactEvent(contactList));
/* SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
userId = prefs.getInt(LoginPresenter.PREF_USER_ID, 0);
if (userId != 0) {
postPhoneBookContactList(userId, contactList);
}*/
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
private List<UserProfileInfo> getContactsFromPhone() {
//Read Column names of ContactsContract table to get contact info from phone book
Uri CONTENT_URI = ContactsContract.Contacts.CONTENT_URI;
Uri DATA_CONTENT_URI = ContactsContract.Data.CONTENT_URI;
String ID = ContactsContract.Contacts._ID;
String DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME;
String PHONE_CONTENT_ITEM_TYPE = ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE;
String EMAIL_CONTENT_ITEM_TYPE = ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE;
String DATA_CONTACT_ID = ContactsContract.Data.CONTACT_ID;
String ADDRESS_CONTENT_ITEM_TYPE = ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE;
String ORG_CONTENT_ITEM_TYPE = ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE;
String DATA_MIME_TYPE = ContactsContract.Data.MIMETYPE;
String HAS_PHONE_NUMBER = ContactsContract.Contacts.HAS_PHONE_NUMBER;
String EVENT_CONTENT_ITEM_TYPE = ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE;
String EVENT_START_DATE = ContactsContract.CommonDataKinds.Event.START_DATE;
String NOTE_CONTENT_ITEM_TYPE = ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE;
String WEB_CONTENT_ITEM_TYPE = ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE;
String RELATION_CONTENT_ITEM_TYPE = ContactsContract.CommonDataKinds.Relation.CONTENT_ITEM_TYPE;
int CONTACT_TYPE_MOBILE = 1;
int CONTACT_TYPE_WORK = 2;
int CONTACT_TYPE_HOME = 3;
int CONTACT_TYPE_WORK_FAX = 4;
int CONTACT_TYPE_HOME_FAX = 5;
int CONTACT_TYPE_PAGER = 6;
int CONTACT_TYPE_OTHER = 7;
int USER_PROFILE_TYPE = 2;
ContentResolver cr = this.getContentResolver();
Cursor cursor = cr.query(CONTENT_URI, null, null, null,
DISPLAY_NAME + " ASC ");
List<UserProfileInfo> userInfoList = new ArrayList<>();
if (cursor.moveToNext()) {
do {
String contactId = cursor.getString(cursor.getColumnIndex(ID));
UserProfileInfo userInfo = new UserProfileInfo();
UserProfile profile = new UserProfile();
UserType userType = new UserType();
/**
* Querying the table ContactsContract.Data to retrieve individual items like
home phone, mobile phone, work email etc corresponding to each contact
*/
Cursor dataCursor = cr.query(DATA_CONTENT_URI, null,
DATA_CONTACT_ID + "=" + contactId,
null, null);
if (dataCursor.moveToFirst()) {
/**
* checking if respective contactId has contact number or not
* If yes..then only add that user to list
* otherwise read next user
*/
int hasContactNumber = Integer.parseInt(dataCursor.getString(
dataCursor.getColumnIndex(HAS_PHONE_NUMBER)));
if (hasContactNumber == 0) {
continue;
}
// Getting Display Name
String displayName = dataCursor.getString(dataCursor.getColumnIndex(DISPLAY_NAME));
profile.setName(displayName);
do {
// Getting Phone numbers
List<Contact> phones = new ArrayList<>();
if (dataCursor.getString(dataCursor.getColumnIndex(DATA_MIME_TYPE)).equals(PHONE_CONTENT_ITEM_TYPE)) {
Contact contactNum = new Contact();
ContactTypeDm contactTypeDm = new ContactTypeDm();
switch (dataCursor.getInt(dataCursor.getColumnIndex("data2"))) {
case ContactsContract.CommonDataKinds.Phone.TYPE_HOME:
String homePhone = dataCursor.getString(dataCursor.getColumnIndex("data1"));
userInfo.setUserName(homePhone);
contactNum.setContactNumber(homePhone);
contactTypeDm.setContactTypeId(CONTACT_TYPE_HOME);
contactNum.setContactTypeDm(contactTypeDm);
phones.add(contactNum);
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE:
String mobilePhone = dataCursor.getString(dataCursor.getColumnIndex("data1"));
userInfo.setUserName(mobilePhone);
contactNum.setContactNumber(mobilePhone);
contactTypeDm.setContactTypeId(CONTACT_TYPE_MOBILE);
contactNum.setContactTypeDm(contactTypeDm);
phones.add(contactNum);
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_WORK:
String workPhone = dataCursor.getString(dataCursor.getColumnIndex("data1"));
userInfo.setUserName(workPhone);
contactNum.setContactNumber(workPhone);
contactTypeDm.setContactTypeId(CONTACT_TYPE_WORK);
contactNum.setContactTypeDm(contactTypeDm);
phones.add(contactNum);
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_OTHER:
String other = dataCursor.getString(dataCursor.getColumnIndex("data1"));
userInfo.setUserName(other);
contactNum.setContactNumber(other);
contactTypeDm.setContactTypeId(CONTACT_TYPE_OTHER);
contactNum.setContactTypeDm(contactTypeDm);
phones.add(contactNum);
break;
}
userInfo.setContacts(phones);
}
// Getting EMails
if (dataCursor.getString(dataCursor.getColumnIndex(DATA_MIME_TYPE)).equals(EMAIL_CONTENT_ITEM_TYPE)) {
switch (dataCursor.getInt(dataCursor.getColumnIndex("data2"))) {
case ContactsContract.CommonDataKinds.Email.TYPE_HOME:
String homeEmail = dataCursor.getString(dataCursor.getColumnIndex("data1"));
profile.setEmail(homeEmail);
break;
case ContactsContract.CommonDataKinds.Email.TYPE_WORK:
String workEmail = dataCursor.getString(dataCursor.getColumnIndex("data1"));
profile.setEmail(workEmail);
break;
}
}
// Getting Organization details
if (dataCursor.getString(dataCursor.getColumnIndex(DATA_MIME_TYPE)).equals(ORG_CONTENT_ITEM_TYPE)) {
String companyName = dataCursor.getString(dataCursor.getColumnIndex("data1"));
String title = dataCursor.getString(dataCursor.getColumnIndex("data4"));
profile.setOrgName(companyName);
profile.setTitle(title);
}
// Getting BDay
if (dataCursor.getString(dataCursor.getColumnIndex(DATA_MIME_TYPE)).equals(EVENT_CONTENT_ITEM_TYPE)) {
int indexEvent = dataCursor.getColumnIndex(EVENT_START_DATE);
String dobStr = dataCursor.getString(indexEvent);
profile.setBDay(dobStr);
}
//Getting Note
if (dataCursor.getString(dataCursor.getColumnIndex(DATA_MIME_TYPE)).equals(NOTE_CONTENT_ITEM_TYPE)) {
String note = dataCursor.getString(dataCursor.getColumnIndex("data1"));
profile.setNotes(note);
}
//Getting Postal Address Details...
if (dataCursor.getString(dataCursor.getColumnIndex(DATA_MIME_TYPE)).equals(ADDRESS_CONTENT_ITEM_TYPE)) {
String street = dataCursor.getString(dataCursor.getColumnIndex("data4"));
String city = dataCursor.getString(dataCursor.getColumnIndex("data7"));
String state = dataCursor.getString(dataCursor.getColumnIndex("data8"));
String postalCode = dataCursor.getString(dataCursor.getColumnIndex("data9"));
Address addressInfo = new Address();
addressInfo.setStreet(street);
addressInfo.setCity(city);
addressInfo.setZip(postalCode);
addressInfo.setState(state);
userInfo.setAddress(addressInfo);
}
//Getting Website
if (dataCursor.getString(dataCursor.getColumnIndex(DATA_MIME_TYPE)).equals(WEB_CONTENT_ITEM_TYPE)) {
String webUrl = dataCursor.getString(dataCursor.getColumnIndex("data1"));
profile.setWebsite(webUrl);
}
//Getting Relation
if (dataCursor.getString(dataCursor.getColumnIndex(DATA_MIME_TYPE)).equals(RELATION_CONTENT_ITEM_TYPE)) {
String relationship = dataCursor.getString(dataCursor.getColumnIndex("data1"));
profile.setRelationShip(relationship);
}
}
while (dataCursor.moveToNext());
}
userType.setUserTypeId(USER_PROFILE_TYPE);
profile.setUserType(userType);
userInfo.setUserProfile(profile);
userInfoList.add(userInfo);
} while (cursor.moveToNext());
}
return userInfoList;
}
public void postPhoneBookContactList(int id, List<UserProfileInfo> userInfoList) {
contactService.postPhoneContacts(new ContactServiceListener() {
#Override
public void onSuccess(UserProfileInfo responseBody) {
EventBus.getDefault().post(new GetSyncedContactListEvent(responseBody));
}
#Override
public void onError(String error) {
}
}, id, userInfoList);
}
}
I'm trying to adapt my data from my SQLite database to my ListView, when the table has some lines, there is no problem, but when I delete all the inserts from the table, I have an error:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.String.toString()' on a null object reference
My adapter's code:
public class AdapterTop extends ArrayAdapter<Top> {
private LayoutInflater mInflat;
private ArrayList<Top> top = new ArrayList<Top>();
private int mVRessId;
public AdapterTop (Context context, int ressId, ArrayList<Top> topu){
super(context,ressId,topu);
this.top =topu;
mInflat = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mVRessId =ressId;
}
public View getView(int position, View convertedView, ViewGroup parents){
convertedView = mInflat.inflate(mVRessId,null);
Top topu = top.get(position);
if (topu != null) {
TextView name = (TextView) convertedView.findViewById(R.id.txtnomp);
TextView nbre = (TextView) convertedView.findViewById(R.id.txtnbre);
if (name != null) {
name.setText("" + topu.getNom() + ": " + topu.getPrenom());
}
if (nbre != null) {
nbre.setText(String.valueOf(+topu.getNum()));
}
}
return convertedView;
}
}
The function used to return the cursor:
public Cursor topuser(){
SQLiteDatabase db = this.getReadableDatabase();;
Cursor data = db.rawQuery("Select U." +KEY_NOM+ ", U." +KEY_PRENOM+ ", count (A." +KEY_MATRICULE+ " ) FROM " +TABLE_ANSWER+ " A, "+TABLE_USER+ " U where U." +KEY_MATRICULE+ " = A." +KEY_MATRICULE+ " LIMIT 3",null );
return data;
}
My main java code:
ArrayList<Top> users;
Top top;
mCsr = openhelper.topuser();
int rows = mCsr.getCount();
if (rows == 0) {
Toast.makeText(Kpis.this, "no users", Toast.LENGTH_LONG).show();
} else {
while (mCsr.moveToNext()) {
top = new Top(mCsr.getString(0).toString(), mCsr.getString(1).toString(), mCsr.getInt(2));
users.add(top);
}
AdapterTop adapttop = new AdapterTop(this, R.layout.activity_template_top_users, users);
mListView.setAdapter(adapttop);
}
Is there any problem with that? I did the condition if (rows == 0) tu avoid this but still have the same problem.
The Top classe is made like that:
public class Top {
private String nom;
private String prenom;
private int num;
public Top(String nom, String prenom, int num) {
this.nom = nom;
this.prenom = prenom;
this.num = num;
}
public String getNom() {
return nom;
}
public String getPrenom() {
return prenom;
}
public int getNum() {
return num;
}
}
I tried to initiate the top when creating it but didn't work.
I did the condition if (rows == 0) tu avoid this but still have the same problem.
It'll prevent you getting an out of bounds exception, but probably when you saved your data, the columns were nullable. So do you have records, but this record have some field null.
At this point:
top = new Top(mCsr.getString(0).toString(), mCsr.getString(1).toString(), mCsr.getInt(2));
You are calling toString() on something you do know what.
So the easy way to handle this error would be:
String noum = "";
if(mCsr.getString(0) != null){
noum = mCsr.getString(0).toString()
}
String preNoum = "";
if(mCsr.getString(1) != null){
preNoum = mCsr.getString(1).toString()
}
top = new Top(noum, preNoum, mCsr.getInt(2));
You could improve your code with some patterns, but it'll do the trick.
The situation:
I've added a custom action to a contact in Android following the instructions in this question and the related sample app on GitHub. When pressed I want to dial that contact in my application. I am able to successfully retrieve the Contact in the Activity that is opened when the custom action is pressed.
I execute this:
Cursor cursor = context.getContentResolver().query(data, null, null, null, null);
if (cursor != null) {
newIntent = true;
contact = LocalContactAsync.getContacts(cursor, context.getContentResolver()).get(0);
cursor.close();
}
And the data I retrieve from Android is:
content://com.android.contacts/data/2849
Notice the number 2849 at the end, this is not the native ID of the contact. The native ID of the contact is 459. I am able to successfully retrieve the contact executing this query, the following data returns:
cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID);
-returns '2849'
cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)) ;
-returns 'sample samplee' wich is correct
But although this is true:
cursor.getInt(cur.getColumnIndex(
ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0)
The following function returns an empty cursor:
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
new String[]{id}, null);
-id = 2849 in this case but if I fill in 459 I retrieve the right amount of telephone numbers
The real contact has 3 numbers so it should return 3 numbers.
How am I able to fix this?
Edited:
This is how I retrieve numbers, to be clear: I get the correct name, but the following query returns null while the contact has numbers.
ArrayList<Number> numbers = new ArrayList<>();
if (cur.getInt(cur.getColumnIndex(
ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) {
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
new String[]{id}, null);
while (pCur.moveToNext()) {
numbers.add(new nl.coffeeit.clearvoxnexxt.objects.dto.Number(pCur.getString(pCur.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER))));
}
pCur.close();
}
return numbers;
Please note that I do not request an intent, I receive it through a custom action that is added to a native contact, like Viber and WhatsApp do:
Full code LocalContacts Async:
private static final String TAG = "LocalContactAsync";
private static List<Contact> contacts;
private Context context;
private boolean refreshOtherFragments;
private boolean renew;
private synchronized List<Contact> getContacts(Context context) {
if (!renew && contacts != null) {
return contacts;
}
ContentResolver cr = context.getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
null, null, null, null);
if (cur != null && cur.getCount() > 0) {
contacts = getContacts(cur, cr);
cur.close();
return contacts;
}
if (cur != null) {
cur.close();
}
return new ArrayList<>();
}
public static List<Contact> getContacts(Cursor cur, ContentResolver cr) {
List<Contact> contacts = new ArrayList<>();
while (cur.moveToNext()) {
String id = getId(cur);
String name = getName(cur);
ArrayList<Number> numbers = getNumbers(cur, cr, id);
if (name != null) {
contacts.add(new Contact(id, name, numbers));
}
}
Log.d(TAG, "amount of contacts" + contacts.size());
return contacts;
}
private static ArrayList<Number> getNumbers(Cursor cur, ContentResolver cr, String id) {
ArrayList<Number> numbers = new ArrayList<>();
if (cur.getInt(cur.getColumnIndex(
ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) {
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
new String[]{id}, null);
while (pCur.moveToNext()) {
numbers.add(getNumber(pCur));
}
pCur.close();
}
return numbers;
}
private static Number getNumber(Cursor pCur) {
return new nl.coffeeit.clearvoxnexxt.objects.dto.Number(pCur.getString(pCur.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER)));
}
private static String getId(Cursor cur) {
return cur.getString(
cur.getColumnIndex(ContactsContract.Contacts._ID));
}
private static String getName(Cursor cur) {
return cur.getString(cur.getColumnIndex(
ContactsContract.Contacts.DISPLAY_NAME));
}
Code for Number DTO:
public class Number implements Parcelable, Serializable {
#SerializedName("number")
#Expose
public String number;
#SerializedName("type")
#Expose
public String type = "";
#SerializedName("inherited")
#Expose
public Boolean inherited = false;
public Number(String number) {
this.number = number;
}
protected Number(Parcel in) {
number = in.readString();
type = in.readString();
byte inheritedVal = in.readByte();
inherited = inheritedVal == 0x02 ? null : inheritedVal != 0x00;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(number);
dest.writeString(type);
if (inherited == null) {
dest.writeByte((byte) (0x02));
} else {
dest.writeByte((byte) (inherited ? 0x01 : 0x00));
}
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<Number> CREATOR = new Parcelable.Creator<Number>() {
#Override
public Number createFromParcel(Parcel in) {
return new Number(in);
}
#Override
public Number[] newArray(int size) {
return new Number[size];
}
};
public Number setNumber(String number) {
this.number = number;
return this;
}
}
The first thing to notice is that a call to the contacts picker like this:
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
will return a Uri like this:
content://com.android.contacts/contacts/lookup/3163r328-4D2941473F314D2941473F3131/328
The second to last path (3163r....) is the lookup key, while 328 is the NAME_RAW_ID.
Compare this with the Intent you get from the sample application. This contains an Uri that looks like this:
content://com.android.contacts/data/2849
As you have said, calling the content resolver with this Uri is not sufficient to retrieve phone numbers, although it may be used to retrieve the name of the contact and the id. So we will use the incomplete Intent Uri to construct a new Lookup Uri that we can use to get the phone numbers.
Let's add the following methods to your LocalContactAsync (I won't refactor anything you have done so far, I'll just add in the style you have used):
public static Uri getLookupUri(Cursor cur) {
return getContentUri(getLookupKey(cur), getNameRawId(cur));
}
private static String getLookupKey(Cursor cur) {
return cur.getString(
cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
}
private static String getNameRawId(Cursor cur) {
return cur.getString(cur.getColumnIndex(ContactsContract.Contacts.NAME_RAW_CONTACT_ID));
}
private static Uri getContentUri(String lookupKey, String nameRawId) {
return new Uri.Builder()
.scheme("content")
.authority("com.android.contacts")
.appendPath("contacts")
.appendPath("lookup")
.appendPath(lookupKey)
.appendPath(nameRawId)
.build();
}
Let's alter the ViewingActivity inside the sample application so that it actually retrieves the contact details. We can now do that with the following code inside onResume():
#Override
protected void onResume() {
super.onResume();
Uri uri = getIntent().getData();
Cursor intentCursor = this.getContentResolver().query(uri, null, null, null, null);
Contact contact = null;
if (intentCursor != null) {
intentCursor.moveToFirst();
Uri lookupUri = LocalContactAsync.getLookupUri(intentCursor);
Cursor lookupCursor = this.getContentResolver().query(lookupUri, null, null, null, null);
contact = LocalContactAsync.getContacts(lookupCursor, this.getContentResolver()).get(0);
intentCursor.close();
lookupCursor.close();
}
}
The contact will now contain the phone numbers as required.
I have code to get phone contact from server in android , I use menu item to make it , this is my code
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
int row = cursor.getCount();
friend_item = new MenuItem [row];
//int i=0;
while(cursor.moveToNext()){
nama = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
phone = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
// friend_item[i] = new MenuItem(nama,phone);
//i++;
}
cursor.moveToFirst();
while(!cursor.isAfterLast()){
Log.d("", "" + cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
phone = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
phoneList.add(phone);
cursor.moveToNext();
}
cursor.close();
String [] phonearray = (String[]) phoneList.toArray(new String[phoneList.size()]);
// friendarray();
String friends=phonearray[0]+"";
for(int a=1; a<phonearray.length; a++){
friends = friends + ","+ phonearray[a];
}
Log.d("" , "" + friends);
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("phone", mPhoneNumber));
params.add(new BasicNameValuePair("friend", friends));
// getting JSON string from URL
JSONObject json = jParser.makeHttpRequest(Constants.url_phone_contact, "POST", params);
// Check your log cat for JSON reponse
Log.d("All Friend: ", json.toString());
try {
friend = json.getJSONArray("friend");
friend_item = new MenuItem[friend.length()];
// looping through All Products
for (int a = 0; a < friend.length(); a++) {
JSONObject c = friend.getJSONObject(a);
//Storing each json item in variable
phone_friend= c.getString("phone");
id_friend = c.getString("id_ref");
Log.e("id_user", id_friend);
namaFriend = getName(phone_friend);
if(phone_friend == null){
Toast.makeText(getApplicationContext(), "contact not found", Toast.LENGTH_LONG).show();
}else{
friend_item[a] = new MenuItem(namaFriend, phone_friend);
// creating new HashMap
HashMap<String, String> map1 = new HashMap<String, String>();
// adding each child node to HashMap key => value
//map1.put("phone", mPhoneNumber);
map1.put("id_ref", id_friend);
map1.put("nama_friend", namaFriend);
// adding HashList to ArrayList
friendList.add(map1);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
//i++;*/
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url) {
pDialog.dismiss();
if(friend_item != null && friend_item.length > 0){
mainlist.setAdapter(new ListMenuAdapter(friend_item));
} else
Toast.makeText(getApplicationContext(), "You don't have friend using Shoop! yet, please invite them :)", Toast.LENGTH_LONG).show();
}
}
to get name from android device , I use this code
private String getName(String number) {
// define the columns I want the query to return
String[] projection = new String[] {
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER};
// encode the phone number and build the filter URI
Uri contactUri = Uri.withAppendedPath(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI, Uri.encode(number));
// query time
Cursor c = getContentResolver().query(contactUri, projection, null,
null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME +" ASC");
// if the query returns 1 or more results
// return the first result
if (c.moveToFirst()) {
String name = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
return name;
}
// return the original number if no match was found
return number;
}
this List menu adapter
private class ListMenuAdapter extends BaseAdapter{
private MenuItem [] item;
protected ListMenuAdapter(MenuItem... item){
this.item = item;
}
public int getCount() {
return item.length;
}
public Object getItem(int pos) {
return item[pos];
}
public long getItemId(int position) {
return position;
}
public ViewGroup getViewGroup(int position, View view, ViewGroup parent){
if(view instanceof ViewGroup){
return (ViewGroup) view;
}
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
ViewGroup viewgroup = (ViewGroup)inflater.inflate(R.layout.custom_content_friend, null);
return viewgroup;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewGroup group = getViewGroup(position, convertView, parent);
MenuItem menu = item[position];
TextView name = (TextView) group.findViewById(R.id.content_friend_myname);
TextView phone = (TextView) group.findViewById(R.id.content_friend_desc);
if(menu.my_name == null || menu.phone == null){
Toast.makeText(getApplicationContext(), "Contact not found", Toast.LENGTH_LONG).show();
}else{
name.setText(menu.my_name);
phone.setText(menu.phone);
}
return group;
}
}
private class MenuItem{
private String my_name, phone;
protected MenuItem(String my_name, String phone){
this.my_name = my_name;
this.phone= phone;
}
}
and now , I want to get List view that contain name and phone with sorting ascending by name , How to do that?? thanks for ur advice
- First use an ArrayList instead of Array to store the data which will further being used by the Adapter.
- Use java.util.Comparator<T> to sort the name and phone (ie. contacts) according to the name.
- Use Collections.sort(List<?> l , Comparator c) to invoke the sorting.
- And also call notifyDataSetChanged() on the Adapter after setting the ListView with the adapter.
Eg:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
class Car {
private String name;
private String brand;
private double cost;
public Car(String name, String brand, double cost) {
this.name = name;
this.brand = brand;
this.cost = cost;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getCost() {
return cost;
}
public void setCost(double cost) {
this.cost = cost;
}
public String toString() {
return getName();
}
}
public class Hog {
ArrayList<Car> cars = new ArrayList<Car>();
public void setIt() {
cars.add(new Car("Padmini", "Fiat", 100008.00));
cars.add(new Car("XYlo", "Mahindra", 100000.00));
cars.add(new Car("Swift", "Maruti", 200000.00));
}
public void sortIt() {
Collections.sort(cars, new NameComparator());
System.out.println(cars);
Collections.sort(cars, new BrandComparator());
System.out.println(cars);
Collections.sort(cars, new CostComparator());
System.out.println(cars);
}
class NameComparator implements Comparator<Car> {
public int compare(Car c1, Car c2) {
return c1.getName().compareTo(c2.getName());
}
}
class BrandComparator implements Comparator<Car> {
public int compare(Car c1, Car c2) {
return c1.getBrand().compareTo(c2.getBrand());
}
}
class CostComparator implements Comparator<Car> {
public int compare(Car c1, Car c2) {
return new Double(c1.getCost()).compareTo(new Double(c2.getCost()));
}
}
public static void main(String[] args) {
Hog h = new Hog();
h.setIt();
h.sortIt();
}
}
In your activity class write this:
public class MyActivity extends Activity {
....
private ListView listView01;
private ArrayList<MenuItem> list;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ...
listView01 = (ListView)findViewById(R.id.listView1);
list=new ArrayList<MyActivity.MenuItem>();
// code to fill your ArrayList
Collections.sort(list, myComparator);
listView01.setAdapter(new ListMenuAdapter());
}
Comparator<MenuItem> myComparator = new Comparator<MenuItem>()
{
public int compare(MenuItem arg0,MenuItem arg1)
{
return arg0.my_name.compareTo(arg1.my_name);
}
};
}
I have two buttons inside of my application, one for next and one for prev. I want the next button to get the next record inside of my database and display it inside of my view, and the prev button to get the previous record and display it inside of my view. How would I call the next or previous record? I have looked for tutorials and stuff but didn't find any. I anyone has a tutorial please share with me. Thanks for any help. I wish I had some code to provide but I really don't know where to start.
I use an int to pull the record from the dbase.
From my ContactView class
static long record = 1;
public void getData() {
DBase db = new DBase(this);
db.open();
lastRecord = db.lRec();
firstRecord = db.fRec();
rRec = db.getRec(record);
db.close();
}
then my query is from my Dbase class
public String[] getRec(long record) {
record = ContactView.record;
String[] columns = new String[] { KEY_ROWID, KEY_ONE, KEY_TWO,
KEY_THREE, KEY_FOUR, KEY_FIVE, KEY_SIX };
Cursor c = ourDatabase.query(DATABASE_TABLE, columns, KEY_ROWID + "="
+ record, null, null, null, null);
if (c != null && c.moveToFirst()) {
String rRec = c.getString(0);
String rOne = c.getString(1);
String rTwo = c.getString(2);
String rThree = c.getString(3);
String rFour = c.getString(4);
String rFive = c.getString(5);
String rSix = c.getString(6);
String[] rData = { rRec, rOne, rTwo, rThree, rFour,
rFive, rSix };
return rData;
}
return null;
}
and the next few are from my ContactView class
my buttons
#Override
public void onClick(View arg0) {
switch (arg0.getId()) {
case R.id.bSQLvPrev:
recordMinus();
display();
break;
case R.id.bSQLvNext:
recordPlus();
display();
break;
}
}
and the methods they call
public void display() {
etSQLvRec.setText(rRec[0]);
etSQLvOne.setText(rRec[1]);
etSQLvTwo.setText(rRec[2]);
etSQLvThree.setText(rRec[3]);
etSQLvFour.setText(rRec[4]);
etSQLvFive.setText(rRec[5]);
etSQLvSix.setText(rRec[6]);
}
public void recordPlus() {
record++;
}
public void recordMinus() {
record--;
}
That will get the record from the database based on the "record" variable, and the buttons increment it, or decrement it, it also skips any "empty" records.
EDIT OK, I had changed some stuff around since I lasted used my db, so use the next recordPlus() and recordMinus() code instead
public void recordPlus() {
if (record < lastRecord) {
record++;
} else {
record = firstRecord;
}
getData();
do {
if (record < lastRecord) {
record++;
} else {
record = firstRecord;
}
getData();
} while (rRec == null);
}
public void recordMinus() {
if (record == 1) {
record = lastRecord;
} else {
record--;
}
getData();
do {
if (record == 1) {
record = lastRecord;
} else {
record--;
}
getData();
} while (rRec == null);
}
And you'll need my fRec() and lRec() which find the first and last records in the DB
public long fRec() {
Cursor c = ourDatabase.query(DATABASE_TABLE, new String[] { "min(" +
KEY_ROWID
+ ")" }, null, null, null, null, null);
c.moveToFirst();
long rowID = c.getInt(0);
return rowID;
}
}
public long lRec() {
long lastRec = 0;
String query = "SELECT ROWID from Table order by ROWID DESC limit 1";
Cursor c = ourDatabase.rawQuery(query, null);
if (c != null && c.moveToFirst()) {
lastRec = c.getLong(0);
}
return lastRec;
}