wifiManager.getScanResult() returns null value - java

I'm searching to do a scan of available wifi networks but the method getScanResults() returns null list.
I included all permissions needed :
android.permission.ACCESS_COARSE_LOCATION
android.permission.CHANGE_WIFI_STATE
android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_WIFI_STATE
The main activity class is :
public class Home extends Activity {`
Context context;
WifiManager wifiManager = null;
WiFiReceiver wifiReceiver = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home);
context = this;
wifiManager = (WifiManager)
context.getSystemService(Context.WIFI_SERVICE);
wifiReceiver = new WiFiReceiver(wifiManager);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
registerReceiver(wifiReceiver, intentFilter);
wifiManager.startScan();
List<ScanResult> results = wifiReceiver.results;
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(wifiReceiver);
}
}
The Broadcast Receiver is :
public class WiFiReceiver extends BroadcastReceiver {`
public List<ScanResult> results;
private WifiManager wifiManager;
public WiFiReceiver(WifiManager wifiManager) {
this.wifiManager = wifiManager;
}
#Override
public void onReceive(Context context, Intent intent) {
boolean success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
if (success) {
results = wifiManager.getScanResults();
Log.e("wiFi Manager", "Done");
} else {
Log.e("wiFi Manager", "Scan failure");
}
}
}

The issue is that your are assuming that startScan() will produce a result immediately but it actually only does what is says, starting the scan. Your are accessing then results variable before onReceive in your WiFiReceiver has been triggered which is why it will always be null (your logging should confirm that).
What you need to to is use a callback to get the results when they're ready like the code here does. Notice how the onReceive method calls scanSuccess() and the results are only accessed in scanSuccess() and not immediately after calling startScan().
Also notice how they are checking if starting the scan was actually successful by checking the Boolean startScan() returns

From API level 23 (Android 6.0 Marshmallow) we need to ask Run-time permission from the user-end. Specifically ACCESS_FINE_LOCATION. You need to check whether the permission is granted before wifiManager.startScan(), and if permission is not granted, you need to call requestPermissions().
here is an example:
public void startScanningWifi(){if ( Build.VERSION.SDK_INT >= 23){
if (ActivityCompat.checkSelfPermission(context, Manifest.
permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED ){
requestPermissions(new String[]{
Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_CODE_ASK_PERMISSIONS);
Log.i(TAG, "User location NOT ENABLED, waiting for permission");
}else{
//Start scanning for wifi
}}
You will also need to include this method in the activity
#Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE_ASK_PERMISSIONS:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//start scanning
wifiManager.startScan();
} else {
// Permission for location Denied
Toast.makeText( this,"Well cant help you then!" ,
Toast.LENGTH_SHORT)
.show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
Dont forget to declare this in your activity as well
private final int REQUEST_CODE_ASK_PERMISSIONS = 1;

Related

Before asking for permissions Android application closed ? How resolve that?

The first time I install this application, and when I launch MapsActivity, I am asked for permissions, which is normal. But the problem is that the application closes in the meantime. How can I modify my code to keep the application open, and the permission pop-up just overlaps. Thank you very much for your answer.
Error code in logcat :
2020-02-02 11:17:01.340 11559-11574/? E/le.rsr_pechhlu: Unable to peek into adb socket due to error. Closing socket.: Connection reset by peer
2020-02-02 11:17:01.470 11559-11636/? E/AwareLog: AtomicFileUtils: readFileLines file not exist: android.util.AtomicFile#2f88384
2020-02-02 11:17:01.470 11559-11636/? E/AwareLog: AtomicFileUtils: readFileLines file not exist: android.util.AtomicFile#7fa676d
2020-02-02 11:17:01.471 11559-11603/? E/MemoryLeakMonitorManager: MemoryLeakMonitor.jar is not exist!
2020-02-02 11:17:10.787 11559-11559/com.example.rsr_pechhlup E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.rsr_pechhlup, PID: 11559
java.lang.RuntimeException: Unable to pause activity {com.example.rsr_pechhlup/com.example.rsr_pechhlup.MapsActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.location.LocationManager.removeUpdates(android.location.LocationListener)' on a null object reference
at android.app.ActivityThread.performPauseActivityIfNeeded(ActivityThread.java:4742)
at android.app.ActivityThread.performPauseActivity(ActivityThread.java:4691)
at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:4626)
at android.app.servertransaction.PauseActivityItem.execute(PauseActivityItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2199)
at android.os.Handler.dispatchMessage(Handler.java:112)
at android.os.Looper.loop(Looper.java:216)
at android.app.ActivityThread.main(ActivityThread.java:7625)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.location.LocationManager.removeUpdates(android.location.LocationListener)' on a null object reference
at com.example.rsr_pechhlup.MapsActivity.onPause(MapsActivity.java:159)
at android.app.Activity.performPause(Activity.java:7663)
at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1536)
at android.app.ActivityThread.performPauseActivityIfNeeded(ActivityThread.java:4726)
at android.app.ActivityThread.performPauseActivity(ActivityThread.java:4691) 
at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:4626) 
at android.app.servertransaction.PauseActivityItem.execute(PauseActivityItem.java:45) 
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2199) 
at android.os.Handler.dispatchMessage(Handler.java:112) 
at android.os.Looper.loop(Looper.java:216) 
at android.app.ActivityThread.main(ActivityThread.java:7625) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987) 
public class MapsActivity extends FragmentActivity implements LocationListener {
private GoogleMap googleMap; //google map is contained in the fragment work on it to change the position of the map and so on.
private Marker marker;
private Button buttonCallNow;
private RelativeLayout callPanelWrapper;
private static final int PERMS_CALL_ID = 1234; //permission identifier, unique identifier
private static final int REQUEST_PHONE_CALL = 4321;
private LocationManager locationManager; // Android manager service of android platform.
private SupportMapFragment mapFragment;
private Utils utils;
private PhoneCallListener phoneCallListener;
private boolean firstTime;
private String adresse;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps2);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
mapFragment= (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
}
/**
* //When the activity comes back to the foreground, I have to subscribe to the different location information providers, so I will receive the new location information and I will be able to resynchronize my mapping on this location.
*/
#Override
protected void onResume() {
super.onResume();
checkPermissions();
firstTime=true;
}
private void checkPermissions(){
//For older versions of android we check that the ACCES_FINE_LOCATION and ACCES_COARSE_LOCATION permissions are enabled.
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)!=PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION },PERMS_CALL_ID); //We must provide three parameters: it is the activity that requires the activation of these permissions (here it is this), then a table that specifies the set of permissions to allow. And we need a request code.
return;
}
locationManager= (LocationManager) getSystemService(LOCATION_SERVICE);//I ask android to give me that service locationManager. LOCATION SERVICE comes inheritance FragmentActivity, which inherits from Context, which contains this constant.
if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){//If on this locationManager, a particular provider here : LocationManager.GPS_PROVIDER is allowed. If I have a GPS type sensor that is enabled, on the locationManager I will be able to subscribe to events.
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,1000,0,this);//This function requires the type of provider: LocationManager.GPS.it needs the frequency in milliseconds at which I want new location information(Here all the seconds).It needs to notify a person, who is going to receive this notification information, it's the MapsActivity, so this.
}
if(locationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER)){//If on this locationManager, a particular provider here : LocationManager.PASIVE_PROVIDER is allowed. If I have a GPS type sensor that is enabled, on the locationManager I will be able to subscribe to events.
locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,1000,0,this);//This function requires the type of provider: LocationManager.GPS.it needs the frequency in milliseconds at which I want new location information(Here all the seconds).It needs to notify a person, who is going to receive this notification information, it's the MapsActivity, so this.
}
if(locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)){//If on this locationManager, a particular provider here : NETWORK is allowed. If I have a GPS type sensor that is enabled, on the locationManager I will be able to subscribe to events.
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,1000,0,this);//This function requires the type of provider: LocationManager.GPS.it needs the frequency in milliseconds at which I want new location information(Here all the seconds).It needs to notify a person, who is going to receive this notification information, it's the MapsActivity, so this.
}
dispMap();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode==PERMS_CALL_ID){ //This method will be activated each time a permission request is made. And to know where I'm coming from I need the requestCode. This request is coupled with this requestCode here.
checkPermissions(); //i call again chack permission do disp again pop-up permission.
}
}
/**
* //When my application leaves the foreground, I unsubscribe from the different providers of location information so as not to consume a lot of resources.
*/
#Override
protected void onPause() {
super.onPause();
//If the locationManager has been initialized, I make one of this, one of the earphone of all suppliers
locationManager.removeUpdates(this);
}
private void dispMap(){
mapFragment.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
MapsActivity.this.googleMap=googleMap;
marker = googleMap.addMarker(new MarkerOptions().position(new LatLng(43.799345,6.725426)));
}
});
}
/**
* React each time new positioning information is calculated
* #param location
*/
#Override
public void onLocationChanged(Location location) { //This location is obtained through the provider. Of course this can be any provider, GPS_PROVIDER is more accurate than PASSIVE_PROVIDER etc..
double latitude= location.getLatitude();//I'm getting the latitude.
double longitude=location.getLongitude();// I'm getting the longitude.
Toast.makeText(this, "Location: " + latitude + "/" + longitude,Toast.LENGTH_SHORT).show();
LatLng googleLocation=new LatLng(latitude,longitude);
if(firstTime){
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(googleLocation, 16.2f));
adresse= Utils.getCompleteAddressString(latitude, longitude,this);
BitmapDescriptor subwayBitmapDescriptor = BitmapDescriptorFactory.fromResource(R.drawable.map_marker);
marker = googleMap.addMarker(new MarkerOptions().position(googleLocation).icon(subwayBitmapDescriptor).title(adresse));
googleMap.setInfoWindowAdapter(new CustomInfoWindowAdapter(this));
}
firstTime=false;
if(this.googleMap!=null){//If my map is correctly displayed
adresse = Utils.getCompleteAddressString(latitude, longitude,this);
googleMap.setInfoWindowAdapter(new CustomInfoWindowAdapter(this));
marker.setTitle(adresse);
marker.setPosition(googleLocation);
marker.showInfoWindow();
}
}
/**
* To react to every change of state
* #param provider
* #param status
* #param extras
*/
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
/**
* When a location provider is closed.
* #param provider
*/
#Override
public void onProviderEnabled(String provider) {
}
/**
* When a location provider is closed.
* #param provider
*/
#Override
public void onProviderDisabled(String provider) {
}
public void btnBackClick(View view) {
Intent myIntent = new Intent(this, HomeActivity.class);
startActivity(myIntent);
}
public void btnCallMapclicked(View view) {
callPanelWrapper.setVisibility(View.VISIBLE);
buttonCallNow.setVisibility(View.GONE);
}
public void buttonFinalCallClicked(View view) {
call();
}
public void popupClosedClicked(View view) {
callPanelWrapper.setVisibility(View.GONE);
buttonCallNow.setVisibility(View.VISIBLE);
}
}
}
I'm not able to put comment,Thus forward my answer as post.
you may should describe about your problem more but do you add ACCESS_FINE_LOCATION and
ACCESS_COARSE_LOCATION to your Manifest file?
EDIT:
just change onPause to following:
#Override
protected void onPause() {
super.onPause();
if(locationManager != null) // add this line to your code
locationManager.removeUpdates(this);
}
Cause:
When Permission dialog has been shown your activity onPause() is called, and since you not initialize location manager yet, it throws NullPointerException.
Try this code to initialize map with required run time permission.
public class MapActivity extends AppCompatActivity implements OnMapReadyCallback,
GoogleApiClient.OnConnectionFailedListener{
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onMapReady(GoogleMap googleMap) {
Toast.makeText(this, "Map is Ready", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onMapReady: map is ready");
mMap = googleMap;
if (mLocationPermissionsGranted) {
getDeviceLocation();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setMyLocationButtonEnabled(false);
init();
}
}
private static final String TAG = "MapActivity";
private static final String FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
private static final String COURSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1234;
//vars
private Boolean mLocationPermissionsGranted = false;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
getLocationPermission();
}
private void initMap(){
Log.d(TAG, "initMap: initializing map");
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(MapActivity.this);
}
private void getLocationPermission(){
Log.d(TAG, "getLocationPermission: getting location permissions");
String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION};
if(ContextCompat.checkSelfPermission(this.getApplicationContext(),
FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
if(ContextCompat.checkSelfPermission(this.getApplicationContext(),
COURSE_LOCATION) == PackageManager.PERMISSION_GRANTED){
mLocationPermissionsGranted = true;
initMap();
}else{
ActivityCompat.requestPermissions(this,
permissions,
LOCATION_PERMISSION_REQUEST_CODE);
}
}else{
ActivityCompat.requestPermissions(this,
permissions,
LOCATION_PERMISSION_REQUEST_CODE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
Log.d(TAG, "onRequestPermissionsResult: called.");
mLocationPermissionsGranted = false;
switch(requestCode){
case LOCATION_PERMISSION_REQUEST_CODE:{
if(grantResults.length > 0){
for(int i = 0; i < grantResults.length; i++){
if(grantResults[i] != PackageManager.PERMISSION_GRANTED){
mLocationPermissionsGranted = false;
Log.d(TAG, "onRequestPermissionsResult: permission failed");
return;
}
}
Log.d(TAG, "onRequestPermissionsResult: permission granted");
mLocationPermissionsGranted = true;
initMap(); // once permission granted then only initMap()
}
}
}
}
}

java.lang.SecurityException: was not granted this permission: android.permission.WRITE_SETTINGS

I going to change some system setting in android and i use this code :
ContentResolver cr = getContentResolver();
Settings.System.putInt(cr, Settings.System.HAPTIC_FEEDBACK_ENABLED, 0);
this code used for change screen Brightness use Brightness sensor,
but in android 6 I get this exception
java.lang.SecurityException: com.vpn.sabalan was not granted this permission: android.permission.WRITE_SETTINGS.
i can use this method to get permission from user , but i need get permission programmetically can any one help me ?
private void showBrightnessPermissionDialog( )
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !android.provider.Settings.System.canWrite(this))
{
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:"+getPackageName()));
startActivity(intent);
}
}
Update Android Marshmallow and Higher
You can start System settings to grant Write System Settings. Once this permission is grant by user you can set brightness without any issues
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Settings.System.canWrite(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
}
Follow the step by step provided in documentation. It is very thorough.
https://developer.android.com/training/permissions/requesting.html
All you have to do is request permission, and override the callback for onRequestPermissionsResult to check if you got it or not. If you did, then you are good to go. You still need it in your manifest though or it won't work.
UPDATE to show details based on your comments.
public class MainActivity extends AppCompatActivity implements ActivityCompat.OnRequestPermissionsResultCallback{
private static final int REQUEST_WRITE_PERMISSION = 1001;
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_WRITE_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
doFileWork();
}else{
//handle user denied permission, maybe dialog box to user
}
}
#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 {
doFileWork();
}
}
}
There are also many good libraries out there that wrap this callback context if you really want to go that route, but it isn't that complex. Make sure you also have write permission in your Manifest.

Cant see dialog-box for dangerous permission on the fly

I tried to test my GPS permission on my app .
I have built permission manager and added GPS permission in the manifest because GPS is a dangerous permission.
However, when I run my app I cannot see any dialog box for this permission,
because of that the app toast me that I haven't allowed this permission even though I never have the chance to allow or block this permission on the dialog box.
Would appreciate any kind of help,those are my classes:
Manifest permission
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
MainActiviey
public class MainActivity extends AppCompatActivity {
public static final int GPS=1;
public static final String gpsFinePermission="Manifest.permission.ACCESS_FINE_LOCATION";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PermissionManager.check(MainActivity.this, gpsFinePermission, GPS);
System.out.println("1");
}
#Override
protected void onStart() {
//startService(new Intent(this,CurrentLocation.class));
super.onStart();
System.out.println("2");
}
#Override//when user allowed OR denied a permission
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
System.out.println("3");
if(grantResults[0] == PackageManager.PERMISSION_GRANTED && requestCode == GPS){//Allowed
Toast.makeText(MainActivity.this, "GPS permission granted", Toast.LENGTH_LONG).show();
System.out.println("4");
}else
Toast.makeText(MainActivity.this, "GPS permission is IMPORTANT for this app", Toast.LENGTH_LONG).show();
}
}
Permission manager
public class PermissionManager {
//A method that can be called from any Activity, to check for specific permission
public static void check(Activity activity, String permission, int requestCode){
System.out.println("5");
//If requested permission isn't Granted yet
if (ActivityCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
System.out.println("6");
//Request permission from user
ActivityCompat.requestPermissions(activity,new String[]{permission},requestCode);
}
}
}
You should get a string from Manifest.permission class. But you are passing Manifest.permission.ACCESS_FINE_LOCATION as String.
You should not use this.
public static final String gpsFinePermission="Manifest.permission.ACCESS_FINE_LOCATION";
Use this.
public static final String gpsFinePermission= Manifest.permission.ACCESS_FINE_LOCATION;

onRequestPermissionResult is never called from Activity

I am trying to implement SplashScreenActivity, which will request all necessary permissions and then redirect to the MainActivity:
public class SplashScreenActivity extends Activity {
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.splash_screen);
try {
PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), 0);
((TextView) findViewById(R.id.versionView)).setText(info.versionName);
} catch (Exception e) {
throw new IllegalStateException(e);
}
if (ActivityCompat.checkSelfPermission(this, CAMERA) != PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{READ_PHONE_STATE, CAMERA}, 200);
} else {
onPermissionsReady();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 200) {
onPermissionsReady();
}
}
private void onPermissionsReady() {
new Fork() {
#Override public void run() {
ApplicationContext.getInstance(SplashScreenActivity.this);
startActivity(new Intent(SplashScreenActivity.this, MainActivity.class));
}
};
}
}
I have two issues with it:
The splash screen design does not show before the Permission request dialog and the screen stays from the android background with application icons.
When you agree with the permissions, the onRequestPermissionsResult is NEVER called and the application ends.
EDIT: I created a sample application here: https://github.com/knyttl/TestApp – it demonstrates both two issues.
EDIT2: This is what happens when i agree/disagree with the permissions requests - the application just ends: https://www.youtube.com/watch?v=lhvhXcEJxLw&feature=youtu.be
You should extend from AppCompatActivity.
Try to change the line:
if (ActivityCompat.checkSelfPermission(this, CAMERA) != PERMISSION_GRANTED
to
`if (ActivityCompat.checkSelfPermission(this, Manifest.Permission.CAMERA) != PERMISSION_GRANTED`
Move the code for checking permission to onResume. Or leave it in onCreate but delay it, for example with Handler
I found out the problem: the activity has noHistory=true, which leads to killing the application as described here:
Requesting Android M permissions from Activity with noHistory="true" and/or showOnLockScreen="true"

Android runtime permissions- how to implement

Android Developer Documentation gives this example of requesting permissions at runtime:
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
What is "MY_PERMISSIONS_REQUEST_READ_CONTACTS" in this example? It says it's an app-defined int constant, but does that mean I should make a Constants.java and declare a public static int? What should the value be?
In other examples I see people use 1 here, or 0 or 0xFFEEDDCC, but I can't find an explanation of what it is. Can someone explain to me what needs to go here and why? (In my case, I need to make sure the app has permission to access fine location)
The ActivityCompat documentation says "Application specific request code to match with a result reported to onRequestPermissionsResult"? This does not help me.
What is "MY_PERMISSIONS_REQUEST_READ_CONTACTS" in this example?
It is an int, to tie a particular requestPermissions() call to the corresponding onRequestPermissionsResult() callback.
Under the covers, requestPermissions() uses startActivityForResult(); this int serves the same role as it does in startActivityForResult().
does that mean I should make a Constants.java and declare a public static int?
I would just make it a private static final int in the activity. But, you can declare it wherever you want.
What should the value be?
I seem to recall that it needs to be below 0x8000000, but otherwise it can be whatever you want. The value that you use for each requestPermissions() call in an activity should get a distinct int, but the actual numbers do not matter.
If your activity has only one requestPermissions() call, then the int value really does not matter. But many apps will have several requestPermissions() calls in an activity. In that case, the developer may need to know, in onRequestPermissionsResult(), what request this is the result for.
Look just a little further down in the documentation under "Handle the permissions request response" and you will see its purpose.
A callback method called onRequestPermissionsResult gets sent back the same code as a parameter so you know which permission was being requested/granted:
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
Since the constant is used by you only you can give it whatever value you like as a public static final int. Each permission being requested needs its own constant.
I went through all answers, but doesn't satisfied my exact needed answer, so here is an example that I wrote and perfectly works, even user clicks the Don't ask again checkbox.
Create a method that will be called when you want to ask for runtime permission like readContacts() or you can also have openCamera() as shown below:
private void readContacts() {
if (!askContactsPermission()) {
return;
} else {
queryContacts();
} }
Now we need to make askContactsPermission(), you can also name it as askCameraPermission() or whatever permission you are going to ask.
private boolean askContactsPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
return true;
}
if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
Snackbar.make(parentLayout, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
.setAction(android.R.string.ok, new View.OnClickListener() {
#Override
#TargetApi(Build.VERSION_CODES.M)
public void onClick(View v) {
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
}
}).show();
} else if (contactPermissionNotGiven) {
openPermissionSettingDialog();
} else {
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
contactPermissionNotGiven = true;
}
return false;
}
Before writing this function make sure you have defined the below instance variable as shown:
private View parentLayout;
private boolean contactPermissionNotGiven;;
/**
* Id to identity READ_CONTACTS permission request.
*/
private static final int REQUEST_READ_CONTACTS = 0;
Now final step to override the onRequestPermissionsResult method as shown below:
/**
* Callback received when a permissions request has been completed.
*/
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
if (requestCode == REQUEST_READ_CONTACTS) {
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
queryContacts();
}
}
}
Here we are done with the RunTime permissions, the addon is the openPermissionSettingDialog() which simply open the Setting screen if user have permanently disable the permission by clicking Don't ask again checkbox. below is the method:
private void openPermissionSettingDialog() {
String message = getString(R.string.message_permission_disabled);
AlertDialog alertDialog =
new AlertDialog.Builder(MainActivity.this, AlertDialog.THEME_DEVICE_DEFAULT_LIGHT)
.setMessage(message)
.setPositiveButton(getString(android.R.string.ok),
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivity(intent);
dialog.cancel();
}
}).show();
alertDialog.setCanceledOnTouchOutside(true);
}
What we missed ?
1. Defining the used strings in strings.xml
<string name="permission_rationale">"Contacts permissions are needed to display Contacts."</string>
<string name="message_permission_disabled">You have disabled the permissions permanently,
To enable the permissions please go to Settings -> Permissions and enable the required Permissions,
pressing OK you will be navigated to Settings screen</string>
Initializing the parentLayout variable inside onCreate method
parentLayout = findViewById(R.id.content);
Defining the required permission in AndroidManifest.xml
<uses-permission android:name="android.permission.READ_CONTACTS" />
The queryContacts method, based on your need or the runtime permission you can call your method before which the permission was needed. in my case I simply use the loader to fetch the contact as shown below:
private void queryContacts() {
getLoaderManager().initLoader(0, null, this);}
This works great happy coding :)
public class SplashActivity extends RuntimePermissionsActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
SplashActivity.super.requestAppPermissions(new
String[]{android.Manifest.permission.READ_PHONE_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE}, R.string.app_name
, 20);
}
#Override
public void onPermissionsGranted(int requestCode) {
try {
TelephonyManager tele = (TelephonyManager) getApplicationContext()
.getSystemService(Context.TELEPHONY_SERVICE);
String imei =tele.getDeviceId()
} catch (Exception e) {
e.printStackTrace();
}
}
public abstract class RuntimePermissionsActivity extends AppCompatActivity {
private SparseIntArray mErrorString;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mErrorString = new SparseIntArray();
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
int permissionCheck = PackageManager.PERMISSION_GRANTED;
for (int permission : grantResults) {
permissionCheck = permissionCheck + permission;
}
if ((grantResults.length > 0) && permissionCheck == PackageManager.PERMISSION_GRANTED) {
onPermissionsGranted(requestCode);
} else {
finish();
}
}
public void requestAppPermissions(final String[] requestedPermissions,
final int stringId, final int requestCode) {
mErrorString.put(requestCode, stringId);
int permissionCheck = PackageManager.PERMISSION_GRANTED;
boolean shouldShowRequestPermissionRationale = false;
for (String permission : requestedPermissions) {
permissionCheck = permissionCheck + ContextCompat.checkSelfPermission(this, permission);
shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale || ActivityCompat.shouldShowRequestPermissionRationale(this, permission);
}
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
if (shouldShowRequestPermissionRationale) {
ActivityCompat.requestPermissions(RuntimePermissionsActivity.this, requestedPermissions, requestCode);
/*Snackbar.make(findViewById(android.R.id.content), stringId,
Snackbar.LENGTH_INDEFINITE).setAction("GRANT",
new View.OnClickListener() {
#Override
public void onClick(View v) {
ActivityCompat.requestPermissions(RuntimePermissionsActivity.this, requestedPermissions, requestCode);
}
}).show();*/
} else {
ActivityCompat.requestPermissions(this, requestedPermissions, requestCode);
}
} else {
onPermissionsGranted(requestCode);
}
}
public abstract void onPermissionsGranted(int requestCode);
}

Categories