Android browser history URI? - android

I need to save the last visited webpage by user.
Evething works fine with my Galaxy S4 (5.0.1) with Chrome Browser.
However, on some phones I got nothing or very mixed results. From what I gathered, the biggest problem is with Browser URI itself. Some phones use Chrome as their main browser, some use something else.
I have three sources:
content://com.android.chrome.browser/bookmarks
content://com.sec.android.app.sbrowser/bookmarks
Browser.BOOKMARKS_URI
So right now I'm working on something like this:
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
h.removeCallbacks(this);
h.postDelayed(this, 500);
}
public void run() {
String[] proj = new String[] { Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.URL,Browser.BookmarkColumns.DATE };
String selection = Browser.BookmarkColumns.BOOKMARK + " = 0"; // 0 = history, 1 = bookmark
Cursor mCur = null;
try {
mCur = contentResolver.query(getURI(), proj, selection, null, null);
if(mCur != null && mCur.moveToLast()){
String title = "";
String url = "";
title = mCur.getString(mCur.getColumnIndex(Browser.BookmarkColumns.TITLE));
url = mCur.getString(mCur.getColumnIndex(Browser.BookmarkColumns.URL));
...
}
} catch (Exception e){
...
} finally {
if(mCur != null)
mCur.close();
}
}
private Uri getURI(){
Uri uri = Uri.parse("content://com.android.chrome.browser/bookmarks");
return uri;
}
Whet is the best way to provide correct URI?
onChange is triggered as content observer on browsers history.
So user can browse internet on Chrome and I still get history results from ASOP browser.
When I observe chrome directly, on some phones I get failed to find provider info, because there is no chrome installed.
What are other "popular" sources to search for browser history? I'd prefer to make this as bulletproof as possible.

try it: (run perfectly in android > 4.0 and 5 or 6.0 ); Anything, create a contentObserver array in FOREACH and add a list and record a different URI for each.
in service android (background):
HistoryObserver hObserver;
public void onCreate() {
hObserver = new HistoryObserver(new Handler(), this);
getApplicationContext().getContentResolver().registerContentObserver(Uri.parse("content://com.android.chrome.browser/history"), true, hObserver);
}
Class historicObserver:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.provider.Browser;
import android.util.Log;
public class HistoryObserver extends ContentObserver {
public final String TAG = "HistoryObserver";
Context context;
public HistoryObserver(Handler handler, Context c) {
super(handler);
Log.d(TAG, "Creating new HistoryObserver");
context = c;
}
public HistoryObserver(Context c) {
super(null);
Log.d(TAG, "Creating a new HistoryObserver without a Handler");
context = c;
}
#Override
public boolean deliverSelfNotifications() {
Log.d(TAG, "delivering self notifications");
return true;
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.d(TAG, "onChange without uri: " + selfChange);
// onChange(selfChange, null);
}
#SuppressLint("NewApi")
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
Log.d(TAG, "onChange: " + selfChange + "\t " + uri.toString());
String[] proj = new String[] { Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL, Browser.BookmarkColumns.DATE };
String selection = Browser.BookmarkColumns.BOOKMARK + " = 0"; // 0 =
// history,
// 1 =
// bookmark
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
Cursor mCursor = context.getContentResolver().query(Browser.BOOKMARKS_URI,
proj, selection, null, null);
// this.startManagingCursor(mCursor);
mCursor.moveToFirst();
int count = mCursor.getColumnCount();
String COUNT = String.valueOf(count);
Log.e("Browser sayac", COUNT);
String title = "";
String url = "";
String date = "";
if (mCursor.moveToFirst() && mCursor.getCount() > 0) {
while (mCursor.isAfterLast() == false) {
title = mCursor.getString(mCursor
.getColumnIndex(Browser.BookmarkColumns.TITLE));
url = mCursor.getString(mCursor
.getColumnIndex(Browser.BookmarkColumns.URL));
date = mCursor.getString(mCursor
.getColumnIndex(Browser.BookmarkColumns.DATE));
Long timestamp = Long.parseLong(date);
SimpleDateFormat dateFormat = new SimpleDateFormat(
"dd/MM/yyyy/HH:mm");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timestamp);
String finaldate = dateFormat.format(calendar.getTime());
String smsDate = finaldate.toString();
// Log.e("DTE", date);
Log.e("URL", title);
Log.e("TARIH", smsDate);
mCursor.moveToNext();
}
}
}
}

Related

Is it possible to add a reminder programatically without creating event in android calendar?

I use Google Calendar Provider for Android to add Events in my Google Calendar:
https://developer.android.com/guide/topics/providers/calendar-provider.html#overview
And this is the example to add Reminder for the Event:
ContentValues values = new ContentValues();
values.put(CalendarContract.Reminders.MINUTES, 15);
values.put(CalendarContract.Reminders.EVENT_ID, reminderEventId);
values.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);
getContentResolver().insert(CalendarContract.Reminders.CONTENT_URI, values);
But in my Google Calendar app I can create Reminders without having EVENT_ID. Is it possible to create the same reminders with Google Calendar Provider for Android?
The same like this:
https://gsuiteupdates.googleblog.com/2016/04/launch-of-reminders-for-google-calendar.html
I have see that Google launch reminders for Google Calendar 2016 (This is a different Reminders from Event Reminders) and at the moment I can`t find in Android SDK (API 25) this kind of Google Calendar Reminders (and possibility to add programmatically appointment slots too).
A tricky approach I'm using is creating the remainders, instead of calendar, in the contacts, using Custom Reminder (and the ContactContract provider). So, you can use any label, and the reminder is shown in the specific date.
Cons:
- You have to have the "Birthday" calendar enable
- The remainder is date based (not time)
- They don't repeat the reminder (as the new calendar does)
package es.goodsal.mobile.provider.contact;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.provider.ContactsContract.CommonDataKinds.Event;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import es.goodsal.mobile.app.App;
import es.goodsal.mobile.model.ReminderType;
/**
* Created by jmalbarran on 16/9/17.
*/
public class Reminder implements Comparable<Reminder> {
private static final String TAG = Reminder.class.getSimpleName();
private static final SimpleDateFormat fullPeriodicDateFormat = new SimpleDateFormat("--MM-dd");
private static final SimpleDateFormat periodicDateFormat = new SimpleDateFormat("MM-dd");
private static final SimpleDateFormat nonPeriodicDateFormat = new SimpleDateFormat("yyyy-MM-dd");
private static final String DUE_DATE = Event.DATA4;
private static final String COMMENT = Event.DATA5;
private static final Uri CONTENT_URI = ContactsContract.Data.CONTENT_URI;
private static final String[] PROJECTION = new String[]{
Event._ID, //0
Event.CONTACT_ID, //1
Event.LOOKUP_KEY, //2
Event.START_DATE, //3
Event.TYPE, //4
Event.LABEL, //5 Label for custom event
Reminder.DUE_DATE, // 6
Reminder.COMMENT // 7 Use this field to save Comments
};
static {
periodicDateFormat.setCalendar(Calendar.getInstance()); // Set local time zone
nonPeriodicDateFormat.setCalendar(Calendar.getInstance()); // Set local time zone
}
private long id = -1;
private ConContact contact;
private Date reminderDate;
private Date dueDate;
private ReminderType type;
private String comment;
// region Constructor
public Reminder(ConContact contact, Date reminderDate,
Date dueDate, ReminderType type, String comment) {
this.contact = contact;
this.reminderDate = reminderDate;
this.dueDate = dueDate;
this.type = type;
this.comment = comment;
}
public Reminder(#NonNull String reminderUri) {
this(Uri.parse(reminderUri));
}
public Reminder(#NonNull Uri reminderUri) {
Cursor cursor;
cursor = App.getContentResolverInstance().query(reminderUri,
PROJECTION, null, null, null);
if (cursor == null) {
throw new IllegalArgumentException(reminderUri.toString() + " opportunity not found.");
} else {
cursor.moveToFirst();
setFromCursor(null, cursor);
}
}
private Reminder(#NonNull Cursor cursor) {
this(null, cursor);
}
private Reminder(#Nullable ConContact contact, #NonNull Cursor cursor) {
setFromCursor(contact, cursor);
}
private void setFromCursor(#Nullable ConContact contact, #NonNull Cursor cursor) {
int eventType;
String eventLabel;
Calendar calDueDate, calReminderDate;
Date now;
String strSplitDate[];
String strDueDate;
this.id = cursor.getLong(0);
if (contact != null) {
this.contact = contact;
} else {
this.contact = new ConContact(cursor.getLong(1), cursor.getString(2));
}
// Type
eventType = cursor.getInt(4); //Event.TYPE
eventLabel = cursor.getString(5); //Event.LABEL
switch (eventType) {
case ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY:
type = ReminderType.anniversary;
break;
case ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY:
type = ReminderType.birthday;
break;
case ContactsContract.CommonDataKinds.Event.TYPE_CUSTOM:
type = ReminderType.other;
eventLabel = cursor.getString(5);
for (ReminderType iType : ReminderType.values()) {
if (iType.getLabel().equals(eventLabel)) {
type = iType;
break;
}
}
break;
default:
type = ReminderType.other;
}
// Due / Reminder date
try {
now = new Date();
if (type.isPeriodic()) {
// Periodic Due date
calDueDate = Calendar.getInstance();
calDueDate.setTime(now);
strSplitDate = cursor.getString(6).split("-"); // DATA4
if (strSplitDate != null && strSplitDate.length == 3) {
calDueDate.set(Calendar.MONTH, Integer.parseInt(strSplitDate[1]));
calDueDate.set(Calendar.DAY_OF_MONTH, Integer.parseInt(strSplitDate[2]));
if (calDueDate.before(now)) { // Crossed end-of-year boundary
calDueDate.add(Calendar.YEAR, 1); // Next year
}
} else {
Log.e(TAG, "getReminders: Invalid date for periodic reminder due date " +
cursor.getString(6));
}
dueDate = calDueDate.getTime();
// Periodic Reminder date
calReminderDate = Calendar.getInstance();
calReminderDate.setTime(dueDate);
strSplitDate = cursor.getString(3).split("-"); // START_DATE
if (strSplitDate != null && strSplitDate.length == 3) {
calReminderDate.set(Calendar.MONTH, Integer.parseInt(strSplitDate[1]));
calReminderDate.set(Calendar.DAY_OF_MONTH, Integer.parseInt(strSplitDate[2]));
if (calReminderDate.after(dueDate)) { // Crossed end-of-year boundary
calDueDate.add(Calendar.YEAR, -11); // Previous year
}
} else {
Log.e(TAG, "getReminders: Invalid date for periodic reminder start date " +
cursor.getString(6));
}
reminderDate = calReminderDate.getTime();
} else {
// Non periodic date
reminderDate = nonPeriodicDateFormat.parse(cursor.getString(3)); // START_DATE
dueDate = nonPeriodicDateFormat.parse(cursor.getString(6)); // DATA4
dueDate = dueDate !=null ? dueDate : reminderDate;
}
} catch (Exception e) { // NullPointer and/or ParseFormat
dueDate = null;
reminderDate = null;
}
// Comment
comment = cursor.getString(7); // DATA5
}
// endregion Constructor
// region Getter/Setter
public Uri getUri() {
Uri uri;
uri = null;
if (id != -1) {
uri = ContentUris.withAppendedId(CONTENT_URI, id);
}
return uri;
}
public ConContact getContact() {
return contact;
}
public Date getReminderDate() {
return reminderDate;
}
public Date getDueDate() {
return dueDate;
}
public ReminderType getReminderType() {
return type;
}
public String getComment() {
return comment;
}
public boolean isPeriodic() {
return type.isPeriodic();
}
public void setContact(ConContact contact) {
this.contact = contact;
}
public void setReminderDate(Date reminderDate) {
this.reminderDate = reminderDate;
}
public void setDueDate(Date dueDate) {
this.dueDate = dueDate;
}
public void setType(ReminderType type) {
this.type = type;
}
public void setComment(String comment) {
this.comment = comment;
}
// endregion Getter/Setter
// region Commands
public boolean save() {
boolean ret;
ContentValues values;
Uri savedUri;
ret = false;
values = new ContentValues();
values.put(ContactsContract.CommonDataKinds.Event.MIMETYPE,
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE);
//values.put(ContactsContract.CommonDataKinds.Event.CONTACT_ID, contact.getContactId());
values.put(ContactsContract.CommonDataKinds.Event.RAW_CONTACT_ID, contact.getRawContactId());
if (type.isPeriodic()) {
values.put(ContactsContract.CommonDataKinds.Event.START_DATE,
fullPeriodicDateFormat.format(reminderDate));
values.put(ContactsContract.CommonDataKinds.Event.DATA4,
fullPeriodicDateFormat.format(dueDate));
} else {
values.put(ContactsContract.CommonDataKinds.Event.START_DATE,
nonPeriodicDateFormat.format(reminderDate));
values.put(ContactsContract.CommonDataKinds.Event.DATA4,
nonPeriodicDateFormat.format(dueDate));
}
values.put(ContactsContract.CommonDataKinds.Event.TYPE,
Integer.toString(type.getContactEventType()));
values.put(ContactsContract.CommonDataKinds.Event.LABEL, type.getLabel());
values.put(ContactsContract.CommonDataKinds.Event.DATA5, comment);
if (id == -1L) {
// Create new
savedUri = App.getContentResolverInstance().insert(ContactsContract.Data.CONTENT_URI, values);
id = ContentUris.parseId(savedUri);
ret = true;
Log.d(TAG, "save: Inserted uri=" + savedUri + " id=" + id);
} else {
// update existing id
// if (0<App.getContentResolverInstance().update(ContactsContract.Data.CONTENT_URI, values,
// ContactsContract.Data._ID + "='" + Long.toString(id) + "'", null)){
if (0 < App.getContentResolverInstance().update(
ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, id),
values,
null,
null)) {
ret = true;
Log.d(TAG, "save: Updated id=" + id);
} else {
Log.e(TAG, "save: Error updating id=" + id);
}
}
contact.resetReminders();
return ret;
}
public boolean delete() {
boolean ret = false;
if (id != -1) {
if (0 < App.getContentResolverInstance().delete(
ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, id),
null,
null)) {
Log.d(TAG, "delete: Deleted id=" + id);
ret = true;
} else {
Log.w(TAG, "delete: Not found id=" + id);
}
}
return ret;
}
// endregion Commands
#Override
public int compareTo(#NonNull Reminder o) {
if (reminderDate == null) {
return 1; // null always at end
} else {
if (o.reminderDate == null) {
return -1;
} else {
return reminderDate.compareTo(o.reminderDate);
}
}
}
/**
* Get reminders for all contact, in a specific date (including periodics)
*
* #param date exact to search for (reminder date NOT due date)
* #return List of reminders
*/
public static List<Reminder> getReminders(Date date) {
Cursor cursor;
ArrayList<Reminder> retList;
String where;
String[] selectionArgs;
Date dueDate;
String dateSelection;
String[] strSplitDate;
Calendar calDueDate;
retList = null;
Uri uri = ContactsContract.Data.CONTENT_URI;
String sortOrder = null;
// Execute one query per reminder type
for (ReminderType type : ReminderType.values()) {
dateSelection = type.isPeriodic() ?
"%" + periodicDateFormat.format(date) :
"%" + nonPeriodicDateFormat.format(date);
if (type.getContactEventType() == ContactsContract.CommonDataKinds.Event.TYPE_CUSTOM) {
// Check event label too
where = ContactsContract.CommonDataKinds.Event.MIMETYPE + "= ? AND " +
ContactsContract.CommonDataKinds.Event.START_DATE + " LIKE ? AND " +
ContactsContract.CommonDataKinds.Event.LABEL + "= ? AND " +
ContactsContract.CommonDataKinds.Event.TYPE + "=" + type.getContactEventType();
selectionArgs = new String[]{
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
dateSelection,
type.getLabel()
};
} else {
// Non custom reminder. Don't check label
where = ContactsContract.CommonDataKinds.Event.MIMETYPE + "= ? AND " +
ContactsContract.CommonDataKinds.Event.START_DATE + " LIKE ? AND " +
ContactsContract.CommonDataKinds.Event.TYPE + "=" + type.getContactEventType();
selectionArgs = new String[]{
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
dateSelection
};
} // where & selection per event type
cursor = App.getContentResolverInstance().query(uri, PROJECTION,
where, selectionArgs, sortOrder);
if (cursor != null) {
retList = new ArrayList<Reminder>();
while (cursor.moveToNext()) {
retList.add(new Reminder(cursor));
}
cursor.close();
} // if cursor
} // for per every type
return retList;
}
/**
* Get reminders for a specific contact, from a date forward
*
* #param contact Contact for search for
* #param date current or future date to search (including periodic)
* #return List of reminders for current or future search
*/
public static List<Reminder> getReminders(ConContact contact, Date date) {
Uri uri;
Cursor cursor;
ArrayList<Reminder> retList = null;
String where;
String[] selectionArgs;
String sortOrder;
int contactEventType;
String label;
Calendar calReminderDate, calDueDate;
String strReminderDate, strDueDate;
ReminderType type;
Date reminderDate;
Date dueDate;
String strDescription;
String[] strSplitDate;
uri = ContactsContract.Data.CONTENT_URI;
sortOrder = null;
// Check event label too
where = ContactsContract.CommonDataKinds.Event.MIMETYPE + " = ? AND " +
ContactsContract.CommonDataKinds.Event.CONTACT_ID + " = ? AND " +
"(" +
ContactsContract.CommonDataKinds.Event.START_DATE + " LIKE '--%' OR " +
ContactsContract.CommonDataKinds.Event.START_DATE + " >= ?" +
")";
selectionArgs = new String[]{
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE,
Long.toString(contact.getContactId()),
nonPeriodicDateFormat.format(date)
};
sortOrder = ContactsContract.CommonDataKinds.Event.START_DATE;
cursor = App.getContentResolverInstance().query(uri, PROJECTION,
where, selectionArgs, sortOrder);
if (cursor != null) {
retList = new ArrayList<Reminder>();
while (cursor.moveToNext()) {
retList.add(new Reminder(contact, cursor));
}
Collections.sort(retList);
cursor.close();
} // if cursor
// for per every type
return retList;
}
} // end Reminder class
As stated in https://developer.android.com/guide/topics/providers/calendar-provider.html#overview
Reminders are specified in minutes before the event and have a method
that determines how the user will be alerted.
A reminder that doesn't belong to an event will not have a time of reference to go off.
I think for what you are trying to achieve () it would be best for you to look at Androids AlarmManager https://developer.android.com/reference/android/app/AlarmManager.html
Or see what other people are saying about similar things https://stackoverflow.com/a/16549111/6431430

getting the default and chrome browsers in android

I have a code that retrieve the history of the default browser in android, lately I added the chrome browser history. But I have a problem- I get only the chrome history. E.g. if there is no chrome, I get the default browser, if there is chrome, both methods get the chrome only history.
I use this code-
String[] mProjection = {
Browser.BookmarkColumns.BOOKMARK,
BookmarkColumns.CREATED, BookmarkColumns.DATE,
BookmarkColumns.TITLE, BookmarkColumns.URL,
BookmarkColumns.VISITS,
BookmarkColumns._ID };
String mSelectionClause = "DATE > ? ";
String[] selectionArgs = {getEpochDate("DefaultBrowser")}; //"1332115200-000"
String mSortOrder = "DATE";
Cursor cr = getContentResolver().query(Browser.BOOKMARKS_URI, mProjection, mSelectionClause, selectionArgs, mSortOrder);
cr.moveToFirst();
if (cr.moveToFirst() && cr.getCount() > 0) {
while (cr.isLast() == false) {
try {
if (cr.getString(cr.getColumnIndex("BOOKMARK")).equals("0")) {
Log.d("getHistory", cr.getString(cr.getColumnIndex("TITLE")));
mc.writeDataToDB("URL", mc.ConvertFromEpoch(cr.getString(cr.getColumnIndex("DATE"))), cr.getString(cr.getColumnIndex("URL")), cr.getString(cr.getColumnIndex("TITLE")),"");
}
} catch (Exception e) {
e.printStackTrace();
}
cr.moveToNext();
}
mc.insertPref("HistoryDate", cr.getString(cr.getColumnIndex("DATE")));
}
// get google chrome history
String[] selectionArgsChrome = {getEpochDate("ChromeBrowser")};
Uri uriCustom = Uri.parse("content://com.android.chrome.browser/bookmarks");
if (getContentResolver().query(uriCustom, mProjection, mSelectionClause, selectionArgsChrome, mSortOrder) !=null){
Cursor mCur = getContentResolver().query(uriCustom, mProjection, mSelectionClause, selectionArgsChrome, mSortOrder);
mCur.moveToFirst();
String title = "";
String url = "";
String DATE = "";
if (mCur.moveToFirst() && mCur.getCount() > 0) {
boolean cont = true;
while (mCur.isAfterLast() == false && cont) {
title = mCur.getString(mCur.getColumnIndex(Browser.BookmarkColumns.TITLE));
url = mCur.getString(mCur.getColumnIndex(Browser.BookmarkColumns.URL));
DATE = mCur.getString(mCur.getColumnIndex(Browser.BookmarkColumns.DATE));
mc.writeDataToDB("URL", mc.ConvertFromEpoch(DATE), url, title,"");
mCur.moveToNext();
}
mc.insertPref("ChromeHistoryDate", cr.getString(cr.getColumnIndex("DATE")));
}}
can I get the default browser and then the chrome? I did try to change the "Browser.BOOKMARKS_URI" to uri- "content://com.android.browser/bookmarks", but it didn't worked.
any suggestions?
I suppose you're using a ContentObserver. Something like the following:
//Query values:
static final String[] projection = new String[] { BookmarkColumns.URL, BookmarkColumns.TITLE, BookmarkColumns.VISITS, BookmarkColumns.DATE };
static final String selection = Browser.BookmarkColumns.BOOKMARK + " = 0";
static final String sortOrder = Browser.BookmarkColumns.DATE;
private static class BrowserHistoryObserver extends ContentObserver {
public BrowserObserver(Handler handler) {
super(handler);
}
#Override
public void onChange(boolean selfChange) {
onChange(selfChange, null);
}
#Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange);
//Retrieve all the visited URLs:
final Cursor cursor = getContentResolver().query(Browser.BOOKMARKS_URI, projection, selection, null, sortOrder);
cursor.moveToFirst();
while ( !cursor.isAfterLast() ) {
final String url = cursor.getString(cursor.getColumnIndex(projection[0]));
final String title = cursor.getString(cursor.getColumnIndex(projection[1]));
//visits = ... (cursor.getColumnIndex(projection[2]))
//date = ... (cursor.getColumnIndex(projection[3]))
Log.d(TAG, title + " : " + url + "\n");
cursor.moveToNext();
}
//Close the cursor:
cursor.close();
}
}
And you register/unregister it with something like:
browserHistoryObserver = new BrowserHistoryObserver(new Handler());
getContentResolver().registerContentObserver(Browser.BOOKMARKS_URI, true, browserObserver);
...
getContentResolver().unregisterContentObserver(browserHistoryObserver);
The code above, of course, works for the default Android browser (indeed I've always used Browser.BOOKMARKS_URI). If you want to make it working for Google Chrome, you just need to replace Browser.BOOKMARKS_URI with Uri.parse("content://com.android.chrome.browser/bookmarks").
Note that you will have to replace it in both getContentResolver().registerContentObserver(...) and getContentResolver().query(...).

Android - get access to browser history

I'm writing an application, which have to help me get all information about browser history, so I wrote a simple code:
public class WebHistory {
private Context context;
private Cursor cr;
public StringBuilder sb;
public WebHistory(Context c){
this.context = c;
}
public void takeHistory(){
cr = context.getContentResolver().query(Browser.BOOKMARKS_URI,Browser.HISTORY_PROJECTION, null, null, null);
cr.moveToFirst();
String title = "";
String date = "";
String visits = "";
String url = "";
String info = "";
if(cr.moveToFirst() && cr.getCount() > 0){
while(cr.isAfterLast() == false){
title = cr.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX);
date = cr.getString(Browser.HISTORY_PROJECTION_DATE_INDEX);
url = cr.getString(Browser.HISTORY_PROJECTION_URL_INDEX);
visits = cr.getString(Browser.HISTORY_PROJECTION_VISITS_INDEX);
info = title + " date: " + date + " url: " + url + " visits" + visits + "\n";
Toast.makeText(context, info, Toast.LENGTH_LONG).show();
cr.moveToNext();
}
}
}
}
Method takeHistory() helps me to take some data about browser history, but I need more functionality, like:
- HISTORY_PROJECTION_DATE_INDEX gives my only one date, and I need all dates (and also hours) when the user visited this page
- Browser.HISTORY_PROJECTION_VISITS_INDEX returns all visits which I made, but I want to divide this amount into gruops of visits which took place at the specified timestamp
Can anybody suggest how can I cull this information or recommend a tutorial, in which I can find necessary information? Thank you in advance for your advice.
You will need to start content observor and record all the changes that occur. I have done similar code. Start a content observor and in the onChange(); function, read the history that has changed since last time you read it(you can use shared preferences for that). And you need to do this all in a service
public void onChange(boolean selfChange) {
super.onChange(selfChange);
/**
* Get SharedPreferneces of the user
*/
SharedPreferences pref= myContext.getSharedPreferences("com.tpf.sbrowser",
Context.MODE_PRIVATE);
long wherelong = pref.getLong("Date", 0);
DatabaseManager db=new DatabaseManager(myContext,1);
String[] proj = new String[] { Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL, BookmarkColumns.DATE,};
String sel = Browser.BookmarkColumns.BOOKMARK + " = 0";
Cursor mCur = myContext.getContentResolver().query(
Browser.BOOKMARKS_URI, proj, sel, null, null);
Log.d("onChange", "cursorCount"+mCur.getCount());
mCur.moveToFirst();
String title = "";
String url = "";
long lastVisitedDate=0;
//You will need to create a database manager to manage your database and use its helper functions
DbMessage msg = new DbMessage(lastVisitedDate,url, title);
/**
* Start reading the user history and dump into database
*/
if(mCur.moveToFirst() && mCur.getCount() > 0) {
while (mCur.isAfterLast() == false) {
title =mCur.getString(0);
url = mCur.getString(1);
lastVisitedDate =mCur.getLong(2);
if ((lastVisitedDate>wherelong) && (!title.equals(url))) {
msg.set(lastVisitedDate, url, title);
db.InsertWithoutEnd(msg);
pref.edit().putBoolean("BrowserHistoryRead", true).commit();
pref.edit().putLong("Date", lastVisitedDate).commit();
myContext.updateTime(wherelong,lastVisitedDate);
wherelong=lastVisitedDate;
}
mCur.moveToNext();
}
}
mCur.close();
}
}
/**
* (non-Javadoc)
* #see android.app.Service#onDestroy()
*/
#Override
public void onDestroy() {
super.onDestroy();
getApplication().getContentResolver().unregisterContentObserver(
observer);
Toast.makeText(this, "Service destroyed ...", Toast.LENGTH_LONG).show();
state = 0;
}
}

Android - Handling changing apn connection

I was wondering how Android is doing that.
Example:
WAP Push indicates an incoming MMS.
Change APN to MMS.
Download MMS.
Restore connectivity to default APN.
So how is this change of APN done?
Why:
I want to use an other APN to connect to the internet instead of the default or MMS APN.
Following Activity solves your problem of changing default APN and than revert back to original.
package com.slk.apnapp;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.net.Uri;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.util.Log;
public class NewAPNActivity extends Activity {
/*
* Information of all APNs Details can be found in
* com.android.providers.telephony.TelephonyProvider
*/
public static final Uri APN_TABLE_URI = Uri
.parse("content://telephony/carriers");
/*
* Information of the preferred APN
*/
public static final Uri PREFERRED_APN_URI = Uri
.parse("content://telephony/carriers/preferapn");
private static final String TAG = "CHANGE_APN";
public static final String NEW_APN = "NewAPN";
private int getDafaultAPN() {
Cursor c = this.getContentResolver().query(PREFERRED_APN_URI,
new String[] { "_id", "name" }, null, null, null);
int id = -1;
if (c != null) {
try {
if (c.moveToFirst())
id = c.getInt(c.getColumnIndex("_id"));
} catch (SQLException e) {
Log.d(TAG, e.getMessage());
}
c.close();
}
return id;
}
/*
* Set an apn to be the default apn for web traffic Require an input of the
* apn id to be set
*/
public boolean setDefaultAPN(int id) {
boolean res = false;
ContentResolver resolver = this.getContentResolver();
ContentValues values = new ContentValues();
// See /etc/apns-conf.xml. The TelephonyProvider uses this file to
// provide
// content://telephony/carriers/preferapn URI mapping
values.put("apn_id", id);
try {
resolver.update(PREFERRED_APN_URI, values, null, null);
Cursor c = resolver.query(PREFERRED_APN_URI, new String[] { "name",
"apn" }, "_id=" + id, null, null);
if (c != null) {
res = true;
c.close();
}
} catch (SQLException e) {
Log.d(TAG, e.getMessage());
}
return res;
}
private int checkNewAPN() {
int id = -1;
Cursor c = this.getContentResolver().query(APN_TABLE_URI,
new String[] { "_id", "name" }, "name=?",
new String[] { NEW_APN }, null);
if (c == null) {
id = -1;
} else {
int record_cnt = c.getCount();
if (record_cnt == 0) {
id = -1;
} else if (c.moveToFirst()) {
if (c.getString(c.getColumnIndex("name")).equalsIgnoreCase(
NEW_APN)) {
id = c.getInt(c.getColumnIndex("_id"));
}
}
c.close();
}
return id;
}
public int addNewAPN() {
int id = -1;
ContentResolver resolver = this.getContentResolver();
ContentValues values = new ContentValues();
values.put("name", NEW_APN);
values.put("apn", NEW_APN);
/*
* The following three field values are for testing in Android emulator
* only The APN setting page UI will ONLY display APNs whose 'numeric'
* filed is TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC. On
* Android emulator, this value is 310260, where 310 is mcc, and 260
* mnc. With these field values, the newly added apn will appear in
* system UI.
*/
values.put("mcc", "310");
values.put("mnc", "260");
values.put("numeric", "310260");
Cursor c = null;
try {
Uri newRow = resolver.insert(APN_TABLE_URI, values);
if (newRow != null) {
c = resolver.query(newRow, null, null, null, null);
// Obtain the apn id
int idindex = c.getColumnIndex("_id");
c.moveToFirst();
id = c.getShort(idindex);
Log.d(TAG, "New ID: " + id + ": Inserting new APN succeeded!");
}
} catch (SQLException e) {
Log.d(TAG, e.getMessage());
}
if (c != null)
c.close();
return id;
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
int id = checkNewAPN();
int default_id = getDafaultAPN();
if (id == -1) {
id = addNewAPN();
}
if (setDefaultAPN(id)) {
Log.i(TAG, NEW_APN
+ " set new default APN successfully and Default id is "
+ id);
}
if (setDefaultAPN(default_id)) {
Log.i(TAG,
NEW_APN
+ " set previous default APN successfully and Default id is "
+ default_id);
}
}
}

Cant get latest item from calllog

I have registered an contentobserver monitoring the call log.
But I cant get the latest call, the furthest I came is getting the latest call the first time, after that it just takes the previous and then the previous..
Also it returns 2 log entries at a time.
The code im using is:
import java.text.SimpleDateFormat;
import java.util.Date;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Handler;
import android.provider.BaseColumns;
import android.provider.CallLog;
import android.util.Log;
class CallMonitor extends ContentObserver {
private PositionDbAdapter mDbHelper;
Cursor cur;
Context CallMon = Position.MAIN_ACTIVITY;
int idColumn;
int numberColumn;
int dateColumn;
int typeColumn;
int durColumn;
public CallMonitor(Handler handler, Context context){
super(handler);
CallMon = context;
}
#Override
public void onChange(boolean selfChange) {
if(cur==null){
cursorInit(CallMon);
}
if (!cur.moveToNext()) {
//do we really want to close the cursor?
//cur.close();
return;
}
String number = cur.getString(numberColumn);
String id = cur.getString(idColumn);
String type = cur.getString(typeColumn);
String date = cur.getString(dateColumn);
String dur = cur.getString(durColumn);
Date dateN = new Date(Long.parseLong(date));
Date date2 = new Date();
Log.d("Position", date2+": "+dateN+":"+id+", "+number+", "+type+", "+dur);
//cur.moveToNext();
}
public void Destroy() {
Log.d("Position", "Destroy Call Monitor");
cur.close();
}
public void cursorInit(Context context){
String[] projection = new String[]{
BaseColumns._ID,
CallLog.Calls.DATE,
CallLog.Calls.NUMBER,
CallLog.Calls.DURATION,
CallLog.Calls.TYPE
};
ContentResolver resolver = context.getContentResolver();
cur = resolver.query(CallLog.Calls.CONTENT_URI, projection, null,null, "date DESC");
//cur.moveToFirst();
numberColumn = cur.getColumnIndex(CallLog.Calls.NUMBER);
typeColumn = cur.getColumnIndex(CallLog.Calls.TYPE);
dateColumn = cur.getColumnIndex(CallLog.Calls.DATE);
durColumn = cur.getColumnIndex(CallLog.Calls.DURATION);
idColumn = cur.getColumnIndex(CallLog.Calls._ID);
}
}
I've tried various cur.moveToFirst .moveToNext etc...
The closest I came is when it fires the first time, i get the correct callog item, but then i get another one.
Then the second time and third etc.. i get older.
I thought that i i close the cursor then it would start over from the beginning, but when I do this, it throws an error, probably because the cursor is closed when it automatically get the second one, the one i dont want.
So can somebody please help me?
I have done this type of operation but through BroadcastReceiver. may be that will be helpful for you:
public class CallReceiver extends BroadcastReceiver {
//<----------------- Fields------------->
private String phone_no = "";
private int phone_id;
private String incoming_time = "";
private Context context;
#Override
public void onReceive(Context ctx, Intent intent) {
context = ctx;
final Bundle bundle = intent.getExtras();
incomingCalls(bundle);
}
/**
* Check incoming call and match in database
* #param bundle
*/
private void incomingCalls(Bundle bundle) {
if (null == bundle)
return;
Log.i("IncomingCallReceiver", bundle.toString());
final String state = bundle.getString(TelephonyManager.EXTRA_STATE);
Log.i("IncomingCallReceiver", "State: " + state);
phone_no = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)
&& phone_no != null && !phone_no.equalsIgnoreCase("")) {
final DateFormat formatter = new SimpleDateFormat(
"MMM dd yyyy HH:mm");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
incoming_time = formatter.format(calendar.getTime());
Log.i("IncomingCallReceiver", "Incomng Number: " + phone_no);
if (phone_id != 0) {
Log.i("Phone number", phone_no);
Log.i("Phone ID", phone_id+"");
Log.i("Incoming time", incoming_time);
}
}
}
}
if you want call log to be displayed from older to newer entries
ContentResolver resolver = context.getContentResolver();
cur = resolver.query(CallLog.Calls.CONTENT_URI, projection, null,null, "date DESC");
while(cur.moveToNext()){
numberColumn = cur.getColumnIndex(CallLog.Calls.NUMBER);
typeColumn = cur.getColumnIndex(CallLog.Calls.TYPE);
dateColumn = cur.getColumnIndex(CallLog.Calls.DATE);
durColumn = cur.getColumnIndex(CallLog.Calls.DURATION);
idColumn = cur.getColumnIndex(CallLog.Calls._ID);
//display call log or do ur logic
}
and if you want call logs to be displayed from newer to older(i.e latest entry at first)
ContentResolver resolver = context.getContentResolver();
cur.moveToLast()
cur = resolver.query(CallLog.Calls.CONTENT_URI, projection, null,null, "date DESC");
while(cur.moveToPerivous()){
numberColumn = cur.getColumnIndex(CallLog.Calls.NUMBER);
typeColumn = cur.getColumnIndex(CallLog.Calls.TYPE);
dateColumn = cur.getColumnIndex(CallLog.Calls.DATE);
durColumn = cur.getColumnIndex(CallLog.Calls.DURATION);
idColumn = cur.getColumnIndex(CallLog.Calls._ID);
//display call log or do ur logic
}

Categories

Resources