How much sleep do I need?

Post your questions and help other users.

Moderator: Martin

Post Reply
Econdoc
Posts: 153
Joined: 28 May 2016 20:06

How much sleep do I need?

Post by Econdoc » 01 Dec 2017 12:58

I am using Quicksettings to change the state of Airplane mode, LockScreen, Wifi, Bluetooth, Location, and Power Saving. Let’s assume that there are 6 Boolean variables that designate what state I want a setting to be in. For example, TurnAirplaneON. For each of the six settings, there is a variable that should show the state of that setting after it has been changed. For example, global_airplane = focus("Airplane mode on.");

The other five settings have similar logic. Now, (finally) to my question. I cannot determine how to reliably run this script in the shortest elapsed time. I have a variable at the top of the script that sets the sleep time for all the delays built into the script. If ThisDelay is set to 1000, the script runs reasonably fast, but is not always reliable; sometimes the settings do not get made. If ThisDelay is set to 3000, the script is reliable but sloooow.
1. Do I have sleep delays in the script that are not necessary?
2. Can some delays be shortened to say 1000 or 500, while others should be lengthened?
Are there any guidelines on WHEN, WHERE, and For How Long Sleep delays in a script should be?

As always, thanks for your advice.


Here is the flow…
--------------------------------
-----------------------------------------------------------------------
ThisDelay = 1000;
sleep( ThisDelay );
quickSettings();
sleep( ThisDelay );

/////////////////////////////////////
// Airplane Mode
/////////////////////////////////////
if (TurnAirplaneON)
{
click("Airplane mode off."); //This will turn AP ON
sleep(ThisDelay);
}
else
{
click("Airplane mode on."); //This will turn AP OFF
sleep(ThisDelay);
}
sleep(ThisDelay);
global_airplane = focus("Airplane mode on.");
sleep(ThisDelay);


/////////////////////////////
// BlueTooth
/////////////////////////////
if (TurnBTON)
{
click("Bluetooth off."); // This will turn BT ON. It is off. Clicking will turn on.
sleep(ThisDelay);
}
else
{
click("Bluetooth on."); // This will turn BT OFF
sleep(ThisDelay);
}
sleep(ThisDelay);
global_BT_on=(focus("Bluetooth on.") OR focus("Bluetooth connecting."));


/////////////////////////o
// WiFi
/////////////////////////
sleep(ThisDelay);
if (TurnWifiON)
{
click("Wifi off.."); // Turn WiFi ON
sleep(ThisDelay);
global_wifi_on=true;
}
else
{
if (focus("Wifi off..")==false)
{
click(292, 627);// Turns WiFi Off
sleep(ThisDelay);
}
global_wifi_on=false;
}
sleep(ThisDelay);


/////////////////////////////////////////////
//Location ON set to battery savings
////////////////////////////////////////////
click(889, 1248); // open the location window

sleep(ThisDelay);

if (TurnLocationON) //Location
{
click("OFF"); // Turn Location on
sleep(ThisDelay);
click("Battery saving");
sleep(ThisDelay);
back( );
}
else
{
click("ON"); // Turns Location Off
sleep(ThisDelay);
back( );
}
global_loc_on=focus("Battery saving");
sleep(ThisDelay);



/////////////////////////////////////////////
// Battery Saving set to Efficiency or Balanced
////////////////////////////////////////////
click(786, 627);
sleep( ThisDelay);
sleep( ThisDelay);
// open up the battery options
if (TurnPowerSavingON) //Battery power save mode
{
click("Power save");
sleep(ThisDelay);back( );
}
else
{
click("Balanced"); // Turn balanced mode on
sleep(ThisDelay);back( );
sleep(ThisDelay);
}
global_batt_saver=focus("Power save");

sleep(ThisDelay);


/////////////////////////////////////////////
//ScreenLock ON
////////////////////////////////////////////


if (TurnScreenLockON) //Screen Lock
{
//sleep( ThisDelay );
click("Lock screen off.");
sleep( ThisDelay);
}
else
{
click("Lock screen on.");
sleep( ThisDelay);
}
global_lockscreen=focus("Lock screen on.");
sleep(ThisDelay);
sleep(ThisDelay);

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: How much sleep do I need?

Post by Desmanto » 02 Dec 2017 04:18

Answer from Google : "While sleep requirements vary slightly from person to person, most healthy adults need between 7 to 9 hours of sleep per night to function at their best"
Ooops, wrong context :D Sorry, your thread's title ("How much sleep do I need?") is so tempting to google it. :)

Back to the real thing. I will start from optimizing the code first. Seems everyone naturally ended up finding the way to set the sleep in Control UI to single variable, which can be adjusted later on easily. I use {sle} only (shortened from sleep). If there are parts where the UI loading is slower, and I need more time for the sleep(), I will just multiply it with 2 or 4.

Code: Select all

sleep(sle*2); //or sleep(sle*4);
instead of

Code: Select all

sleep(sle);
sleep(sle);
This also answers question no 2.

Next, you can optimize the code for the if-else part. If both true and false always need sleep, just take the sleep outside of the if-else. So instead of.

Code: Select all

if (TurnAirplaneON) 
{
click("Airplane mode off."); //This will turn AP ON
sleep(ThisDelay);
}
else
{
click("Airplane mode on."); //This will turn AP OFF
sleep(ThisDelay);
}
Take the sleep() outside, becomes

Code: Select all

if (TurnAirplaneON) 
{
click("Airplane mode off."); //This will turn AP ON
}
else
{
click("Airplane mode on."); //This will turn AP OFF
}
sleep(ThisDelay); //the sleep() moved to outside of the if-else
Then about the GloVar. Do you use GloVar trigger based on the value? Or you use the GloVar just to store the state only? If you never use them as trigger, only to save the state; you can group them all together into single GloVar - Map. So instead of saving them to 6 GloVar boolean values, just put into single Map GloVar. You can create the GloVar manually, change the type to Map, add the key and value manually. Or you can just use script to create it (execute it).

Code: Select all

global_network_state = newMapFromValues(
"airplane", true,
"lockscreen", true,
"wifi", true,
"bluetooth", true,
"location", true,
"powersave", true );
Later, in the script, to access airplane state, instead of global_airplane, call it using global_network_state["airplane"].

Code: Select all

global_network_state["airplane"] = focus("Airplane mode on.");
Yeah, you should modify all your script which use the variable. But it will save your 5 precious spaces in GloVar list. Save your scroll when trying to select them. It is more organized, and you can always add new element to the Map to store another state.

Done for the code optimization part. Can't helped not to comment your code, it is my OCD to see a cleaner code. :D I will split the Control UI explanation to next post, for more separated topic (so others won't get confused). Can't finish this last night, took several hours to type this all (including the next post).
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: How much sleep do I need?

Post by Desmanto » 02 Dec 2017 04:31

Warning : Prepare yourself for incoming wall of text and code.

Everyone using Control UI, naturally want the shortest execution time but still maintain high reliability (best value). To balance both need a lot of try and error. There is no shortcut or guideline for it. As accessibility works at different speed at different phone, or even different ROM (on same phone). So, everyone should try it out by themselves. But there are some point you can consider.

1. If you use trigger app task started or action launch app then the Control UI, usually sleep is not needed in the first line. Since the Control UI will only executed after the launch app completely finish (the app completely launch and load all its UI). But sometimes the Control UI just won't start if I don't put a sleep() at the beginning. So I usually put sleep(100) to make sure it is reliable. This should answer question no 1.

2. sleep() is needed when the UI action change the UI element, opened new windows, or maybe scroll the list. But for querying text, checking existence of certain element or any other where it doesn't modify the current view; not sleep is needed. But generally, I will put sleep in between any UI action. It is the length of the sleep that we adjust later for the best value. This point and later will answer about where, when and how long the sleep() is needed.

3. You should check first if the app you are trying to control, is using software rendering (SW) or hardware rendering (Hardware acceleration/HW acc). You can try to find it out if the app has UI element where it has a long scroll list (more than 50 itmes on the list). Try to scroll very fast, swipe up and down quickly. Is it very smooth? Or is it quite jaggy/laggy? If it is laggy, it is using SW, the sleep need to be higher. Probably 200 ms is the minimum value it can works reliably. But should be tested first, generally it is higher. If the scroll is very smooth, then it must be using HW acc, the sleep() can be shorter, probably as low as 20 ms.

But somehow, certain app can use SW rendering on some UI element, but HW acc on others. So still need to be tested first. The default value 1000 ms from automagic is generally good for most operation. From there, you can try to reduce it to 500 ms, 200 ms, 100 ms, 50 ms until 10 ms. Test it out and see which one works the best, fastest but still reliable.

4. If you encounter some part stopped during testing, you can always multiply the sleep time by 2. So let say you have 5 UI click.

Code: Select all

sle = 100;
click("1");
sleep(sle);
click("2");
sleep(sle);
click("3");
sleep(sle);
click("4");
sleep(sle);
click("5");
And after testing with 100, you find out it will always stop at 4 (after 3, doing nothing). So you know the transition from 3 to 4 is longer than 100 ms. You can try to change that part to 2 times.

Code: Select all

click("3");
sleep(sle*2);
click("4");
Or you can try other multiplier, as 1.5 or 3; try it out to see. If it works, then maybe that is the best value then.

5. When choosing from click(pattern), click(x,y) or clickById(id); I will always go with clickById(id) if it is possible. It is more reliable, as there is no possible duplicate name that can happen if you use click(pattern) >> (somehow maybe the "Airplane mode on." appear twice, only the first one will be used/checked).

6. If you really need a very reliable wait/sleep() in each UI action, you can use while() and loop the sleep() when the element is not exist yet. This is for flow where error can not be tolerated, precision is the most important thing. Any error will result in apocalypse, triggering the nuke button (ok, I overstated it :)). Example is for action where you have to delete some files or list from certain app, which can only be done using Control UI. If the waiting time is skipped, it is possible you can delete the wrong files. So no error tolerant, it must be always success 100% of the time.

The example script will assume you have element id "android:id/button1" exist before executing the click. The actual script before using while() maybe like this.

Code: Select all

sleep(100);
clickById("android:id/button1");
After modified to use the while(), it will be like this

Code: Select all

while(NOT existsElementById("android:id/button1"))
  sleep(100);
clickById("android:id/button1");
This way, the Control UI script will wait until the button1 exist, before proceeding to the next click on button1. Change this button1 to the element you have there. You can adjust the 100 ms to be shorter or longer. It will determine the latency you get.

For example run time, using 100 ms; if the button1 exist after 120 ms. First check at 0 ms, button still not exist, sleep for 100 ms. Second check (after 100 ms), button1 still not exist, sleep for another 100 ms. At 120 ms, the button1 already appear; but the script won't continue, because there is 80 ms more. Third check at 200 ms, button1 already exist; script continue to click the button. You lose the 80 ms as the latency after the button1 appear. (maximum latency 100 - 1). It is OK, as 80 ms is very short to our eyes.

You can decrease this to example sleep(10), you will get a better latency. Because at the 13th check (120 ms), the button already appear, and you probably only lose max 10 ms as the latency. But the script will be executed more frequently, will consume more battery. So there is always a tradeoff, need to balance between the latency and the power consumption. Max 100 ms latency is very good already, it is just 1/10 seconds; very fast. FYI, widget latency is around 500 ms; UI event detection latency is around 500-600 ms. So 100 ms is nothing compared to both. But still, suit to your need. Probably you need the script to be executed as fast as possible regardless the power consumption.

7. Escaping from the loop. The problem with above method is the infinite loop. There is no exit from the loop, unless the button1 appear. Somehow if you press back/home or tap any other element during the execution, it is possible you get out from the execution. You might think the flow has stopped, but in fact it is still running background, consuming your battery. It won't be stopped by Emergency stop, since there is no new element execution. The flow will be a runaway flow, looping infinitely and later you will be asking why automagic consume so much battery.

Well, it won't run infinitely. If the sleep is 100 ms, the flow will stop after 16 minutes 40 seconds. Why? Because automagic has internal max loop limit at 10000 loops. So when the loop reach 10001, the flow will stop with error "too many iterations". 100 ms x 10000 = 1000000 ms = 1000 s = 16 minutes 40 seconds.

But unless you are very sure about the execution will be always perfect or you have other ways to prevent the flow from runaway (infinite loop), you should put extra lines for timeout. You can do this by increment a certain value and check for the value if it passed the limit or not. Here I will use {ela} as the counter (shortened from elapsed). The timeout limit will be 10 seconds (10000 ms)

Code: Select all

ela = 0;
while(NOT existsElementById("android:id/button1"))
{
  if(ela <= 10000)
  {
    sleep(100); 
    ela = ela + 100; //increment the elapsed time
  }
  else
  {
    ela/0; //this will produce error
  }
}
clickById("android:id/button1");
The if() will check if the elapsed time is less than 10 seconds. If it is still less, then loop the sleep. Once it passed 10 seconds, it will execute the else statement ela/0; which will definitely produce error. This will stop the whole execution of the following lines (it won't execute clickById("android:id/button1") or any lines after it). To catch this error, you should add a new action to this Control UI, and change the connector to "exception". Example, add notification on screen : "script timeout at 10 seconds, button1 not found". I used this method at my flowception flows as well.

8. When you see point 6 & 7, you will think : "Oh my god, I just wanna find out the best value for the sleep(). Can I just use the simple sleep()?" Yes, the script above can be used to find the best sleep value. Just add debug dialog, and check the value of {ela}. You don't need the if-else part though. There is no need for timeout limit, as it is for testing, to find the best value only. And the time should be reduced to 10 ms for more accurate latency. (or 20 ms or 50 ms, depends on your phone)

Code: Select all

ela = 0;
while(NOT existsElementById("android:id/button1"))
{
  sleep(10); 
  ela = ela + 10; //increment the elapsed time
}
clickById("android:id/button1");
Add debug dialog or notification on screen and check the value of {ela}. After several test run, you will get the average value of the ela and let say it is 120. You can markup it by 50% and use 180 as the sleep value, or just 200 for safety. Remove the above code and replace it with

Code: Select all

sleep(200);
clickById("android:id/button1");
Generally, if the number is not too high, you should double the value for a very big tolerance. You don't know what happen during the execution time, probably there are other flow running as well, which will slowdown the UI loading. Better safe than sorry. But it is all back to the usage case. Just remember, this is only test code. Replace button1 with the element you have there. And remember to change the code back to sleep() after you find the best value.

Be careful not decrease the testing code sleep(10) to a very low value (example sleep(1)). Because the script checking the existence of element and function sleep() itself also consume some time. So sleep(1) along with the while() loop maybe takes 2-5 ms to complete (depends on your phone). If you use sleep(1), you probably get the {ela} value way lower, maybe only 20-30 (20 x 5 ms = 100 ms >> actual); which is definitely wrong. Just use 10, or you can try 20 to check if that is more accurate at your phone.

9. While point 8 only test for single UI action; you can expand the idea to test the whole process of the Control UI script to check time elapsed in each part. Use a list to check the time. Example, you have 3 click actions on 3 buttons, and you want to find the average value for each.

Code: Select all

ela = newList(0, 0, 0);

while(NOT existsElementById("android:id/button1"))
{
  sleep(10); 
  ela[0] = ela[0] + 10;
}
clickById("android:id/button1");

while(NOT existsElementById("android:id/button2"))
{
  sleep(10); 
  ela[1] = ela[1] + 10;
}
clickById("android:id/button2");

while(NOT existsElementById("android:id/button3"))
{
  sleep(10); 
  ela[2] = ela[2] + 10;
}
clickById("android:id/button3");
At the end, lis will contain 3 values for each action. Add the list element as needed. You can run it for several times to find the average value and determine the best value for each part.
But this will be more troublesome to test. As you need to copy each element Id name to each while(), kinda counterproductive especially when you have more than 5 actions. It is better to test by adjusting the {sle} value and have rough testing and estimation rather than modifiying the whole script just for the testing purpose.

10. The last part (for now :)) is where you protect the Control UI when executing. Sometimes you have optimized the sleep and have found the best value. But still, it takes several seconds to complete the whole cycle of the script. This will increase the risk of mistouching the element part and disrupting the whole script. You can minimize the risk by putting a full overlay to block all touch and remove it after the Control UI finish. This way, at least it protect the script from any random touch which might interrupt the script. But it won't protect against hardware capacitive button, volume button or power button.

a. Create a full screen widget, set the resolution to your screen resolution (example at mine it is 1080x1920).
b. Then split the clickable action, so you can have small square at some corner. At mine, I split to 6 rows. Then split the first row to 3 columns. I use the top right corner as the "Dead Man Switch".
c. At your UI script flow, before the Control UI, show this widget with full screen resolution and clickable. You might need to turn on immersive mode first if you need to protect the whole screen.
d. Then back to the widget and add action double click to Hide widget overlay at the top right corner square. This is for safety reason. If the Control UI error at some part, you still can hide the widget by double tapping this top right square.
e. back to the flow, add another action Hide widget overlay too after the Control UI (and disable immersive mode if needed).[/list]

By doing this, Automagic will protect the touch screen by showing widget overlay before running the Control UI script. It is kinda interesting, as automagic still can click the UI element below the overlay.

I have thought about more advanced way of DMS. Since sometimes double click is too easy. I put my phone at pocket, and if the flow need to be executed, sometimes double click can done while in pocket (yeah, the touchscreen is quite sensitive). I have thought about using high speed swipe from top right and bottom left corner. both must be done within maybe 3-5 seconds, in order to hide the widget. But I haven't created the flow yet, so far I think it is achieveable.

===================================
Since there is no guideline for best practice yet for Control UI, you can consider above point as the common practice for now. :) Sorry for the wall of text. You ask for it. :D I also type this all for my own future reference, so I won't forget it later (or at least I can revisit my own post for reminder).
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

Econdoc
Posts: 153
Joined: 28 May 2016 20:06

Re: How much sleep do I need?

Post by Econdoc » 02 Dec 2017 13:28

Wow! You really went all out on answering my question. Terrific job! You have given me lots to think about. I really appreciate the hours of work you put into this.
Two very quick questions:
1. You refer frequently to script actions like ClickById("android:id/Title") and other elements that use "ById". I confess that I have no idea how to use this. I have searched the forum for examples, but could not find any. For my present script, I would be looking at items in the quickSettings: Airplane mode, BlueTooth, etc. How do I find "android:id/Title") for any of these buttons?
2. You write such nicely formatted code. Do you have a program that neatens or tidies your code? Or do you write perfectly indented if-else structures automatically?

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: How much sleep do I need?

Post by Desmanto » 02 Dec 2017 15:11

Hehehe, I always wanna type this out. Need someone to trigger the question first :) And not several hours straight, I type it while also doing something else.

1. This is the question I also wanna ask Martin :D It seems not every app exposed their element Id to accessibility. So there is no way to determine the element Id unless we dig into the layout xml of the app, by decompling the apk. But when element Id can be accessed, I always pick that one. If there is no Id, then I would use the click(pattern), and the last will be click(x,y) (which is unreliable, i will avoid it). Sometimes the element Id is there, but it is hosting several buttons at the same id. Just like in automagic list when you wanna choose the action/condition. All are using the same Id, "ch.gridvision.ppam.androidautomagic:id/name_text_view". For something like this, I still have to use the click(pattern). Till now it is still reliable, but I must make sure there is no duplicate names in the current opened windows.

2. It is just a habit. :D I am melancholy, and for coding I always wanna put it tidy, or simmetric. It is a good habit, so I wanna preserve it. I manually typed 2 spaces for new if(), else(), for(), while() or any sub level. If there is nested level, I would put 4 spaces, 6 spaces and so on. It makes the code's logic easier to follow. You will know these several lines of code are on the same level logic. I would rather overused newlines and spaces for code readability.
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

Econdoc
Posts: 153
Joined: 28 May 2016 20:06

Re: How much sleep do I need?

Post by Econdoc » 02 Dec 2017 18:43

Hello again. Still on this same topic. I have a code snippet below which is from an earlier post. (Note that I have adopted your "sle" variable and am starting to indent my if-then-else structures. You are a good influence!)

If you plug this snippet into action Control UI and then append a Debug Dialogue, you will find (maybe) that aaa=true, and bbb and ccc are both false. Can you make sense of this? This kind of weirdness drives me crazy. :cry:


------------------------------------------------------
sle = 1000;
sleep( sle );
quickSettings();
sleep( sle );

/////////////////////////////////////
// Airplane Mode
/////////////////////////////////////
TurnAPON = true;
if (TurnAPON)
{
click("Airplane mode off."); //This will turn AP ON
}
else
{
click("Airplane mode on."); //This will turn AP OF
}
sleep(sle);
aaa = focus("Airplane mode on.");
sleep(sle);
bbb= focus("Airplane mode on.");
sleep(sle);
ccc=focus("Airplane mode on.");
sleep(sle);
back();

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: How much sleep do I need?

Post by Desmanto » 03 Dec 2017 07:57

Control UI doesn't work well at my phone quicksetting. I can't even get the click(pattern), only click(x,y) and focus(x,y).

focus() will only move the focus to the selected element. Since aaa already move the focus to that element, operation complete (true); bbb and ccc didn't move anymore, operation failed (false).
To test the element, probably you should replace the focus() with isChecked(). Don't know if it works or not, at mine still won't work.
The other alternative is to use getText() and later check if the result is the same as string needed.

If you really need to check the real value of airplane mode (and some other value), there are better ways to do it.
Use action Init Variable System Setting, choose Global database, at Name, find "airplane_mode_on" (or any similiar name).
You can do the similar things with wifi, bluetooth and others.

But to change the value, you have to use action Set System Setting, and should have root or at least grant Automagic Write secure setting permission in adb at PC

Code: Select all

adb shell pm grant ch.gridvision.ppam.androidautomagic android.permission.WRITE_SECURE_SETTINGS
And changing the value directly here doesn't work at all phone. I can change the airplane mode to 1, but airplane mode is still not turned on. I still have to toggled it manual it settings (quicksetting won't work for me).

I missed to tell about this in the first comment. Too focus on the control UI instead. :)
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

Post Reply