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!
Related
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.
I am trying to send an explicit broadcast to a receiver that's dynamically registered inside an activity but it doesn't seem to work. I've tried adding the action that the intent filter is expecting but that doesn't work either. Only when I use a public implicit intent it picks up the broadcast.
Could any one tell me why? The code is for Android 8.0+ and I have marked the line inside CustomReceiver.
In summary it should...
Service starts, dynamically registers a CustomReceiver to listen for a implicit broadcast.
CustomReceiver receives implicit broadcast, tries to send explicit broadcast to MainActivity.
MainActivity receiver catches the explicit broadcast and does something.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.demos.democode">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<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>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".CustomService" />
</application>
</manifest>
MainActivity.java
package com.demos.democode;
import androidx.appcompat.app.AppCompatActivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter intentFilter = new IntentFilter(CustomService.customActionActivity);
getApplicationContext().registerReceiver(activityReceiver, intentFilter);
Intent serviceIntent = new Intent(this,CustomService.class);
this.startForegroundService(serviceIntent);
Log.d("DEMO_APP", "create");
}
BroadcastReceiver activityReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("DEMO_APP", "activity receiver");
}
};
}
CustomReceiver.java - Explicit broadcast from here doesn't work.
package com.demos.democode;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class CustomReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("DEMO_APP", "custom receiver");
// DOESN'T WORK! this explicit broadcast doesn't work even after setting an action in - why?
Intent i = new Intent(context, MainActivity.class);
i.setAction(CustomService.customActionActivity);
context.sendBroadcast(i);
// this implicit public broadcast works fine
i = new Intent(CustomService.customActionActivity);
context.sendBroadcast(i);
}
}
CustomService.java
package com.demos.democode;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
public class CustomService extends Service {
protected Context context = null;
public static String customAction = "EVENT_1";
public static String customActionActivity = "EVENT_2";
#Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
NotificationChannel serviceChannel = new NotificationChannel(
"DEMO_CHANNEL",
"Demo App",
NotificationManager.IMPORTANCE_LOW
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
Notification notification = new NotificationCompat.Builder(context, "DEMO_CHANNEL")
.setSmallIcon(R.drawable.ic_launcher_foreground)
//.setContentText("Total screen time today: " + totalTimeDisplay )
.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(1, notification);
startForeground(1, notification);
IntentFilter intentFilter = new IntentFilter(customAction);
CustomReceiver customReceiver = new CustomReceiver();
context.registerReceiver( customReceiver , intentFilter);
Log.d("DEMO_APP", "service created");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
final Intent i = new Intent(customAction);
Log.d("DEMO_APP", "service started");
sendBroadcast(i);
return Service.START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
You are trying to launch an Activity using sendBroadcast()
In this code:
// DOESN'T WORK! this explicit broadcast doesn't work even after setting an action in - why?
Intent i = new Intent(context, MainActivity.class);
i.setAction(CustomService.customActionActivity);
context.sendBroadcast(i);
You are trying to launch an Activity, so the last line needs to be:
content.startActivity(i);
Sorry I am rather late to the party, but I think the error is in registration of receiver in the MainActivity. You have used
getApplicationContext().registerReceiver(activityReceiver, intentFilter);
Which is using application context to register receiver.
It should be replaced by:
registerReceiver(activityReceiver, intentFilter);
In which the receiver will be registered for that specific activity instance of Context.
I have tried so many different ways to run background service to get location of user but android system automatically kills service after some time.
Though it works on some devices but not working on most of the devices.
I am building app similar to UBER. I want driver's location to be updated after some interval of time even if app is in background or Foreground until user does not set status to offline
You can use Foreground Service, which is just a normal service with an ongoing notification in the foreground, which stops the OS to stop/kill your service process.
By the way, this does not gurantee that your service will be give CPU/processing time when device goes into Doze or App Standby modes.
Although you cannot bypass these doze, standby and battery optimizations, but I've tested a hack to avoid these by creating a wake lock in your foreground service and starting that service in a separate process.
Hope it helps.
You could use a few mechanisms provided by Android.
For devices running pre-Oreo, you could just use background service as it is and it should live most of the time, keep it on a separate process by declaring it in the manifest file. You can also register to device boot complete broadcast, so you will get a call back when device reboots, you will then have a chance to restart you background service. For devices running oreo+, the most reliable way to go is using a foreground service. Make sure your service is sticky in any case.
Set up fire base schedule job to restart your service in case it stops
Geo fence policy to get additional feedback
Schedule with alarm manager to restart your service in case it stops
Use google activity recognition api you can also get callback to have additional chances to pull more location info
Push notifications
I’d suggest using a combination of all with policy tailored to your application, they together should give you enough about a users location at any time.
Yes, you can do it but maybe it will consume more battery power.
Find below code it will help you,
There is an alternative way to use mobile location, Google has release fused location provider which are more helpful in your case.
1.Add Google Location gradle line in your Build.gradle file
implementation 'com.google.android.gms:play-services-location:15.0.1'
2.Get User Location Using Location Service
import android.Manifest;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.NotificationCompat;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationAvailability;
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;
import com.uffizio.taskeye.BuildConfig;
import com.uffizio.taskeye.R;
import com.uffizio.taskeye.extra.Constants;
import com.uffizio.taskeye.ui.activity.MainActivity;
/**
* Created by Kintan on 16/8/18.
*/
public class LocationServiceDemo extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
public static LocationServiceDemo locationService;
private static GoogleApiClient mGoogleApiClient;
private static LocationRequest mLocationRequest;
private FusedLocationProviderClient mFusedProviderClient;
private MyLocationCallback mMyLocationCallback;
private Location curLocation;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
#Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
showNotificationAndStartForegroundService();
locationService = this;
init();
}
//Google location Api build
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
protected void createLocationRequest() {
mMyLocationCallback = new MyLocationCallback();
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(3000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(5.0f);
requestUpdate();
}
//Start Foreground Service and Show Notification to user for Android O and higher Version
private void showNotificationAndStartForegroundService() {
final String CHANNEL_ID = BuildConfig.APPLICATION_ID.concat("_notification_id");
final int REQUEST_CODE = 1;
PendingIntent pendingIntent = PendingIntent.getActivity(this,
REQUEST_CODE, new Intent(this, MainActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this,
CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getString(R.string.app_name))
.setAutoCancel(false)
.setContentIntent(pendingIntent);
startForeground(Constants.NOTIFICATION_ID, notificationBuilder.build());
}
public void requestUpdate() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mFusedProviderClient.requestLocationUpdates(mLocationRequest, mMyLocationCallback,
Looper.myLooper());
}
public void removeUpdate() {
mFusedProviderClient.removeLocationUpdates(mMyLocationCallback);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
createLocationRequest();
}
#Override
public void onConnectionSuspended(int i) {
buildGoogleApiClient();
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
buildGoogleApiClient();
}
private void init() {
buildGoogleApiClient();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mFusedProviderClient = LocationServices.getFusedLocationProviderClient(LocationServiceDemo.this);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
return START_STICKY;
}
mFusedProviderClient.getLastLocation().addOnSuccessListener(location -> {
if (location != null) {
curLocation = location;
}
});
if (mGoogleApiClient.isConnected()) {
createLocationRequest();
} else {
buildGoogleApiClient();
}
return START_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
startService();
}
#Override
public void onLowMemory() {
super.onLowMemory();
startService();
}
#Override
public void onDestroy() {
super.onDestroy();
startService();
}
public void startService() {
startService(new Intent(LocationServiceDemo.this, LocationServiceDemo.class));
}
public class MyLocationCallback extends LocationCallback {
#Override
public void onLocationResult(LocationResult locationResult) {
//get your location here
if (locationResult.getLastLocation() != null) {
for (Location location : locationResult.getLocations()) {
curLocation = location;
}
}
}
#Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
super.onLocationAvailability(locationAvailability);
}
}
private class MyBinder extends Binder {
LocationServiceDemo getService() {
return LocationServiceDemo.this;
}
}
}
3.Finaly Grant Access the admin permission so,android system will not automatically kills service after some time.
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class LocationHome extends AppCompatActivity {
private static final int REQUEST_CODE = 0;
private DevicePolicyManager mDPM;
private ComponentName mAdminName;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
mAdminName = new ComponentName(this, DeviceAdmin.class);
Button button = new Button();
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Grant Admin Permission
if (mDPM.isAdminActive(mAdminName)) {
startService(new Intent(this, LocationService.class));
} else {
adminPermission();
}
}
});
}
public void adminPermission() {
try {
if (!mDPM.isAdminActive(mAdminName)) {
try {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdminName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "Click on Activate button to secure your application.");
startActivityForResult(intent, REQUEST_CODE);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//Check Permission is granted or not
if (requestCode == REQUEST_CODE) {
if (resultCode == RESULT_OK) {
startService(new Intent(this, LocationService.class));
} else {
if (!mDPM.isAdminActive(mAdminName)) {
adminPermission();
}
}
}
}
}
Create XMl folder add device_admin.xml
<device-admin>
<uses-policies>
</uses-policies>
</device-admin>
And Finaly Modify Your Manifest and Enjoy.
<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_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-feature
android:name="android.hardware.location.gps"
android:required="false" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:name=".common.MyApplication"
android:theme="#style/AppTheme">
<receiver
android:name=".ui.DeviceAdmin"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="#xml/device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
</application>
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>
Today I started writing for android. I want a simple (I think) app that waits for notification with specified title and then does something. I tried this code for service
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.support.v4.content.LocalBroadcastManager;
import android.widget.Toast;
public class NotificationListener extends NotificationListenerService {
Context context;
public int onStartCommand(Intent intent, int flags, int startId) {
// Let it continue running until it is stopped.
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
return START_STICKY;
}
#Override
public void onCreate() {
Toast.makeText(this, "onCreate", Toast.LENGTH_LONG).show();
super.onCreate();
context = getApplicationContext();
}
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
String pack = sbn.getPackageName();
Toast.makeText(this,"NOTIFICATION",Toast.LENGTH_SHORT).show();
String text = "";
String title = "";
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
Bundle extras = extras = sbn.getNotification().extras;
text = extras.getCharSequence("android.text").toString();
title = extras.getString("android.title");
}
Log.i("Package",pack);
Log.i("Title",title);
Log.i("Text",text);
}
#Override
public void onNotificationRemoved(StatusBarNotification sbn) {
Toast.makeText(this,"NOTIFICATION removed",Toast.LENGTH_SHORT).show();
Log.i("Msg","Notification was removed");
}
}
Then added this to manifest:
<service
android:name=".NotificationListener"
android:enabled="true"
android:label="#string/app_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
finally started the service in MainActivity onCreate() startService(new Intent(context, NotificationListener.class));
onNotificationPosted does not work. It seems like service was started correctly, because toasts from onStartCommand and onCreate were shown. I tried on emulator and real device. I also allowed notification access in settings. Please help, I wasted 5 hours on that.