Open KieronQuinn opened 1 year ago
Thank you for the heads up. Fixed in 0.4.9!
I did set it to android:foregroundServiceType="specialUse". Let's see if Google has any issues with that!
@joaomgcd See https://developer.android.com/about/versions/14/changes/fgs-types-required#special-use we are supposed to also add the property and this will all go through a google form very soon :(
If this road is chosen then the value should be well defined and we should already prepare a talk to convince Google, this will be a nightmare as each and every time :(
You can override the service declaration in your manifest with your own description and the manifest merger will merge it. The important thing in this fix was the code.
I perfectly know that, but you missed the important part: Google Form to publish in Play Store in a couple of months or less depending on their decisions.
If all apps puts random things there it will be harder to have a common ground discussion with Google so that they accept the permission and not reject your app and you'll be wondering what to do in that case.
The specialUse case is for certain one that will be under the form and will be the harder to get validated by the dumb support team.
I don't read it as that. I read it as it's a freeform field to put your use for it, like how it is in the various forms on the Play Console. I think having a shared one would actually be detrimental as they'd view it as either spam or potentially malicious if everyone submitted the same generic "This is for Tasker" reason.
The use is the same for everyone as it's the same library and the same service name.
I suppose you never had to deal with Google support for permission forms and the joy it is. At 99,99% the answer will be rejected, we can not confirm that this is a core feature of your application. The reviewer barely speak English and everything needs to be very simple sentences. Try to explain this is to allow automation from another app named tasker.
I regularly deal with Google's policy team, in fact I spent much of last week arguing with them to turn on a VPN because they indeed do not read what is in front of them. This was for an app with 1.2 million users and was blocking an important update - they are useless.
However, I reiterate, I do not think sending the same message from multiple apps to them is a very good idea. Their ideas of "spam" are very rudimentary, and I'm pretty confident this would fall under them. The use is not the same for everyone, plugins do not all do the same thing. For example, the plugin at the root of this thread is for allowing Tasker to update and modify components of my app to effect what is displayed in a widget - it's not just "Allows Tasker to work with my app". They are more likely to approve an app-specific description than one they've seen before from another app.
Well I'll let you discover then when they tell you that you do not need a foreground service for that.
Tasker is foreground if it binds to our service for your need you do not need to go foreground.
To update widget they will tell you work manager that is made for this. The concept of other app calling your app won't matter. That's why yes it matters to explain why tasker needs to start a foreground service to communicate with our app even if in most case it actually don't.
You've essentially just proven my point. If I were to use a generic message, they would indeed ask why I need a foreground service to update a widget. That is why it should be custom, so you can provide a explanation of why it is needed. Just saying "oh it works with this app called Tasker" would most likely just be rejected, whereas a detailed message about what the Tasker integration provides and why a separate service is needed would be far, far better.
Anyway, since we're never going to reach an agreement on this, how about as a compromise there could be a generic reason in the library, with a strong emphasis of overriding it with your own. If you want to run the risk of using a generic message, that's on you. But when in a year they blanket ban every app with the generic message because it's deemed "spam" or because one of them was doing something deemed malicious and therefore they're all connected, don't say you weren't warned.
I'll remove the plugin and tell user to call my API instead.
And the explanation will be on the form that you fill not in the 20 char you'll use there. So yes having all tasker services using the same explanation that you justify in the form will. It's easier to keep the service name via R8 to ensure Google is aware than having each and every user explaining that no we do not need foreground but Takser current API requires ven if in fact it does not
Future will tell but 12 years on Play Store touching with many perm form we already know it will be a shit show. They want the end of foreground services.
The developer page specifically asks for the explanation to be in the manifest, and asks you to provide enough information in it alone - putting a brief explanation in here and expecting them to read the form will probably not go well
I agree the service name will stay the same - it will have to - but the use case does not need to.
And yes, they are doing everything they can to kill off foreground services. The Play Store is minefield to submit to nowadays, which is why I no longer submit personal projects due to the risk of their stupid "association" bans impacting my work, because one test phone was on the same IP once or something ridiculous like that. It's bad enough having to communicate with the policy team for large apps, let alone small ones.
Again there is no need for the service to be foreground for 99% of the cases. So either we can have a default communication or most people will be rejected. Tasker is foreground if it binds to our service we are foreground too.
So the actual real solution is to fix the API to not require foreground when not needed, not hoping that everyone will be able to pass a dumb review system handled by monkeys. This will be frustration for the whole Tasker eco system with no benefits.
Sorry for the late Response.
@Tolriq foreground services are required if the actions done in the service take more than 5 seconds to complete.
Unfortunately you can't really control how much time your service will take because sometimes users' devices are slow and will take a long time to perform even trivial operations.
Because of this I thought it would be appropriate to make foreground services a requirement?
What do you think?
Also, ( also for @KieronQuinn ) just thinking here: since not all plugins require actions or conditions (a plugin could only have an action or a condition and not both) I shouldn't declare the services at all in the plugin library's manifest, right? Because if I do, plugin developers will have to justify services that they don't even use. Am I thinking correctly?
@joaomgcd I don't know Tasker internals but since tasker is foreground it can just bind to the service and do not have any limitation in times. The 5 second limit for a service is the time to go foreground if you call startforeground else it ANR. But this is another story since you can bind and not call startForeground at all. (https://developer.android.com/guide/components/foreground-services#background-start-restriction-exemptions)
For the other question, yes if there's things that does not require the foreground services at all clients should not be forced to deal with the stupid Google review team.
One way could be to split the library in 2 parts so that it's clear what requires it (if it really requires) and what does not.
But really the question is are the services really needing the foreground here? I'm pretty sure we can solve this without foreground at all.
Hhmm, switching to binding services from what we have now is kind of a big refactor. π I would also have to do plenty of tests with it because I don't have much experience with binding services myself...
Thanks for the suggestion. I'll look into it.
You are not forced to go full bind and aidl :) You can just cheat the system.
You bind to the service without anything special or calls to the service (just a service connection to manage) and you keep doing what you do without calling startForeground, just a normal start.
The only question would be if OEMs have broken implementations that does not propagate the foreground state, but we already have to deal with OEMs that do not respect foreground at all so in the end it would not change a lot.
I see what you mean. Ok, let me try that and see how it works. Thanks!
So, first shot at this.
If you could try building the plugin library from source (get the latest version) and then make hasToRunServicesInForeground always return false and then try using this version of Tasker and see if it correctly runs your actions with the bound service but without putting it in the foreground...
Can you try that? π Thanks in advance!
I can try tomorrow but I'm not an advanced Tasker user. So not sure I'll be able to test all. A part of the plugin export state I don't even know how to properly use it on Tasker :p
It's really just a matter of adding a Yatse plugin action in a task and running it and see if it runs correctly :) If nothing crashes and it runs as expected (after you did the change to the code I mentioned above), then it means that Tasker is running the plugin correctly without asking it to be in the foreground.
Let me know if you have any questions!
@joaomgcd So tested with the hasToRunServicesInForeground to false and removing the FGS type from manifest to be sure and it does not crash and the simple commands like playpause works properly.
Not sure this counts as a full test, but this works in Android 14 :)
Sounds good :) And your app is already targeting Android 14, correct?
Yes and it crashed before I added the fgs types.
Cool! Ok, I'll try a release with this change then. Thanks for testing!
It will probably require some coordination between the lib and tasker to ensure no issue.
If the library is updated to remove the fgs type we need to check that tasker is up to date or find a way to warn the users to update tasker.
Yep.
<meta-data android:name="canBind">
tag is not present in the plugin service manifest declaration<meta-data>
tag is present, Tasker will bind instead of calling in the foreground and will signal the plugin that it did that, so that the plugin doesn't try to start its service in the foreground eitherThe problem is that the current public version of Tasker doesn't have this check yet, so I'll have to hurry and update it as soon as possible π
What I meant is if I update Yatse with a new lib that have the tag and no more FGS type. But the user on his phone still have an older tasker version. Then tasker won't bind and if it does call startForeground then we'll have ANRs or crash on A14 no? Hence this case to handle.
If
Tasker will always call plugin service in the foreground and plugin will always call startForeground in its service.
Oh, but you're right, the service does need to retain the FGS type tag :/, because it would crash if it runs with an old Tasker version.
But if the FGS tag is retained we end up where we started with the Play Store issues :/
Hmm... do you see any solution for this?
If tasker always startforeground calls and it's not the plugin doing something then there's not much.
Only solution is to add a way to check tasker version in the library, keep the FGS type for now until Google add the form.
And during the intermediary time the apps can check if tasker is uptodate or not in the calls and tell the user that he should update.
Not perfect but well.
Yeah, I don't think there's a way to retrofit it so it works with old Tasker versions and doesn't have the FGS type tag. Thanks again
The release is now in beta.
Version 0.4.10 of the plugin library with this change is also now available.
So, if you use the Tasker beta with the latest library the plugin actions should not be started in the foreground anymore.
Hope this helps and thanks for the help as well :)
Do we have a method to detect Tasker supporting that to ask user to update to anticipate ?
At some point when the form will be there we will probably want to remove the Fgs types.
You can check if Tasker version code is >= 5373. You can tell users that they need at least version 6.2.15. Will that work for you?
I guess there's no choice :)
Unfortunately it seems that it may be a while until this becomes available on Google Play :(
https://www.reddit.com/r/tasker/comments/17egc8m/dev_tasker_update_on_google_play_rejected_here_we/
It's totally unrelated to this issue BTW.
Hopefully I can get this sorted soon... Sorry!
This is really ridiculous ... For Android 16 and that will be allowed is basic apps and games ... No more innovation possible.
So the form is already accessible after I tried to push a new Yatse APK
We need to provide a video link .....
For each fucking permission we need to provide a video link.
And if we select other an explanation about why it can't be delayed and paused / stopped.
Yeah, it's a pain specially because I get the impression that they don't even care what's in the video :P I'm still trying to get the VpnService stuff sorted out, sorry!
Lol no problem we still have time, but in all case for tasker showing them a video of another app would be problematic anyway :)
So the dead line is now official it's 7th December to be approved or no more updates allowed :(
Have you made progress with Google and that other permission?
I'm working on the release now. The problem is that I now need to update the app on all tracks without the permission, so I can't widely test the new version that doesn't have the permission. I'm hoping to do a public release next week though!
It's so weird how they demand that you update all release tracks at once without the permission and don't even allow you to beta test it :(
One of the many Google mysteries :( That and who they employ for the AA and Wear reviews.
But I'm sure we'll face the same issue with tasker plugins won't be able to test a release without the perm in beta without getting the form first. So absurd.
Ok, I've sent the app for review now in Production. Hope they approve it soon.
@joaomgcd any luck with the publishing? Deadline is short now.
Just saw your post on reddit :( So sorry, Google is really a pain those days this is incredible :(
@KieronQuinn did you attempt the form with the custom permission did they validate it?
Just saw your post on reddit :( So sorry, Google is really a pain those days this is incredible :(
@KieronQuinn did you attempt the form with the custom permission did they validate it?
I don't publish on Google Play, for this very reason.
Yeah, sorry, they keep making stuff up and I can't really understand why.
Now they're saying I'm sending SMS and Contact data to http://myserver.com/ ....
And worst of all, they're taking a really long time to get back to me about it after I asked for proof. Sorry! :(
Don't be sorry this is not your fault if Google is becoming more and more hostile to indie devs :(
We just need to adapt with the little info we have.
@joaomgcd don't know why can't post the patch file on reddit.
You probably forget to change something.
Here's the Yatse patch that pleased them .
Wear/build.gradle.kts | 1 +
1 file changed, 1 insertion(+)
diff --git a/Wear/build.gradle.kts b/Wear/build.gradle.kts
index 89baa7021..fdf8efd60 100644
--- a/Wear/build.gradle.kts
+++ b/Wear/build.gradle.kts
@@ -217,6 +217,7 @@ dependencies {
implementation(libs.playservices.wearable)
implementation(libs.androidx.wear)
implementation(libs.androidx.activity.ktx)
+ implementation(libs.androidx.core.splashscreen)
implementation(libs.androidx.compose.activity)
implementation(libs.androidx.fragment.ktx)
implementation(libs.coroutines.android)
Wear/src/main/AndroidManifest.xml | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/Wear/src/main/AndroidManifest.xml b/Wear/src/main/AndroidManifest.xml
index 6e9733f6d..936276a90 100644
--- a/Wear/src/main/AndroidManifest.xml
+++ b/Wear/src/main/AndroidManifest.xml
@@ -11,7 +11,7 @@
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="${applicationLabel}"
- android:theme="@android:style/Theme.DeviceDefault"
+ android:theme="@style/Theme.App.Starting"
tools:ignore="GoogleAppIndexingWarning">
<uses-library
@@ -21,7 +21,8 @@
<activity
android:name=".ui.MainActivity"
android:exported="true"
- android:launchMode="singleTop">
+ android:launchMode="singleTop"
+ android:taskAffinity="">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -44,8 +45,10 @@
<activity
android:name=".ui.VoiceHandlerActivity"
+ android:excludeFromRecents="true"
android:exported="true"
- android:launchMode="singleTop" />
+ android:launchMode="singleTop"
+ android:noHistory="true" />
<meta-data
android:name="com.google.android.gms.version"
.../main/java/org/leetzone/android/yatsewidgetfree/ui/MainActivity.kt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Wear/src/main/java/org/leetzone/android/yatsewidgetfree/ui/MainActivity.kt b/Wear/src/main/java/org/leetzone/android/yatsewidgetfree/ui/MainActivity.kt
index 02959b730..d23a62ff4 100644
--- a/Wear/src/main/java/org/leetzone/android/yatsewidgetfree/ui/MainActivity.kt
+++ b/Wear/src/main/java/org/leetzone/android/yatsewidgetfree/ui/MainActivity.kt
@@ -7,6 +7,7 @@ import androidx.activity.viewModels
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.fragment.app.FragmentActivity
import androidx.wear.ambient.AmbientModeSupport
import com.google.android.gms.wearable.CapabilityClient
@@ -41,6 +42,7 @@ class MainActivity : FragmentActivity(), AmbientModeSupport.AmbientCallbackProvi
}
override fun onCreate(savedInstanceState: Bundle?) {
+ installSplashScreen()
super.onCreate(savedInstanceState)
AmbientModeSupport.attach(this)
runCatching {
Wear/src/main/res/drawable/splash_screen.xml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/Wear/src/main/res/drawable/splash_screen.xml b/Wear/src/main/res/drawable/splash_screen.xml
new file mode 100644
index 000000000..f73db93e0
--- /dev/null
+++ b/Wear/src/main/res/drawable/splash_screen.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:width="@dimen/splash_screen_icon_size"
+ android:height="@dimen/splash_screen_icon_size"
+ android:drawable="@mipmap/ic_launcher"
+ android:gravity="center" />
+</layer-list>
\ No newline at end of file
Wear/src/main/res/values/dimens.xml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Wear/src/main/res/values/dimens.xml b/Wear/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..aeb08d638
--- /dev/null
+++ b/Wear/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- Round app icon can take all of default space -->
+ <dimen name="splash_screen_icon_size">48dp</dimen>
+</resources>
\ No newline at end of file
Wear/src/main/res/values/styles.xml | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/Wear/src/main/res/values/styles.xml b/Wear/src/main/res/values/styles.xml
new file mode 100644
index 000000000..eb46f38cc
--- /dev/null
+++ b/Wear/src/main/res/values/styles.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <style name="Theme.App" parent="@android:style/Theme.DeviceDefault" />
+
+ <style name="Theme.App.Starting" parent="Theme.SplashScreen">
+ <!-- Set the splash screen background to black -->
+ <item name="windowSplashScreenBackground">@android:color/black</item>
+ <!-- Use windowSplashScreenAnimatedIcon to add a drawable or an animated
+ drawable. -->
+ <item name="windowSplashScreenAnimatedIcon">@drawable/ic_yatse_default</item>
+ <!-- Set the theme of the Activity that follows your splash screen. -->
+ <item name="postSplashScreenTheme">@style/Theme.App</item>
+ </style>
+</resources>
\ No newline at end of file
Thank you very much! I actually did all of that :/
They actually got back to me now again and added a small piece of information: Note that the production APK of your app must be compliant with our policy.
So, that means that, once again, I have to publish the updates I wanted to test directly to production... π€·ββοΈ
It seems like they are losing the grasp on what beta testing means... I've published it to production now, so lets see if they accept it this time. Maybe the whole problem was that they were looking at the production version all along...
As of Android 14, all foreground services need a type.
Currently, when targeting 14, you get this exception when running a plugin:
Note that the services declared in the manifest must also have this type, I suggest maybe the special use one might be best. Unsure how this would be taken in Play review though.