UrlChecker
UrlChecker copied to clipboard
Incognito for chromium browsers
#115
This is still a WIP, there are a lot of things to be done yet, but I don't want to keep these and not upload it (again). I think it would be best to check this code first, make the necessary changes and then build on top of it, that's why there are some TODOs in the code. The strings from the OpenModule config have not been updated yet because of this.
Added support for all firefox(fenix) forks.
Added support for chromium forks, it launches the incognito activity and then stores the URL in the clipboard, the user is expected to paste it in the search bar, we then restore the clipboard contents.
No screenshots, nothing in the GUI has changed (yet).
Here is a diagram that kind of explains the code, there are some differences because threading is not linear.
flowchart TD
incognito(User opens URL in incognito mode)
store[Store previous clipboard content]
load[Load incognito URL into clipboard]
wait[Wait]
interrupt{"User requested
to open another
incognito?"}
check{"Is the clipboard
content the same
as the loaded URL?"}
restore[Restore stored clipboard content]
replace[Store to later restore]
finish(Process finished)
incognito --> store --> load --> wait
wait --> check
%% User does nothing
check --> |Yes| interrupt
%% Uses the clipboard
check --> |No| replace
replace --> interrupt
interrupt --> |Yes| load
interrupt --> |No| restore
restore --> finish
Can't believe GitHub has support for these, I was going to link to the official mermaid web.
The order I would advise checking the files (as is the one in which I made them) is:
- ClipboardBorrower
- AutoClipboard
- UrlHelper
- Incognito
Clipboard Borrower is meant to handle the logic of borrowing the clipboard, the user should be able to freely use their clipboard even when we are borrowing it, so we keep track of the last item the clipboard had that we did not put in there. At the very end we restore it. The only situation a user would not have access to their clipboard content is inmediatly after opening an URL in incognito, they would have to wait until we restore the clipboard. This could be solved in the future by using the SemiAuto form UrlHelper, which would restore it after X seconds but if you tap the bubble it would restore it immediately.
Auto Clipboard borrows the clipboard inmediatly and restores it after X seconds, if called again before this, it cancels the thread and starts the timer again.
UrlHelper keeps track of the options available for this "compatibility" we made:
- AutoClipboard: Restores the clipboard after a set amount of time.
- ManualClipboard: Restores it when the user taps in the bubble (not implemented).
- SemiAutoClipboard: Restores the clipboard after a set amount of time, if the user taps the bubble earlier, it is restored earlier.
Some things to be considered:
- Auto should never use a bubble, it doesn't make much sense to not use instead SemiAuto.
- Auto should only use: nothing (current implementation, only for android 9 or less), notifications (android 10 or more), acessibility service (don't know yet which versions)
- Manual and SemiAuto should not use notifications, it's just a total hassle to swipe down and the find the notification to tap it, a bubble is just more convenient.
Incognito now has a static section in which scripts can be added to detect apps that can run incognito and modify the intent to do so, I thought this could be extracted into a database file, but I didn't do it because it's probably mesier and, honestly, aside from fenix and chromium, we don't know how other apps work with incognito, it could be more complex.
As a side note, this whole system can help if an application can't open the URLs it is supposed to and has access to a search bar or something similar, which is unlikely, but the option is there.
I think that's all, after you've made all the necessary changes, just ping me and I'll come back to do what's left (bubble and notification), after that I'll push and then I might look at the accesibily service, but I don't promise anything. Take all the time you need.
Also as stated in this comment there is some kind of compatibility with customs tabs, but I have not made any tests with it yet, as I want everything else working correctly first.
This PR builds correctly, here is the generated apk. This unsigned version can be installed alongside the original app and should only be used for testing the changes, not for daily usage.
Download testing apk |
---|
You must be logged in for the link to work. The link will expire at 2023-12-31T15:48:40Z.
This is an automatic comment created by a Github Action
Note: I haven't forgot about this. But due to the complexity and their experimental value I'm going to prioritize other tasks over this, sorry. I may add it as an experimental feature though.
In any case, don't hesitate to keep working on it and ask any question you may need (I need my computer to fully review a pr, but I read all messages from my phone so it is much much faster)
I'll continue with the bubble then, it should bring support to all android versions.
This PR builds correctly, here is the generated apk. This unsigned version can be installed alongside the original app and should only be used for testing the changes, not for daily usage.
Download testing apk |
---|
You must be logged in for the link to work. The link will expire in 14 days, at Thu Sep 19 16:16:19 UTC 2024.
This is an automatic comment created by a Github Action
Finally, I added support for borrowing a clipboard using a bubble. I started working on this like a month ago and it took 2 weeks, since then I couldn't find the time to clean the code. I think that should be it for some time. There is still work to do but, if anyone wants to test this they should be able to, they need to first give permission manually to the app so it can draw over other apps, or it will crash. Currently there is no way to change the helper used, this one creates a bubble that when tapped will restore the contents of the clipboard, it will also do the same after 10 seconds of being created.
So, things that still need tweaking:
- There are some strings here and there that are hardcoded, they are properly tagged with either FIXME or TODO.
- To check if we have access to the clipboard I access directly to it, which triggers the toasts, this and the need to keep previous contents of the clipboard stored make it so that for every
release
,borrow
orcanUseClip
call it shows 2 toast each, for a total of 6 every time the user wants to open chromium in incognito. - I don't like at all the way I made to choose the helper
getHelper
, it is really bad. But I did not want to keep pushing this any longer.
Now, the "janky" parts. Because we are trying to use the clipboard when we shouldn't, I had to make some weird workarounds. If we are not focused we create a Bubble so we get focus, and before it shows we do what we need with the clipboard and we proceed to kill the bubble, that means that we need to wait for the UI thread to start creating the Bubble to complete background operations on the clipboard. We also can't reuse the bubble that is visible because of its flags, I spent a lot of time trying to figure it out, but I think is not possible without ruining the user experience, if we have focus on the bubble, we can't use the keyboard on other apps.
I also don't know if using a notification will help avoid using a fake bubble, but it is very unlikely.
I changed the logic to check if the clipboard has changed, in debug it doesn't check the label, in release it is just equals
. This is because the emulator keeps syncing the clipboard of the PC and Android.
Things that still need to be done:
- Remember the position of the bubble.
- Make it impossible so the user can move the coordinates of the bubble outside the screen (although the view doesn't go out).
I think that's all.
So, this should be almost everything done. The only thing that I haven't added is keeping the coordinates of the bubble, which last time I tried I couldn't do properly (also tried to keep in mind foldables).
Added a button in the open module config to change the settings, and also, there is an explanation, however... is a huge wall of text, don't really know if it can be summarized as the feature is really complex, and I feel a lot of that information can be relevant to the end user.
Because of that complexity I think an option (worst case scenario) could be to just hide this feature, I still use the prototype frequently, and while I can't say I find it convenient is not as inconvenient as this hacky code could make it seem, and someone could put this feature to use.
Also there is now a "None" helper, when selected if the user tries to open the URL in chrome in incognito it will work just like it currently does, it opens it without incognito.
Let me know what you think when you can (don't worry, there is no hurry).
While I was at it I also made a working version that uses the accessibility service, so it is fully automatic, in the emulator it was really sloppy, but on my phone it was great. The code is not store specific (yet), and I won't upload it until you tell me, this pr, another pr, or just not, as I remember you saying that you weren't sure about using the accessibility service. The feature is in this branch . Feel free to check it out.
All the work here is incredible, and being able to make it work was no easy task I'm sure.
I've think about it, and how to include it in the app without permission issues or other things that play store may not like. And I had an idea that, now that the feature is complete, I think makes even more sense. Tell me your opinion.
The idea is: create a separate app.
This app would have a main screen, that will explain the purpose and the usage (that wall of text you mention for example) and maybe a button to try and configure.
Then it would have a transparent single activity that will perform the "open in a private session in chrome" feature from the provided link. From the user perspective they could either "send" the link to the activity (and it will be opened) or click and choose (if they don't have a default browser). Similar to other apps that also allows you to "open a link" differently.
The separate app would also allow it to have as many permissions as needed, or to create different versions depending on the store. Plus maybe adding support for other browsers!
But the main benefit is that, by being separate, you could even use it with other "url managers", or even none (with the share option). Even in that case, however, URLCheck can have special code to detect this app and "integrate" with it (by for example removing from the list of available apps and calling it when using the incognito button with chrome).
Sorry if this seems more like a "I don't want this on the app" response. It's not. It's just that this functionality is way more complex than a simple "button", and I'm afraid that adding it to the app itself will make it very difficult to maintain. Plus I genuinely think that people will benefit from this feature independently.
If you like the idea, I can help you setup an independent app with the code. And feel free to reuse any util/class from URLCheck of course (like the readme says: as long as you mention me somewhere it's enough :)
Plus I can also try to publish it on my Play Store account if you don't plan to create one yourself (although in this case I recommend to start with FDroid first).
Let me know what you think. If you like the idea of a separate app or not. In either case I'll support you 👍
I understand, to be honest I was feeling the same while coding this, I could only think about how all this originates from a single boolean, which is there on purpose for some reason, and how it made these unnecesary permissions necessary, and while I tried my best to make good code, the "nature of fighting back" against something not meant to be that way made it impossible to have code as clean as I had hoped.
It's a shame, making this a library won't fix the problem either, so I guess the only alternative is making it a separate app, as you propose. This is one of the most requested features, and it is really useful, so I think it should be released, if that means a new app I'm okay with it. Although it will take some time and I don't even know where to start.
I would like, if possible, to at least have an experimental apk of this branch, or another one more up to date, on the releases tab of the github. This way if anyone wants to test it, there is the possibility of having early feedback. We can store the branch on the shelf too.
Ok! No problem. Let's do the following then:
- Update the branch with the latest master changes (to be precise merge master into incognito-clipboard). This will make it work with the latest version, and help with future changes. I'm experienced with merges, and I should probably be able to do it myself without issue this weekend, but I'll wait for your comment (just in case your already started it).
- Split the code as much as possible. Try to separate everything into an independent package, and try to have the minimum "modifications" to the standard code. Basically try to reduced the number of modified files in the pr as much as possible. This may be hard in some cases, but from what I see it is already highly separated.
- Maybe move the code to a separate version. Versions allows apps to have a common core but different "versions" which can include new classes, alternate assets, or even manifest modifications. This would be perfect and even though I've only used versions for minor changes I know more or less what to look for.
- And finally, merge the PR.
This should allow to keep the original app and additionally build the modified version without issue (and maybe even publish it as apk free on Github if I finally have the time to implement the apk releases...ahem).
Anyway, let's start from the beginning: do you want me to do the branches update or you want to try it yourself?
do you want me to do the branches update or you want to try it yourself?
I'll do the merge myself, I want to add the accessibility service too, and I have some fixes in that branch, then I'll see how to split it properly, I think the incognito class could be a problem as I added a lot of the code there.
I'm going to move all the extra functions I added to the incognito class, chromium should be its own class, same goes for fenix. I added those there at first because I felt I shouldn't be adding much for this feature, but now that it is going to be a standalone package, I don't think these restrictions are necessary anymore. So it might take a little longer, not much though.
Also, I don't understand, why merge with master first, shouldn't it be last when merging the PR? Seems like an extra step, as the conflicts are still here in github and if there is a new commit, say right now, that wouldn't be in this PR.
Also, I don't understand, why merge with master first, shouldn't it be last when merging the PR? Seems like an extra step, as the conflicts are still here in github and if there is a new commit, say right now, that wouldn't be in this PR.
Because of the merges, precisely. A pr with merge conflicts cannot be merged directly (git just doesn't know what to do) so it needs to be "resolved" manually. I could do it myself, no issue, but it's a good practice for the owner of the pr to do it (after all, the one that made the code should know better how to resolve the conflicts).
The process is to merge master into the pr branch. Depending on how you are doing it (command line, ide, web) it could be either resolved automatically or not. In the end you should have a commit that is basically the merge of both, and that commit is "added" to the branch. That will make the pr "clean" and easier to review.
As for the merge, your merge is not valid I'm afraid. A valid merge commit should display two parents (the one from the branch and the other from master). Yours have only one, so from git point of view is as if you changed those files yourself independently. How did you made the merge? I can try to fix it for you if you prefer.
your merge is not valid
As I was suspecting, thanks for making it clear.
How did you made the merge?
I use Sublime Merge, seems it is because I squashed the merge, didn't want to fill this PR with commits from a backlog of 6 months, now I know I shouldn't do it that way.
Since it's just both of us I guess I could try to delete that last commit from the history, to keep it clean, if that's okay, I know it's a hassle but that way I can learn.
Still I don't understand why do this first instead of last, just before merging, in case there is any commits from master in between.
How did you made the merge? I use Sublime Merge, seems it is because I squashed the merge, didn't want to fill this PR with commits from a backlog of 6 months, now I know I shouldn't do it that way.
Merges are displayed differently, git knows that it's a merge so it doesn't show the others (you can see this in the #361)
Since it's just both of us I guess I could try to delete that last commit from the history, to keep it clean, if that's okay, I know it's a hassle but that way I can learn.
Yeah. You could also make a "revert" commit, but in this case just force-push to the previous and it'll be cleaner.
Still I don't understand why do this first instead of last, just before merging, in case there is any commits from master in between.
Even though it's useful to have your branch updated, truth is that I should have added the merge step as third, just before the pr merge. I rewrote that comment a couple times so it may have been displaced. Sorry!
Done, I'll start on it then. ~Let's pretend I didn't force push to this repo instead of mine, almost had a heart attack, apologies about that, could have ended badly.~
Done, I'll start on it then. ~Let's pretend I didn't force push to this repo instead of mine, almost had a heart attack, apologies about that, could have ended badly.~
XD don't worry about that. I should lock master (maybe it is already? I don't remember) but even if you did, there is always a way to restore it. With git nothing is deleted (almost) never.
I should lock master (maybe it is already? I don't remember)
I think it is, tried to fix one hardcoded string a month or so ago and couldn't (don't worry, you fixed it at some point later)
So, I moved everything to a new package, tried to make it like a library, that's why there are some repeated folders. Things that are still outside said package are resources, everything else is nicely packed together. Now I should make it a real library, and move the resources there, also I would need to duplicate some code like the enum interface and methods as well as GenericPrefs.
Maybe move the code to a separate version
I understand this is a specific tool, but can't find out how to start on this since the word is so common, my searches yield no result. Could you point me on how to do this?
Also I found a bug with the clipboard borrower on my personal phone, but for reasons I will not explain I can't debug it right now, it will have to wait (just writing it somewhere to not forget about it).
Maybe move the code to a separate version
I understand this is a specific tool, but can't find out how to start on this since the word is so common, my searches yield no result. Could you point me on how to do this?
Oh, search for "gradle flavours", and flavourDimension (the code I was using as reference uses "version" as one of those flavours, but maybe any word can be used). It's apparently similar to buildTypes, but has some different considerations. Honestly I don't know much about them, but I know one of those allows to add extra modules...somehow
Is this still in progress or is it now ready to be reviewed? I'm asking because if this is still in progress I think it is a good idea to mark the pr as a draft (don't know why I haven't suggested that before...)
I also see some conflicts, but I can try to fix them myself if needed.
Is this still in progress or is it now ready to be reviewed?
It is still WIP, I haven't been at home for a few weeks (in fact I got the mail notification just after coming back), but before that, I tried at least 3 times to move the code to a separate "Android Library" so then it can be easily transfered to the other app. However, I can't make it work, since I have never made an app from scratch there are some things I couldn't figure out (like making the resources of the library work properly, and then actually calling the library from the main app). I was going to give it one last shot before asking for help.
mark the pr as a draft
Sure, I'll do it myself while I'm here.
I also see some conflicts, but I can try to fix them myself if needed.
Do not worry about the conflicts, those I will fix myself when everything is ready to be merged.
So, this time I had more luck and found what I needed, so I did it myself!
Anyways, before the module/library thing, there are 2 bugs currently I discovered yesterday, both I cannot debug:
- Sometimes, the accessibility service doesn't start or something similar. This happened after rebooting my device. Since there is no way for us to control the life cycle of the service, that task lies on the OS, we can't start it, so the only fix is to reboot the device, I even tried to enable and disable the service multiple times. It is not easily reproducible because it happens at random, and it is out of our control, so I think this can't be solved.
- If using the clipboard as helper, if it is empty (easily doable with Simple Clipboard Editor), it thinks we can't access it (I coded it that way, whoops). I found the bug on my phone, which for reasons, I can't connect to my PC and the emulator keeps the clipboard with a label (even when I told it not to sync with my PC), so it is always non-empty. Therefore I have no way to debug this properly, I will still try to fix it, but I can't test if it works.
Now, the module, this branch starting 3rd of September, contains alll the small changes made to create the module library. Some commits are worth checking, as I'm not sure I did it right:
- Fix incorrect library naming, copy missing classes and functions: There are some classes copied from URLChecker, as I was using them previously, the module is supposed to work without URLChecker so the code must be either packaged with the module or on another module that substitutes the duplicate code. Duplicate code is preceded by a comment:
// ---
// Everything, starting here, is copied from URLChecker
// TODO: move to external library?
// ---
- Move resources to library, copy missing resources: Same as before, duplicate resources have the comment at the end instead:
<!-- -->
<!-- This resource is copied from URLChecker -->
<!-- TODO: move to external library? -->
<!-- -->
-
Extract calls to ForceURL and Add assertions to avoid calling methods when IS_INCOGNITO is false (whoops, I forgot to merge those): The
IncognitoDimension.java
file, contains minimal code, the purpose of the file is to wrap allimport ...forceurl
here, so only calls to the module are allowed here. There are 2 versions, gradle chooses which file will use based on the flavor. The methods of the file should only be called when IS_INCOGNITO is true, that way the code is not scarced without reason. - The rest of build.gradle I copied from URLChecker.
- The old naming scheme for the strings doesn't make much sense in the new module.