i'm writing an application that need to add some events to a calendar in android. For inserting i just used the following code:
public void onItemClick(AdapterView<?> adapter, View curview, int position, long id) {
WhoisEntry entry = this.adapter.getItem(position);
String domainName = entry.getDomainName();
Date expDate = entry.expirationDate;
Toast.makeText(getApplicationContext(), "Domain: " + domainName, Toast.LENGTH_SHORT).show();
Calendar cal = Calendar.getInstance();
Intent intent = new Intent(Intent.ACTION_EDIT);
intent.setType("vnd.android.cursor.item/event");
intent.putExtra("beginTime", entry.expirationDate);
intent.putExtra("allDay", false);
intent.putExtra("endTime", cal.getTimeInMillis()+60*60*1000);
intent.putExtra("title", "Expiration of " + entry.domainName);
startActivity(intent);
}
Now i'm wondering if is possible to get an id associated to that event, in that way after an event is inserted, and its id is saved into my application, the user can recall that event directly from inside the application.
Is it possible?
I extracted a list of columns used to store events into android calendar.
Here the list:
[0] "originalEvent" (id=830007842672)
[1] "availabilityStatus" (id=830007842752)
[2] "ownerAccount" (id=830007842840)
[3] "_sync_account_type" (id=830007842920)
[4] "visibility" (id=830007843008)
[5] "rrule" (id=830007843080)
[6] "lastDate" (id=830007843144)
[7] "hasAlarm" (id=830007843216)
[8] "guestsCanModify" (id=830007843288)
[9] "guestsCanSeeGuests" (id=830007843376)
[10] "exrule" (id=830007843464)
[11] "rdate" (id=830007843528)
[12] "transparency" (id=830007843592)
[13] "timezone" (id=830007843672)
[14] "selected" (id=830007843744)
[15] "dtstart" (id=830007843816)
[16] "title" (id=830007843888)
[17] "_sync_time" (id=830007843952)
[18] "_id" (id=830007844024)
[19] "hasAttendeeData" (id=830007844088)
[20] "_sync_id" (id=830007844176)
[21] "commentsUri" (id=830007844248)
[22] "description" (id=830007844328)
[23] "htmlUri" (id=830007844408)
[24] "_sync_account" (id=830007844480)
[25] "_sync_version" (id=830007844560)
[26] "hasExtendedProperties" (id=830007844640)
[27] "calendar_id" (id=830007844736)
Then if i want to get the new event id for my event:
public static long getNewEventId(ContentResolver cr, Uri cal_uri){
Uri local_uri = cal_uri;
if(cal_uri == null){
local_uri = Uri.parse(calendar_uri+"events");
}
Cursor cursor = cr.query(local_uri, new String [] {"MAX(_id) as max_id"}, null, null, "_id");
cursor.moveToFirst();
long max_val = cursor.getLong(cursor.getColumnIndex("max_id"));
return max_val+1;
}
ANd for insert event:
public void insertDomainEntry(Date exp_date, String name, long event_id){
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put("exp_date", exp_date.getTime()/1000);
values.put("event_id", event_id);
values.put("domainname", name);
db.insertOrThrow("domains_events", null, values);
}
That solution seems to work, even if probably this is not a very good solution.
EDIT 02/2015
The purpose of getNextEventId is to create a new Event Entry for the event table, here the code with the usage of this method:
#Override
public void onItemClick(AdapterView<?> adapter, View curview, int position,
long id) {
WhoisEntry entry = this.adapter.getItem(position);
long event_id = CalendarUtils.getNewEventId(getContentResolver(), null);
Toast.makeText(getApplicationContext(), "Domain: " + entry.getDomainName(),
Toast.LENGTH_SHORT).show();
Intent intent = new Intent(Intent.ACTION_EDIT);
intent.setType("vnd.android.cursor.item/event");
intent.putExtra("beginTime", entry.getExpiration().getTime());
intent.putExtra("_id", event_id);
intent.putExtra("allDay", false);
intent.putExtra("endTime", entry.getExpiration().getTime()+60*30);
intent.putExtra("title", "Expiration of " + entry.getDomainName());
startActivity(intent);
database.insertDomainEntry(entry.getExpiration(),
entry.getDomainName(), event_id);
}
Update 09/2015
As requested in the comment i add how to get the Calendar URI (it is basically where the calendar is stored, and the application try to guess it, searching in all known possible calendar paths)
public static String getCalendarUriBase(Activity act) {
String calendarUriBase = null;
Uri calendars = Uri.parse("content://calendar/calendars");
Cursor managedCursor = null;
try {
managedCursor = act.getContentResolver().query(calendars,
null, null, null, null);
} catch (Exception e) {
}
if (managedCursor != null) {
calendarUriBase = "content://calendar/";
} else {
calendars = Uri.parse("content://com.android.calendar/calendars");
try {
managedCursor = act.getContentResolver().query(calendars,
null, null, null, null);
} catch (Exception e) {
}
if (managedCursor != null) {
calendarUriBase = "content://com.android.calendar/";
}
}
calendar_uri= calendarUriBase;
return calendarUriBase;
}
You can easily get event id after inserting an event.
long calID = 3;
long startMillis = 0;
long endMillis = 0;
Calendar beginTime = Calendar.getInstance();
beginTime.set(2012, 9, 14, 7, 30);
startMillis = beginTime.getTimeInMillis();
Calendar endTime = Calendar.getInstance();
endTime.set(2012, 9, 14, 8, 45);
endMillis = endTime.getTimeInMillis();
...
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
values.put(Events.DTSTART, startMillis);
values.put(Events.DTEND, endMillis);
values.put(Events.TITLE, "Jazzercise");
values.put(Events.DESCRIPTION, "Group workout");
values.put(Events.CALENDAR_ID, calID);
values.put(Events.EVENT_TIMEZONE, "America/Los_Angeles");
Uri uri = cr.insert(Events.CONTENT_URI, values);
// get the event ID that is the last element in the Uri
long eventID = Long.parseLong(uri.getLastPathSegment());
//
// ... do something with event ID
//
//
Related
in my project after user sign up , i want to display the username in next page
so, this line works but with only first user sign up if another user sign up it will display the first username.
displName =findViewById(R.id.displayName);
displName.setText(database.getAllNote().get(0).getUserName());
my database
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
public void openDatabase() {
db = this.getWritableDatabase();}
#SuppressLint("Range")
public List<UserTasks> getAllNote(){
List<UserTasks> listNote = new ArrayList<>();
Cursor cur = null;
db.beginTransaction();
try{
cur = db.query(TABLE_NAME, null, null, null, null, null, null, null);
if(cur != null){
if(cur.moveToFirst()){
do{
UserTasks note = new UserTasks();
note.setUser_id(cur.getInt(cur.getColumnIndex(UID)));
note.setUserName(cur.getString(cur.getColumnIndex(UserName)));
note.setPassword(cur.getString(cur.getColumnIndex(Password)));
note.setNote(cur.getString(cur.getColumnIndex(Note)));
note.setStatus(cur.getInt(cur.getColumnIndex(STATUS)));
note.setDate(cur.getString(cur.getColumnIndex(date)));
note.setTitle(cur.getString(cur.getColumnIndex(titleChe)));
note.setDecs(cur.getString(cur.getColumnIndex(desc)));
note.setDay(cur.getString(cur.getColumnIndex(day)));
listNote.add(note);
}
while(cur.moveToNext());
}
}
}
finally {
db.endTransaction();
assert cur != null;
cur.close();
}
return listNote;
}
how i can fix this small issue? pls help
You always get the first sign up user because you always retrieve table index 0
displName.setText(database.getAllNote().get(0).getUserName());
So I suggest you to use SharedPreference to increment the count of signup user.
When user successfully signup you have to increase the number of user
SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0);
Int countUser = pref.getInt("count_user", 0); // getting Integer
Editor editor = pref.edit();
editor.putInt("count_user", countUser+1);
editor.apply();
After that, change your displName.setText to this:
SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0);
Int countUser = pref.getInt("count_user", 0); // getting Integer
displName.setText(database.getAllNote().get(countUser).getUserName());
You will always get latest signup username.
My purpose is to set a list that comes from API which includes phonenumbers of the users of my app. So i only need to see contact that are in this list. But I dont know how set below code to do this. I mean in the below it opens contacts with all of the contact that are in the phone. I dont need to see the all the contacts but the ones that are in the given list
Intent contactPickerIntent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(contactPickerIntent,1);
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode){
case 1 :
if (resultCode == Activity.RESULT_OK) {
Uri contactData = data.getData();
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(contactData, null, null, null, null);
if (cur.getCount() > 0) {// thats mean some resutl has been found
if(cur.moveToNext()) {
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Log.e("Names", name);
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0)
{
// Query phone here. Covered next
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ id,null, null);
while (phones.moveToNext()) {
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Log.e("Number", phoneNumber);
}
phones.close();
}
}
}
cur.close();
}
break;
}
}
Consider you already have a list which has data from API, and create new list which will have common elements from API list and ContentResolver, now to add elements to your desired list, in ContentResolver check if the PhoneNumber is in API list before adding it to output.
ArrayList<String> apiPhoneNumbers;// this data is populated by API
ArrayList<String> commonPhoneNumbers = new ArrayList<>();
//inside onActivityResult
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0){
// Query phone here. Covered next
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ id,null, null);
while (phones.moveToNext()) {
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Log.e("Number", phoneNumber);
if(apiPhoneNumbers.contains(phoneNumber)){//add to output only if it is in API list
commonPhoneNumbers.add(phoneNumber);
}
}
phones.close();
}
FileNotFoundException occur when capture the screen and save the screenshot into SDCard after power off the cellular phone, It seems that the server to flash the buffer into disk has disconnected during shutdown, but anyone can help me explain more detail? The output error message is:
02-24 14:03:28.180 27412 27412 D TakeScreenshotService:
#isFloatingBallVisible() ,visible = false
02-24 14:03:29.402 27412 10176 E SaveImageInBackgroundTask: error in
SaveImageInBackgroundData,
exception:java.io.FileNotFoundException:
/storage/emulated/0/Pictures/Screenshots/Screenshot_20170224-140329.jpg:
open failed: ENOTCONN (Transport endpoint is not connected)
02-24 14:03:29.526 27412 27412 D TakeScreenshotService: onUnbind,
isMultiScrenshot:false intent:Intent {
cmp=com.android.systemui/.screenshot.TakeScreenshotService }
The corresponding codes are:
#Override
protected SaveImageInBackgroundData doInBackground(SaveImageInBackgroundData... params) {
Log.d(TAG, "doInBackground:");
if (params.length != 1) return null;
if (isCancelled()) {
params[0].clearImage();
params[0].clearContext();
return null;
}
// By default, AsyncTask sets the worker thread to have background thread priority, so bump
// it back up so that we save a little quicker.
Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
Context context = params[0].context;
Bitmap image = params[0].image;
Resources r = context.getResources();
try {
// Create screenshot directory if it doesn't exist
mScreenshotDir.mkdirs();
// media provider uses seconds for DATE_MODIFIED and DATE_ADDED, but milliseconds
// for DATE_TAKEN
long dateSeconds = mImageTime / 1000;
// Save
boolean compressRet = true;
OutputStream out = new FileOutputStream(mImageFilePath);
if(PhoneStatusBar.LEUI_ENABLE) {
compressRet = image.compress(Bitmap.CompressFormat.JPEG, 100, out);
} else {
compressRet = image.compress(Bitmap.CompressFormat.PNG, 100, out);
}
out.flush();
out.close();
if(!compressRet){
//When storage is full screenshot image will compress failed, so we delete the file
File f = new File(mImageFilePath);
if(f.exists()){
f.delete();
Log.d(TAG,"screenshot " + mImageFilePath + " compress failed, so we delete it");
}
params[0].clearImage();
params[0].result = 1;
}else {
// Save the screenshot to the MediaStore
ContentValues values = new ContentValues();
ContentResolver resolver = context.getContentResolver();
values.put(MediaStore.Images.ImageColumns.DATA, mImageFilePath);
values.put(MediaStore.Images.ImageColumns.TITLE, mImageFileName);
values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, mImageFileName);
values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, mImageTime);
values.put(MediaStore.Images.ImageColumns.DATE_ADDED, dateSeconds);
values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, dateSeconds);
if(PhoneStatusBar.LEUI_ENABLE) {
values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/jpeg");
} else {
values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");
}
values.put(MediaStore.Images.ImageColumns.WIDTH, mImageWidth);
values.put(MediaStore.Images.ImageColumns.HEIGHT, mImageHeight);
values.put(MediaStore.Images.ImageColumns.SIZE, new File(mImageFilePath).length());
Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
// Create a share intent
String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
if(PhoneStatusBar.LEUI_ENABLE) {
sharingIntent.setType("image/jpeg");
} else {
sharingIntent.setType("image/png");
}
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, mImageFileName);
// Create a share action for the notification
final PendingIntent callback = PendingIntent.getBroadcast(context, 0,
new Intent(context, GlobalScreenshot.TargetChosenReceiver.class)
.putExtra(GlobalScreenshot.CANCEL_ID, mNotificationId),
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
Intent chooserIntent = Intent.createChooser(sharingIntent, null,
callback.getIntentSender());
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
| Intent.FLAG_ACTIVITY_NEW_TASK);
mNotificationBuilder.addAction(R.drawable.ic_screenshot_share,
r.getString(com.android.internal.R.string.share),
PendingIntent.getActivity(context, 0, chooserIntent,
PendingIntent.FLAG_CANCEL_CURRENT));
// Create a delete action for the notification
final PendingIntent deleteAction = PendingIntent.getBroadcast(context, 0,
new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class)
.putExtra(GlobalScreenshot.CANCEL_ID, mNotificationId)
.putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()),
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
mNotificationBuilder.addAction(R.drawable.ic_screenshot_delete,
r.getString(com.android.internal.R.string.delete), deleteAction);
params[0].imageUri = uri;
params[0].image = null;
params[0].result = 0;
}
} catch (Exception e) {
// IOException/UnsupportedOperationException may be thrown if external storage is not
// mounted
Log.e(TAG, "error in SaveImageInBackgroundData, exception:" + e);
params[0].clearImage();
params[0].result = 1;
}
// Recycle the bitmap data
if (image != null) {
image.recycle();
}
return params[0];
}
So in the app I am developing the user can types in a string and selects an address. When they select done the address is put into a geofence and when they enter that geofence a notification is posted. The problem I am having is when I try to add the strings of a row from that name on notification press. The names are the same yet the cursor can not find the row with the string. Thanks in advance!
Here is the error:
android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 1
at android.database.AbstractCursor.checkPosition(AbstractCursor.java:426)
at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
at com.nick.mowen.receiptmanager.ManagerDatabaseAdapter.getDataArray(ManagerDatabaseAdapter.java:64)
at com.nick.mowen.receiptmanager.GeofenceTransitionsIntentService.getAppToOpen(GeofenceTransitionsIntentService.java:35)
at com.nick.mowen.receiptmanager.GeofenceTransitionsIntentService.sendNotification(GeofenceTransitionsIntentService.java:82)
at com.nick.mowen.receiptmanager.GeofenceTransitionsIntentService.onHandleIntent(GeofenceTransitionsIntentService.java:64)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.os.HandlerThread.run(HandlerThread.java:61)
Here is the method to get the String[] of values:
public String[] getDataArray(String name) {
String[] columns = {ManagerHelper.NAME,ManagerHelper.CODE,ManagerHelper.ADDRESS};
SQLiteDatabase db = helper.getWritableDatabase();
Cursor cursor = db.query(ManagerHelper.TABLE_NAME, columns, ManagerHelper.NAME + " = '" + name + "'", null, null, null, null);
String[] data = new String[3];
data[0] = cursor.getString(1);
data[1] = cursor.getString(2);
data[2] = cursor.getString(3);
return data;
}
Here is the code to add the notification and get details:
public String[] getAppToOpen(String names) {
managerDatabaseAdapter = new ManagerDatabaseAdapter(this);
selectArgs = managerDatabaseAdapter.getDataArray(names);
return selectArgs;
}
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = "There is hopefully no error";
Log.e(TAG, errorMessage);
return;
}
// Get the transition type.
int geofenceTransition = geofencingEvent.getGeofenceTransition();
// Test that the reported transition was of interest.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER) {
// Get the geofences that were triggered. A single event can trigger
// multiple geofences.
List triggeringGeofences = geofencingEvent.getTriggeringGeofences();
// Get the transition details as a String.
String geofenceTransitionDetails = getGeofenceTransitionDetails(
geofenceTransition,
triggeringGeofences
);
// Send notification and log the transition details.
sendNotification(geofenceTransitionDetails);
//Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
}
}
private String getGeofenceTransitionDetails(int geofenceTransition, List triggeringGeofences) {
String[] split = {":", " "};
String name = triggeringGeofences.get(0).toString();
newSplit = name.split(split[0]);
secondSplit = newSplit[1].split(split[1]);
return secondSplit[0];
}
private void sendNotification(String geofenceTransitionDetails) {
NotificationCompat.Builder builder = (NotificationCompat.Builder) new NotificationCompat.Builder(this).setContentTitle("Receipt Code Reminder").setContentText(geofenceTransitionDetails).setSmallIcon(R.drawable.ic_stat_maps_local_restaurant).setTicker("Receipt Code Reminder").setAutoCancel(true);
Intent localIntent = new Intent(this, ViewCodeActivity.class);
localIntent.putExtra(EXTRA_MESSAGE, getAppToOpen(geofenceTransitionDetails));
TaskStackBuilder localTaskStackBuilder = TaskStackBuilder.create(this);
localTaskStackBuilder.addParentStack(ViewCodeActivity.class);
localTaskStackBuilder.addNextIntent(localIntent);
builder.setContentIntent(localTaskStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT));
((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)).notify(this.mID, builder.build());
}
}
"Index -1 requested" indicates that you are querying a Cursor without first calling cursor.moveToFirst(). Also, it is highly recommended that you use constants with semantic names for your columns, rather than 1, 2 and 3.
I'm using a contact picker as such:
startActivityForResult(
new Intent(
Intent.ACTION_PICK,
Phone.CONTENT_URI
), CONTACT_PICKER_RESULT //1001
);
This type of contact picker picks out a specific phone number that a contact has.
I then get an ID for this contact with:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != CONTACT_PICKER_RESULT || resultCode != RESULT_OK)
return;
String id = data.getData.getLastPathSegment();
}
However, when I use a PhoneLookup query, such as:
Cursor cur = getContentResolver().query(
Uri.withAppendedPath(
PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(...) //phone number of contact is filled in
),
new String[] {
PhoneLookup.DISPLAY_NAME,
Phone._ID
}, null, null, null
);
if (!cur.moveToFirst())
return;
String id = cur.getString(
cur.getColumnIndex(Phone._ID)
);
The ID I get from the PhoneLookup is different from the onActivityResult. For example, the contact picker returns 1408 while the cursor returns 444.
How can I get:
data.getData().getLastPathSegment() equal to cur.getColumnIndex(...)?
You can't use a PhoneLookup in this case. You need to query Phone.CONTENT_URI to obtain the ID that matches up with the contact picker. The following code below does exactly this.
Cursor cur = getContentResolver().query(
Phone.CONTENT_URI,
new String[] {
Phone.DISPLAY_NAME,
Phone._ID
},
Phone.NORMALIZED_NUMBER + "=?",
new String[] {
... //phone number placed here
}, null);
if (!cur.moveToFirst())
return;
String id = cur.getString(cur.getColumnIndex(Phone._ID)));