I was looking for the solution to my problem the whole day now, but I couldn't find out. I'm absolutely new to java/android studio/app programming and probably it's just a very small thing that I don't see.
I just want my App to show the current location of the device. Nothing more.
When running the App on the emulator, no error is shown and the App starts.
Then I open the extended controls and push the "SEND"-button in "Location".
Now I would expect my App to show the current location, but nothing happens. The TextViews "textLat", "textLong" and "textAlt" are staying empty.
I have absolutely no Idea what my fault is. I wrote that code with the help of different tutorials. I also tried it on my real device.
I would be very grateful for any help! Thanks alot!
package com.example.findlocation_test2;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
TextView textLat;
TextView textLong;
TextView textAlt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textLat = (TextView) findViewById(R.id.textLat);
textLong = (TextView) findViewById(R.id.textLong);
textAlt = (TextView) findViewById(R.id.textAlt);
LocationManager lm = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
LocationListener ll = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
if(location != null) {
double dLat = location.getLatitude();
double dLong = location.getLongitude();
double dAlt = location.getAltitude();
textLat.setText(Double.toString(dLat));
textLong.setText(Double.toString(dLong));
textAlt.setText(Double.toString(dAlt));
}
else {
textLat.setText("Fehler");
textLong.setText("Fehler");
textAlt.setText("Fehler");
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
Toast.makeText(getBaseContext(), "GPS wurde akiviert",
Toast.LENGTH_SHORT).show();
}
#Override
public void onProviderDisabled(String provider) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
Toast.makeText(getBaseContext(), "GPS wurde deaktiviert",
Toast.LENGTH_SHORT).show();
}
};
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 100, 0, ll);
}
}
And in the manifest I added the permissions:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.findlocation_test2">
<uses-permission android:name="android.permission.ACCESS_INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> /**Erlaubnis, um auf die GPS Daten zuzugreifen*/
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Related
I am working on Nordic NRF52840 periodic advertising and scan the device with Android app Android 10. I ask a question yesterday then I rewrite my code using the tutorial on the internet, basically my app is very easy, press the button then the app will scan and print the ble device on log, but I still can't find my device I don't know what's wrong with my code I add a ton of permission in Manifest.xml but nothing changed I still can't find the device I want. Update: I can find some device,but not my device, I still can't find my device there are a few question I want to ask
I can't find my device, but can find other device.
how to stop scanning, I add a button to stop scanning, but it won't stop.
how to get device name, when I call getName() error pop up and the app closed
getName error
AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.tryble_scanner">
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission
android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
/>
<uses-permission
android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission
android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-feature android:name="android.hardware.bluetooth"
android:required="true"/>
<uses-feature android:name="android.hardware.bluetooth_le"
android:required="true"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.TryBle_scanner">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.java
package com.example.tryble_scanner;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothLeScanner mBluetoothLeScanner = null;
public static final int REQUEST_BT_PERMISSIONS = 0;
public static final int REQUEST_BT_ENABLE = 1;
private boolean mScanning = false;
private Handler mHandler = null;
private ScanCallback mLeScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, final ScanResult result) {
//super.onScanResult(callbackType, result);
BluetoothDevice btdevice = result.getDevice();
Log.d("BLE", btdevice.getAddress());
}
#Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.d("BLE", "error");
}
};
private ScanCallback mLeScanCallback2=new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.d("BLE","scan stop");
}
#Override
public void onScanFailed(int errorCode) {
Log.d("BLE","stop scan failed");
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnScan = (Button) findViewById(R.id.btnScan);
BluetoothManager bluetoothManager = getSystemService(BluetoothManager.class);
mBluetoothAdapter = bluetoothManager.getAdapter();
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
this.mHandler = new Handler();
}
public void stop_scan(View view) {
Log.d("Ble","scan stop pressed");
// mBluetoothLeScanner.stopScan(mLeScanCallback2);
mBluetoothAdapter.getBluetoothLeScanner().stopScan(mLeScanCallback2);
}
public void onBtnScan(View view) {
Log.i("Btn","get click");
checkBTPermission();
String[] names=new String[]{"Auden test"};
List<ScanFilter> filters=null;
if(names != null){
filters=new ArrayList<>();
for(String name:names){
ScanFilter filter=new ScanFilter.Builder().setDeviceName(name).build();
filters.add(filter);
}
}
if(mBluetoothLeScanner==null){
Log.i("BLE","could not get scanner");
}else{
mBluetoothLeScanner.startScan(mLeScanCallback); //filters,scanSettings,mLeScanCallback
}
}
private void checkBTPermission(){
if(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP){
int pc=this.checkSelfPermission("Manifest.permission.ACCESS_FINE_LOCATION");
pc+=this.checkSelfPermission("Manifest.permission.ACCESS_COARSE_LOCATION");
if(pc!=0){
this.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION},1001);
}else {
Log.d("BLE","checkBT permission");
}
}
}
}
If you're done with permissions and the rest, probably you are instantiating the BluetoothAdapter in an incorrect way. Try instantiating it like the following example in your main activity's onCreate method:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnScan = (Button) findViewById(R.id.btnScan);
BluetoothManager bluetoothManager = getSystemService(BluetoothManager.class);
mBluetoothAdapter = bluetoothManager.getAdapter();
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
mHandler = new Handler();
}
Update for test
Well I had to make a new basic project to test it. I'll share te manifest and activity code, also the output. I've tested it on my Android 11 installed mobile. Note that I've removed all scan filters.
manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.karalama">
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-feature android:name="android.hardware.bluetooth" android:required="true"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<application
android:allowBackup="true"
android:dataExtractionRules="#xml/data_extraction_rules"
android:fullBackupContent="#xml/backup_rules"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.Karalama"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="#string/app_name"
android:theme="#style/Theme.Karalama.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity
package com.example.karalama;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.os.Build;
import android.os.Bundle;
import com.google.android.material.snackbar.Snackbar;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import com.example.karalama.databinding.ActivityMainBinding;
import android.view.Menu;
import android.view.MenuItem;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private AppBarConfiguration appBarConfiguration;
private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothLeScanner mBluetoothLeScanner = null;
private boolean mScanning = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
com.example.karalama.databinding.ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
BluetoothManager bluetoothManager = getSystemService(BluetoothManager.class);
mBluetoothAdapter = bluetoothManager.getAdapter();
Log.d("BLE", "onCreate: Bluetoothadapter null"+(mBluetoothAdapter == null));
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
binding.fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
checkBTPermission();
String[] names=new String[]{"Auden test"};
List<ScanFilter> filters=null;
if(names != null){
filters=new ArrayList<>();
for(String name:names){
ScanFilter filter=new ScanFilter.Builder().setDeviceName(name).build();
filters.add(filter);
}
}
if(mBluetoothLeScanner==null){
Log.i("BLE","could not get scanner");
}else{
mBluetoothLeScanner.startScan(mLeScanCallback);
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
return NavigationUI.navigateUp(navController, appBarConfiguration)
|| super.onSupportNavigateUp();
}
private final ScanCallback mLeScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, final ScanResult result) {
//super.onScanResult(callbackType, result);
BluetoothDevice btdevice = result.getDevice();
Log.d("BLE", "Found -> "+btdevice.getAddress());
}
#Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.d("BLE", "error");
}
};
private void checkBTPermission(){
if(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP){
int pc=this.checkSelfPermission("Manifest.permission.ACCESS_FINE_LOCATION");
pc+=this.checkSelfPermission("Manifest.permission.ACCESS_COARSE_LOCATION");
if(pc!=0){
this.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION},1001);
}else {
Log.d("BLE","checkBT permission");
}
}
}
}
The logcat output
I/RenderThread: type=1400 audit(0.0:1130983): avc: denied { ioctl } for uid=10254 path="/dev/kgsl-3d0" dev="tmpfs" ino=15422 ioctlcmd=945 scontext=u:r:untrusted_app:s0:c254,c256,c512,c768 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1 app=com.example.karalama
I/RenderThread: type=1400 audit(0.0:1130984): avc: denied { read write } for uid=10254 path="/dev/kgsl-3d0" dev="tmpfs" ino=15422 scontext=u:r:untrusted_app:s0:c254,c256,c512,c768 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1 app=com.example.karalama
D/BluetoothAdapter: isLeEnabled(): ON
D/BluetoothLeScanner: onScannerRegistered() - status=0 scannerId=6 mScannerId=0
D/BLE: Found -> C8:FD:19:7F:5A:7D
D/BLE: Found -> 5F:EE:47:E9:F3:A3
D/BLE: Found -> D4:36:39:B5:D3:5D
D/BLE: Found -> D4:36:39:8B:C1:98
D/BLE: Found -> 40:94:41:26:D2:D6
D/BLE: Found -> D4:36:39:8A:A9:AB
D/BLE: Found -> D4:36:39:8B:C1:98
D/BLE: Found -> 5F:EE:47:E9:F3:A3
D/BLE: Found -> 4B:A2:87:44:4C:79
D/BLE: Found -> D4:36:39:8A:A9:AB
D/BLE: Found -> D4:36:39:8B:C1:98
D/BLE: Found -> D4:36:39:B5:D3:5D
D/BLE: Found -> 40:94:41:26:D2:D6
D/BLE: Found -> 4B:A2:87:44:4C:79
D/BLE: Found -> C8:FD:19:7F:5A:7D
D/BLE: Found -> D4:36:39:B5:D3:5D
D/BLE: Found -> D4:36:39:8B:C1:98
D/BLE: Found -> 7A:0F:6B:DD:EC:FB
Update 2 - Get rid of the "getName" error
#Override
public void onScanResult(int callbackType, final ScanResult result) {
//super.onScanResult(callbackType, result);
BluetoothDevice btdevice = result.getDevice();
// The device may not have a name and getName may return null. Fix it in the following way
String name = btdevice.getName() == null ? "No name" : btdevice.getName();
Log.d("BLE", name+" - "+btdevice.getAddress());
}
You do indeed declare the permissions in your manifest file, but keep in mind that some of them are so called runtime permissions. You need to ask the user of your app for the permission at runtime. The Request app permissions site of the Android Developer Guide gives you more information on that topic.
You basically need a permissions callback to handle the users response:
// 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.
}
});
You also need to actually ask the user for the permission:
if (ContextCompat.checkSelfPermission(
CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
PackageManager.PERMISSION_GRANTED) {
// You can use the API that requires the permission.
performAction(...);
} else if (shouldShowRequestPermissionRationale(...)) {
// In an educational UI, explain to the user why your app requires this
// permission for a specific feature to behave as expected. In this UI,
// include a "cancel" or "no thanks" button that allows the user to
// continue using your app without granting the permission.
showInContextUI(...);
} else {
// You can directly ask for the permission.
// The registered ActivityResultCallback gets the result of this request.
requestPermissionLauncher.launch(
Manifest.permission.REQUESTED_PERMISSION);
}
The one permission that's most likely missing is the Location permission. This part of the Developer Guide lists the required permissions for BLE on Android < 11.
Please also use a generic BLE scanner such as nRF Connect to verify that your device actually advertises itself.
you can take help from this link
https://punchthrough.com/android-ble-guide/
if this still not works for use than u can use scan library
https://github.com/NordicSemiconductor/Android-Scanner-Compat-Library
after tinkering with the paths XML and my manifest provider settings I was finally able to get my app to stop crashing when trying to send an attachment in an email intent.
HOWEVER, while everything seems normal in the app, when Gmail or drive opens the file is not attached.
Screenshots:
My code is as follows
MainActivity.java
package com.loopbreakr.filesend;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import java.io.File;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
public String reciever;
public String subject;
public String body;
public final String stringPath = "/storage/emulated/0/Android/data/com.loopbreakr.firstpdf/files/PDF_files/Abdile&Name 2021-01-29&15:59:55.pdf";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
reciever = "mkercode#gmail.com";
subject = "my subject";
body = "blank email";
File file = new File(stringPath);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
prepareEmail(file);
}
});
}
private void prepareEmail(File report) {
ArrayList<Uri> uris = new ArrayList<>();
uris.add(FileProvider.getUriForFile(getApplicationContext(), "com.loopbreakr.filesend", report));
Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.setType("message/rfc822");
intent.putExtra(Intent.EXTRA_EMAIL, reciever);
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, body);
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(intent, "Send email via:").addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION));
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.loopbreakr.filesend">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.Filesend">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.loopbreakr.filesend"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
<meta-data
android:name="com.google.android.actions"
android:resource="#xml/file_paths" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>
As the program can find my file, I don't think it's a permission error anymore. The file is also on external storage. Is it possible that I am missing something in the intent? Many thanks!
EDITED
Note that I originally manually set the permissions to make my question more readable, however after adding runtime storage reading permissions to my code and simplifying the filename, as well as changing the intent to only send one file I get the couldn't attach file toast message
MainActivity.java:
package com.loopbreakr.filesend;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.File;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
public String reciever;
public String subject;
public String body;
public final String stringPath = "/storage/emulated/0/Android/data/samplefile.pdf";
private int STORAGE_PERMISSION_CODE = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
reciever = "mkercode#gmail.com";
subject = "my subject";
body = "blank email";
File file = new File(stringPath);
Button button = findViewById(R.id.button);
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this, "You have already granted this permission!",
Toast.LENGTH_SHORT).show();
} else {
requestStoragePermission();
}
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
prepareEmail(file);
}
});
}
private void prepareEmail(File report) {
Uri uri = FileProvider.getUriForFile(getApplicationContext(), "com.loopbreakr.filesend", report);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("message/rfc822");
intent.putExtra(Intent.EXTRA_EMAIL, reciever);
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, body);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Intent chooser = Intent.createChooser(intent, "Share File");
List<ResolveInfo> resInfoList = this.getPackageManager().queryIntentActivities(chooser, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
this.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
startActivity(chooser);
}
private void requestStoragePermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_EXTERNAL_STORAGE)) {
new AlertDialog.Builder(this)
.setTitle("Permission needed")
.setMessage("This permission is needed because of this and that")
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
}
})
.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.create().show();
} else {
ActivityCompat.requestPermissions(this,
new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == STORAGE_PERMISSION_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission GRANTED", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Permission DENIED", Toast.LENGTH_SHORT).show();
}
}
}
}
Am I missing something in my manifest?
I tried to send PDF attachment with ACTION_SEND_MULTIPLE and I found your problem is that you need to grant the explicit permission to email Intent (not to the chooser Intent as you do). My code:
Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);//ACTION_SEND does not support purParcelableArrayListExtra
emailIntent.setType("text/plain");
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{testBox.getEmail()});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Covid Test Certificate result");
emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);//attaching the pdf file(s) to the email
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//does not really work right now, I had to give explicit permissions
//GRANTING THE PERMISSIONS EXPLICITLY HERE! to all possible choosers (3rd party apps):
List<ResolveInfo> resolvedInfoActivities =
activity.getPackageManager().queryIntentActivities(emailIntent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo ri : resolvedInfoActivities) {
for (Uri uri : uris) {
Log.d(TAG, "Granting permission to - " + ri.activityInfo.packageName);
activity.grantUriPermission(ri.activityInfo.packageName,uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
}
try {
Intent chooserIntent =Intent.createChooser(emailIntent, "Send mail...").addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.startActivity(
chooserIntent
);
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(activity, "There are no email clients installed.", Toast.LENGTH_SHORT).show();
Log.e(TAG, "ERROR, THERE ARE NO EMAIL CLIENTS INSTALLED.");
}
And for others wondering about the permissions, this is a good article:
https://medium.com/#benexus/dealing-with-permissions-when-sharing-files-android-m-cee9ecc287bf
It says the explicit permissions are needed, because the permissions added via provider in Manifest and via Intent do not work.
Currently making a Location Service for an app I'm currently building. I'm trying to print the obtained latitude and longitude through a Log and through a Toast.makeText from a broadcast receiver but nothing is showing when I run. Was hoping if you guys could see any faults.
LocationService.java
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
public class LocationService extends Service {
FusedLocationProviderClient fusedLocationProviderClient;
LocationCallback locationCallback;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
locationCallback = new LocationCallback(){
// Whenever there is a Location Update, this method is where it occurs
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
// Log Result for Longitude and Latitude, call method to receive elsewhere
Log.d("Location Log", "Latitude is: " + locationResult.getLastLocation().getLatitude() +
"Longitude is: " + locationResult.getLastLocation().getLongitude());
Intent intent = new Intent("ACT_LOC");
intent.putExtra("Latitude", locationResult.getLastLocation().getLatitude());
intent.putExtra("Longitude", locationResult.getLastLocation().getLongitude());
sendBroadcast(intent);
}
};
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
requestLocation();
return super.onStartCommand(intent, flags, startId);
}
// Method to request the Location every 3 seconds
private void requestLocation(){
LocationRequest locationRequest = new LocationRequest();
locationRequest.setInterval(3000);
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback,
Looper.myLooper());
}
}
MainActivity.java
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.Toast;
import com.google.android.gms.location.LocationServices;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(Build.VERSION.SDK_INT >= 23){
// If the permission Access Fine Location is not granted
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED){
// Request Location
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}
else{
// Request Location Permission
startService();
}
}
else{
// Start Location Service
startService();
}
}
// Start the service with a new intent for the MainActivity and Location Services
// Register Broadcast Receiver with intent action from LocationService.java
void startService(){
LocationBroadcastReceiver receiver = new LocationBroadcastReceiver();
IntentFilter filter = new IntentFilter("ACT_LOC");
Intent intent = new Intent(MainActivity.this, LocationServices.class);
startService(intent);
registerReceiver(receiver, filter);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch(requestCode){
case 1:
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
startService();
}
else{
Toast.makeText(this, "Give me permissions", Toast.LENGTH_LONG).show();
}
}
}
public class LocationBroadcastReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// check if action is required or not
if(intent.getAction().equals("ACT_LOC")){
double lat = intent.getDoubleExtra("Latitude", 0f);
double lng = intent.getDoubleExtra("Longitude", 0f);
Toast.makeText(MainActivity.this, "Latitude is: " + lat + ", Longitude is: " + lng, Toast.LENGTH_LONG).show();
}
}
}
}
AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.anongeolocation">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
<service android:name=".LocationService"/>
</application>
</manifest>
Any help would be greatly appreciated. Thanks in advance.
If log or toast doesnt run it could only have one reason.the compiler doesnt get into their methods somehow.i suggest you log everywhere compiler can go from on create of main activity and follow logs one by one to find out where exactly compiler is!
I am trying to get permissions (from users running versions of Android higher than 6.0) for ACCESS_FINE_LOCATION at runtime. This was unsuccessful in my main app so I tried making a test app with a sole purpose of requesting location permissions from the user.
The problem I am having is that no permissions dialog box is being shown to the user - from the logcat I can see that the 'onRequestPermissionsResult' method is being run straight away (without asking the user to accept permissions), and it is showing that permissions were not granted.
After looking through other questions around this topic, I have double checked that the 'uses-permission' line is in my Android Manifest XML file, but couldn't find any other solution.
Here is my code:
package com.user.testapplication;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_LOCATION_ID = 1;
private static final String TAG = MainActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkLocationPermissions();
}
private void checkLocationPermissions(){
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.i(TAG, "Device version above 6.0 - Requesting location permissions.");
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_LOCATION_ID);
}
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_LOCATION_ID: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "Permissions granted successfully!");
} else {
Log.i(TAG, "Permissions were not granted.");
}
return;
}
}//end switch
}
}//end class
My Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.user.testapplication">
<uses-permission android:name="android.permisssion.ACCESS_FINE_LOCATION"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
And the relevant lines from the logcat:
11-27 13:27:47.752 31839-31839/com.user.testapplication I/MainActivity: Device version above 6.0 - Requesting location permissions.
11-27 13:27:47.881 31839-31839/com.user.testapplication I/MainActivity: Permissions were not granted.
Any help is much appreciated - I think I may just be missing something.
Use this in onStart() method, it will solve your issue.
//This checks for the permission
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_FINE_LOCATION)){
// You can show your dialog message here but instead I am
// showing the grant permission dialog box
ActivityCompat.requestPermissions(this, new String[] {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION },
10);
}
else{
//Requesting permission
ActivityCompat.requestPermissions(this, new String[] {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION },
10);
}
}
The reason for no Dialog box being shown was a typo in the AndroidManifest, you can see that the permission was spelt android-permisssion rather than android-permission.
I also had the same problem my issue was i had written following line in manifest
<permission android:name="android.permission.ACCESS_FINE_LOCATION" />
instead of
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Each time I run the application, my SecurityException gets thrown and the error from the debugger reads as so:
java.lang.SecurityException: "gps" location provider requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.
This seems like a simple mistake, however, my manifest file is completely correct. Here it is, and here is my MapActivity code as well:
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="com.dev.cromer.jason.coverme.permission.MAPS_RECEIVE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value= "#string/google_maps_key" />
<activity
android:name=".MapActivity"
android:label="#string/title_activity_map" >
</activity>
</application>
My Activity:
package com.dev.cromer.jason.coverme;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
public class MapActivity extends FragmentActivity implements LocationListener {
private GoogleMap mMap; // Might be null if Google Play services APK is not available.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
setUpMapIfNeeded();
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
//mMap.setMyLocationEnabled(true);
//mMap.setOnMyLocationChangeListener(this);
setUpMap();
}
}
}
private void setUpMap() {
mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
mMap.setMyLocationEnabled(true);
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
try {
Location myLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (myLocation != null) {
Log.d("TAG", "Not null");
}
else {
Log.d("TAG", "NULL");
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
}
catch (SecurityException se) {
Log.d("TAG", "SE CAUGHT");
se.printStackTrace();
}
}
#Override
public void onLocationChanged(Location location) {
Log.d("CHANGED", "LOCATION UPDATED");
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
}
ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, and WRITE_EXTERNAL_STORAGE are all part of the Android 6.0 runtime permission system. In addition to having them in the manifest as you do, you also have to request them from the user at runtime (using requestPermissions()) and see if you have them (using checkSelfPermission()).
One workaround in the short term is to drop your targetSdkVersion below 23.
But, eventually, you will want to update your app to use the runtime permission system.
For example, this activity works with five permissions. Four are runtime permissions, though it is presently only handling three (I wrote it before WRITE_EXTERNAL_STORAGE was added to the runtime permission roster).
/***
Copyright (c) 2015 CommonsWare, LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
by applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.
From _The Busy Coder's Guide to Android Development_
https://commonsware.com/Android
*/
package com.commonsware.android.permmonger;
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private static final String[] INITIAL_PERMS={
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.READ_CONTACTS
};
private static final String[] CAMERA_PERMS={
Manifest.permission.CAMERA
};
private static final String[] CONTACTS_PERMS={
Manifest.permission.READ_CONTACTS
};
private static final String[] LOCATION_PERMS={
Manifest.permission.ACCESS_FINE_LOCATION
};
private static final int INITIAL_REQUEST=1337;
private static final int CAMERA_REQUEST=INITIAL_REQUEST+1;
private static final int CONTACTS_REQUEST=INITIAL_REQUEST+2;
private static final int LOCATION_REQUEST=INITIAL_REQUEST+3;
private TextView location;
private TextView camera;
private TextView internet;
private TextView contacts;
private TextView storage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
location=(TextView)findViewById(R.id.location_value);
camera=(TextView)findViewById(R.id.camera_value);
internet=(TextView)findViewById(R.id.internet_value);
contacts=(TextView)findViewById(R.id.contacts_value);
storage=(TextView)findViewById(R.id.storage_value);
if (!canAccessLocation() || !canAccessContacts()) {
requestPermissions(INITIAL_PERMS, INITIAL_REQUEST);
}
}
#Override
protected void onResume() {
super.onResume();
updateTable();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.actions, menu);
return(super.onCreateOptionsMenu(menu));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.camera:
if (canAccessCamera()) {
doCameraThing();
}
else {
requestPermissions(CAMERA_PERMS, CAMERA_REQUEST);
}
return(true);
case R.id.contacts:
if (canAccessContacts()) {
doContactsThing();
}
else {
requestPermissions(CONTACTS_PERMS, CONTACTS_REQUEST);
}
return(true);
case R.id.location:
if (canAccessLocation()) {
doLocationThing();
}
else {
requestPermissions(LOCATION_PERMS, LOCATION_REQUEST);
}
return(true);
}
return(super.onOptionsItemSelected(item));
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
updateTable();
switch(requestCode) {
case CAMERA_REQUEST:
if (canAccessCamera()) {
doCameraThing();
}
else {
bzzzt();
}
break;
case CONTACTS_REQUEST:
if (canAccessContacts()) {
doContactsThing();
}
else {
bzzzt();
}
break;
case LOCATION_REQUEST:
if (canAccessLocation()) {
doLocationThing();
}
else {
bzzzt();
}
break;
}
}
private void updateTable() {
location.setText(String.valueOf(canAccessLocation()));
camera.setText(String.valueOf(canAccessCamera()));
internet.setText(String.valueOf(hasPermission(Manifest.permission.INTERNET)));
contacts.setText(String.valueOf(canAccessContacts()));
storage.setText(String.valueOf(hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)));
}
private boolean canAccessLocation() {
return(hasPermission(Manifest.permission.ACCESS_FINE_LOCATION));
}
private boolean canAccessCamera() {
return(hasPermission(Manifest.permission.CAMERA));
}
private boolean canAccessContacts() {
return(hasPermission(Manifest.permission.READ_CONTACTS));
}
private boolean hasPermission(String perm) {
return(PackageManager.PERMISSION_GRANTED==checkSelfPermission(perm));
}
private void bzzzt() {
Toast.makeText(this, R.string.toast_bzzzt, Toast.LENGTH_LONG).show();
}
private void doCameraThing() {
Toast.makeText(this, R.string.toast_camera, Toast.LENGTH_SHORT).show();
}
private void doContactsThing() {
Toast.makeText(this, R.string.toast_contacts, Toast.LENGTH_SHORT).show();
}
private void doLocationThing() {
Toast.makeText(this, R.string.toast_location, Toast.LENGTH_SHORT).show();
}
}
(from this sample project)
For the requestPermissions() function, should the parameters just be "ACCESS_COARSE_LOCATION"? Or should I include the full name "android.permission.ACCESS_COARSE_LOCATION"?
I would use the constants defined on Manifest.permission, as shown above.
Also, what is the request code?
That will be passed back to you as the first parameter to onRequestPermissionsResult(), so you can tell one requestPermissions() call from another.
My simple solution is this
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
googleMap.setMyLocationEnabled(true);
googleMap.getUiSettings().setMyLocationButtonEnabled(true);
} else {
Toast.makeText(this, R.string.error_permission_map, Toast.LENGTH_LONG).show();
}
or you can open permission dialog in else like this
} else {
ActivityCompat.requestPermissions(this, new String[] {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION },
TAG_CODE_PERMISSION_LOCATION);
}
CAUSE: "Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app." In this case, "ACCESS_FINE_LOCATION" is a "dangerous permission and for that reason, you get this 'java.lang.SecurityException: "gps" location provider requires ACCESS_FINE_LOCATION permission.' error (https://developer.android.com/training/permissions/requesting.html).
SOLUTION: Implementing the code provided at https://developer.android.com/training/permissions/requesting.html under the "Request the permissions you need" and "Handle the permissions request response" headings.