New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement basic Android client #6

Open
ErikBjare opened this Issue Jul 8, 2016 · 21 comments

Comments

Projects
None yet
5 participants
@ErikBjare
Copy link
Member

ErikBjare commented Jul 8, 2016

Note if you came from the README: ActivityWatch for Android is likely to take quite a while to get built, but Google is adding an Usage dashboard to Android P, and there are several apps already good at collecting usage-data (such as SmarterTime). We suggest you use something like SmarterTime in the meanwhile (or anything else that has a good data export), and we'll work together on creating a way to import that data into ActivityWatch later. Thank you for understanding 🙂


Two parts:

  • A basic client lib in Java
  • An Android watcher (app)

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@ErikBjare

This comment has been minimized.

Copy link
Member

ErikBjare commented Jul 8, 2016

@emarforio could possibly check this out. A good lead would be to look how RescueTime does this (requiring accessibility permissions in settings for instance).

@ErikBjare

This comment has been minimized.

Copy link
Member

ErikBjare commented Mar 28, 2017

python-for-android seems to have gotten a lot better lately. It even supports using a webview connected to a local webserver as the app.

Might be feasible after all.

@ErikBjare

This comment has been minimized.

Copy link
Member

ErikBjare commented Oct 3, 2017

Reviving interest due to feedback on this idea.

Looks like we could create a service and a webview with python-for-android.

However, I'm not sure how they would communicate. It might not be a good idea to have aw-server running in the background all the time, perhaps it should only run when the webview is active?

@emarforio

This comment has been minimized.

Copy link
Member

emarforio commented Oct 6, 2017

One possible way of implementing the app:

  • When installed, app does nothing, user has to open it to enable features, kind of "opt-in"
  • From the front-end the user can activate the service
  • When front-end is closed, the service keeps on running in the background
  • To disable the service, open the front-end and stop it explicitly

About how the service and webview will communicate, i have no python-for-android solution in mind but in regular (Java) development you could use Broadcasts, maybe that could be used here as well?

@ErikBjare

This comment has been minimized.

Copy link
Member

ErikBjare commented Oct 6, 2017

Thanks for the suggestions!

It seems that Broadcasts arrive in arbitrary order, so I don't think that's an option.

@exagil

This comment has been minimized.

Copy link

exagil commented Nov 24, 2017

I am a professional Android App developer and could contribute to building a native version of the app. What do you think about it?

@ErikBjare

This comment has been minimized.

Copy link
Member

ErikBjare commented Nov 24, 2017

@chi6rag That would be amazing, but we're not really sure how to build/architecture/design the Android app. (Bolt looks great btw!)

A good start would be to first write a service that can get the things we want and then see how to do the UI/server/datastore/syncing parts without having to rewrite those parts in Java/Kotlin. If you're interested in that just let me know!

@emarforio

This comment has been minimized.

Copy link
Member

emarforio commented Nov 24, 2017

@exagil

This comment has been minimized.

Copy link

exagil commented Nov 25, 2017

@ErikBjare we don't need to re-write the server/datastore/syncing parts in Java/Kotlin since the current python app could expose public interfaces to exchange data. However, on the Android side, we definitely need to write some syncing logic, using the native APIs. Yup, I am interested and we could discuss it. Do we have a slack channel for communication?

@johan-bjareholt

This comment has been minimized.

Copy link
Member

johan-bjareholt commented Nov 25, 2017

@chi6rag That's pretty much exactly the same way we have thought about it before aswell. If we packaged aw-server to run on android, we then would only need to program a android watcher to run in the background and use the REST API to push the events. Then we can get the data from the REST API again and visualize it in the app.

The part which we have little to no experience with is actually running python programs (in this case aw-server) on android. We know that it's possible, just not the best way to go about it.

We have discussed syncing before but have made no progress in terms of development. #35

|--------------------|
| aw-watcher-android |
| reports app usage  |    (REST)
|--------------------| ------------> |----------------------------|
                                     | aw-server                  |
                                     | stores and transforms data |
|--------------------| <------------ |----------------------------|
| activitywatch app  |    (REST)
| visualizes data    |
|--------------------|
@exagil

This comment has been minimized.

Copy link

exagil commented Nov 25, 2017

@johan-bjareholt I have a different idea in my mind and would need the team's feedback on it.
The server's responsibility is:

  1. Receive requests
  2. Perform computation
  3. Return Response.

In ActivityWatch's case, the server is aw-server which persists the data in a Mongo DB instance.
The whole point of exposing an interface (in this case, via a REST API) is because systems which speak different languages (in this case Python and Java) can communicate and synchronize.

This is why I would suggest not to embed aw-server inside the Android App. Instead, a better implementation would be to continuously push data to the server by following the contract it expects.

I saw that we were considered about the database being a single point of failure. I would say that there are ways to integrate HA into the system, which I believe, is not a problem we need to solve right now 😄.

Talking from the implementation perspective, we could use one of the following to sync the data captured from the mobile:
1. SyncAdapter: https://developer.android.com/training/sync-adapters/index.html
2. Firebase Job Dispatcher: https://developer.android.com/topic/performance/scheduling.html
3. JobScheduler: https://developer.android.com/reference/android/app/job/JobScheduler.html
4. AlarmManager: https://developer.android.com/reference/android/app/AlarmManager.html
5. Android Job: https://github.com/evernote/android-job

@ErikBjare @emarforio @johan-bjareholt what do you think?

@johan-bjareholt

This comment has been minimized.

Copy link
Member

johan-bjareholt commented Nov 25, 2017

@chi6rag Not having aw-server locally would create multiple issues

  1. You need to set up an aw-server on a computer to use the app
  2. You would need internet access to see the results
  3. You would have a single point of failure (a single remote aw-server)

Number one and number two are the biggest downsides, in my opinion it is very important to have an app which can be used instantly after it is installed so it's easy to use and doesn't need any configuration.

Our original idea was more akin to having one aw-server for each device and then sync buckets between all the servers making a private decentralized network, similar to how syncthing works.

@exagil

This comment has been minimized.

Copy link

exagil commented Nov 26, 2017

@johan-bjareholt Okay, if I understand clearly, we want a client app which can be used instantly after install - This means that the user should be able to track his usage of time spent on various other apps without worrying about connecting to the internet.

In order to do that, we don't need to be subscribed to the internet always. Which means, even when the user doesn't have internet access, he would be able to use the app and the app would continue to track his activities in the background. If the user opens the app while he is not connected to the internet, he would continue to see the time he spent on different apps. There is a category of apps known as offline-first-apps which are built especially to be used while the user is offline. So point no. 2 is not a problem.

Coming to point no. 1, one would have to set up aw-server somewhere. Right now, if you install the ActivityWatch client, it anyways runs the aw-server module using the following piece of code:

if "aw-server" in autostart_modules:
      self.start("aw-server")

One clear problem that I see is that if we run aw-server on Android, it would need to run a MongoDB instance on the phone, and MongoDB doesn't have an Android distribution yet.

The way RescueTime does that is that they sync the data to the cloud. Since ActivityWatch is an open source version of it, we have several options:

  1. Sync it on ActivityWatch's cloud and keep the code open source so that one could see what runs on the backend. If you think this would be a single point of failure, it is possible to put replication and auto-failover in place so that data is never lost. Also, it would be nice to give the user, an option to sync the data with the cloud or not. In case he doesn't want to sync the data to the cloud, he can continue using the app.
  2. Connect to Firebase Realtime Database both on the app and the Desktop client side, and sync the data from there. One doesn't need to always get the data from the API. It would be synced to local every time. Also, in this case, the user could use their Firebase API key (which would be a configuration) to keep data on their own instance of Firebase Realtime DB.

I would have to read more about the approach that Syncthing is taking before I could comment more about it.

@ErikBjare

This comment has been minimized.

Copy link
Member

ErikBjare commented Nov 26, 2017

ActivityWatch supports several storage backends, one of them is MongoDB but right now SQLite is the default.

The way RescueTime does that is that they sync the data to the cloud. Since ActivityWatch is an open source version of it, we have several options: ...

We don't want to run a cloud service or use a centralized service like Firebase, so we have to investigate alternative methods of syncing. This makes the problem a bit harder, but I believe it's doable and could helps with privacy and prevents data lock-in. It's been discussed in #35.

@ErikBjare

This comment has been minimized.

Copy link
Member

ErikBjare commented Nov 26, 2017

I'd just like to add that I don't think we should be too concerned about sync this early since we haven't even solved it on the desktop yet. As long as the bucket and event model looks the same I think we can work out how to get sync to work later.

@v4dkou

This comment has been minimized.

Copy link

v4dkou commented Feb 26, 2018

@ErikBjare @johan-bjareholt

About @chi6rag's idea of using an off-the-shelf platform to sync NoSQL database.
If nobody wants to be bothered with Firebase or rolling out custom syncing, there's always an alternative:
https://realm.io/
Quite solid community, can be self-hosted, OOS

Running aw-server on an Android device will undoubtedly be a PITA due to certain restrictions on background services imposed in later versions of Android. We could try just running the server with SQLite storage backend when the Dashboard is active, but listening for notifications in background through your own channel (as opposed to push-notifications) is a big no-no for Android due to battery limitations.

Above all, I would outline the scope of what we expect from an Android version of ActivityWatch.
For instance, should we track what user is doing on their device or just display the info?
If it's the latter, we can start with a fairly simple online-only client app for aw-server.
It's a whole different story otherwise, and there is a problem to be discussed right there.

Meanwhile, I am wondering, why isn't an iOS version considered, given there's already a macOS version available?

@ErikBjare

This comment has been minimized.

Copy link
Member

ErikBjare commented Feb 26, 2018

@v4dkou Thanks for the input, I've looked at Realm before but will take another look.

I think the first thing we want out of an Android app is just tracking, visualization and such is not as highly prioritized. So simply dumping events into a plain SQLite database would be a good first step.

An iOS version isn't considered at this time because the lead developers (me, @johan-bjareholt) have absolutely zero experience with it. We own neither a Mac nor an iOS device so we wouldn't even be able to develop for it.

@v4dkou

This comment has been minimized.

Copy link

v4dkou commented Feb 27, 2018

@ErikBjare @johan-bjareholt OK, let's work the tracking through

About tracking

  1. "Misuses" of the AccessibilityService are seemingly frowned upon by Google now, although nobody really knows if they will take action.
    https://www.reddit.com/r/Android/comments/7c4go5/is_google_play_really_going_to_suspend_all_apps/

  2. Permissions to get required info from ActivityManager (::getRunningTasks, ::getRecentTasks) are elevated to "signatureOrSystem", and now those methods return only a small subset of data, typically only about the calling app itself.

For the first iteration, I would recommend using UsageStatsManager, given it provides at the very least some date we need: periods of data, when a certain app was open.
The user should be prompted to enable access to this data in Settings, but after that it's a clear cut.

The upside is that the system keeps track of the data, and we are free to collect it anytime we want, which means the app will not draw performance down.
The downside is that the data is not really detailed.

My opinion would be that it's a good first step, because later on we can let the user decide, if they want the app to go light on battery or a more detailed report.

Goals

To focus our efforts I'd like to gather a few usecases/user stories.
Feel free to join me.

  • I would love to have tracked data from my PC on my phone to fill time reports in JIRA while I am commuting (public transport), as I don't want to be bothered with that in the office.
  • I would like to have data from the PC and my phone combined to see how much time I've spent on work-related tasks on my phone (messanging, business calls, productivity apps)

Overall architecture

  1. What is your stance on using Kotlin, given it's recognized as an official language for Android? Is there any preferred stack of frameworks (i.e. Dagger 2 for DI)? I could make a neutral demo with few dependencies and pure Android SDK, but that will take a lot of boilerplate or just do it the way we do in our development shop.
    Also, I would mention cross-platform solutions like React Native, but I think it will make outside contribution to this venture way too hard.
  2. What we do with the DB and syncing:
    a) Make a DB similar to aw-server's, then connecting to it via REST API, dumping data in something like aw-watcher-android bucket, essentially making the Android app yet another watcher
    b) Schedule running aw-server locally
    c) Use Realm as a DB and syncing implementation.

Personally, I think that point a) feels way more natural than the rest, being the cleanest to implement and having some of my goals for an Android app met. Later on we could expand upon that app, having it behave as both aw-server and aw-watcher-android.

What do you guys think?
I've found the core ActivityWatch app to be superb, so I'd love to write a specification with wireframes for the app this weekend, and then help you with the development, so that this ecosystem excels in yet another way. 😄

@ErikBjare

This comment has been minimized.

Copy link
Member

ErikBjare commented Mar 10, 2018

Sorry for the really late reply @v4dkou, I have exams coming up. Really appreciating you taking the time to write that up, hope I didn't let you down by waiting to reply!

I think right now just getting started is what is most important. So just throwing basic data into a simple SQLite database and having the possibility to export it as a JSON file (which could then be imported into aw-server). A fancy UI, syncing, etc would probably come later.

I can't say much about Kotlin since I've never really tried it, but I'd probably prefer it to Java now that it has received Googles blessing. I don't know anything about Android frameworks, but you seem pretty knowledgeable, so what do you think is the best approach?

Feel free to throw together some wireframes or prototype something that collects data with UsageStatsManager 🙂

@ErikBjare

This comment has been minimized.

Copy link
Member

ErikBjare commented Dec 16, 2018

I started building something small, mostly because I was curious about Android development in general. Find the code here: https://github.com/ActivityWatch/aw-android

@v4dkou

This comment has been minimized.

Copy link

v4dkou commented Dec 17, 2018

@ErikBjare Great to see the project is going forward. 🤘
Sorry I disappeared; didn't notice the reply and got caught up with work

I am going to send some pull requests every once in a while.
I see there is a little bit of cleaning up to be done (i.e. getVersion() left after the Gradle resValue solution 🙂), and you are curious about Android development, which begs the question: what kind of help is more welcome with you?

  1. Reviews, refactoring, general Kotlin/Android SDK tips
  2. Feature development
  3. UI improvements

If you are OK with somebody else setting up the SQLite/JSON data pipeline, I could help you in a couple of days.
I suggest using greenDAO as ORM, because of its high performance compared to other solutions. It might be a little bit trickier to set up than the official and recently popular Room, but given the amount of data we have, I'd say it's worth it.

As you are the most acquainted with the system as a whole, could you write an API spec for usage stats in a way that makes sense for ActivityWatch?

In any way, I think it would be great if you'd set up Slack or something for rapid discussion of smaller topics. Going to share some wireframes this January.

Good luck!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment