Android Question retiving chrome browser history (java to b4a)

Roycefer

Well-Known Member
Licensed User
B4X:
'This will return a List of Strings of the form "title:url"
Public Sub GetChromeHistory as List
     Dim jo as JavaObject
     jo = Me
'     jo.InitializeContext   'uncomment this and comment above if using in an activity
     Return jo.RunMethod("GetChromeHistoryJava", Null)
End Sub

#If JAVA
public anywheresoftware.b4a.objects.collections.List GetChromeHistoryJava()
{
     String[] proj = new String[]{Browser.BookmarkColumns.TITLE,Browser.BookmarkColumns.URL };
     Uri uriCustom = Uri.parse("content://com.android.chrome.browser/bookmarks");
     String sel = Browser.BookmarkColumns.BOOKMARK +" = 0"; // 0 = history, 1 = bookmark
     Cursor mCur = getContentResolver().query(uriCustom, proj, sel,null,null);
     mCur.moveToFirst();
     @SuppressWarnings("unused")
     String title ="";
     @SuppressWarnings("unused")
     String url ="";
     anywheresoftware.b4a.objects.collections.List res = new anywheresoftware.b4a.objects.collections.List();
     res.Initialize();

     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));
             // Do something with title and url
             res.Add(title + ":" + url);
             mCur.moveToNext();
          }
     }
     return res;
}
#End If
I haven't tested this code and original author of the Java snippet claims not to have tested it, so beware.
 
Last edited:

Devv

Active Member
Licensed User
i got an error
B4A version: 5.20
Parsing code. (0.00s)
Compiling code. (0.04s)
Compiling layouts code. (0.00s)
Generating R file. (0.08s)
Compiling debugger engine code. (1.06s)
Compiling generated Java code. Error
B4A line: 35
End Sub
javac 1.8.0_60
src\b4a\example\main.java:393: error: '.class' expected
String[] proj =newString[]{Browser.BookmarkColumns.TITLE,Browser.BookmarkColumns.URL };
^
1 error
any ideas ?
 

Roycefer

Well-Known Member
Licensed User
There should be a space between "new" and "String[]....". I fixed a few other typos in the Java snippet as well.
 

Devv

Active Member
Licensed User
There should be a space between "new" and "String[]....". I fixed a few other typos in the Java snippet as well.

B4A version: 5.20
Parsing code. (0.00s)
Compiling code. (0.02s)
Compiling layouts code. (0.00s)
Generating R file. (0.07s)
Compiling generated Java code. Error
javac 1.8.0_60
src\b4a\example\main.java:382: error: not a statement
res.Initialize;
^
1 error
was the last edit working on your device ?
 

Roycefer

Well-Known Member
Licensed User
Initialize should have parentheses after it: Initialize(). And a few other typos.

Like I said before, this is untested code, presented without warranty. I haven't tested it and the original author of the Java snippet on Stack Overflow claims not to have tested it. It's going to take some troubleshooting on your part to get it working if it works at all.
 

Devv

Active Member
Licensed User
Initialize should have parentheses after it: Initialize(). And a few other typos.

Like I said before, this is untested code, presented without warranty. I haven't tested it and the original author of the Java snippet on Stack Overflow claims not to have tested it. It's going to take some troubleshooting on your part to get it working if it works at all.
OK i can do all the troubleshooting and logging, could you plz try to fix it ?
 

Roycefer

Well-Known Member
Licensed User
This version compiles and behaves "correctly". There's no troubleshooting and logging left for you to do:
B4X:
'This will return an array of Strings of the form "title:url"
Public Sub GetChromeHistory As String()
     Dim jo As JavaObject
'     jo = Me       'use from within a class
     jo.InitializeContext   'use from within an activity
     Return jo.RunMethod("GetChromeHistoryJava", Null)
End Sub

#If JAVA
import android.provider.Browser;
import android.net.Uri;
import android.database.Cursor;
import anywheresoftware.b4a.objects.collections.List;

public String[] GetChromeHistoryJava()
{
     String[] proj = new String[]{Browser.BookmarkColumns.TITLE,Browser.BookmarkColumns.URL };
     Uri uriCustom = Uri.parse("content://com.android.chrome.browser/bookmarks");
     String sel = Browser.BookmarkColumns.BOOKMARK +" = 0"; // 0 = history, 1 = bookmark
     Cursor mCur = getContentResolver().query(uriCustom, proj, sel,null,null);
     mCur.moveToFirst();
     @SuppressWarnings("unused")
     String title ="";
     @SuppressWarnings("unused")
     String url ="";
     List res = new List();
     res.Initialize();

     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));
             // Do something with title and url
             res.Add(title + ":" + url);
             mCur.moveToNext();
          }
     }
    mCur.close();
    String[] resArr = new String[res.getSize()];
    for(int i=0;i<res.getSize();i++)
    {
        resArr[i] = (String)res.Get(i);
    }
     return resArr;
}
#End If
You will need to add this line to the Manifest Editor:
B4X:
AddPermission("com.android.browser.permission.READ_HISTORY_BOOKMARKS")
I would be remiss in my moral obligations if I did not point out that this is a MONUMENTAL privacy violation. This doesn't just retrieve the Chrome history on the device that runs this code (as one reading the permission request would expect). If the user is signed in to Chrome, it retrieves the FULL Chrome history. That is, the Chrome history for every device in which they have signed in to Chrome with the same Google account. If this runs on their phone and they are signed in to Chrome with the same account as on their tablet, desktop, smart TV, semi-intelligent microwave oven, MacBook, netbook, Chromebook and ultrabook you will see the full Chrome history for those devices as well.

Even more heinous is the fact that the com.android.browser.permission.READ_HISTORY_BOOKMARKS permission doesn't tell the user that this is going on. It merely says that this app requests permission to view browser history and bookmarks. It says nothing about accessing the full Chrome history from all devices connected to that account.
 

Devv

Active Member
Licensed User
This time it compiles successfully but it only logged this:
[Ljava.lang.String;@429ae3d0
(What i'm doing wrong ?)

B4X:
Sub Activity_Create(FirstTime As Boolean)
    Log(GetChromeHistory)
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

'This will return an array of Strings of the form "title:url"
Public Sub GetChromeHistory As String()
     Dim jo As JavaObject
'     jo = Me       'use from within a class
     jo.InitializeContext   'use from within an activity
     Return jo.RunMethod("GetChromeHistoryJava", Null)
End Sub

#If JAVA
import android.provider.Browser;
import android.net.Uri;
import android.database.Cursor;
import anywheresoftware.b4a.objects.collections.List;

public String[] GetChromeHistoryJava()
{
     String[] proj = new String[]{Browser.BookmarkColumns.TITLE,Browser.BookmarkColumns.URL };
     Uri uriCustom = Uri.parse("content://com.android.chrome.browser/bookmarks");
     String sel = Browser.BookmarkColumns.BOOKMARK +" = 0"; // 0 = history, 1 = bookmark
     Cursor mCur = getContentResolver().query(uriCustom, proj, sel,null,null);
     mCur.moveToFirst();
     @SuppressWarnings("unused")
     String title ="";
     @SuppressWarnings("unused")
     String url ="";
     List res = new List();
     res.Initialize();

     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));
             // Do something with title and url
             res.Add(title + ":" + url);
             mCur.moveToNext();
          }
     }
    mCur.close();
    String[] resArr = new String[res.getSize()];
    for(int i=0;i<res.getSize();i++)
    {
        resArr[i] = (String)res.Get(i);
    }
     return resArr;
}
#End If

i also attached my project

thanks in advanced
 

Attachments

Roycefer

Well-Known Member
Licensed User
Read the comments for GetChromeHistory. It returns an array of Strings. You have to iterate through the array:
B4X:
Dim MassivePrivacyViolation() as String = GetChromeHistory
For i = 0 to MassivePrivacyViolation.Length-1
    Log(i & ": " & MassivePrivacyViolation(i))
Next
 
Last edited:

Devv

Active Member
Licensed User
That's great bro, thank you a lot for your help
let me know if yo find out any other privacy violations :D
 

Devv

Active Member
Licensed User
Read the comments for GetChromeHistory. It returns an array of Strings. You have to iterate through the array:
B4X:
Dim MassivePrivacyViolation() as String = GetChromeHistory
For j = 0 to MassivePrivacyViolation.Length-1
    Log(i & ": " & MassivePrivacyViolation(i))
Next
is getting the stock android browser history possible ?
 

DonManfred

Expert
Licensed User
is getting the stock android browser history possible ?
You should start a new thread for this as it is not related to THIS thread.
You posted a link to stackoverflow with the state
Use this uri: content://com.android.chrome.browser/bookmarks instead of Browser.BOOKMARKS_URI
You realized it now... You need to go the opposite way to get the other history (using Browser.BOOKMARKS_URI) i believe
 

Roycefer

Well-Known Member
Licensed User
Oh? Are you in the market for more privacy violations? If I find any, I'll be sure to post them.

I think DonManfred's tip will probably work. It should be a straight-forward matter of copy-paste to create another Java method using the indicated Uri.
 

Devv

Active Member
Licensed User
You should start a new thread for this as it is not related to THIS thread.
You posted a link to stackoverflow with the state


You realized it now... You need to go the opposite way to get the other history (using Browser.BOOKMARKS_URI) i believe

i tried replacing "content://com.android.chrome.browser/bookmarks" with "Browser.BOOKMARKS_URI" in the java object code
but i got this error

** Activity (main) Create, isFirst = true **
main_getchromehistory (B4A line: 42)
Return jo.RunMethod("GetChromeHistoryJava", N
java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:130)
at b4a.example.main._getchromehistory(main.java:423)
at b4a.example.main._activity_create(main.java:351)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
at b4a.example.main.afterFirstLayout(main.java:106)
at b4a.example.main.access$000(main.java:21)
at b4a.example.main$WaitForLayout.run(main.java:84)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at b4a.example.main.GetChromeHistoryJava(main.java:467)
... 21 more
 

Roycefer

Well-Known Member
Licensed User
Browser.BOOKMARKS_URI is the Uri. Don't do Uri.parse on it. Just do Uri uriCustom = Browser.BOOKMARKS_URI; (no quotes).
 

Devv

Active Member
Licensed User
Great now everything is working, any change of getting the time or date of each site visited on stock or chrome ?
 

Roycefer

Well-Known Member
Licensed User
Add Browser.BookmarkColumns.DATE to the end of the proj array. Then create a String variable date just below where the title and url String variables are created. Then, in the main loop, add:
B4X:
date = mCur.getString(mCur.getColumnIndex(Browser.BookmarkColumns.DATE));
Then change the res.Add() line in the loop to include the date String.
 

Devv

Active Member
Licensed User
Add Browser.BookmarkColumns.DATE to the end of the proj array. Then create a String variable date just below where the title and url String variables are created. Then, in the main loop, add:
B4X:
date = mCur.getString(mCur.getColumnIndex(Browser.BookmarkColumns.DATE));
Then change the res.Add() line in the loop to include the date String.
I had no luck to do that, i know nothing about java, can you please write that for me ? i could pay a little over paypal if you are interested
 

Roycefer

Well-Known Member
Licensed User
B4X:
'This will return an array of Strings of the form "title:url:date"
Public Sub GetChromeHistory As String()
  Dim jo AsJavaObject
'  jo = Me 'use from within a class
  jo.InitializeContext 'use from within an activity
  Return jo.RunMethod("GetChromeHistoryJava", Null)
End Sub

#If JAVA
import android.provider.Browser;
import android.net.Uri;
import android.database.Cursor;
import anywheresoftware.b4a.objects.collections.List;

public String[] GetChromeHistoryJava()
{
String[] proj = new String[]{Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.URL, Browser.BookmarkColumns.DATE };   //NEW
Uri uriCustom = Uri.parse("content://com.android.chrome.browser/bookmarks");
String sel = Browser.BookmarkColumns.BOOKMARK +" = 0"; // 0 = history, 1 = bookmark
Cursor mCur = getContentResolver().query(uriCustom, proj, sel,null,null);
mCur.moveToFirst();

@SuppressWarnings("unused")
String title ="";
@SuppressWarnings("unused")
String url ="";
@SuppressWarnings("unused")  //NEW
String date ="";                      //NEW
List res = new List();
res.Initialize();

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));      //NEW

      res.Add(title + ":" + url + ":" + date);      //NEW
      mCur.moveToNext();
   }
}
mCur.close();
String[] resArr = new String[res.getSize()];
for(int i=0;i<res.getSize();i++)
{
   resArr[i] = (String)res.Get(i);
}
return resArr;
}
#End If
I haven't tested this new version but it should work. Lines that have been added or modified are marked with a "NEW" comment so you know where to focus your efforts if you should get errors.
 
Last edited:
Top