I have been working on an SMS application. Everything was smooth until yesterday, when I updated my Nexus 4 to Android 4.4, KitKat. Features such as marking an SMS as read/unread, and deleting all messages in a thread have stopped working. Why is this happening? It works on other Samsung devices (not running KitKat).
This is my code to mark a message as read or unread:
public static void markRead(final Context context, final Uri uri,
final int read) {
Log.d(TAG, "markRead(" + uri + "," + read + ")");
if (uri == null) {
return;
}
String[] sel = Message.SELECTION_UNREAD;
if (read == 0) {
sel = Message.SELECTION_READ;
}
final ContentResolver cr = context.getContentResolver();
final ContentValues cv = new ContentValues();
cv.put(Message.PROJECTION[Message.INDEX_READ], read);
try {
cr.update(uri, cv, Message.SELECTION_READ_UNREAD, sel);
} catch (IllegalArgumentException e) {
Log.e(TAG, "failed update", e);
Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
For deleting all messages in a thread, I use:
public static void deleteMessages(final Context context, final Uri uri,
final int title, final int message, final Activity activity) {
Log.i(TAG, "deleteMessages(..," + uri + " ,..)");
final Builder builder = new Builder(context);
builder.setTitle(title);
builder.setMessage(message);
builder.setNegativeButton(android.R.string.no, null);
builder.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
#Override
public void onClick(final DialogInterface dialog,
final int which) {
final int ret = context.getContentResolver().delete(
uri, null, null);
Log.d(TAG, "deleted: " + ret);
if (activity != null && !activity.isFinishing()) {
activity.finish();
}
if (ret > 0) {
Conversation.flushCache();
Message.flushCache();
SmsReceiver.updateNewMessageNotification(context,
null);
// adapter.notifyDataSetChanged();
}
try {
testFromFragment(context);
} catch (Exception e) {
e.printStackTrace();
}
}
});
builder.show();
}
With Android 4.4, several things have changed with regard to SMS. Among them is the fact that only the app that is registered as the default SMS app has write access to the provider.
Check here for a short blurb on changes to SMS.
Check this link for a more in depth look. This one explains what criteria your app needs to meet to be the default messaging app.
And here's the official fun stuff.
So, if your app is not the default messaging app, that would be why the specified functionalities have stopped working.
A possible workaround for the default Provider restriction can be found in the answer here.
Related
I am trying to delete the image By Its URI because I Have an image's Uri.
But it gave me This Error
android.app.RecoverableSecurityException: com.example.xyz has no access to content://media/external/images/media/206362
I am using this method to delete a file in my Pictures folder.
private boolean deleteFile(Uri imagePath) {
ContentResolver resolver = contextWeakReference.get().getContentResolver();
int noOfRawDeleted = 0;
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.Q){
noOfRawDeleted = resolver.delete(imagePath, null);
}else{
noOfRawDeleted = resolver.delete(imagePath,null,null );
}
return noOfRawDeleted > 0;
}
In Android Q and above, trying to delete an file which is owned by another app will throw a RecoverableSecurityException. You must catch such exception and use its IntentSender to request the delete permission for the target file.
public void delete(final Context context, final Uri uri) {
try {
context.getContentResolver().delete(uri, null, null);
} catch (SecurityException exception) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (exception instanceof RecoverableSecurityException) {
final IntentSender intent = ((RecoverableSecurityException)exception).getUserAction()
.getActionIntent()
.getIntentSender();
startIntentSenderForResult(intent, YOUR_REQUEST_CODE, null, 0, 0, 0, null);
return;
}
}
throw exception;
}
}
More details in the documentation.
I am trying to scan internal storage for all the available images, but getting 0 results, where as, i store one image just before doing the scan, that image is "wallpaper.jpg".
Thanks in advance for any help.
boolean fileFlag= fileExistance("/wallpaper.jpg");
System.out.println(fileFlag); // this returns "true"
initMediaContentLevels(TAG, Images.Media.INTERNAL_CONTENT_URI, CoreConstants.DATATYPE_PHOTO, listener);
protected void initMediaContentLevels(final String tag, final Uri mediaUri, final int dataType, final DataManagerListener listener) {
LOG.i(TAG, "initMediaContentLevels("+tag+","+mediaUri+","+dataType+") mClassItemsTotal="+mClassItemsTotal);
//TODO if the data card is not mounted or missing then this returns 0 .. should test that sd card is available when app starts
String[] projection = {MediaStore.MediaColumns.DATA};
Cursor mediaExtCur = sContext.getContentResolver().query(
mediaUri,
projection,
null,
null,
null);
LOG.d(TAG, "initMediaContentLevels("+tag+","+mediaUri+","+dataType+") mediaExtCur="+mediaExtCur);
if (mediaExtCur!=null) {
int numItems = mediaExtCur.getCount(); //allows for chaining of class for one upload group (row of UI)
LOG.d(TAG, "initMediaContentLevels("+tag+") numItems="+numItems);
try {
if (numItems > 0) {
while (mediaExtCur.moveToNext()) {
String filepath = getString(mediaExtCur, MediaColumns.DATA);
File f = new File(filepath);
if (!f.exists() || !f.canRead()) {
LOG.e(TAG, "initMediaContentLevels("+tag+") file "+f.getAbsolutePath()+" "+(f.exists()?"is not readable":"does not exist"));
continue;
}
long fileSize = f.length();
if (exceedsFileSizeLimit(fileSize)) {
LOG.e(TAG, "initMediaContentLevels("+tag+") file is too large to announce "+filepath+": "+fileSize);
//files larger than the max are not counted
continue;
}
mBytesTotal += fileSize; //db sizes are unreliable
mClassItemsTotal++;
}
LOG.d(TAG, "initMediaContentLevels("+tag+") mBytesTotal="+mBytesTotal+", mClassItemsTotal="+mClassItemsTotal);
}
}
catch (Exception e) {
LOG.e(TAG,"problem getting media count "+e.toString());
}
finally {
if (!mediaExtCur.isClosed()) {
mediaExtCur.close();
}
}
}
LOG.d(TAG, "initMediaContentLevels("+tag+") listener="+listener);
listener.initialiseClassCount(dataType, mClassItemsTotal, mBytesTotal);
LOG.d(TAG, "initMediaContentLevels("+tag+") done");
}
Good day to all!!!
We can delete call history using CallLog.AUTHORITY. Here is an utility method to delete calls...
public static void deleteCallLogsFromNative(Context context, long[] rowIds) {
ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(
rowIds.length);
for (int i = 0, N = rowIds.length; i < N; i++) {
operations.add(ContentProviderOperation
.newDelete(CallLog.Calls.CONTENT_URI)
.withSelection(CallLog.Calls._ID + " = ?",
new String[] { String.valueOf(rowIds[i]) }).build());
}
try {
context.getContentResolver().applyBatch(CallLog.AUTHORITY,
operations);
} catch (Exception e) {
Log.e(TAG,
"Error while deleting calls from native: " + e.toString());
}
}
You can observe that for applying batch operation, we need an AUTHORITY and here is CallLog.AUTHORITY is required to delete call logs.
Similarly I have another utility method for deleting messages...
public static void deleteMessagesFromNative(Context context, long[] rowIds) {
ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(
rowIds.length);
for (int i = 0, N = rowIds.length; i < N; i++) {
long rowId = rowIds[i];
operations.add(ContentProviderOperation
.newDelete(Uri.parse("content://sms/"))
.withSelection(BaseColumns._ID + " = ?",
new String[] { String.valueOf(rowId) }).build());
}
try {
// here I need AUTHORITY value for deleting messages
} catch (Exception e) {
// TODO: handle exception
}
}
Now my question is, What is the value of AUTHORITY to delete messages?
I have been working on an SMS application. Everything was smooth until yesterday, when I updated my Nexus 4 to Android 4.4, KitKat. Features such as marking an SMS as read/unread, and deleting all messages in a thread have stopped working. Why is this happening? It works on other Samsung devices (not running KitKat).
This is my code to mark a message as read or unread:
public static void markRead(final Context context, final Uri uri,
final int read) {
Log.d(TAG, "markRead(" + uri + "," + read + ")");
if (uri == null) {
return;
}
String[] sel = Message.SELECTION_UNREAD;
if (read == 0) {
sel = Message.SELECTION_READ;
}
final ContentResolver cr = context.getContentResolver();
final ContentValues cv = new ContentValues();
cv.put(Message.PROJECTION[Message.INDEX_READ], read);
try {
cr.update(uri, cv, Message.SELECTION_READ_UNREAD, sel);
} catch (IllegalArgumentException e) {
Log.e(TAG, "failed update", e);
Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
For deleting all messages in a thread, I use:
public static void deleteMessages(final Context context, final Uri uri,
final int title, final int message, final Activity activity) {
Log.i(TAG, "deleteMessages(..," + uri + " ,..)");
final Builder builder = new Builder(context);
builder.setTitle(title);
builder.setMessage(message);
builder.setNegativeButton(android.R.string.no, null);
builder.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
#Override
public void onClick(final DialogInterface dialog,
final int which) {
final int ret = context.getContentResolver().delete(
uri, null, null);
Log.d(TAG, "deleted: " + ret);
if (activity != null && !activity.isFinishing()) {
activity.finish();
}
if (ret > 0) {
Conversation.flushCache();
Message.flushCache();
SmsReceiver.updateNewMessageNotification(context,
null);
// adapter.notifyDataSetChanged();
}
try {
testFromFragment(context);
} catch (Exception e) {
e.printStackTrace();
}
}
});
builder.show();
}
With Android 4.4, several things have changed with regard to SMS. Among them is the fact that only the app that is registered as the default SMS app has write access to the provider.
Check here for a short blurb on changes to SMS.
Check this link for a more in depth look. This one explains what criteria your app needs to meet to be the default messaging app.
And here's the official fun stuff.
So, if your app is not the default messaging app, that would be why the specified functionalities have stopped working.
A possible workaround for the default Provider restriction can be found in the answer here.
After factory reset of the device.
I'm trying to retrieve the calendars display names(by the code below), it returns that there is no calendars.
but when opening the device Calendar application at least one time, the default phone calendar will be retrieved correctly.
Is there any way to retrieve the calendars (especially the default ) without opening the device Calendar application?
Thanks in advance.
Here is the code for retrieving calendars exist on the device:
private Uri getCalendarUri() {
return Uri.parse(Integer.parseInt(Build.VERSION.SDK) > 7 ? "content://com.android.calendar/calendars" : "content://calendar/calendars");
}
private String[] getCalendars(Context context) {
String[] res = null;
ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = null;
try {
cursor = contentResolver.query( getCalendarUri(),
Integer.parseInt(Build.VERSION.SDK) > 13 ? new String[]{"_id", "calendar_displayName"} : new String[]{"_id", "displayName"}, null, null, "_id ASC");
if (cursor.getCount() > 0) {
res = new String[cursor.getCount()];
int i = 0;
while (cursor.moveToNext()) {
res[i] = cursor.getString(0) + ": " + cursor.getString(1);
i++;
}
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (cursor != null)
cursor.close();
}
return res;
}
I solved the issue.
using this code in my activity:
private static boolean calendar_opened = false;
private void openCalendar() {
String[] calendars = getCalendars(this);
if (!calendar_opened && calendars != null && calendars.length <= 0) {
new Timer().schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
try {
//bring back my activity to foreground
final Intent tmpIntent = (Intent) MainScreen.this.getIntent().clone();
tmpIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
tmpIntent.setClass(MyExams.getInstance(), MainScreen.class);
PendingIntent.getActivity(MyExams.getInstance(), 0, tmpIntent, PendingIntent.FLAG_UPDATE_CURRENT).send();
}
catch (Exception e) {
}
}
});
}
}, 100 );//time is your dissection
Intent i = new Intent();
i.setClassName("com.android.calendar", "com.android.calendar.LaunchActivity");
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(i);
calendar_opened = true;
}
}
//After my activity is on foreground I killed the calendar using this code, even there's no need because of FLAG_ACTIVITY_NO_HISTORY:
ActivityManager activityManager = (ActivityManager) MainScreen.this.getSystemService(Context.ACTIVITY_SERVICE);
activityManager.killBackgroundProcesses("com.android.calendar");
I think the device calendar application must be installing a calendar when you open it which may not be available before you open it after a factory reset.
I think you don't want the user to have to open the calendar application. If you don't mind the calendar application being opened in background, you could consider opening it through a Service an then closing it soon so that the user won't notice and the device calendar would be available.
android-codes-examples.blogspot.in/2011/11/… Check this link out, is it useful?