CatimaLoyalty / Android

Catima, a Loyalty Card & Ticket Manager for Android
https://catima.app
GNU General Public License v3.0
729 stars 141 forks source link

[Feature offered] Power screen cards #146

Closed djechelon closed 2 years ago

djechelon commented 3 years ago

I'd like to contribute to this project, if I can manage to find time and learn the internals of the code, to provide an extremely useful feature for people who wanto to use this app in their daily life. Currently, I own CardMate adware app and I would like to switch to something open source. Thanks dns66 anyway.

Android 11, for thos who already got it, provides APIs to customize the Power Menu screen. Here is another interesting article.

User story. User holds the power button and the Device Controls menu is displayed. Maybe the user has Google Pay credit cards on top, or some Google Home devices. Catima will show the most favourite cards that are configured from the user interface.

In the future, the cards displayed and their order on Device Controls/Power Menu Screen could be based on other factors as well.

TheLastProject commented 3 years ago

That would be a great feature to have. Sadly I do not currently own an Android 11 device myself (I'm still running Android 9, although I do expect to be able to upgrade to 11 in the future) so I cannot personally test it beyond trying it in an emulator but I will very much welcome this feature.

djechelon commented 3 years ago

I'm starting research anyway. I need to ensure that the information I found is correct and applicable. Not that easy but that guy wrote an app

djechelon commented 3 years ago

Grrrrrrrrr, it looks like there are no public apis that Google Pay use. I'll try to poke into some decompiled source. There MUST be some unobfuscated "import" java somewhere.

Damn!

TheLastProject commented 3 years ago

I know the Home Assistant Android app supports showing things on the power screen. Maybe looking into their source code can help you? https://github.com/home-assistant/android

djechelon commented 3 years ago

Aha, looks like Home Assistant open source uses APIs to integrate with Device Controls feature, the same used by Google Home. I am telling this because after installing Home Assistant from F-Droid I now see both icons "Google Home" and "Home Assistant" on my power menu.

But those fall into the Device Controls APIs I mentioned in my original link, which are not fit for card wallet etc (mainly because they are templated: you don't want to display a loyalty card like a temperature gauge). Maybe this video shows the best that can be achieved: a button for each "most frequently used" card (and there is one actual barcode some people want to display on every purchase)

The best fit is the Quick Access Wallet but it has a tremendous drawback. It will totally disable smart pay, and probably nobody is going to give up on XXXPay.

djechelon commented 3 years ago

Google, are you f**** kidding me? 😄

https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java

djechelon commented 3 years ago

Will be reopened in the event that Google allows third party to develop powerscreen widgets

TheLastProject commented 3 years ago

I'd rather keep it open because we do still want this feature and I don't want to lose track of it. But I created a new label to make clear we can't do much here because Google.

TheLastProject commented 2 years ago

I am thinking we should maybe just implement it as Device Controls.

As you noticed, Google does require a StatefulBuilder but... what about these settings?

setAppIntent -> An intent that opens the loyalty card view setCustomColor -> Loyalty card colour setCustomIcon -> Loyalty card icon setDeviceType -> Try TYPE_UNKNOWN or TYPE_ROUTINE setStatus -> Control.STATUS_OK setTitle -> Loyalty card store name setSubtitle -> Loyalty card note / expiry / etc. (who knows what fits)

It may work decently enough?

djechelon commented 2 years ago

This is what is looks like when you have both payment cards and domotics. I added a few widgets now till my hardware is on an isolated network (ideally themostats show room temperature)

Screenshot_20210812-172625

But for my needs (covid pass and lottery pass) should be... hmmm... decently acceptable?

TheLastProject commented 2 years ago

Go for it and tell me if you need any help :)

djechelon commented 2 years ago

I understood that every card has a unique int id, and that the activity responsible for displaying a single entry should be LoyaltyCardViewActivity.class. Is that correct?

I also think, but it's easy to make both tests once I succeed one, that we should only use the StatelessBuilder for the kind/amount of information here. Unless we want to display loyalty points & such.

You should know better than me how to verify backwards compatibility. I had to upgrade to Java 11 otherwise no reactive streams, and I am working on the new service. @RequiresApi is a source level annotation, so I count that Android < 11 just do not attempt to invoke the new methods.

I hope to push something once I make it work on the emulator.

TheLastProject commented 2 years ago

Yup, just starting an intent for the ViewActivity class with the id value is enough to show the card. Something like this:

https://github.com/TheLastProject/Catima/blob/83ea6ffbf70275e6560ab5e6eaeb270a084f946c/app/src/main/java/protect/card_locker/MainActivity.java#L695-L699

As I understand the system, we need to use a StatefulBuilder too because Android requires it, but I'm 100% in favour of keeping it as simple as possible.

SpotBugs should tell us if we try to do anything not acceptable on older Android versions, so no need to worry too much about that.

djechelon commented 2 years ago

😠😠😠 Can't start any emulator. "The emulator process for AVD....... is terminated"

I don't know if this has anything to do with my Windows & virtualization setup (despite having shut down Hyper V and Docker)

Damnit!!! Any idea on how to test the code?

djechelon commented 2 years ago

Status

Can have Android detect the controls and allow selections of card to display on power menu. Only one app at once available, just as the NFC payment integration.

Can customize the title (between screens 1 and 2 I changed the resource)

But they still look "loading" when added permanently to the power screen

😢

Shots

Screenshot_20210831-181430 Screenshot_20210831-181534 Screenshot_20210831-185940

TheLastProject commented 2 years ago

Cool progress! If I look at https://developer.android.com/guide/topics/ui/device-control#create-publishers-for-controls, it seems to me that Android will call a createPublisherFor() code for each card it wants to show and you should return a StatefulBuilder there. Did you implement that function? I think that may be why it's loading forever.

djechelon commented 2 years ago

Not quite.

When you go to the settings in order to manage the available widgets on screen, Android calls createPublisherForAllAvailable() to get all of them. Using the SQLite cursor, it's easy to make a reactive list of widgets with a title and a label. Perhaps the Intent is quite useless in this phase. You then add your desired widgets to the screen, because not all are required to appear.

Next, when you press the Power button Android renders the power controls. Android remembers the IDs of the controls from before, and calls createPublisherFor() with the list of the control IDs to render. By that time, the implementor has to render stateful controls, especially for what concerns about state of control (e.g. temperature). I suspect that Android can, at any time, issue a refresh by calling that method. In our case, we are not displaying loyalty points.

Finally, despite the Control holding an Intent, I couldn't get performControlAction() to be invoked, perhaps because of the loading state.

From what I learned, the intent is not necessarily invoked directly. As stateless templates, the widgets will invoke the method with a particular subclass of ControlAction, which is CommandAction. That may be used to fire the intent. Anyway the app has to return to the OS the OK signal.

I believe the problem is still in the second method

djechelon commented 2 years ago

The problem was not calling subscriber.onSubscribe() which takes a subscription.

The real pain was creating a brand new subscription class, while Rxjs (and possibly Rxjava) have their own Subscription implementation and handle all the canceling staff.

Luckily, Catima can send widgets one-shot and doesn't need to provide periodic asynchronous updates like home automation widgets

djechelon commented 2 years ago

Hello Maintainer, do you have an update with the issue/PR? I'd love 💗 to see any of the two implementations (short tap, long tap) in production.

For the record, my Pixel 5 got upgraded to A12 and now the power screen works differently. Does not appear using "power" button. I actually forgot how the menu appears now, there are some settings...

Thanks

TheLastProject commented 2 years ago

Sorry, got distracted with other PRs and October was very busy due to Hacktoberfest. I'll try to take another look this weekend and merge it with the current master branch.

I'll probably not put it in the next release, given that is already a big release, but if I get spotBugs to be happy it will probably make it into the release after.