"App in foreground?" for multiple apps?

791 views
Skip to first unread message

James Lin

unread,
Nov 20, 2015, 9:53:29 PM11/20/15
to Automate
Hi,

I would like to use Automate to change several system settings (e.g. autorotation, volume, brightness) when running certain applications.  If there is only one application, this seems straightforward: I can use the "App in foreground?" block with Proceed="When Changed" for a specific application.  If, however, I want to do the same for additional applications, I'm not quite sure what the best approach is.

At first I thought that I could chain multiple "App in foreground?" blocks (with all but the first using Proceed=Immediately), but the "No" case runs when the specified application goes to the background, not when running applications other than the specified one.

I then tried using the "App in foreground?" block with no specified package/activity, instead having it set an output variable `cur_app`.  I then connected its Yes output to an "Expression true?" block that did:

    cur_app = "com.applicationA" || cur_app = "com.applicationB" || cur_app = "com.applicationC"

This works better, but I discovered that a particular application (Waze) runs itself when showing its Settings panel (which I guess is implemented as a separate activity), and this unexpectedly re-applies the changes from my flow.

I can solve that by adding more variables (i.e. by checking if the current application is different from the previous application, or keeping track of whether I already applied the changes, etc.), but this is feeling overly complicated and clunky.  Is there a better way to do this?

Thanks!

- James

Henrik Lindqvist

unread,
Nov 21, 2015, 6:34:58 PM11/21/15
to Automate
Either create a flow for each specific app, or use the Fork block to create a sub-flow for the app, or leave the package/class fields empty and compare them using a Expression true block.

If you're using the Expression true block, try storing all apps in a array:
apps = ["com.applicationA/com.applicationA.Activity", "com.applicationB/com.applicationA.Activity",
"com.applicationC/com.applicationA.Activity"]

then use the expression to find a match:
contains(apps, package++"/"++class)

James Lin

unread,
Nov 21, 2015, 9:48:34 PM11/21/15
to Automate
Thanks.  Creating a separate flow for each app would be a maintenance nightmare.  Using a Fork block sounds interesting, but currently my flow looks like:

Flow beginning
     |
     +<-----------------------+
     |                        ^
App in foreground?            |
     |                        |
Expression true? ------------>+
     |                        ^
[Change system settings]      |
     |                        |
     +------------------------+


That is, I have my flow go back to checking "App in foreground?" when it's done.  How could I do this with a Fork-based approach without constantly creating new fibers?

(Or maybe you'd be willing to entertain a feature request to let "App in foreground?" specify multiple applications? =D )

- James

Henrik Lindqvist

unread,
Nov 22, 2015, 5:15:37 PM11/22/15
to Automate
You could enable "allow parallel launch" in the Flow beginning block, then at startup use the Activity resolve block to pick an activity for each launch.

With the Fork solution you fork a sub flow for each app:
Flow beginning
     |
   Fork1 --- [sub flow]
     |
   Fork2 --- [sub flow]
     :
   ForkN --- [sub flow]

        [sub flow]
+-----------+
|           |
|      App in foreground ---------+
|  package & class for each app   |
|           |                     |
|         Fork ---- [settings]    |
+-----------+---------------------+

The [settings] connect to the same sub flow.
       

Alternative, use the For each block to pull the package & class, instead of duplicating the same sub flow:
Flow beginning
      |
+-----+
|  For each ---- [sub flow]
+-----+

Let the [For each] iterate an array of dictionaries [{ "package": "com.app...", "class": "com.app...Activity" }, ...]
or an array of components: ["com.app.../com.app...Activity",...] then use the split function split(value, "/")[0] for package and split(value, "/")[1] for class.


Implementing multiple "sets" for every condition block would make the block UI very complex.
Some users may wish to create AND instead of OR, it would soon become impossible to maintain.
That's why i've decided to only allow a single condition "set" in each block, forcing the use of Fork, or any of the other solutions.

Rob Lund

unread,
Aug 28, 2017, 3:35:53 PM8/28/17
to Automate
What I've opted for is a combination of the When and If settings on the Foreground block to check for multiple apps in an OR capacity.  Looks like this...

Flow beginning
     |
+-----------+
|           |
|      When App in foreground ----+
|  package = ""                   |
|  class = ""                     |
|           |                     |
+-----------+---------------------+
                           |
                          |
+-----------+
|           |
|      Is App in foreground ------+----(no branch to other foreground checks)
|  package = "app"                |
|           |                     |
+-----------+---------------------+
            | (yes branch)


The When at the top just makes the flow wait until an app is present.  Blank package / class parameters.  Then we check immediately if it's the app we are looking for.

beefe...@gmail.com

unread,
Feb 4, 2018, 12:39:07 AM2/4/18
to Automate
the solution i have settled on for this problem, inspired by this very thread, is to use a dictionary variable with a key of the desired app activity and a value of the associated app package. build this dictionary either from a text file in storage or using a variable assign block with the pairs hardcoded in a "initialize" subroutine at the start of the flow. in the first (when) app foreground block leave the input variables blank and save the current app activity to an output variable. in the second (is) app foreground block set the app package input to "= dictionary[current-app-activity]". thos will only return true if the activity of the current foreground app is in your dictionary variable and paired with the current app package. so apps with multiple activities only trigger your yes branch if you have approved that specific activity by including it in your dictionary.

alternatively instead of a second app foreground block use a expression true block and instead of the package as dictionary value set the value as a string of characters that you could use to trigger specific settings. example: "wgob" would indicate you want this app to have wifi, gps, screen stay On, and bluetooth enabled. so you can use the contains expression to read dictionary[current-activity] for which settings you want in a dynamic deterministic fashion in your code rather than a fixed branch per app activity, making your flow modular and reducing or eliminating duplicated blocks.

hope this helps someone. i know this thread was old, but this is still good reference.

Reply all
Reply to author
Forward
0 new messages