I am trying to make an app that will access my phone's contact list then pick a contact and show the name, number, id, and the display picture. i can access contact . when I press the addFab button it shows my phones contactlist but when I pick a contact using the cursor the app crashes. I have also tried with a physical phone but same result. I am getting this ERROR:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.sosandvideo, PID: 11666
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=2, result=-1, data=Intent { dat=content://com.android.contacts/contacts/lookup/0r2-2C/2 flg=0x1 }} to activity {com.example.sosandvideo/com.example.sosandvideo.MainActivity}: android.database.sqlite.SQLiteException: near "2": syntax error (code 1 SQLITE_ERROR): , while compiling: SELECT phonetic_name, status_updates.status_res_package AS status_res_package, custom_ringtone, contacts_status_updates.status_ts AS contact_status_ts, account_type, data_version, photo_file_id, contacts_status_updates.status_res_package AS contact_status_res_package, group_sourceid, display_name_alt, sort_key_alt, presence.mode AS mode, 0 AS last_time_used, starred, contacts_status_updates.status_label AS contact_status_label, has_phone_number, presence.chat_capability AS chat_capability, raw_contact_id, carrier_presence, contact_last_updated_timestamp, res_package, photo_uri, data_sync4, phonebook_bucket, 0 AS times_used, display_name, sort_key, data_sync1, version, data_sync2, data_sync3, photo_thumb_uri, status_updates.status_label AS status_label, agg_presence.mode AS contact_presence, in_default_directory, 0 AS times_contacted, _id, account_type_and_data_set, name_raw_contact_id, status_updates.status AS status, phonebook_bucket_alt, 0 AS last_time_contacted, pinned, is_primary, photo_id, contact_id, agg_presence.chat_capability AS contact_chat_capability, contacts_status_updates.status_icon AS contact_status_icon, in_visible_group, phonebook_label, account_name, display_name_source, data9, dirty, sourceid, phonetic_name_style, send_to_voicemail, data8, lookup, data7, data6, phonebook_label_alt, data5, is_super_primary, data4, data3, data2, data1, data_set, contacts_status_updates.status AS contact_status, backup_id, preferred_phone_account_component_name, raw_contact_is_user_profile, status_updates.status_ts AS status_ts, data10, preferred_phone_account_id, data12, mimetype, status_updates.status_icon AS status_icon, data11, data14, data13, hash_id, data15 FROM view_data data LEFT OUTER JOIN agg_presence ON (contact_id = agg_presence.presence_contact_id) LEFT OUTER JOIN status_updates contacts_status_updates ON (status_update_id=contacts_status_updates.status_update_data_id) LEFT OUTER JOIN presence ON (presence_data_id=data._id) LEFT OUTER JOIN status_updates ON (status_updates.status_update_data_id=data._id) LEFT OUTER JOIN (SELECT 0 as STAT_DATA_ID,0 as x_times_used, 0 as x_last_time_used,0 as times_used, 0 as last_time_used where 0) as data_usage_stat ON (STAT_DATA_ID=data._id) WHERE (1 AND mimetype_id=5) AND (contact_id 2)
at android.app.ActivityThread.deliverResults(ActivityThread.java:5015)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:5056)
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: android.database.sqlite.SQLiteException: near "2": syntax error (code 1 SQLITE_ERROR): , while compiling: SELECT phonetic_name, status_updates.status_res_package AS status_res_package, custom_ringtone, contacts_status_updates.status_ts AS contact_status_ts, account_type, data_version, photo_file_id, contacts_status_updates.status_res_package AS contact_status_res_package, group_sourceid, display_name_alt, sort_key_alt, presence.mode AS mode, 0 AS last_time_used, starred, contacts_status_updates.status_label AS contact_status_label, has_phone_number, presence.chat_capability AS chat_capability, raw_contact_id, carrier_presence, contact_last_updated_timestamp, res_package, photo_uri, data_sync4, phonebook_bucket, 0 AS times_used, display_name, sort_key, data_sync1, version, data_sync2, data_sync3, photo_thumb_uri, status_updates.status_label AS status_label, agg_presence.mode AS contact_presence, in_default_directory, 0 AS times_contacted, _id, account_type_and_data_set, name_raw_contact_id, status_updates.status AS status, phonebook_bucket_alt, 0 AS last_time_contacted, pinned, is_primary, photo_id, contact_id, agg_presence.chat_capability AS contact_chat_capability, contacts_status_updates.status_icon AS contact_status_icon, in_visible_group, phonebook_label, account_name, display_name_source, data9, dirty, sourceid, phonetic_name_style, send_to_voicemail, data8, lookup, data7, data6, phonebook_label_alt, data5, is_super_primary, data4, data3, data2, data1, data_set, contacts_status_updates.status AS contact_status, backup_id, preferred_phone_account_component_name, raw_contact_is_user_profile, status_updates.status_ts AS status_ts, data10, preferred_phone_account_id, data12, mimetype, status_updates.status_icon AS status_icon, data11, data14, data13, hash_id, data15 FROM view_data data LEFT OUTER JOIN agg_presence ON (contact_id = agg_presence.presence_contact_id) LEFT OUTER JOIN status_updates contacts_status_updates ON (status_update_id=contacts_status_updates.status_update_data_id) LEFT OUTER JOIN presence ON (presence_data_id=data._id) LEFT OUTER JOIN status_updates ON (status_updates.status_update_data_id=data._id) LEFT OUTER JOIN (SELECT 0 as STAT_DATA_ID,0 as x_times_used, 0 as x_last_time_used,0 as times_used, 0 as last_time_used where 0) as data_usage_stat ON (STAT_DATA_ID=data._id) WHERE (1 AND mimetype_id=5) AND (contact_id 2)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:186)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:472)
at android.content.ContentResolver.query(ContentResolver.java:1183)
at android.content.ContentResolver.query(ContentResolver.java:1115)
at android.content.ContentResolver.query(ContentResolver.java:1071)
at com.example.sosandvideo.MainActivity.onActivityResult(MainActivity.java:130)
at android.app.Activity.dispatchActivityResult(Activity.java:8304)
at android.app.ActivityThread.deliverResults(ActivityThread.java:5008)
... 11 more
Here are the relevant code that I have used:
package com.example.sosandvideo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.nfc.Tag;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import org.jetbrains.annotations.NotNull;
public class MainActivity extends AppCompatActivity {
// private Button add;
private ImageView thumbnailTv;
private TextView contactTv;
private FloatingActionButton addFab;
private static final int CONTACT_PERMISSION_CODE = 1;
private static final int CONTACT_PICK_CODE = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
thumbnailTv = findViewById(R.id.thumbnailTv);
contactTv = findViewById(R.id.contactTv);
addFab = findViewById(R.id.addFab);
addFab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//first we need to check contact permission
if (checkContactPermission()) {
//if granted, pick a contact
pickContact();
} else {
//not granted request for permission
requestContactPermission();
}
}
});
}
private Boolean checkContactPermission() {
//checking if the contact permission is granted or not
boolean result = ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_CONTACTS) == (PackageManager.PERMISSION_GRANTED);
return result;// true if granted or false
}
private void requestContactPermission() {
//permission to request
String[] permission = {Manifest.permission.READ_CONTACTS};
ActivityCompat.requestPermissions(this, permission, CONTACT_PERMISSION_CODE);
}
private void pickContact() {
//intent to pick contact
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, CONTACT_PICK_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull @NotNull String[] permissions, @NonNull @NotNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// handle request for permission
if (requestCode == CONTACT_PERMISSION_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//permission granted now we can pick contacts
pickContact();
} else {
//permission denied
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show();
}
}
}
@SuppressLint("Range")
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable @org.jetbrains.annotations.Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//handle intent results
if (resultCode == RESULT_OK) {
//calls when user pick a contact from the list
if (requestCode == CONTACT_PICK_CODE) {
Cursor cursor1;
Cursor cursor2;
//get data from intent
Uri uri = data.getData();
cursor1 = getContentResolver().query(uri, null, null, null, null);
if (cursor1.moveToFirst()) {
//get contact date
String contactId = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts._ID));
String contactName = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
String contactThumnail = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.PHOTO_THUMBNAIL_URI));
String idResult = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
int idResulthold = Integer.parseInt(idResult);
if (idResulthold == 1) {
cursor2 = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID " " contactId,
null,
null);
while (cursor2.moveToNext()) {
String contactNum = cursor2.getString(cursor2.getColumnIndex
(ContactsContract.CommonDataKinds.Phone.NUMBER));
contactTv.append("ID" contactId);
contactTv.append("\nName" contactName);
contactTv.append("\nNumber" contactNum);
contactTv.append("\n\n");
if (contactThumnail != null) {
thumbnailTv.setImageURI(Uri.parse(contactThumnail));
} else {
thumbnailTv.setImageResource(R.drawable.ic_baseline_person_24);
}
}
cursor2.close();
}
cursor1.close();
}
}
} else {
//calls when user pressed back button or haven't selected any contacts
}
}
}
Here is the manifest code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.sosandvideo">
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.SOSandVideo">
<activity android:name=".Home"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity">
</activity>
</application>
</manifest>
How can I solve this ERROR
CodePudding user response:
shrinking down your error log to the relevant parts...
SQLiteException: near "2": ... while compiling: SELECT ... contact_id 2
your SQL should be SELECT ... contact_id=2
In your source code you have this snipped that looks kind of wrong...
ContactsContract.CommonDataKinds.Phone.CONTACT_ID " " contactId,
The way you are concating your sql statement you are prone to sql injection you should read more on that topic as well...
CodePudding user response:
I changed my main activity file to this and changed how to fetch data using cursor As I said there is no work of SQL, Cursor generates SQL code automatically. i had a problem with fetching data from cursor movement.
package com.example.sosandvideo;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
;
import com.example.sosandvideo.Contacts.Contact;
import com.example.sosandvideo.Contacts.ContactAdapter;
import com.example.sosandvideo.Contacts.DBhelper;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final int RESULT_PICK_CONTACT =1;
ListView listview;
List<Contact> list;
ContactAdapter contactAdapter;
private Button add;
DBhelper db=new DBhelper();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_main);
// phone = findViewById (R.id.contactTv);
add = findViewById (R.id.addButton);
listview=(ListView)findViewById(R.id.listView);
list = db.getAllContacts();
contactAdapter=new ContactAdapter(this,list);
listview.setAdapter(contactAdapter);
add.setOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View v) {
Intent in = new Intent (Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
startActivityForResult (in, RESULT_PICK_CONTACT);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case RESULT_PICK_CONTACT:
contactPicked(data);
break;
}
} else {
Toast.makeText(this, "Failed To pick contact", Toast.LENGTH_SHORT).show();
}
}
@SuppressLint("Range")
private void contactPicked(Intent data) {
Cursor cursor = null;
try {
String phoneNo = null;
int id;
String name;
Uri uri = data.getData ();
cursor = getContentResolver ().query (uri, null, null,null,null);
cursor.moveToFirst ();
id= cursor.getColumnIndex (ContactsContract.CommonDataKinds.Phone.CONTACT_ID);
String phoneid= cursor.getString (id);
String phoneNum= cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
name=cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
db.addContact(new Contact(phoneid,phoneNum,name));
list = db.getAllContacts();
contactAdapter.refresh(list);
} catch (Exception e) {
e.printStackTrace ();
}
}
}