Is it possible to count the number of times I open google? - android

I want to develop an application (or service) that will count the number of times I open http://www.google.com url. But I do not know if this is possible with Android.
I want to do a research on this field but I do not know how to start. As far I was looking, there is no intent fired when some uri in the browser is oppened, but I guess there is so way to do this. I do not expect to be simple but I hope it is possible. My hope is the fact that some applications measure the network traffic, meaning everything is somehow tracked.

This isn't guaranteed to work across all flavours of Android, but according to the documentation you can read the browser database.
Browser is a static helper that provides access to the bookmarks database and, handily for your requirements, also exposes browser history via a method called getAllVisitedUrls.
Cursor cursor=Browser.getAllVisitedUrls(getContentResolver());
cursor.moveToFirst();
int occasions=0;
while (cursor.moveToNext()) {
String urlVisited=cursor.getString(cursor.getColumnIndex(BookmarkColumns.URL));
if (urlVisited.contains("www.google.")) {
occasions++;
}
Log.d("History",cursor.getString(cursor.getColumnIndex(BookmarkColumns.URL)));
}
Log.d("History","occasions="+occasions);
EDIT: Sorry to update this after it's been accepted as an answer, but contrary to what I initially wrote you can indeed register to listen for changes to the bookmarks URI:
getContentResolver().registerContentObserver(Browser.BOOKMARKS_URI, true,
new ContentObserver(new Handler()) {
#Override
public void onChange(boolean selfChange) {
Log.d("History","Bookmarks has changed");
super.onChange(selfChange);
}
});
I hope that's helpful.
EDIT: I neglected to mention that you need to add a permission to your manifest: com.android.browser.permission.READ_HISTORY_BOOKMARKS

Related

How many mayLaunchUrl we can run at a time?

I am trying to utilize ChromeCustomTabs into our project. I ran into several issue when I used mayLaunchUrl. I checked the code Google has on the github. I simply set up an button to test the mayLaunchURL (prerender feature), when I looked up the traffic using chrome dev tool. I did the the traffic and tab got trigger and the url got loaded ( it is simply a GET call with params). However, when I click it multiple times, (after 8-10times, with different params everytime), it STOP working. I stop seeing the requests sent out. (Not seen on chrome dev tool, nor the Proxy I set up).
I wonder if there is a limit times ( restriction) for mayLaunchURL feature, in other words, how many pages we can pre-render in this case? Is there a way to manually cancel the pre-render page and free the resource?
is there a restriction in terms of times to bindCustomTabsService? The way I did to call mayLaunchURL is to have an activity and kill the activity once I finish the tab. Can I bind the service each time even I “kill (finish)” the activtiy every time?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
customTabActivityHelper = new CustomTabActivityHelper();
customTabActivityHelper.setConnectionCallback(this);
}
#Override
protected void onStart() {
super.onStart();
customTabActivityHelper.bindCustomTabsService(this);
}
#Override
public void onCustomTabsConnected() {
Boolean mayLaunchUrlAccepted = customTabActivityHelper.mayLaunchUrl(Uri.parse(“the URL?f=“+params), null, null);
// the mayLaunchUrlAccepted always return true in my case. Even when there is no request sent.
}
Yes, mayLaunchURL() are very expensive in terms of battery/RAM/network, so it is throttled on app UID level. But limits get dropped after some time.
Best strategy is to use mayLaunchURL() if the confidence that the user will navigate to the URL is very high.
There is the "low confidence" mayLaunchURL() which is not throttled, but performs a more limited set of actions (currently preconnect, not specified which, may change). The low confidence mayLaunchURL is triggered by providing null as the uri and a list of URLs in otherLikelyBundles.

Check for access to notifications using NotificationListenerService

I'm using the >=4.3 NotificationListenerService to access notifications. On the first start, my app takes the user to the "Access Notifications" system panel, but I'd like to take the user there whenever the checkbox for my app in "Access Notifications" is disabled. I haven't found a isNotificationAccessEnabled()-method anywhere, but I definitely know that it's possible because apps like Krome do this, too.
Edit June 15th, 2016
I'm not sure which version of the support library this was added to, but it looks like this functionality is now built in. Simply use:
NotificationManagerCompat.getEnabledListenerPackages(context); (link to docs)
This returns a Set<String> that you can iterate through to find your package name. Note however that I haven't personally tested this. But it looks like it's probably preferred to use this in place of my old solution below.
Old Solution
This code is working for my app:
ContentResolver contentResolver = context.getContentResolver();
String enabledNotificationListeners = Settings.Secure.getString(contentResolver, "enabled_notification_listeners");
String packageName = context.getPackageName();
// check to see if the enabledNotificationListeners String contains our package name
if (enabledNotificationListeners == null || !enabledNotificationListeners.contains(packageName))
{
// in this situation we know that the user has not granted the app the Notification access permission
throw new Exception();
}
else
{
doSomethingThatRequiresNotificationAccessPermission();
}
Typical values that I've seen for the enabledNotificationsListeners String look like this:
User has given none of their apps Notification access permission
null or ""
User has given one app Notification access permission
"com.woodblockwithoutco.remotecontrollerexample/com.woodblockwithoutco.remotecontrollerexample.RemoteControlService"
User has given two apps Notification access permission
"com.scootrnova.android/com.scootrnova.android.ListenerService:com.woodblockwithoutco.remotecontrollerexample/com.woodblockwithoutco.remotecontrollerexample.RemoteControlService"
This implementation is very straightforward and works great :)
P.S. I got the idea to use the hardcoded "enabled_notification_listeners" String from this answer.
Starting with Android 8.1 (SDK 27) you can call isNotificationListenerAccessGranted on the NotificationManager. This is the correct API to use. Older Android versions should use getEnabledListenerPackages as a second best option. Relying on your listener callbacks can give incorrect results. See explanation below.
Im developer of Krome. What have I done to check if service is enabled is add public static variable that changes to true in onBind method and to false in unbind. That is how this service work.
Edit:
public static boolean isNotificationAccessEnabled = false;
#Override
public void onListenerConnected() {
isNotificationAccessEnabled = true;
}
#Override
public void onListenerDisconnected() {
isNotificationAccessEnabled = false;
}
Works well with slightly modified #Damians answer
public class NotifyListener extends NotificationListenerService{
public static boolean listnerConnected = false;
#Override
public IBinder onBind(Intent intent) {
Log.d(name,"onBind Called");
listnerConnected = true;
return super.onBind(intent);
}
#Override
public void onDestroy()
{
super.onDestroy();
Log.e("destroy", "called");
listnerConnected = false;
}
}
Starting with Android 8.1 (SDK 27) you can call isNotificationListenerAccessGranted on the NotificationManager. This is the correct API to use, not the one of the accepted answer. See explanation below.
Like shai tibber also already said the accepted answer is incorrect.
onListenerConnected() and onListenerDisconnect() can get called even when there is no NotificationListener access granted. So relying on this callbacks to set a boolean will give wrong results. And getEnabledListenerPackages(context‌​) will just return all the packages that have an enabled notification listener defined in there AndroidManifest (android:enabled=true). It's NOT directly related to the user access. The documentation states exactly that:
Get the set of packages that have an enabled notification listener component within them.

Observing changes in Android content observer for Audio.Media.EXTERNAL_CONTENT_URI

I am developing an Android app in which I have to detect changes in Android SD card for audio files with the file name, file path and operation performed upon it. Example if I am adding a file in my SD card then I want to know
Name of the file which is added
Path of the file
Operation -- Add
Previously I Have tried file observer But for that I have to apply it on each and every directory. So I searched for some other solution and got the info about Audio.Media.EXTERNAL_CONTENT_URI. Then I created a content observer like this
UriObserver.java -- which is a content observer
class UriObserver extends ContentObserver {
public UriObserver(Handler handler) {
super(handler);
// TODO Auto-generated constructor stub
}
#Override
public void onChange(boolean selfChange) {
// TODO Auto-generated method stub
super.onChange(selfChange);
Log.d("INSTANT", "GETTING CHANGES");
}
}
This is the code for registration for it
UriObserver observer = new UriObserver(new Handler());
Log.d("INSTANT", "registered content observer");
this.getApplicationContext()
.getContentResolver()
.registerContentObserver(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false,
observer);
Log.d("INSTANT", "registered content observer");
It let me know that some change has been occur in sdcard related to audio files. But it doesn't gives any sort of info about which file has been added, edited or deleted.
Then I searched for for solution and got this post
Android: How to detect a change in MediaStore when connected over MTP
In this post some code is given by Bhiefer as an answer which I think it could work, so I tried to implement that but I am not able to do so.
What can I do for this?
Update
Can I query Audio.Media.EXTERNAL_CONTENT_URI for its latest changes? This code:
mCursor = context.getContentResolver().query(
Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, "_id");
mCursor.moveToLast();
doesn't give the latest changes. Is there any other method to get the latest changes?
Let me try to unwind
ContentObserver
It doesn't give you information on what has changed
It's per design. Nothing in documentation says that it will give you this info.
FileObserver
It isn't recursive
Yes. It's know issue. What is the problem with iterating through all directories and setting observers? Per my understand by default there shouldn't be many (let say a dozen or so).
Android: How to detect a change in MediaStore when connected over MTP
The code which you found is just ContentObserver wrapped in UriObserver.
It does several things
He gets a cursor for one of content provides (in his case I believe it's images from MediaStore)
He registers an observer for this
As soon as some changes happens it forward this changes to external listener
However, this solution has two limitation:
It has inherit problem of ContentObserver that it doesn't report what happened to the data.
I believe it will report only changes to files which are registered in this MediaStore content provider. I believe system scans only special directories on SD card to check for images and so on. So, if a file will be places in some another directory, this solution won't see it.
So, What was your question about his code?
Summary
In the case, if you want to know exact type of changes for ALL files on scdard, I don't think that you can find anything better than FileObserver
Update 1
Couple more ideas, which may be not suitable for you. If you can root a device then you have the option to write filter driver for a filesystem, so your driver will be called each time when something has changed.
You can take a look at this link:
http://www.gossamer-threads.com/lists/linux/kernel/355190
Or you can reuse some existing linux changes notifications systems. As example, look at this:
http://stefan.buettcher.org/cs/fschange/. However, it could be that FileObserver is based exactly on it.
Anyway, both these approaches are low level and will require more time to figure out.
You can get the latest additions/modifications by querying on the DATE_ADDED and DATE_MODIFIED columns, but you will NOT get DELETIONS.
Here is how I do it:
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
long lastDatabaseUpdateTime = preferences.getLong("lastDatabaseUpdateTime", 0);
long newDatabaseUpdateTime = (new Date()).getTime();
String[] cols = new String[] {MediaStore.Audio.Media._ID /* and other columns */};
String where = "("+MediaStore.MediaColumns.DATE_ADDED + ">" + (lastDatabaseUpdateTime/1000);
where += " or " + MediaStore.MediaColumns.DATE_MODIFIED + ">" + (lastDatabaseUpdateTime/1000);
where += ") and "+MediaStore.Audio.AudioColumns.IS_MUSIC+"==1 ";
Cursor cursor = MusicUtils.query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, cols, where, null, null);
/* Do my work on the cursor and close the cursor */
//If no exceptions, then save the new timestamp
SharedPreferences.Editor editor = preferences.edit();
editor.putLong("lastDatabaseUpdateTime", newDatabaseUpdateTime);
editor.commit();

Pause android DownloadManager

In my application I'm downloading movies from the server. Some of them are very big (4gb or more). I tried to implement my own download manager as a service and it was not quit good. On some devices the app just crashes into itself without any notice, and overall the download seems to be too slowly.
So, I wanted to use Android's default DownloadManager, but my only problem is that I can't pause/resume it.
Is there a way to implement that?
From what I can tell by looking at the source code, this isn't supported (although the DownloadManager will automatically retry after failures on its own and after system reboots, etc.).
If you haven't seen this or this already, it looks like there is some useful information there on how to implement your own service yourself with these capabilities.
I found another very impressive library
https://github.com/Trinea/android-common
You can pause by set the Downloads.Impl.COLUMN_CONTROL to Downloads.Impl.CONTROL_PAUSED.
And resume by set the Downloads.Impl.COLUMN_CONTROL, Downloads.Impl.CONTROL_RUN
public void pauseOrResumeDownload(boolean pause, long... ids) {
ContentValues values = new ContentValues();
if (pause) {
values.put(Downloads.Impl.COLUMN_CONTROL, Downloads.Impl.CONTROL_PAUSED);
} else {
values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING);
values.put(Downloads.Impl.COLUMN_CONTROL, Downloads.Impl.CONTROL_RUN);
}
mResolver.update(mBaseUri, values, getWhereClauseForIds(ids), getWhereArgsForIds(ids));
}

Handling the C2DM error ACCOUNT_MISSING in Android

The registration for C2DM may result in an error ACCOUNT_MISSING. This error must be handled, according to the documentation, in this way "The application should ask the user to open the account manager and add a Google account."
I would like to offer to the user this possibility from the application. I have seen two ways to show this screen:
//Intent
context.startActivity(newIntent(Settings.ACTION_ADD_ACCOUNT).putExtra(Settings.EXTRA_AUTHORITIES, new String[] {?}));
The problem for this solution that the I have tried several EXTRA_AUTHORITIES ("com.google", "com.google.android.gsf, etc) and none of them show anything and if the parameter EXTRA_AUTHORITIES is omitted all the phone account are shown.
//Account manager
AccountManager.get(context).addAccount("com.google", null, null, null, this, new AccountManagerCallback<Bundle>() {
public void run(AccountManagerFuture<Bundle> accountManagerHandle) {
//TODO Handle response.
}
}, null);
}
The problem for this solution is that it requires the permission MANAGE_ACCOUNTS, and the users would probably not like to accept an extra permission just for that.
How would you deal with this situation?
For the EXTRA_AUTHORITIES field you can use "gmail-ls" to show only the Google account selector.
After much googling I found the constant in the android.provider.Gmail source code:
public static final String AUTHORITY = "gmail-ls"
This class is not part of the public API so as a workaround it's a bit fragile :-(.

Categories

Resources