NPE on Environment.getExternalStorageState()? - android

Cannot find the reason why I am getting "Null pointer exception" . I could give an explicit check to see if "getStorageState is null" but that doesnt explain why I am getting this error.
The error is :
java.lang.NullPointerException
at android.os.Environment.getStorageState(Environment.java:719)
at android.os.Environment.getExternalStorageState(Environment.java:694)
at com.ciqual.android.insight.sessionService.RemoveFiles(SessionService.java:664)
com.vyshas.android.sessionService.onEndSession(SessionService.java:460)
at : (the line that error points to is this :)(seen in jellybean 4.3 and kitkat)
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//
}

Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState) wouldnt cause a NPE while Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) does cause NPE and crashes the application.
I still dont know why getExternalStorageState is null eventhough I have permissions set but the solutions atleast wouldn't crash the application.

I have similar repot from Android 4.3 .
Source code is:
/**
* Gets the current state of the primary "external" storage device.
*
* #see #getExternalStorageDirectory()
*/
public static String getExternalStorageState() {
try {
IMountService mountService = IMountService.Stub.asInterface(ServiceManager
.getService("mount"));
final StorageVolume primary = getPrimaryVolume();
return mountService.getVolumeState(primary.getPath());
} catch (RemoteException rex) {
Log.w(TAG, "Failed to read external storage state; assuming REMOVED: " + rex);
return Environment.MEDIA_REMOVED;
}
}
I have nothing to do but try catch it.

Related

Rename errors on crashlitics

I have a project where all errors and warnings were written in logs in classes where they occurred. I started to use crashlytics. And tried to combine all the logic connected to logging and errors to a specific class. And force this class to decide where to report an error (error + warning) and where to log warnings. But when I made it I started to receive all the errors as they have occurred in this class. Is it possible to rename errors? For example, manually add activity name in the report so I will get different errors and not the same error all the time. Not like on the picture.
class AppLogs {
companion object CrashReport {
private fun reportToCrashlytics(
errorMessage: String,
user: String = "user id",
log: String = "log",
additionalInfoTitle: String = "title",
additionalInfoMessage: String = " message"
) {
FirebaseCrashlytics.getInstance().log(log)
FirebaseCrashlytics.getInstance().setUserId(user)
FirebaseCrashlytics.getInstance()
.setCustomKey(additionalInfoTitle, additionalInfoMessage)
FirebaseCrashlytics.getInstance().recordException(throw Exception(errorMessage))
}
private fun reportLog(errorMessage: String) {
Timber.e(errorMessage)
}
fun report(errorMessage: String, errorType: Char) {
if (errorType == 'e') {
reportLog(errorMessage)
reportToCrashlytics(errorMessage)
} else {
reportLog(errorMessage)
}
}
}
}
Answer for the actual issue
... manually add activity name in the report so I will get different errors and not the same error all the time ...
The answer is short - no it is not possible (without enormous effort).
But why?
Crashlytics uses the stack trace of the throwable object which was reported. Using this stack allows us to get reports that track the exception right to the line where it occurred.
It means that to create another issue record in the list of issues you have to modify the stack trace of the throwable object.
TrimmedThrowableData is the class that collects stack trace data to report. As you can see it gets unmodified stack trace of the throwable.
Most likely the only solution
If you want to get different stack trace - create Exception objects where reportToCrashlytics is used and pass these objects as arguments. Or throw and catch exceptions, and report exceptions that were caught.
Previous answer (bug found)
You are throwing the exception making the application crash. You should create Exception object and just pass it in as an argument.
If you open IDE you will see that the line where throw is used has recordException method highlighted and if you hover a cursor over it you will see the following:
It means that you never execute recordException because arguments are evaluated first and then passed into the function. But the function is never reached because throw crashes the application.
Do not use throw keyword:
FirebaseCrashlytics.getInstance().recordException(Exception(errorMessage))
You can change Your Stack trace like this :
public class CustomException extends Exception {
public CustomException(String message, int lineNumber) {
super(message);
StackTraceElement[] stackTrace = getStackTrace();
StackTraceElement[] newStackTrace = new StackTraceElement[stackTrace.length + 1];
System.arraycopy(stackTrace, 0, newStackTrace, 1, stackTrace.length);
newStackTrace[0] = new StackTraceElement("className", "methodName", "fileName", lineNumber);
setStackTrace(newStackTrace);
}
}

Fix warning NullPointerException in android

Below code gives a warning when I run Inspect code. How can I change it to fix the warning?
File contents = new File(context.getExternalFilesDir(null).getAbsolutePath(), "Contents");
if (!contents.exists()) {
contents.mkdirs();
}
Warning:
Method invocatiom 'getAbsolutePath' may produce 'NullPointerException'
and File mkdirs() is ignored
You can use boolean to get the result of mkdirs()
boolean isMkDirsSuccess = contents.mkdirs();
Log.e("TAG","This is the value of isMkDirsSuccess " + isMkDirsSuccess );
for NullPointerException you can use
File contents = new File(Objects.requireNonNull(context.getExternalFilesDir(null)).getAbsolutePath(), "Contents");
//requireNonNull needs min API = 19
Hope this will help!
From the docs:
Shared storage may not always be available, since removable media can be ejected by the user. Media state can be checked using Environment#getExternalStorageState(File).
You need to do some checking first:
File externalDir = context.getExternalFilesDir(null);
if(externalDir == null) {
throw new IllegalStateException("No External files directory found.");
}
if(Environment.getExternalStorageState(externalDir).equals(Environment.MEDIA_MOUNTED)) {
throw new IllegalStateException("External Storage not mounted correctly.");
}
File contents = new File(externalDir.getAbsolutePath(), "Contents");
if (!contents.exists()) {
contents.mkdirs();
}
You can replace the exceptions with flags, or logs or whatever your programme needs.
https://developer.android.com/reference/android/content/Context.html#getExternalFilesDir(java.lang.String)
https://developer.android.com/reference/android/os/Environment#getExternalStorageState()

unable to load owl file to android project using owl api

I have been trying to load an OWL file that I made in Protégé. I import OWL API 3.4.3 to my project and also passed the sample.owl file to raw folder, but when I try to load the OWL file, it doesn't work. There was no error but I am just getting this message
unfortunately, sampleproject has stopped
Here is the section of code am using. When I try the code in a standard Java environment it works without a problem.
OWLOntology localOntology = null;
int rID = resources.getIdentifier("com.example.cammclient1:raw/"+"sample", null, null);
InputStream input = resources.openRawResource(rID);
OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
ontology = manager.loadOntologyFromOntologyDocument(input);
try {
for (OWLClass cls : localOntology.getClassesInSignature()) {
Log.d("class in the ontology", ((CharSequence) cls).toString());
}
TV1.setText("reading classes...............");
}
catch (Exception e) {
TV1.setText("Not successfull");
}
You are casting OWLClass instances to CharSequence and then calling toString() on it.
This will cause ClassCastException to be thrown - an OWLClass is not a string.
Just use cls.toString() instead, you will have the same result.
You are also swallowing the exception in the catch block. That's not helpful in diagnosing the issue, as it hides information by just saying "Not successful" without providing more information.

Under what circumstances will Android's Log.wtf terminate my app?

I would like to log error reports for my app to the Android Market error console; it looks like I can use Log.wtf for this.
The documentation for Log.wtf says:
What a Terrible Failure: Report a condition that should never happen. The error will always be logged at level ASSERT with the call stack. Depending on system configuration, a report may be added to the DropBoxManager and/or the process may be terminated immediately with an error dialog.
In my case, I can catch these exceptions and recover from them by showing an error message; I don't want my app to crash, but I do want the report to be sent to the error console.
Under what circumstances will Log.wtf terminate my app? Is it possible to get an error report without causing the app to crash?
It depends on your system settings (certain options can be enabled for debugging but are disabled on normal devices). They are settings enabled when android is compiled for the device and possibly the kernel.
I would suggest using Log.e() with a prefix instead of Log.wtf() to avoid any problems e.g. WTF: Something terrible happened
Here is what happens when you call a Log.wtf()
-> Log.java
/**
* What a Terrible Failure: Report an exception that should never happen.
* Similar to {#link #wtf(String, Throwable)}, with a message as well.
* #param tag Used to identify the source of a log message.
* #param msg The message you would like logged.
* #param tr An exception to log. May be null.
*/
public static int wtf(String tag, String msg, Throwable tr) {
TerribleFailure what = new TerribleFailure(msg, tr);
int bytes = println_native(LOG_ID_MAIN, ASSERT, tag, getStackTraceString(tr));
sWtfHandler.onTerribleFailure(tag, what);
return bytes;
}
-> Log.java
private static TerribleFailureHandler sWtfHandler = new TerribleFailureHandler() {
public void onTerribleFailure(String tag, TerribleFailure what) {
RuntimeInit.wtf(tag, what);
}
};
-> RuntimeInit.java
/**
* Report a serious error in the current process. May or may not cause
* the process to terminate (depends on system settings).
*
* #param tag to record with the error
* #param t exception describing the error site and conditions
*/
public static void wtf(String tag, Throwable t) {
try {
if (ActivityManagerNative.getDefault()
.handleApplicationWtf(mApplicationObject, tag,
new ApplicationErrorReport.CrashInfo(t))) {
// The Activity Manager has already written us off -- now exit.
Process.killProcess(Process.myPid());
System.exit(10);
}
} catch (Throwable t2) {
Slog.e(TAG, "Error reporting WTF", t2);
}
}
-> ActivityManagerNative.java
public boolean handleApplicationWtf(IBinder app, String tag,
ApplicationErrorReport.CrashInfo crashInfo)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(app);
data.writeString(tag);
crashInfo.writeToParcel(data, 0);
mRemote.transact(HANDLE_APPLICATION_WTF_TRANSACTION, data,
reply, 0);
reply.readException();
boolean res = reply.readInt() != 0;
reply.recycle();
data.recycle();
return res;
}
Following nebkat information. Beware using WTF: the API level of the device must be 8 or higher.

Copy the shared preferences XML file from /data on Samsung device failed

There's an exporting feature in my application. It's just a copy operation since all my settings are store in shared preference.
I just copy the xml file from /data/data/package.name/shared_prefs/settings.xml to SD card. It works fine on my HTC desire. However, it might not work on Samsung devices, and i got the following error while I try to copy the file.
I/System.out( 3166): /data/data/package.name/shared_prefs/settings.xml (No such file or directory)
in the directory.
Anyone know how to fix it, or is there another simple way to store the shared preference ?
Thanks.
Never never never never never never never never never hardwire paths.
Unfortunately, there's no getSharedPreferenceDir() anywhere that I can think of. The best solution I can think of will be:
new File(getFilesDir(), "../shared_prefs")
This way if a device manufacturer elects to change partition names, you are covered.
Try this and see if it helps.
CommonsWare's suggestion would a be clever hack, but unfortunately it won't work.
Samsung does not always put the shared_prefs directory in the same parent directory as the getFilesDir().
I'd recommend testing for the existence of (hardcode it, except for package name):
/dbdata/databases/<package_name>/shared_prefs/package.name_preferences.xml and if it exists use it, otherwise fall back to either CommonsWare's suggestion of new File(getFilesDir(), "../shared_prefs") or just /data/data/<package_name>/shared_prefs/package.name_preferences.xml.
A warning though that this method could potentially have problems if a user switched from a Samsung rom to a custom rom without wiping, as the /dbdata/databases file might be unused but still exist.
More details
On some Samsung devices, such as the Galaxy S series running froyo, the setup is this:
/data/data/<package_name>/(lib|files|databases)
Sometimes there's a shared_prefs there too, but it's just Samsung's attempt to confuse you! Don't trust it! (I think it can happen as a left over from a 2.1 upgrade to 2.2, but it might be a left over from users switching roms. I don't really know, I just have both included in my app's bug report interface and sometimes see both files).
And:
/dbdata/databases/<package_name>/shared_prefs
That's the real shared_prefs directory.
However on the Galaxy Tab on Froyo, it's weird. Generally you have: /data/data/<package_name>/(lib|shared_prefs|files|databases)
With no /dbdata/databases/<package_name> directory, but it seems the system apps do have:
/dbdata/databases/<package_name>/yourdatabase.db
And added bonus is that /dbdata/databases/<package_name> is not removed when your app is uninstalled. Good luck using SharedPreferences if the user ever reinstalls your app!
Try using
context.getFilesDir().getParentFile().getAbsolutePath()
Best way to get valid path on all devices - run method Context.getSharedPrefsFile defined as:
/**
* {#hide}
* Return the full path to the shared prefs file for the given prefs group name.
*
* <p>Note: this is not generally useful for applications, since they should
* not be directly accessing the file system.
*/
public abstract File getSharedPrefsFile(String name);
Because of it hidden need use reflection and use fallback on fail:
private File getSharedPrefsFile(String name) {
Context context = ...;
File file = null;
try {
if (Build.VERSION.SDK_INT >= 24) {
try {
Method m = context.getClass().getMethod("getSharedPreferencesPath", new Class[] {String.class});
file = (File)m.invoke(context, new Object[]{name});
} catch (Throwable e) {
Log.w("App TAG", "Failed call getSharedPreferencesPath", e);
}
}
if (file == null) {
Method m = context.getClass().getMethod("getSharedPrefsFile", new Class[] {String.class});
file = (File)m.invoke(context, new Object[]{name});
}
} catch (Throwable e) {
Log.w("App TAG", "Failed call getSharedPrefsFile", e);
file = new File(context.getFilesDir(), "../shared_prefs/" + name + ".xml");
}
return file;
}
On some Samsungs implements like this:
public File getSharedPrefsFile(String paramString) {
return makeFilename(getPreferencesDir(), paramString + ".xml");
}
private File getPreferencesDir() {
synchronized (this.mSync) {
if (this.mPreferencesDir == null) {
this.mPreferencesDir = new File("/dbdata/databases/" + getPackageName() + "/", "shared_prefs");
}
File localFile = this.mPreferencesDir;
return localFile;
}
}
On other Android like this:
public File getSharedPrefsFile(String name) {
return makeFilename(getPreferencesDir(), name + ".xml");
}
private File getPreferencesDir() {
synchronized (mSync) {
if (mPreferencesDir == null) {
mPreferencesDir = new File(getDataDirFile(), "shared_prefs");
}
return mPreferencesDir;
}
}
private File getDataDirFile() {
if (mPackageInfo != null) {
return mPackageInfo.getDataDirFile();
}
throw new RuntimeException("Not supported in system context");
}
After while Google change API for level 24 and later:
https://android.googlesource.com/platform/frameworks/base/+/6a6cdafaec56fcd793214678c7fcc52f0b860cfc%5E%21/core/java/android/app/ContextImpl.java
I've tested in Samsung P1010 with:
//I'm in a IntentService class
File file = this.getDir("shared_prefs", MODE_PRIVATE);
I got:
"/data/data/package.name/app_shared_prefs"
It works fine to me. I can run ffmpeg in this folder.
Look:
Context.getDir
You have to create the shared_prefs directory:
try{
String dir="/data/data/package.name/shared_prefs";
// Create one directory
boolean success = (new File(dir)).mkdirs();
if (success) {
// now copy the file
}
}catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
Also... the package of your app is package.name? Make sure you are referring to the right package.

Categories

Resources