I've got a problem with removing contacts I previously created on SIM card.
First of all I'm checking what values are stored in DB like this:
private static final Uri URI_ICC_ADN = Uri.parse("content://icc/adn/");
private ContentResolver mContentResolver = this.getContentResolver();
Cursor c = mContentResolver.query(URI_ICC_ADN, null, null, null, null);
c.moveToFirst();
while(c.moveToNext()) {
Log.i(LOG_TAG, "name = " + c.getString(c.getColumnIndex("name")));
}
And this provides me with those logs:
name = 1
name = 2
name = 3
name = 1
name = 2
name = 5
// etc
It means that records with name = 1 exist in DB. Now I'm trying to delete those records with this code:
int rowsDeleted = mContentResolver.delete(URI_ICC_ADN, "name=?", new String[] { "1" });
But unfortunately those rows are not removed - rowsDeleted equals 0. I've also tried this:
int rowsDeleted = mContentResolver.delete(URI_ICC_ADN, "name=1", null);
But the result is the same. What am I doing wrong?
"name" is only for read query. For deletion you have to pass "tag" for the name column. Check this link for the actual implementation IccProvider
Related
I'm writing an Android App in Java and I've changed my Database and now I want to migrate it to the new version but to do that I need to compute some of the old values and then insert those into one of the new tables into the db but when I call
database.execSQL()
with my variables and then access them it appears to not have set them as every value is 0.
Is it just not possible or did I simply miss something?
public void migrate(#NonNull SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE 'season' ('id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
'spring' INTEGER DEFAULT 0, 'summer' INTEGER DEFAULT 0, 'autumn' INTEGER
DEFAULT 0, 'winter'
INTEGER DEFAULT 0, 'spook' INTEGER DEFAULT 0)");
database.execSQL("INSERT INTO 'Clothes' (type_of_clothing,clothing_name,description,seasonId,in_laundry,TypeList) " +
"SELECT type_of_clothing,clothing_name,description,type_of_clothing,in_laundry,TypeList " +
"FROM ClothesNew");
Cursor cursor = database.query("SELECT * FROM Clothes");
Cursor secondCursor = database.query("SELECT * FROM ClothesSeason");
ArrayList<Season> seasonsToBeAdded = new ArrayList<>();
while (cursor.moveToNext()) {
secondCursor.moveToNext();
int Sid = cursor.getInt(0);
String seasonString = secondCursor.getString(2);
Season season = new Season(seasonString);
int tempId = Sid;
boolean isInList = false;
for (Season tempSeason : seasonsToBeAdded) {
if (tempSeason.equals(season)) {
tempId = seasonsToBeAdded.indexOf(tempSeason);
isInList = true;
break;
}
}
if (!isInList) {
season.setId(seasonsToBeAdded.size());
tempId = season.getId();
seasonsToBeAdded.add(season);
}
if (seasonsToBeAdded.size() == 0) {seasonsToBeAdded.add(season);}
database.execSQL("UPDATE Clothes SET seasonId = :tempId WHERE uid = :Sid");
}
int id, spring, summer, autumn, winter, spook;
for (Season season : seasonsToBeAdded) {
id = season.getId();
spring = season.getSpring();
summer = season.getSummer();
autumn = season.getAutumn();
winter = season.getWinter();
spook = season.getSpook();
database.execSQL("INSERT INTO season " +
"VALUES(:id, :spring, :summer, :autumn, :winter, :spook) ");
}
Cursor otherCursor = database.query("SELECT * FROM season");
ArrayList<Integer> springValues= new ArrayList<>();
while (otherCursor.moveToNext()) {
springValues.add(otherCursor.getInt(1));
}
}
When I look at the Values stored in springValues they are all 0 even though I add the correct ones in this query
database.execSQL("INSERT INTO season " +
"VALUES(:id, :spring, :summer, :autumn, :winter, :spook) ");
Can I just not use the :var notation here?
I'd suggest utilising The SQLiteDatabase Insert convenience method along with a ContentValues object.
Instead of :-
for (Season season : seasonsToBeAdded) {
id = season.getId();
spring = season.getSpring();
summer = season.getSummer();
autumn = season.getAutumn();
winter = season.getWinter();
spook = season.getSpook();
database.execSQL("INSERT INTO season " +
"VALUES(:id, :spring, :summer, :autumn, :winter, :spook) ");
}
Your code could then be :-
ContentValues cv = new ContentValues(); // Instantiate ContentValues object
for (Season season : seasonsToBeAdded) {
cv.clear();
cv.put("`id`",season.getId());
cv.put("`spring`",season.getSpring());
cv.put("`summer`",season.getSummer());
cv.put("`autumn`",season.getAutumn());
cv.put("`winter`",season.getWinter());
cv.put("`spook`",season.getSpook());
database.insert("season",null,cv); //<<<< Recommended Uses the convenience Insert Method
Note there should be no need to enclose the column names in grave accents `` as used above.
The above code is in-principle code and has not been tested, as such it may contain some errors.
As you can see the SQL is built for you. The insert method returns the rowid (id column) of the inserted row or -1 if the insert failed, you may wish to take advantage of this value.
You may also wish to utilise other insert methods e.g. insertWithOnConflict e.g. database.insertWithOnConflict("season",null,cv,SQLiteDatabase.CONFLICT_IGNORE);
It would also be advisable to utilise transactions by utilising the appropriate SQLiteDatabase transaction handling methods (see beginTransaction)
It also also recommended that you utilise constants for column names so the name is coded in just on place. So little chance of getting the column names wrong.
When downloading images from browser and listing them into the app, date taken column is always null only on android 10+
ArrayList<String> localImages = new ArrayList<>();
Uri uri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon().build();
final String[] projection = {
MediaStore.MediaColumns.DATA,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.MediaColumns.DATE_ADDED
};
final String orderBy = MediaStore.Images.Media.DATE_TAKEN;
String searchQuery = null;//dateQuery == null ? null : MediaStore.Images.Media.DATE_TAKEN + ">" + (dateQuery.getTime());
Cursor cursor = this.getContentResolver().query(uri, projection, searchQuery, null, orderBy + " DESC");
int columnIndexData = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
int columnDateTaken = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_TAKEN);
while (cursor.moveToNext()) {
String imagePath = cursor.getString(columnIndexData);
String dateTaken = cursor.getString(columnDateTaken); // THIS IS ALWAYS NULL
localImages.add(imagePath);
}
"Media Store insert DATE_TAKEN is always null"
DATE_TAKEN is documented to be "The time the media item was taken." and to deliver on that API description, we populate it based on the "DateTimeOriginal" Exif metadata field, or the . If the file being scanned doesn't have this metadata, we can't accurately determine when the file was captured, so DATE_TAKEN is set to NULL to avoid misleading data.
So, some devices don't have DATE_TAKEN field.If you use DATE_TAKEN, you will check value is null or not. And when not, you should fall back to use DATE_ADDED or DATE_MODIFIED, etc.
I referred to this Japanese article: https://zenn.dev/tsutou/articles/59fbb5e71b2988
I am trying to get the phone contacts and store it in a Hashmap. I want to save that locally and use it anywhere in the project.
Following is my code to get phone contacts:
public HashMap getPhoneContacts() {
ArrayList contactList=null;
ContentResolver cr = getContext().getContentResolver(); //Activity/Application android.content.Context
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null
, null, null, null);
if(cursor.moveToFirst())
{
contactList = new ArrayList<String>();
do
{
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
String contactName=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if(Integer.parseInt(cursor.getString(cursor.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())
{
String contactNumber = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
//String contactId = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String noramliseNum;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
noramliseNum = PhoneNumberUtils.normalizeNumber(contactNumber);
}else{
noramliseNum=contactNumber.replaceAll("\\s","");
}
phoneContacts.put(noramliseNum,contactName);
break;
}
pCur.close();
}
} while (cursor.moveToNext()) ;
}
return phoneContacts;
}
Its already taking lot of time to fetch all the contacts. So I dont want to call this function again and again from other classes. Instead I need to call the function only once,and then store it in a Hashmap locally and use it whenever we want,so that it wont take time to fetch the details again.
Please help.
You could put it into SharedPreferences if you don't want to re-download every time you start the app. Then, once the data is retreived, you could have a Singleton class to hold your Hashmap.
If you have many contacts, you should consider using a database.
Take a look at https://developer.android.com/guide/topics/data/data-storage.html
This would be more efficient than keeping everything in memory.
I need to implement an algorithm that access to the database to check the last elemnt in order to calculate the new one. Of course, the first time it would be impossible because the database is empty and I get
IndexOutOfBoundsException) index 0 requested with a size of 0
To avoid it, I tried to check if cursor.getCount==0, and then I introduce a default first element. The problem is that, even when I have stored it in the database, cursor.getCount keeps being 0. Here is the code of my method:
public Measures getLastMeasure(String date) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_MEASURES, new String[] { KEY_ID,
KEY_DATE, KEY_TIME_HOUR, KEY_TIME_MINUTE, KEY_BE_INTAKE,
KEY_GLUCOSE, KEY_BOLUS, KEY_BASAL }, KEY_DATE + "=?",
new String[] { date }, null, null, KEY_TIME_HOUR + " DESC, "
+ KEY_TIME_MINUTE + " DESC", "1");
if (cursor.getCount() == 0) {
Measures m = new Measures("nodate", 0, 0, 0, 0, 0, 0);
return m;
} else {
if (cursor != null)
cursor.moveToFirst();
Measures m = new Measures(Long.parseLong(cursor.getString(0)), // id
cursor.getString(1), // date
Integer.parseInt(cursor.getString(2)), // timeHour
Integer.parseInt(cursor.getString(3)), // timeMinute
Double.parseDouble(cursor.getString(4)), // BE intake
Double.parseDouble(cursor.getString(5)), // glucose
Double.parseDouble(cursor.getString(6)), // bolus
Double.parseDouble(cursor.getString(7)) // basal
);
// return m
return m;
}
}
I hope you can help me. Thanks in advance to everyone.
I could be missing something, but that code looks correct to me. Are you certain that the data you're looking for is actually in the database and that the argument you're passing to getLastMeasure() is correct?
Looks like your query returns no data matching your search. If you only want latest data by date, I suggest order by KEY_DATE desc and limit 1, or max(KEY_DATE) instead of KEY_DATE + "=?"
Side note: no need to check if cursor is null (SQLiteDatabase#query never returns a null Cursor), and anyway your check is useless because you're accessing cursor even if it's null. Also you're not closing the Cursor.
I wrote the following function in order to retrieve one single phone number that belongs to the contact with id "contactID".
The function which is to retrieve the phone number:
private String getContactPhone(String contactID) {
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String[] projection = null;
String where = ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?";
String[] selectionArgs = new String[] { contactID };
String sortOrder = null;
Cursor result = managedQuery(uri, projection, where, selectionArgs, sortOrder);
if (result.moveToFirst()) {
String phone = result.getString(result.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
if (phone == null) {
result.close();
return null;
}
result.close();
return phone;
}
result.close();
return null;
}
How this function is called:
ArrayList<Contact> resultContacts = new ArrayList<Contact>();
Cursor result = null;
Uri uri = ContactsContract.Data.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Event.CONTACT_ID,
ContactsContract.CommonDataKinds.Event.START_DATE,
};
String where = ContactsContract.Data.MIMETYPE+" = ? AND "+ContactsContract.CommonDataKinds.Event.TYPE+" = "+ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY;
String[] selectionArgs = new String[] {ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE};
String sortOrder = null;
result = managedQuery(uri, projection, where, selectionArgs, sortOrder);
while (result.moveToNext()) {
Long id = result.getLong(result.getColumnIndex(ContactsContract.Contacts._ID));
String phone = getContactPhone(String.valueOf(id));
...
}
...
Unfortunately, it doesn't work. I get null if I call this function with the value that I got from "ContactsContract.Contacts._ID". Why is this so? What is wrong?
Edit: I used to map Contacts._ID to CommonDataKinds.Phone.CONTACT_ID - which didn't work. But now I map Contacts.DISPLAY_NAME to CommonDataKinds.Phone.DISPLAY_NAME and it works suddenly - strange, isn't it? But I would rather like to map the IDs instead of the display names. So the question is still topical. Could this be due to different IDs in those tables? Isn't this why there are lookup IDs?
To get the contact id in the first part, you should use:
ContactsContract.Data.CONTACT_ID
instead of:
ContactsContract.Contacts._ID
So the projection should be:
String[] projection = new String[] {
ContactsContract.Data.CONTACT_ID,
ContactsContract.CommonDataKinds.Event.CONTACT_ID,
ContactsContract.CommonDataKinds.Event.START_DATE,
};
And then of course get the correct row:
Long id = result.getLong(result.getColumnIndex(ContactsContract.Data.CONTACT_ID));
You are getting null because you have set your projection to null. The projection is basically the list of columns that you want returned e.g.
String[] projection = {ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.HAS_PHONE_NUMBER};
Usually, when you find the contact, they may have a list of phone numbers, so you have to use another cursor to iterate through the phone numbers, e.g.
Cursor phones = mContext.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId, null, null);
while (phones.moveToNext())
{
phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA));
}
Hope this helps.
Your code for getContactPhone() works fine on my end. I tested by launching a contact picker, selecting a contact, then using the ID that was returned and passed that into your method.
So I suspect you are indeed passing in an invalid ID. Can you post the full stack trace for the null pointer exception?
Yes, lookup keys are available because _IDs are not guaranteed to stay the same since syncs and contact aggregation changes them.