I want to disable camera functionality in my app, if the device does not have a camera. However, I seem to have stumbled into a bug when doing so.
According to the official Android Developer docs, I can use hasSystemFeature() to detect device features at runtime, as shown below:
boolean hasAnyCamera = this.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
Log.i(LOG_TAG, "hasAnyCamera = " + hasAnyCamera);
boolean hasBackCamera = this.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
Log.i(LOG_TAG, "hasBackCamera = " + hasBackCamera);
However, I tried to create an emulator without a front-facing or back-facing camera, and it still returns true for both checks. Is there some other way that I can detect the camera in Android?
Relevant documentation:
Take Photos > Request the camera feature
PackageManager.hasSystemFeature()
PackageManager.FEATURE_CAMERA_ANY
PackageManager.FEATURE_CAMERA
After some research, it appears that this is a known bug, which has been unresolved for 10+ years now.
See: Emulator does not honour Camera support flag
It seems that the only know work-around is to detect the number of cameras using the Camera.getNumberOfCameras() method, which has been deprecated since Android 5.0.
boolean hasCamera = Camera.getNumberOfCameras() > 0;
Log.i(LOG_TAG, "hasCamera = " + hasCamera);
The above method seems to work on my emulator, despite the warning that it is deprecated.
Now according to the docs for Camera.getNumberOfCameras():
"The return value of [getNumberOfCameras()] might change dynamically if the device supports external cameras and an external camera is connected or disconnected."
So perhaps hasSystemFeature() always returns true, because the device might later have an external camera attached?
An emulator started by using a hardware configuration which enables or disables some features in runtime. It would be possible to add / change some configuration for your emulator.
I think, It is not removing camera hardware, just disables them. I created an emulator as you mentionned and there was no camera. When I changed the configuration I was able to use the camera. However, hasSystemFeature returned true for both situtation.
When you create an emulator, the settings you choose is written in hardware-qemu.ini for that AVD. You can find it in ~/.android/avd/YOUR_EMULATOR.avd/hardware-qemu.ini. You can get exact path in show on disk on Device Manager.
My application uses telephonyManager to check the type of network the voice call is carried over. The test is to confirm that calls are being carried over Wifi. However, the printed result from the app is not what I expect, even during calls.
int voiceNetworkTypeVal = 0;
voiceNetworkTypeVal = telephonyManager.getVoiceNetworkType();
However, when I call the phone over Wifi and run the app, the phone always prints voiceNetworkTypeVal as int value 13, NETWORK_TYPE_LTE, instead of the expected value 18 (NETWORK_TYPE_IWLAN) for wifi calls. Anyone knows how to fix this?
What is the proper way to get the serial number from native on Android O without calling the Java Build.getSerial().
On Android < 26 versions from native we could get the device serial number using the following code:
string serial = read_property("ro.boot.serialno");
...
string read_property(const string& property_name) {
char propertyValue[PROP_VALUE_MAX];
int propertyLen = __system_property_get(property_name.c_str(), propertyValue);
...
}
On Android O this throws an error:
Access denied finding property "ro.boot.serialno"
Although the READ_PHONE_STATE permission is granted. Seems to be related to the deprecated Build.SERIAL in Android 26.
I managed to get this property using adb, so the value is not removed and is there:
adb shell getprop ro.boot.serialno
You can use Build.getSerial() to get the serial number.
If the user has granted the READ_PHONE_STATE permission then there is no problem but if the user revoked the permission or has never granted it - you should take into consideration that you will get a SecurityException at runtime when trying to retrieve it.
In general - it looks like Google is slowly pushing to prevent apps from using personal identifiable information (like serial numbers of device) over the last few years so and you should look into alternatives like installationId.
I am trying to use UsageStatsManager on an Android Wear device.
What I did:
I am requesting the permission for it on the mobile app that is running on my phone. After the permission was given by the user, I can access the usage stats data.
Then I created a UsageStatsManager on the wear app and tried to access the usage stats data there. However, on the watch, I do not have the permission to do that and I can not ask for permission. To check if the permission was given by the user I used:
private boolean isPermissionGranted(){
try{
PackageManager packageManager = getPackageManager();
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(getPackageName(), 0);
AppOpsManager appOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);
return mode == AppOpsManager.MODE_ALLOWED;
}catch(PackageManager.NameNotFoundException e){
return false;
}
}
This returns true on the phone but false on the watch.
The problem:
I can ask the user for permission to use UsageStatsManager on the phone but I can not do that on the watch because the setting does not exist. Has anyone figured out if it is possible to get UsageStatsManager running on a watch?
Usage Permission intent isn't possible on Wear.
Same goes for Overlay (Settings.canDrawOverlays()) though at least you can use lower target to overcome it.
Also with latest Android N emulator this isn't resolved.
If I dial
*
#
*
#
8
2
5
5
#
*
#
*
, I get my android device id which starts with android-35c2acdd...
source
If I use Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID) the result starts with a96b4b27...
If I use ((TelephonyManager) Context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId() the result starts with 3538330...
What is the difference between these ID-s? How can I get the result of the
*
#
*
#
8
2
5
5
#
*
#
*
dial?
IMEI
The IMEI is the 'MAC' for the telephony module - the unique ID that the telephone uses when it connects via GSM/GPRS/HSPDA/etc. The GSM network uses it to route calls and data from the phone over the GSM network right up to the gateway into the Internet (which is an IP network).
A telephony module is a chip or circuit board that handles the telephone network, either GSM or CMDA, and often has a slot for a removable SIM card. Some phones have more than one telephony module (active dual- or multi-SIM phones). Each telephony module has its own IMEI.
Manufacturers give each phone (strictly the telephony module) a unique IMEI during manufacturing. However the number can normally be rewritten if you have the right software. This is often done after a phone has been stolen to give the phone a new identity and bipass stolen phone blocking system.
The IMEI can be programmatically obtained using the TelephonyManager.getDeviceId() API.
CDMA phones have a ESN or MEID which are different lengths and formats, even though it is retrieved using the same API.
Android devices without telephony modules - for example many tablets and TV devices - do not have an IMEI. As Schlangi commented, some devices that do not have a telephony module fake the IMEI, so the presence of an IMEI does not (always) guarantee the device has a telephony module.
ANDROID_ID
The ANDROID_ID is another unique number on the phone - this is automatically generated by the OS as it boots for the first time (doing it this way makes it much easier for the manufacturers by removing a step from the production line).
The ANDROID_ID can (and does) change, for example:
Factory reset (including when reflashing the OS)
In software: eg https://play.google.com/store/apps/details?id=com.vcastroi.changeid
It is mainly used by developers (eg identifying and connecting to devices using adb)
ANDROID_ID can be used to identify an Android device given the caveats above, realistically meaning that it uniquely identifies the device over significant portions of the device lifetime, but cannot be relied on.
Also note that there was a bug in Froyo where many devices gave themselves the same ANDROID_ID. This is the bug
Other identifiers
There are a number of other things that can be used identify the device:
MAC address of the WiFi module: WifiManager.getConnectionInfo() -> WifiInfo.getMacAddress(). This can often be changed in software, but generally is constant over the device lifetime. Also it can only be read if the WiFi module is switched on.
MAC address of the BlueTooth module: BluetoothAdaptor.getAddress(). Like WiFi MAC, this can often be changed in software and may be off when you need it
The subscriber's telephone number. This may change if the user requests a new number from the telco, or if the user switches SIMs. It is obtained from TelephonyManager.getLine1Number(). This is only present for Android phone devices with a current SIM installed and a paid service with a telco.
The SIM contains its own identifying number (IMSI). This is obtained from the TelephonyManager.getSubscriberId() API. Obviously the SIM may not be present at any specific time, and it changes when the SIM is changed - and users can upgrade/replace their SIM while keeping the same number, so you can't say that this is one-to-one to a specific phone or user.
Related to the IMSI is the MSISDN. This functions as the identification of a subscription (your contract for a specific telephone number with your mobile provider) and therefore gives the device its telephone number. The MSISDN may be associated with several SIM cards, and therefore several phones. It comes with all the caveats for reading the SIM above. This may be retrieved with TelephonyManager.getSimSerialNumber(). Thanks Schlangi for the corrections and additions
Gingerbread and later has android.os.Build.SERIAL which many manufacturers set (but not all. Bugger).
Other notes
You need specific permissions to access each and every API, so if you try for all of them, your app's permissions in the Google Play store look fairly permissive.
I think this link explains all the other available options also https://android-developers.googleblog.com/2011/03/identifying-app-installations.html
Found on the web:
private static final Uri URI = Uri.parse("content://com.google.android.gsf.gservices");
private static final String ID_KEY = "android_id";
String getAndroidId(Context ctx) {
String[] params = { ID_KEY };
Cursor c = ctx.getContentResolver()
.query(URI, null, null, params, null);
if (!c.moveToFirst() || c.getColumnCount() < 2)
return null;
try {
return Long.toHexString(Long.parseLong(c.getString(1)));
} catch (NumberFormatException e) {
return null;
}
}
Add permission:
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
However, I doubt that is a documented ID and I would be carefull because that might not work if GTalk gets updated.
Source: http://blog.codepainters.com/2012/01/17/how-to-obtain-gtalk-android-id/
Also worth having a look at: http://www.toxicbakery.com/android-development/getting-google-auth-sub-tokens-in-your-android-applications/
There are some approach to get unique identifier on android phone.
Android ID
It is a 64-bit hex string which is generated on the device's first boot.
Generally it won't changed unless is factory reset.
Secure.getString(getContentResolver(), Secure.ANDROID_ID);
The Android ID , considered unreliable because it can sometimes be null.
The documentation states that it "can change upon factory reset".
This string can also be altered on a rooted phone.
String m_szAndroidID = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
Returns: 9774d56d682e549c . No special permissions required.
2. The WLAN MAC Address string, is another unique identifier that you can use as a device id.
Before you read it, you will need to make sure that your project has the android.permission.ACCESS_WIFI_STATE
permission or the WLAN MAC Address will come up as null.
WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
String m_szWLANMAC = wm.getConnectionInfo().getMacAddress();
Returns: 00:11:22:33:44:55 (not a real address since this is a custom ROM , as you can see the MAC address can easily be faked).
WLAN doesn't have to be on, to read this value.
3. The BT MAC Address string, available on Android devices with Bluetooth, can be read if your project has the android.permission.BLUETOOTH permission.
BluetoothAdapter m_BluetoothAdapter = null; // Local Bluetooth adapter
m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String m_szBTMAC = m_BluetoothAdapter.getAddress();
Returns: 43:25:78:50:93:38 . BT doesn't have to be on, to read it.
4. IMEI only for Android devices with Phone use:
TelephonyManager TelephonyMgr = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String szImei = TelephonyMgr.getDeviceId(); // Requires READ_PHONE_STATE
This requires adding a permission in AndroidManifest.xml, and users will be notified upon installing
your software: android.permission.READ_PHONE_STATE. The IMEI is unique for your phone
and it looks like this: 359881030314356 (unless you have a pre-production device with an invalid IMEI like 0000000000000).
For more info refer this link.
IMEI
There is a mandatory requirement by the standardization bodies, that mobile devices for public networks may be uniquely identified by the IMEI number
It is the manufacturer's responsibility to set IMEI. In practice, developers sometimes see IMEIs like 000000... or 123456... Sometimes phones with identical IMEI go to production, which of course is a bug that should be fixed...
ANDROID_ID
A 64-bit number (as a hex string) that is randomly generated on the device's first boot and should remain constant for the lifetime of the device. (The value may change if a factory reset is performed on the device.)
It looks like Android does not trust the manufacturers and provides an alternative unique ID.
EDIT:
This is what I get (instead of IMEI) on and Android device that is not a phone:
$ adb shell dumpsys iphonesubinfo
Phone Subscriber Info:
Phone Type = GSM
Device ID = null
I think all the information provided above is well enough to understand the codes.
Yet I think you are still "not able to see the result of the ##8255## dial" (plz excuse if I went wrong somewhere in understanding this)
I assume the reason behind this is one of the latest bug fix against USSD code made in Android.
(you may read more about this and check if your device is on the list. its all over the web)
Finally, if you just want to get the android ID straightaway i suggest you to use this app-
https://play.google.com/store/apps/details?id=com.redphx.deviceid&hl=en