Enable/Disable wifi using Xamarin UiTest - android

I try to enable/disable wifi programmatically within my Xamarin Ui Test.
I already found this: Android: How to Enable/Disable Wifi or Internet Connection Programmatically. But it seems not to work within the UiTest.
I also tried something like this:
Context appContext = Android.App.Application.Context;
var wifiManager = (WifiManager)appContext.GetSystemService(Context.WifiService);
bool status = false;
wifiManager.SetWifiEnabled(status);
The first line (Android.App.Application.Context) throws an exception:
Message: System.IO.FileNotFoundException : Could not load file or assembly 'Java.Interop, Version=0.1.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065' or one of its dependencies. The system cannot find the file specified.
I'm using following namespaces:
using Android.Net.Wifi;
using Android.Content;
My project has a reference to Mono.Android.

The backdoor approach works fine for me.
The solution that works for me was a combination of:
Android: How to Enable/Disable Wifi or Internet Connection Programmatically
https://learn.microsoft.com/en-us/appcenter/test-cloud/uitest/working-with-backdoors
Some small own changes (for appcontext/context). Just context did not work for me.
1.: Add following line to the AndroidManifest.xml file of the Android project:
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
2.: Add following lines to the MainActivity.cs of the Android project:
using Java.Interop;
using Android.Net.Wifi;
[Export("ChangeWifiState")]
public void ChangeWifiState(bool state)
{
Context appContext = Android.App.Application.Context;
var wifiManager = (WifiManager)appContext.GetSystemService(WifiService);
wifiManager.SetWifiEnabled(state);
}
3.: Call following method out of the Xamarin Ui Test:
app.Invoke("ChangeWifiState", false); // true to enable wifi, false to disable wifi
PS: I use Xamarin Forms. I've got four different projects: a core project, an Android project, a Ui project, and a test project.
I just found a second solution without using the actual app.
It uses ADB commands to enable/disable wifi:
var process = new System.Diagnostics.Process();
var startInfo = new System.Diagnostics.ProcessStartInfo
{
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
FileName = "cmd.exe",
Arguments = "/C adb shell am start -a android.intent.action.MAIN -n com.android.settings/.wifi.WifiSettings adb shell input keyevent 19 & adb shell input keyevent 19 & adb shell input keyevent 23 & adb shell input keyevent 82 & adb shell input tap 500 1000"
};
process.StartInfo = startInfo;
process.Start();
This can be used without a rooted device :).
Steps explained:
adb shell am start -a android.intent.action.MAIN -n com.android.settings/.wifi.WifiSettings opens the wifi settings.
adb shell input keyevent 23 enables/disables wifi.
I'm not sure why the command adb shell input keyevent 19 is used, but it works.
adb shell input keyevent 82 clicks the menu button to change back to the original app.
adb shell input tap 500 1000 clicks the coordinate x=500, y=1000 (center of screen).This may need be changed for different solutions.
Sources for this solution:
How to turn off Wifi via ADB?
ADB Shell Input Events
Run Command Prompt Commands

Related

Android OS 11+ pushing data files to an applications scoped storage

I have an Android algorithm library that I want to test inside an application that can run on real device. In order to run this test, I need to be able to push data files from a computer to the phone, to a location that can be read by the application being tested. Before OS 11 this could be done using the adb push ... command but the new scoped storage privacy feature will not allow me to do this anymore.
Whatever the solution is, it can not require manual human intervention as the intention of this test is to run automatically as part of a CI/CD pipeline.
Does anyone have any solutions? Thanks in advance for your suggestions!
You can add this permission to the Manifest:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
To grant this permission you need to enable it, but as far as I know this cannot be changed programatically, but you can use this adb command to change it via UI (Or you can write an UI Automator script to be more robust):
adb shell "am start -a android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION \
-d package:<REPLACE_WITH_YOUR_PACKAGE_NAME> ; \
sleep 2 ; \
input keyevent KEYCODE_DPAD_DOWN ; \
input keyevent KEYCODE_DPAD_DOWN ; \
input keyevent KEYCODE_DPAD_CENTER"
Now you can read your files normally:
#Test
fun myTest() {
val content = File("/sdcard/Download/myFile.txt")
.useLines(Charsets.UTF_8) {
it.joinToString("\n")
}
Log.d("TAG", content)
}

Perform a search on google chrome using ADB

I'm setting up a python script for doing some tests on android phones.
I can actually launch a new chrome tab on my phone with ADB:
shell am start -n com.android.chrome/org.chromium.chrome.browser.ChromeTabbedActivity -d "about:newtab" --activity-clear-task
I can't figure out the way I could perform a search on chrome with the search provider included in.
The suggested command by #oss does not care about user settings/defaults , it only require that google chrome is installed!
You may need to create a function like this:
function adbgs () {
local str="${*}";
adb shell am start -n com.android.chrome/org.chromium.chrome.browser.ChromeTabbedActivity -d "google.com/search?q=${str// /+}" --activity-clear-task
}
adbgs how to do stuff;
Or if you want search using default browser :
function adburlopen () {
adb shell am start -a android.intent.action.VIEW -d "${1}"
}
# google
function adbgs () {
local str="${*}";
adburlopen "https://www.google.com/search?q=${str// /+}";
}
# yahoo
function adbys () {
local str="${*}";
adburlopen "https://sg.search.yahoo.com/search?q=${str// /+}";
}

Doze whitelist and deviceidle.xml

I'm trying to add my package in doze whitelist.
With ($ adb shell dumpsys deviceidle whitelist +PACKAGE), I can add my package in whitelist,
and this command makes change in the file /data/system/deviceidle.xml.
Now, I'm curious about who generate deviceidle.xml.
Is there anyone who knows about deviceidle.xml?
I found a clue in framework module,
IDeviceController.addPowerSaveWhitelistApp(String name) helps to add my package into ;
also, /data/system/deviceidle.xml is updated.
You can check with adb dumpsys
$ adb shell dumpsys deviceidle
$ adb shell cat /data/system/deviceidle.xml
As far as I know, doze whitelisting is done by system creators.
You can ask user for whitelisting via intent action: Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS.
In the DeviceIdleController soruce code you can see that it reads deviceidle.xml
in constructor. It might be that, if you know the file structure and have rooted device you can manually create and edit this file.
#VisibleForTesting DeviceIdleController(Context context, Injector injector) {
super(context);
mInjector = injector;
mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));
[...]
}

Android app crashes when adding commands to RootTools v4.2 shell

I have an Android application utilizing RootTools v4.2 (the latest I know of) and I have followed their documentation on how to execute shell commands as root. Sometimes the commands execute just fine, other times the app crashes with the following exception.
java.lang.IllegalStateException: Unable to add commands to a closed shell
Here is the actual code the exception is being throw on:
RootTools.getShell(true).add(cmd);
So I'm wondering since the docs make no mention of this sort of problem if there is something else I'm doing wrong? Looking through the docs I see nothing on how to ensure I get an open shell before I start adding commands.
This code is working with me . Try to install the Library again may be its not vaild .
if(RootTools.isAccessGiven()){
try {
Shell shell = RootTools.getShell(true);
JavaCommand cmd = new JavaCommand(0,this,"input keyevent 26");
shell.add(cmd);
}
catch (Exception e){
Log.d("ERRORS : ",e.getMessage());
}
}

Is it possible to execute adb commands through my android app?

Can anyone say, whether adb commands can be executed through my android application. If it is possible to execute, how it can be implemented?
You can do it with this:
Process process = Runtime.getRuntime().exec("your command");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
Don't forget to surround it with a try and catch statement.
Edit:
#Phix is right, ProcessBuilder would be better to use.
Normal Android apps have different privileges to processes started via adb, e.g., processes started via adb are allowed to the capture the screen whereas normal apps aren't. So, you can execute commands from your app via Runtime.getRuntime().exec(), but they won't have the same privileges as if you had executed from an adb shell.
i came across this post looking for a different query, but i have worked specifically with input on android before, so I'd just like to put some clarity on the matter.
The reason why
Runtime.getRuntime().exec("adb shell input keyevent 120");
Is not working, is because you are not removing
adb shell
The ADB part is only for use on your computer, if you have incorrectly installed ADB, the command would actually be a path to the adb.exe file on your computer, like this
C:\XXXX\ADB Files\adb.exe shell
or
C:\XXXX\ADB Files\adb shell
The shell part tells the ADB program on your computer to access the devices shell, so your device will not know what shell is either...
Using sh /path/to/commandList.sh will execute the commads listed in commandList.sh as it is a shell script (a .batch file on windows is similar )
The command you want to use is
Runtime.getRuntime().exec("input keyevent 120");
However this will cause Environment null and working directory null, you can bypass this by writing the commands to a shell script ( .sh file ) and then running the script with
Runtime.getRuntime().exec("sh path/to/shellScript.sh");
Sometimes the sh is not needed, but i use it just incase.
I hope this clears at least something up :)
adb shell invoked in Runtime.getRuntime().exec is not running under shell user. It provide shell but with same process owner user (like u0_a44). That's the reason all command did not work.
This is what I do in Kotlin, I also get command responses too
fun runShellCommand(command: String) {
// Run the command
val process = Runtime.getRuntime().exec(command)
val bufferedReader = BufferedReader(
InputStreamReader(process.inputStream)
)
// Grab the results
val log = StringBuilder()
var line: String?
line = bufferedReader.readLine()
while (line != null) {
log.append(line + "\n")
line = bufferedReader.readLine()
}
val Reader = BufferedReader(
InputStreamReader(process.errorStream)
)
// if we had an error during ex we get here
val error_log = StringBuilder()
var error_line: String?
error_line = Reader.readLine()
while (error_line != null) {
error_log.append(error_line + "\n")
error_line = Reader.readLine()
}
if (error_log.toString() != "")
Log.info("ADB_COMMAND", "command : $command $log error $error_log")
else
Log.info("ADB_COMMAND", "command : $command $log")
}
Executing
Runtime.getRuntime().exec("adb shell input keyevent 120");
I got the following error:
java.io.IOException: Cannot run program "adb": error=13, Permission denied.
Executing
Runtime.getRuntime().exec("adb shell input keyevent 120");
There is no error but at the same time, my request is not processed to take the screenshot.
I found out this was working in earlier versions of android but later it was removed. Though I'm not able to provide the source here why it is not working.
Hope this helps someone like me who is trying to use this approach to take the screenshot when the app is not in the foreground.
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
string cmd = "/system/bin/input keyevent 23\n";
os.writeBytes(cmd);
the phone must be rooted. here I have executed adb command "input keyevent 23".
remember when you execute adb command through su you does not need to add "adb shell input keyevent 23"

Categories

Resources