getSerial() method on Marshmallow - java

I'm new with Java and android and i need to basically retrieve hardware serial number from my device.
I've tried the following:
import android.content.*;
import android.os.Build;
public static String recup_android()
{
String androidid;
String SerialNumber;
androidid=android.os.Build.MODEL;
SerialNumber=android.os.Build.getserial;
return SerialNumber;
}
I'm facing the following error:
java:40: error: cannot find symbol
SerialNumber=android.os.Build.getserial;
^
symbol: variable getserial
location: class Build
1 error
:compileDebugJavaWithJavac FAILED
What am i missing there?
If I return androidid (MODEL) it then works OK.
Maybe something to have with the class declaration??
Thanks in advance for your precious help
Elie

You are using getSerial incorrectly. Its a method not variable and available from API 26 or higher. For older versions, use Build.SERIAL
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
// Todo Don't forget to ask the permission
SerialNumber = Build.getSerial();
}
else
{
SerialNumber = Build.SERIAL;
}
Make sure you have READ_PHONE_STATE permission before calling getSerial(). Otherwise your app will crash.
Check this tutorial for asking permissions.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && PermissionsUtility.checkPermission
(PermissionsUtility.PHONE_STATE_PERMISSION, getActivity())) {
SerialNumber = Build.getSerial();
} else {
SerialNumber = Build.SERIAL;
}
The best way is to surround it with permission check before calling Build.getSerial() even though you have already asked permission from the user.
This is the clean way to do. This will not crash and works smoothly.
Make sure you have added the permission in the manifest file.
Here PermissionsUtility is the utility class to check permission which returns
returns
public static final String PHONE_STATE_PERMISSION =
Manifest.permission.READ_PHONE_STATE;
public static boolean checkPermission(String permission, Activity activity) {
return ContextCompat.checkSelfPermission(activity, permission) ==
PackageManager.PERMISSION_GRANTED;
}
This simply checks if your app has the permission or not. In Permission pass PHONE_STATE_PERMISSION.

In Android 9, Build.SERIAL is always set to "UNKNOWN" to protect users' privacy.
If your app needs to access a device's hardware serial number, you should instead request the READ_PHONE_STATE permission, then call getSerial().
Build.getSerial() method can be used from API26 and requires READ_PHONE_STATE.
To get more information, please refer to following link:https://developer.android.com/about/versions/pie/android-9.0-changes-28

Related

USB Serial Driver Java Plugin not working in Unity Android build

I'm trying to make an Android app with the Unity editor in order to read from an USB device. I'm using Unity 2019.4.12f1 and the android device I'm building to is a Xiaomi Mi Box S, running Android 9.
What I've done so far is to use Android Studio to compile some java code in order to gain access to the USB port on Xiaomi.
I'm using this repo: https://github.com/mik3y/usb-serial-for-android as the base functionality of the library I'm trying to build.
This is the code I wrote in my Java library:
public class Plugin extends Activity {
private static UsbSerialPort port;
private static final int READ_WAIT_MILLIS = 2000;
public static String Initialize(Context unityContext) throws IOException {
UsbManager manager = (UsbManager) unityContext.getSystemService(Context.USB_SERVICE);
ProbeTable customTable = new ProbeTable();
customTable.addProduct(0x067b, 0x2303, CdcAcmSerialDriver.class);
UsbSerialProber prober = new UsbSerialProber(customTable);
List<UsbSerialDriver> availableDrivers = prober.findAllDrivers(manager);
if (availableDrivers.isEmpty()) {
return "Drivers list is empty";
}
// Open a connection to the first available driver.
UsbSerialDriver driver = availableDrivers.get(0);
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
if (connection == null) {
return "Connection is null";
}
port = driver.getPorts().get(0); // Most devices have just one port (port 0)
port.open(connection);
port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
return "Connection Successful";
}
public static String ReadPort() throws IOException {
if(port == null || !port.isOpen())
return "Null";
byte[] buffer = new byte[8192];
int len = port.read(buffer, READ_WAIT_MILLIS);
return buffer.toString();
}
public static void CloseSerialPort() throws IOException {
if(port != null && port.isOpen())
port.close();
}
And this is the C# code i'm using on the Unity side:
void Start()
{
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject context = activity.Call<AndroidJavaObject>("getApplicationContext");
AndroidJavaClass pluginClass = new AndroidJavaClass("com.hoho.android.usbserial.Plugin");
string response = pluginClass.CallStatic<string>("Initialize", context);
Debug.Log(response);
if (response.Contains("Successful"))
{
string read = pluginClass.CallStatic<string>("ReadPort");
Debug.Log(read);
}
else
{
Debug.Log("Init failed");
}
}
You can see that I've created a custom "Prober" for my device with the it's Vendor and Product ID's, so in theory the Java side should know what to look for. Unfortunately the collection "availableDrivers" is empty after the code executes.
On the C# side, I'm sending my unity activity for the Java to get it's context from. I see that the USB manager needs that context in order to be instanced. I did check and the variable "unityContext" is not null after is passed into the Java library from C#. Right now I'm investigating if maybe the context I'm sending to Java is not the right one, causing the USB manager not being able to access the USB devices.
The return String that I get from the Java code to Unity is: "Drivers list is empty", hence the conclusion that the USB drivers list is empty.
Any help or any kind of leading in the right direction is going to be helpful.
PS. Things I've checked:
I know that the USB device is able to communicate with the Android device because I've used an app to check and everything seemed fine. (https://play.google.com/store/apps/details?id=de.kai_morich.serial_usb_terminal&hl=en)
I'm answering my own question here. Maybe someone else will stumble upon this.
There were a couple of issues that I was not aware of:
The Xiaomi USB port will not continue to communicate with the sensor if it is set to USB Debugging Mode;
Again, even if the Xiaomi USB Debugging mode was turned off, it will not work. To make it work I had to restart the device.
The conclusion being that if you are working with Xiaomi Mi Box S make sure the hardware connection is working before you start changing anything on your code.
To make all of this work:
Make sure you understand how Java <-> C# communication works;
You will need to be a little bit familiar with Android Studio library builds;
Follow the instructions on the repo I posted.
You should be good to go at this point. Let me know if you need any further help.

Carrier custom application

I need to create an Android application to set carrier configuration(VoLte e.g.). The application should fetch configs from our Back-End and apply them on the phone.
In Android documentation I found the following article: This article says, that I can create my own application and override CarrierService.
public class SampleCarrierConfigService extends CarrierService {
private static final String TAG = "SampleCarrierConfigService";
public SampleCarrierConfigService() {
Log.d(TAG, "Service created");
}
#Override
public PersistableBundle onLoadConfig(CarrierIdentifier id) {
Log.d(TAG, "Config being fetched");
PersistableBundle config = new PersistableBundle();
config.putBoolean(
CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL, true);
config.putBoolean(
CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, false);
config.putInt(CarrierConfigManager.KEY_VOLTE_REPLACEMENT_RAT_INT, 6);
// Check CarrierIdentifier and add more config if needed…
return config;
}
}
I created an app with this service, but the method onLoadConfig(CarrierIdentifier id) is never called by the system.
So what I want from the system to call my overridden method, not system's. What should I do?
I found your question when researching how to do something similar.
In the article you linked it says:
The carrier app in question must be signed with the same certificate found on the SIM card, as documented in UICC Carrier Privileges.
Since we can't get the certificate from your carrier (they will never give it to you) I think we can't implement our own flavour sadly :-(

Environment.getExternalStorageDirectory() return null

I m trying to get the Internal Storage path of a Android Device.
Since most of the devices late off return Internal Storage path using Environment.getExternalStorageDirectory().getPath(); so I am using this to get the path.
Every thing is working fine except that when I am calling Environment.getExternalStorageDirectory().getPath(); from an non Activity class it is returning null whereas if I call it from a Activity class it returns the correct path.
I Tried searching other posts but could not find anything useful.
Any help would be really grateful.
EDIT:
if(getExtSdCardPath(con)!=null)
{ path=getExtSdCardPath(con);
if(new File(path).getPath().equal(Environment.getExternalStorageDirectory().getPath())) // This line give null "Null Pointer exception"
{
return null;
}
return path;
}
I am checking if the SD Card path is same as the path which is returned by Environment.getExternalStorageDirectory().getPath()
Ideally, getExtSdCardPath() would be "idempotent", which is a fancy way of saying "does the same work and returns the same thing no matter how many times you call it".
In your case, it is not. The first call to getExtSdCardPath() is returning the value that you want, and the second call to getExtSdCardPath() is returning null.
In your case, there is no particular need to call getExtSdCardPath() twice, and so you can work around the idempotence issue by rewriting your code to be something like:
path=getExtSdCardPath(con);
if(path!=null)
{
if(new File(path).getPath().equal(Environment.getExternalStorageDirectory().getPath())) // This line give null "Null Pointer exception"
{
return null;
}
return path;
}
Sounds like you forgot to put the requested permission in the manifest OR/AND forgot to ask for such a permission in runtime (in case you run this on devices with android 6.0 and above).
try to addto your manifest : <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Here a quick and simple implementation example of how to request the permission in runtime:
public class MainActivity extends AppCompatActivity implements ActivityCompat.OnRequestPermissionsResultCallback{
private static final int REQUEST_WRITE_PERMISSION = 111; //Number is not matter, just put what you want
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_WRITE_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Do your stuff with the file
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermission();
}
private void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_PERMISSION);
} else {
//Do your stuff with the file
}
}
}

Path requests must specify a user by using UserEnvironment

I am getting "Path requests must specify a user by using UserEnvironment" error by using
Environment.getExternalStorageDirectory().getPath()
I traced my code and I found that in java.io.Environment there is a function to produce this error :
private static void throwIfUserRequired() {
if (sUserRequired) {
Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment",
new Throwable());
}
}
I searched in the web and found this solution from here
Environment.setUserRequired(false);
But this solution is not working for me because I cannot access to the "setUserRequired" method of Environment. I get compilation error. I searched this function in the Environment class and I found this :
/** {#hide} */
public static void setUserRequired(boolean userRequired) {
sUserRequired = userRequired;
}
Can anyone help me how can I access to my external storage of my phone? any solution ? it is emergency. Thanks a lot
You need to use UserEnvironment and get the path for this user.
int userId = UserHandle.myUserId();
sCurrentUser = new UserEnvironment(userId);
This code stolen from Environment.java and the code they use to initialize their internal user.
I could solve my problem by removing
Environment.getExternalStorageDirectory().getPath()
inside try-catch block and writing outside of the try-catch block,and it is working now.
Through the reflection to solve this problem
fun setUserRequired() {
var state = Environment.getExternalStorageDirectory()
if ("mounted".equals(state)) {
try {
var environmentcls = Class.forName("android.os.Environment");
var setUserRequiredM = environmentcls.getMethod("setUserRequired", Boolean::class.java);
setUserRequiredM.invoke(null, false);
} catch (e: Exception) {
e.printStackTrace()
}
}
}

error on oncreate() method

I am begginer in Android App and using Java as when I add this code :
GCMRegistrar.checkDevice(this);
GCMRegistrar.checkManifest(this);
final String regId = GCMRegistrar.getRegistrationId(this);
if (regId.equals("")) {
GCMRegistrar.register(this, SENDER_ID);
} else {
Log.v(TAG, "Already registered");
}
I had error on :
SENDER_ID
Log
TAG
the error "cannot be resolved to available "
As I commented if you're a beginner you shouldn't start with GCM, but seems that you're a beginner not only on Android but also in Java (this is not bad, everybody was a beginner, and I'm not that advanced).
I suggest you to start following some basic tutorials on Java, then start with some basic tutorial for Android and so on.
GCM requires also a server side, so this is going to be quite advanced.
Anyway, the error is simple. SENDER_ID is a field that you haven't defined anywhere.
You have to declare it somewhere, like:
String SENDER_ID = "mySenderId";
or at the top of your class:
public class MyClass {
private static final SENDER_ID = "mySenderID";
}

Categories