I want to detect in my Android application if a HDMI cable is connected.
I found a way how to do that:
private boolean isHdmiSwitchSet() {
// The file '/sys/devices/virtual/switch/hdmi/state' holds an int -- if it's 1 then an HDMI device is connected.
// An alternative file to check is '/sys/class/switch/hdmi/state' which exists instead on certain devices.
File switchFile = new File("/sys/devices/virtual/switch/hdmi/state");
if (!switchFile.exists()) {
switchFile = new File("/sys/class/switch/hdmi/state");
}
try {
Scanner switchFileScanner = new Scanner(switchFile);
int switchValue = switchFileScanner.nextInt();
switchFileScanner.close();
return switchValue > 0;
} catch (Exception e) {
return false;
}
}
The problem now ist that I want to do something if HDMI is connected but I dont want to run a threat checking every second if the boolean has flipped. Is there a better way?
Related
I am trying to detect 5G network. I use the telephony manager to get NETWORK_TYPE. Even if I am in 5G network coverage and my phone shows 5G, I do not get NETWORK_TYPE_NR. The NETWORK_TYPE is always 13 i.e. LTE.
The Phones Engineering service mode shows NR related data.
Is there any way to detect NR (Standalone or Non-Standalone) mode?
I also need to get the Cell Information for NR data. I use telephonyManager.getAllCellinfo(), but I never get an instance of cellinfonr.
Any help is appreciated. Thanks
I faced the same problem for a few weeks ago. In my case, I want to detect 5G network on Galaxy S20-5G but the getDataNetworkType() always return 13 NETWORK_TYPE_LTE.
Following by netmonster-core strategy, and here is the code that I extract from them to solve my problem.
public boolean isNRConnected(TelephonyManager telephonyManager) {
try {
Object obj = Class.forName(telephonyManager.getClass().getName())
.getDeclaredMethod("getServiceState", new Class[0]).invoke(telephonyManager, new Object[0]);
// try extracting from string
String serviceState = obj.toString();
boolean is5gActive = serviceState.contains("nrState=CONNECTED") ||
serviceState.contains("nsaState=5") ||
(serviceState.contains("EnDc=true") &&
serviceState.contains("5G Allocated=true"));
if (is5gActive) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
Here is full detector class from netmonster-core:
(DetectorLteAdvancedNrServiceState.kt)
My project is to read button inputs from my car's steering wheel controls and convert them (using a Teensy 3.2 Arduino-alike) into android system actions of my choosing (e.g. Volume Up, Next Track, OK Google).
I have tried several different modes that the Teensy provides in order to solve this, initially as a keyboard emulation, followed by Joystick emulation and now finally a Raw HID device. All of these modes work flawlessly on Windows and Linux but do not work on android (I've tried on the target device running Android 4.1 and an Android 5 device, neither work).
The closest I've managed to get this working is as a RawHID Device with a small app i wrote to decode the packets and convert to system actions. This actually works...for about 2-5 button presses. Then nothing. In order to get my next 2-5 button presses i have to unplug the device and restart the program. The program halts on thisConnection.requestWait() forever. In an older version i used bulkTransfer and it has a similar effect, returning -1 and no data perpetually after 2-5 button presses.
Code for OpenConnection:
public boolean OpenConnection(UsbManager pUsbManager)
{
if(ActiveDevice == null) return false;
if(!hasPermission) return false;
if(ActiveConnection != null && ActiveEndpoint != null) return true;
if(hasAssociatedUsbDevice()) {
ActiveInterface = ActiveDevice.getInterface(InterfaceIndex);
ActiveEndpoint = ActiveInterface.getEndpoint(EndpointIndex);
ActiveConnection = pUsbManager.openDevice(ActiveDevice);
ActiveConnection.claimInterface(ActiveInterface, true);
ActiveRequest = new UsbRequest();
ActiveRequest.initialize(ActiveConnection,ActiveEndpoint);
return true;
}
return false;
}
Code for the device loop (run on a separate low priority thread)
private void deviceLoop(Config.HIDDevice pHIDDevice)
{
try
{
if (!pHIDDevice.OpenConnection(mUsbManager)) return;
ByteBuffer dataBufferIn = ByteBuffer.allocate(64);
//String activeAppName = mAppDetector.getForegroundAppName(); //TODO: Refactor, causing excessive memory alloc
String activeAppName = null;
Config.AppProfile activeProfile = pHIDDevice.getAppProfile(activeAppName);
while (!mExitDeviceThreads)
{
UsbDeviceConnection thisConnection = pHIDDevice.getActiveConnection();
if (thisConnection == null) break; //connection dropped
UsbRequest thisRequest = pHIDDevice.getActiveRequest();
if (thisRequest == null) break; //connection dropped
thisRequest.queue(dataBufferIn, dataBufferIn.capacity());
if (thisConnection.requestWait() == thisRequest)
{
byte[] dataIn = dataBufferIn.array();
for (Config.ButtonPacketMapping thisButtonMapping : pHIDDevice.getButtonPacketMappings())
{
if (thisButtonMapping.Update(dataIn))
{
for (Config.ButtonAction thisButtonAction : activeProfile.getButtonActions(thisButtonMapping.getName()))
{
if (thisButtonMapping.getLastValue() == false && thisButtonMapping.getValue() == true)
{
if (thisButtonAction.buttonAction == Config.ButtonAction.eButtonActionType.Press)
{
thisButtonAction.Set();
}
}
else if (thisButtonMapping.getLastValue() == true && thisButtonMapping.getValue() == false)
{
if (thisButtonAction.buttonAction == Config.ButtonAction.eButtonActionType.Release)
{
thisButtonAction.Set();
}
}
}
}
}
}
else
{
break; //Connection dropped or something went very wrong
}
}
}
finally
{
pHIDDevice.CloseConnection();
}
}
So my question more succinctly is:
Has anyone managed to get a Teensy Arduino to interface with Android in any way at all over USB? Is there anything wrong with my HID approach to cause this "stalling" problem?
In the end, I switched to an Arduino Pro Micro which has native USB support, and used the Project-HID library using the "Consumer Device" method. This works perfectly with any OS/Hardware combo that I've tried.
I want to check if an android devices is rooted or not. If device is rooted I dont want my application to show the appropriate message to the user and the application should not work on a rooted device.
I have gone through various links and blogs which have code snipplets to check if device is rooted or not. But I also found multiple developers saying that it is not possible to programmatically check for sure if a device is rooted or no. The code snippets might not give 100% accurate results on all the devices and results might also depend on the tool used for rooting the android device.
Please let me know if there is any way to confirm for sure that the device is rooted or not programmatically.
Thanks,
Sagar
I don't have enough reputation points to comment, so I have to add another answer.
The code in CodeMonkey's post works on most devices, but at least on Nexus 5 with Marshmallow it doesn't, because the which command actually works even on non-rooted devices. But because su doesn't work, it returns a non-zero exit value. This code expects an exception though, so it has to be modified like this:
private static boolean canExecuteCommand(String command) {
try {
int exitValue = Runtime.getRuntime().exec(command).waitFor();
return exitValue == 0;
} catch (Exception e) {
return false;
}
}
Possible duplicate of Stackoverflow.
This one has an answer
Answer on the second link. The guy tested it on about 10 devices and it worked for him.
/**
* Checks if the device is rooted.
*
* #return <code>true</code> if the device is rooted, <code>false</code> otherwise.
*/
public static boolean isRooted() {
// get from build info
String buildTags = android.os.Build.TAGS;
if (buildTags != null && buildTags.contains("test-keys")) {
return true;
}
// check if /system/app/Superuser.apk is present
try {
File file = new File("/system/app/Superuser.apk");
if (file.exists()) {
return true;
}
} catch (Exception e1) {
// ignore
}
// try executing commands
return canExecuteCommand("/system/xbin/which su")
|| canExecuteCommand("/system/bin/which su") || canExecuteCommand("which su");
}
// executes a command on the system
private static boolean canExecuteCommand(String command) {
boolean executedSuccesfully;
try {
Runtime.getRuntime().exec(command);
executedSuccesfully = true;
} catch (Exception e) {
executedSuccesfully = false;
}
return executedSuccesfully;
}
I have a small issue regarding Ethernet.
My three questions are:
Can we programmatically Turn-On/Off Ethernet?
Can we programmatically Enable/Disable Ethernet?
Can we programmatically Connect Ethernet?
The above Questions are done with the Wifi. Like
We can programmatically Turn-On/Off Wifi.
We can programmatically Enable/Disable Wifi.
We can programmatically Connect Wifi using WifiManager.
Does android provides any EthernetManager like as WifiManager to handle Ethernet?
Or, if this doesn't seem feasible, then my original requirement is:
The first thing I am going to clear is "DEVICE IS ROOTED" .
Can I manipulate the Settings (Default)? Like I don't want any other option in the Settings.apk other than WIFI and Ethernet. It should show only Wifi and Ethernet. That's it. Can I disable all the options from the Settings or Can I remove all the other options from the Settings?
The solution I will present here is a hack using reflection and does only work on a rooted android system.
Your device might have the popular android.net.ethernet package. In an Activity, try
Object emInstance = getSystemService("ethernet");
It returns an valid instance of the EthernetManager or null. Null means you are out of luck.
An additional requirement might be depending on your device: Ethernet and Wifi might only work exclusively. You might need to disable Wifi to enable Ethernet and vice versa.
To enable Ethernet by reflection use your instance of the EthernetManager.
The method you want to invoke is setEthEnabled(boolean enabled)
Class<?> emClass = null;
try {
emClass = Class.forName("android.net.ethernet.EthernetManager");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Object emInstance = getSystemService("ethernet");
Method methodSetEthEnabled = null;
try {
methodSetEthEnabled = emClass.getMethod("setEthEnabled", Boolean.TYPE);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
methodSetEthEnabled.setAccessible(true);
try {
// new Boolean(true) to enable, new Boolean(false) to disable
methodSetEthEnabled.invoke(emInstance, new Boolean(false));
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Your application manifest needs these permissions
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
The permission WRITE_SECURE_SETTINGS can only be acquired by system apps. The app does not need to be signed by a system key. It can be any valid sign (like the regular Android App Export function). Use busybox to remount the system partition for write access and move your apk into the /system/app folder. Reboot the device and it should work.
Can we programmatically Connect Ethernet ?
There is no Access Point to connect you like with Wifi. You either configure it for DHCP or provide static values. This can of course also be done via reflection.
You will need the class EthernetDevInfo for that.
The actual implementation of the EthernetManager and EthernetDevInfo might slightly differ between Android versions and devices as it doesn't have to conform to a public api (yet) and might even be a custom version.
To get a list of getters and setters you can use a Introspector or reflection in general.
Ok here are some methods i made for manipulating with the ETHERNET INTERFACE (eth0).
1) A method for checking if an ethernet interface exists
public static boolean doesEthExist() {
List<String> list = getListOfNetworkInterfaces();
return list.contains("eth0");
}
public static List<String> getListOfNetworkInterfaces() {
List<String> list = new ArrayList<String>();
Enumeration<NetworkInterface> nets;
try {
nets = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
e.printStackTrace();
return null;
}
for (NetworkInterface netint : Collections.list(nets)) {
list.add(netint.getName());
}
return list;
}
2) A method for checking if the ETHERNET is enabled or ON
public static boolean isEthOn() {
try {
String line;
boolean r = false;
Process p = Runtime.getRuntime().exec("netcfg");
BufferedReader input = new BufferedReader (new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
if(line.contains("eth0")){
if(line.contains("UP")){
r=true;
}
else{
r=false;
}
}
}
input.close();
Log.e("OLE","isEthOn: "+r);
return r;
} catch (IOException e) {
Log.e("OLE","Runtime Error: "+e.getMessage());
e.printStackTrace();
return false;
}
}
3) A method for enabling or disabling the Ethernet depending on the state in which it is
public static void turnEthOnOrOff() {
try {
if(isEthOn()){
Runtime.getRuntime().exec("ifconfig eth0 down");
}
else{
Runtime.getRuntime().exec("ifconfig eth0 up");
}
} catch (IOException e) {
Log.e("OLE","Runtime Error: "+e.getMessage());
e.printStackTrace();
}
}
4) A method for connecting via ethernet depending on the chosen type (dhcp/static)
private boolean connectToStaticSettingsViaIfconfig(StaticConnectionSettings scs) {
try {
if(typeChosen.equalsIgnoreCase("dhcp")){
Runtime.getRuntime().exec("ifconfig eth0 dhcp start");
}
else{
Runtime.getRuntime().exec("ifconfig eth0 "+scs.getIp()+" netmask "+scs.getNetmask()+" gw "+scs.getGateway());
}
} catch (IOException e) {
Log.e("OLE","Runtime Error: "+e.getMessage());
e.printStackTrace();
return false;
}
return true;
}
There is one more class which i created for storing all the eth values needed. This class is than initialized with the values the user inserts.
public class StaticConnectionSettings {
private String ip, netmask, dns, mac, gateway, type;
//Getters and Setters
}
This is it ... I will test it shortly... This code lacks a test phase (ping). And maybe it needs setting of DNS. But this can be done easily. I have not included it because i think on our device it will work also without the DNS setting.
It works for Android 6.0.1
Class<?> ethernetManagerClass = Class.forName("android.net.ethernet.EthernetManager");
Method methodGetInstance = ethernetManagerClass.getMethod("getInstance");
Object ethernetManagerObject = methodGetInstance.invoke(ethernetManagerClass);
Method methodSetEthEnabled = ethernetManagerClass.getMethod("setEthernetEnabled", Boolean.TYPE);
methodSetEthEnabled.invoke(ethernetManagerObject, isEnabled);
Three Answeres to your above questions:
Yes. You could try using ifconfig eth0 down ; ifconfig eth0 up. But i have not tested it by myself yet.
Yes, but you do not have to. Android does the switching for you. If you connect to WiFi, Ethernet disables. If you are already connected to WiFi and you plug your ethernet cable into the device; you need only to disable WiFi (which you know how to) and android switches automatically to ethernet.
Not so easy as you may think. I have the same problem and until now i have found only one solution which i have not yet tested. Since android runs on the linux kernel, we can use ifconfig in order to manipulate the ethernet connection.
An explanation is hidden here:
http://elinux.org/images/9/98/Dive_Into_Android_Networking-_Adding_Ethernet_Connectivity.pdf
And the youtube video of this lecture
http://www.youtube.com/watch?v=LwI2NBq7BWM
And a reference on how to use ifconfig for android
Android ethernet configure IP using dhcp
So if you come to a possible solution, please share it!! If i will do it before you i will certenly.
How can I find out for sure that device really has gsm, cdma or other cellular network equipment (not just WiFi)?
I don't want to check current connected network state, because device can be offline in the moment.
And I don't want to check device id via ((TelephonyManager) act.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId() because some devices would just give you polymorphic or dummy device ID.
Actualy, I need to check cell equipment exactly for skipping TelephonyManager.getDeviceId and performing Settings.Secure.ANDROID_ID check on those devices that don't have cellular radio. I have at least one tablet (Storage Options Scroll Excel 7") which returns different IMEIs every time you ask it, although it should return null as it has no cell radio (the same situation here: Android: getDeviceId() returns an IMEI, adb shell dumpsys iphonesubinfo returns Device ID=NULL). But I need to have reliable device id that is the same every time I ask.
I'd be glad to hear your thoughts!
If you're publishing in the store, and you want to limit your application only being visible to actual phones, you could add a <uses-feature> into your manifest that asks for android.hardware.telephony. Check out if that works for you from the documentation.
Just in case somebody needs complete solution for this:
Reflection is used because some things may not exist on some firmware versions.
MainContext - main activity context.
static public int getSDKVersion()
{
Class<?> build_versionClass = null;
try
{
build_versionClass = android.os.Build.VERSION.class;
}
catch (Exception e)
{
}
int retval = -1;
try
{
retval = (Integer) build_versionClass.getField("SDK_INT").get(build_versionClass);
}
catch (Exception e)
{
}
if (retval == -1)
retval = 3; //default 1.5
return retval;
}
static public boolean hasTelephony()
{
TelephonyManager tm = (TelephonyManager) Hub.MainContext.getSystemService(Context.TELEPHONY_SERVICE);
if (tm == null)
return false;
//devices below are phones only
if (Utils.getSDKVersion() < 5)
return true;
PackageManager pm = MainContext.getPackageManager();
if (pm == null)
return false;
boolean retval = false;
try
{
Class<?> [] parameters = new Class[1];
parameters[0] = String.class;
Method method = pm.getClass().getMethod("hasSystemFeature", parameters);
Object [] parm = new Object[1];
parm[0] = "android.hardware.telephony";
Object retValue = method.invoke(pm, parm);
if (retValue instanceof Boolean)
retval = ((Boolean) retValue).booleanValue();
else
retval = false;
}
catch (Exception e)
{
retval = false;
}
return retval;
}