Environment.getExternalStorageDirectory() return null - java

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
}
}
}

Related

onRequestPermissionsResult is deprecated in Android Fragment

This is my current (deprecated) method:
int LOCATION_REQUEST_CODE = 10001;
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
if (requestCode == LOCATION_REQUEST_CODE) {
//Permission granted
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
checkSettingsAndStartLocationUpdates();
} else {
//DO SOMETHING - Permission not granted
}
}
}
According to the android documentation https://developer.android.com/training/basics/intents/result I should use registerForActivityResult():
// GetContent creates an ActivityResultLauncher<String> to allow you to pass
// in the mime type you'd like to allow the user to select
ActivityResultLauncher<String> mGetContent = registerForActivityResult(new GetContent(),
new ActivityResultCallback<Uri>() {
#Override
public void onActivityResult(Uri uri) {
// Handle the returned Uri
}
});
However I am struggling with replacing my method.
Where do I insert my requestcode and my int array in the new method "registerForActivityResult()" ? Why do I need a "Uri" ?
Where do I insert my requestcode and my int array in the new method
"registerForActivityResult()" ?
You do not have any requestCode. In this design, you can think one single callback for each of the requestCode you have used previously. For handling single permission, you can use the built-in ActivityResultContracts.RequestPermission:
// Register the permissions callback, which handles the user's response to the
// system permissions dialog. Save the return value, an instance of
// ActivityResultLauncher, as an instance variable.
private ActivityResultLauncher<String> requestPermissionLauncher = registerForActivityResult(new RequestPermission(), isGranted -> {
if (isGranted) {
// Permission is granted. Continue the action or workflow in your
// app.
} else {
// Explain to the user that the feature is unavailable because the
// features requires a permission that the user has denied. At the
// same time, respect the user's decision. Don't link to system
// settings in an effort to convince the user to change their
// decision.
}
});
Why do I need a "Uri" ?
You may get it wrong. In this way, you need an ActivityResultContract<Input, Output> which connects the two Activities. Previously you can only pass Intent to the starting Activity. Now you can pass any type of object using this contract. Input is the type of object you want to pass, Output is the type of result object back from the new Activity. There are some built-in contracts to handle regular scenerio, one of which is GetContent(). If you want a startActivityForResult(intent) like thing, just use ActivityResultContracts.StartActivityForResult, and registering it will return an ActivityResultLauncher, within that intent, you can pass your array with that intent.
// Similar to how you pass your array with intnt before
Intent i = new Intent(MainActivity.this, NewActivity.class);
i.putExtra ("key_arr", arr); // arr is your int array
resultLauncher.launch(i);
I believe you are using the incorrect method.
The example code you gave me shows how to pass image path as a parameter because when dealing with images in android, images are the actual paths to the local image (do you see "mime type" in the comments?)
Since onRequestPermissionsResult is deprecated you are given two choices to resolve the issue.
add #SuppressWarnings("deprecation") to ignore deprecation warning and use it anyway
Or use the New Permission API. Checkout the code
import androidx.activity.result.contract.ActivityResultContracts.*
import androidx.activity.registerForActivityResult
class SampleActivity : AppCompatActivity() {
val requestLocation: () -> Unit = registerForActivityResult(
RequestPermission(), ACCESS_FINE_LOCATION // Permission Type
) { isGranted ->
// to do after permission is granted
}
private fun requestLocationAction() {
requestLocation()
}
}

Handle Permissions Request Result Without Subclassing Activity and Overriding onRequestPermissionsResult Method

I am calling a permissions request from a non-Activity based class inside of a Cordova plugin, and the main activity of my application cannot be extended so I cannot implement/override the onRequestPermissionsResult method of the activity. I need to run an event after the user has authorized permissions like the commented pseudocode lambda below, but I am not sure how. I have tried creating my own Activity subclass and implementing this method, but I get a NullPointerException.
class MyPlugin extends CordovaPlugin {
private void saveAndOpenFile() {
int permission =
ActivityCompat.checkSelfPermission(
cordova.getActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
cordova.getActivity(),
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
); /*.then((int requestCode, String[] permissions, int[] grantedResults) -> {
// Do something crazy
});*/
}
}
}
I suggest following the documentation on this one.
In short, it appears you should use cordova.hasPermission to check if we have the permission, then use cordova.requestPermission, which "will call the activity and cause a prompt to appear, asking for the permission. Once the user has the permission, the result must be handled with the onRequestPermissionResult method, which every plugin should override." So, it sounds like CordovaPlugin offers an empty base implementation of onRequestPermissionResult that your plugin should override.
Granted, I imagine you can probably get away with calling ActivityCompat.checkSelfPermission and Acitivity.requestPermissions, but either way, your plugin should override onRequestPermissionResult.
class MyPlugin extends CordovaPlugin {
private void saveAndOpenFile() {
/* check permissions
...
*/
}
#Override
public void onRequestPermissionResult(int requestCode, String[] permissions,
int[] grantResults) throws JSONException {
/* check permission granted and proceed accordingly */
}
}

How to access all members and methods in the current activity through one instance method?

Hello Stack Overflow Community. I am currently working on an Android VoIP application, which uses WebRTC and therefore I have been trying to comprehend the source code which I found on GitHub. So far, I have been able to reproduce and understand a bit of the source code I found, but currently I stumbled across a problem with the implementation of the SignalingClient. To further understand my problem I think it is appropriate to be more detailed and ask the question more precisely: How to access all members in the current activity, without declaring an object of it from a class, through one instance method, which is defined in the same other class?I think pointing to it in the source code is also good to understand the question. I have shortened the code so it fits the question as close as possible.
SignalingClient.java
class SignallingClient {
private static SignallingClient instance;
private String roomName = null;
private Socket socket;
boolean isChannelReady = false;
boolean isInitiator = false;
boolean isStarted = false;
private SignalingInterface callback;
...
public static SignallingClient getInstance() {
if (instance == null) {
instance = new SignallingClient();
}
if (instance.roomName == null) {
//set the room name here
instance.roomName = "vivek17";
}
return instance;
}
public void init(SignalingInterface signalingInterface) {
...
}
...
}
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener, SignallingClient.SignalingInterface {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}, ALL_PERMISSIONS_CODE);
} else {
// all permissions already granted
start();
}
}
...
public void start() {
// keep screen on
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
initViews();
initVideos();
getIceServers();
SignallingClient.getInstance().init(this); //Here is my lack of understanding/reproducing/comprehending,
//because at this point I have access to all members(variables)
//in the SignalingClient.java class : boolean isChannelReady,
//boolean isInitiator, boolean isStarted
//and also other methods which are public...
//Shouldnt it be like this?
/*
SignalingClient obj = new SignalingClient();
obj.getInstance();
obj.init(this);
*/
...
}
...
}
After experimenting around and looking up on the web [1][2][3][4] and many other related stackoverflow questions I noticed that this behaviour has something to do with the static modifier according to these sources [5][6][7] but also the fact that
class SignallingClient{... //SignallingClient
private static SignallingClient instance;... //SignallingClient
public static SignallingClient getInstance() {... //SignallingClient
the class, the instance member and also the getInstance method all have/share the same "name" as we can see on the line comments above. Getting back to my question, I would really like to know how this works, or if this is a trick to access all possible members and methods (and other things I don't know yet) without declaring an object. I would really appreciate any answer followed by a good explanation to this topic as well as dropping some good sources/tutorials/university scripts etc. where I can read up on this.
Thank you very much.

possible alternative to static inner classes to prevent memory leaks in android/java?

lately i have been researching about memory leaks in java/android and pretty much everywhere it says that instead of anonymous classes i should use static inner classes with weak references.
so, in my android app i started doing that but very quickly got tired of it because it's a lot of boilerplate code... i think have an alternative solution which i would prefer to use, but i'm juts not sure that it is a valid alternative to static inner classes in terms of preventing memory leaks. as i said before, i haven't seen this solution suggested anywhere else (all say to use static inner classes) so thats why im not sure my alternative will work.
ill use a simple example from my app:
i have a class called WebClient which handles asynchronous web requests and it accepts an interface called iCallback which returns the response from the server to the caller, and in my activity once i get this callback i need to dismiss a dialog, and maybe perform some activity related things (like trigger onBackPressed() and setResult()).
so here is my static inner class i have created:
private static class CallBack implements WebClient.ICallback
{
private WeakReference<ProgressDialog> mProgDiag;
private WeakReference<BaseActivity> mActivity;
public CallBack(BaseActivity activity, ProgressDialog progDiag)
{
this.mProgDiag = new WeakReference<>(progDiag);
this.mActivity = new WeakReference<>(activity);
}
#Override
public void onCallback(String data)
{
String responseAsString = Utils.extractStringFromResponse(...);
final BaseActivity parentActivity = mActivity.get();
ProgressDialog dialog = mProgDiag.get();
if(dialog != null)
{
dialog.dismiss();
}
if (responseAsString == null)
{
if(parentActivity != null)
{
Utils.makeServerErrorDialog(parentActivity,
new iDialogButtonClickedListener()
{
#Override
public void onDialogButtonClicked()
{
parentActivity.onBackPressed();
}
});
}
return;
}
//everything is ok
if (responseAsString.equals("1"))
{
if(parentActivity != null)
{
Intent result = new Intent();
result.putExtra(...);
parentActivity.setResult(Activity.RESULT_OK, result);
}
}
else
{
Utils.reportErrorToServer(...);
if(parentActivity != null)
{
parentActivity.setResult(Activity.RESULT_CANCELED);
}
}
if(parentActivity != null)
{
parentActivity.onBackPressed();
}
}
}
so for every variable i need in this static inner class i have to create a new weak reference, then retrieve the object itself, and then every time i want to access it i need to check whether it's null... that seems like a lot of code to me.
and here is my suggested alternative:
public abstract class BaseActivity extends AppCompatActivity
implements WebClient.ICallback
{
private static final String TAG = "BaseActivity";
WebClient.ICallback mCallBack;
ProgressDialog mProgDiag;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(...);
mCallBack = this;
//some code to invoke a server request on button click
//and passing mCallBack to the request
}
#Override
public void onCallback(String data)
{
String responseAsString = Utils.extractStringFromResponse(...);
mProgDiag.dismiss();
if (responseAsString == null)
{
Utils.makeServerErrorDialog(this,
new iDialogButtonClickedListener()
{
#Override
public void onDialogButtonClicked()
{
onBackPressed();
}
});
return;
}
//everything is ok
if (responseAsString.equals("1"))
{
Intent result = new Intent();
result.putExtra(...);
setResult(Activity.RESULT_OK, result);
}
else
{
Utils.reportErrorToServer(...);
setResult(Activity.RESULT_CANCELED);
}
onBackPressed();
}
#Override
protected void onPause()
{
mCallBack = null;
super.onPause();
}
#Override
protected void onResume()
{
super.onResume();
mCallBack = this;
}
}
to me this seems much cleaner: no creating and retrieving instances of weak references for every variable i need access to, i can directly invoke activity methods (e.g. onBackPressed()), and no checking for null everywhere.
the only place i would now have to check for null is inside WebClient class before invoking the callBack method.
so my question is, does this approach achieve the same result in terms of preventing memory leaks? is it a "worthy" alternative to static inner classes?
Unfortunately, your approach does not work. By implementing the WebClient.ICallback in your activity, rather than an inner class, you don't get rid of the leak. The leak happens not because the references to activity and dialog are implicit in an anonymous class, or in lambda, or in a non-static inner class instance; the happens when the WebClient keeps this reference while the activity is gone (it is not destroyed, because there is a strong reference to it).
The special mCallBack that you set to null when the activity is paused, gains nothing. Just as well, you can simply pass your activity instance to the WebClient. Now there is a strong reference to your activity, which is managed by someone (async handlers of the WebClient), who is not under your control. If you are unlucky, the async handler will get stuck somewhere and will never release this reference.
Please read this detailed explanation.
Note that WebView itself can cause a memory leak, if special measures are not undertaken!

Request runtime permissions from v4.Fragment and have callback go to Fragment?

I'm having a weird issue that is causing a conflict. I had to switch to native Fragments to fix it, but there are bugs with that.
My original problem: I have a navigation drawer setup with v4 Fragments. To ask for permission in one of my Fragments I call ActivityCompat.requestPermissions(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION, 1); The prompt shows up just fine, but when I accept or deny the permission, nothing happens. The callback onRequestPermissionsResult() is never called. Instead it gets called in the Activity that my Fragments are attached to. Useless to me, I need the callback to work in the Fragment.
With this in mind I was told that I need to use FragmentCompat, but that only works with native Fragments (v13+), so I changed navigation drawer to work from native Fragments instead of the v4 support library Fragments. However, because I'm using AppCompatActivity, certain things do not work, like addToBackStack() and going back to a previous fragment.
Long story short, does anyone know how I can use the v4.Fragment and still call for permission in the Fragment and get the callback to be in the Fragment? I feel like this is a bug in Android that hasn't been addressed but I'm not 100%.
Let me know if you need to see my code, it's just the standard methods that you need for runtime permissions, I would like to work with v4 Fragments though which doesn't work from my understanding.
Adding this to the parent activity works for me:
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
fragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
Source: https://code.google.com/p/android/issues/detail?id=189121#c5
If you need to get the permissionResult in fragment v4 make sure you use
Fragment.requestPermission(String[], int);
instead of
AppCompat.requestPermission(Activity, String[], int)
Check out this answer!
This behavior seems to be present in the v4 Fragment support class requestPermissions in Fragment. The Activity/FragmentCompat implementations exist for people who wish to use the native classes with the extended functionality on API levels between 11 and 23.
You can use this part of code
requestPermissions(new String[]{Manifest.permission.GET_ACCOUNTS}, PERMISSION_REQUEST_CODE);
I faced the same situation recently, when I needed to check for a permission inside the support fragment and get a callback there.
I was able to use ContextCompat to checkSelfPermission and then as #NasaGeek said called android.support.v4.app.Fragment's requestPermissions to request the permission and then got a call back to onRequestPermissionsResult in v4 Fragment.
Hope this helps.
Thanks.
v4.Fragment works well. I have an issue with nested fragment of v4.Fragment. Permission is asked, but the callback onRequestPermissionsResult() is never called in nested fragment!
Issue opened
At the moment the most stable solution is doing it by hand. I myself resolved it simply by notifying child fragments from the parent fragments.
if (fragment.getParentFragment() != null) {
Fragment parentFragment = fragment.getParentFragment();
try {
ChildFragmentPermissionRegistry registry = (ChildFragmentPermissionRegistry) parentFragment;
registry.registerPermissionListener((ChildFragmentPermissionCallback) fragment);
parentFragment.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_REQUEST_CODE);
} catch (ClassCastException e) {
Log.e(PermissionVerifier.class.getSimpleName(), e.getMessage());
}
} else {
fragment.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_REQUEST_CODE);
}
Where parent fragment implements interface ChildFragmentPermissionRegistry and registers child fragment,
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (callback != null) {
callback.onRequestPermissionsResult(requestCode, permissions, grantResults);
callback = null;
}
}
and child fragments implements ChildFragmentPermissionCallback
and interfaces are something like this:
public interface ChildFragmentPermissionCallback {
void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults);
}
public interface ChildFragmentPermissionRegistry {
void registerPermissionListener(ChildFragmentPermissionCallback callback);
}
I don't know if it's recently fixed by google, but I can reach the expected result without doing any tricks.
The most important thing is to call super.onRequestPermissionsResult(requestCode, permissions, grantResults); in the activity, so it will pass the result to fragment if it's requested from fragment.
So, what I do is:
1) in fragment, ask permission using v4 fragment.requestPermissions(permissions, requestCode)
2) in activity's onRequestPermissionsResult, must call
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
3) in fragment's onRequestPermissionsResult, write the code I want to handle the result.
In my case I have requested the permission from the fragment and also need to get the response in fragment.
But my phone running on android 8.1
so I was need to add one more condition for check this
so eventually there is my solution
private void doOnWazeButtonClick()
{
int permissionStatus = PackageManager.PERMISSION_DENIED;
if (getContext() != null)
{
permissionStatus = ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION);
}
if (permissionStatus == PackageManager.PERMISSION_GRANTED)
{
showContentWaze();
}
else
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
Objects.requireNonNull(getActivity()).requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_PERMISSION_ACCESS_FINE_LOCATION);
}
else
{
requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_PERMISSION_ACCESS_FINE_LOCATION);
}
}
}
Check runtime permission from Fragment (the 2021 way)
I have answered this in a different question, here is the link: answer link.
In short, we can now use registerForActivityResult in a fragment. In your fragment's constructor (before onCreate), you initialize ActivityResultLauncher<String[]> activityResultLauncher resultLauncher, and when you need permission, simply invoke resultLauncher.launch(stringArrayOfPermissions). Please check the link on the first line for detailed example.
Just use requestPermission("your permission/s in string array",your request code) simply no need to use Fragment.requestPermissons(String[],int );
This method in your fragment calls requestPermissions of android.support.v4.app.Fragment class i.e
public final void requestPermissions(#NonNull String[] permissions, int requestCode) {
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
mHost.onRequestPermissionsFromFragment(this, permissions, requestCode);
}

Categories