This commit is contained in:
estevez-dev 2020-07-06 22:41:42 +03:00
parent 7ebaf736b5
commit 2ec549af7e
5 changed files with 70 additions and 156 deletions

View File

@ -59,7 +59,7 @@
<service
android:name=".LocationUpdatesService"
android:enabled="true"
android:exported="true" />
android:exported="false" />
<receiver android:name=".NotificationActionReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
@ -72,6 +72,11 @@
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
</intent-filter>
</receiver>
<receiver android:name=".Autostart">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name="io.flutter.plugins.androidalarmmanager.AlarmService"
android:permission="android.permission.BIND_JOB_SERVICE"

View File

@ -0,0 +1,37 @@
package com.keyboardcrumbs.hassclient;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
public class Autostart extends BroadcastReceiver {
private PendingResult result;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LocationUpdatesService.LocalBinder binder = (LocationUpdatesService.LocalBinder) service;
binder.getService().requestLocationUpdates();
result.finish();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
public void onReceive(Context context, Intent intent) {
if (/*Utils.requestingLocationUpdates(context) && */Intent.ACTION_BOOT_COMPLETED.equalsIgnoreCase(intent.getAction())) {
context.getApplicationContext().bindService(new Intent(context, LocationUpdatesService.class), mServiceConnection,
Context.BIND_AUTO_CREATE);
result = goAsync();
}
}
}

View File

@ -1,14 +1,11 @@
package com.keyboardcrumbs.hassclient;
import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.location.Location;
import android.os.Binder;
import android.os.Build;
@ -16,8 +13,9 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.work.BackoffPolicy;
import androidx.work.Constraints;
import androidx.work.Data;
@ -36,20 +34,6 @@ import com.google.android.gms.location.LocationServices;
import java.util.concurrent.TimeUnit;
/**
* A bound and started service that is promoted to a foreground service when location updates have
* been requested and all clients unbind.
*
* For apps running in the background on "O" devices, location is computed only once every 10
* minutes and delivered batched every 30 minutes. This restriction applies even to apps
* targeting "N" or lower which are run on "O" devices.
*
* This sample show how to use a long-running service for location updates. When an activity is
* bound to this service, frequent location updates are permitted. When the activity is removed
* from the foreground, the service promotes itself to a foreground service, and location updates
* continue. When the activity comes back to the foreground, the foreground service stops, and the
* notification assocaited with that service is removed.
*/
public class LocationUpdatesService extends Service {
private static final String PACKAGE_NAME =
@ -59,47 +43,23 @@ public class LocationUpdatesService extends Service {
private static final String CHANNEL_ID = "location_service";
static final String ACTION_BROADCAST = PACKAGE_NAME + ".broadcast";
static final String EXTRA_LOCATION = PACKAGE_NAME + ".location";
private static final String EXTRA_STARTED_FROM_NOTIFICATION = PACKAGE_NAME +
".started_from_notification";
private final IBinder mBinder = new LocalBinder();
/**
* The identifier for the notification displayed for the foreground service.
*/
private static final int NOTIFICATION_ID = 954311;
/**
* Used to check whether the bound activity has really gone away and not unbound as part of an
* orientation change. We create a foreground service notification only if the former takes
* place.
*/
private boolean mChangingConfiguration = false;
private NotificationManager mNotificationManager;
private LocationRequest mLocationRequest;
private long requestInterval = 90000;
/**
* Provides access to the Fused Location Provider API.
*/
private FusedLocationProviderClient mFusedLocationClient;
/**
* Callback for changes in location.
*/
private LocationCallback mLocationCallback;
private Handler mServiceHandler;
/**
* The current location.
*/
private Location mLocation;
public LocationUpdatesService() {
@ -117,7 +77,9 @@ public class LocationUpdatesService extends Service {
}
};
createLocationRequest();
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
getLastLocation();
HandlerThread handlerThread = new HandlerThread(TAG);
@ -125,14 +87,11 @@ public class LocationUpdatesService extends Service {
mServiceHandler = new Handler(handlerThread.getLooper());
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Android O requires a Notification Channel.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Location updates";
// Create the channel for the notification
NotificationChannel mChannel =
new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_LOW);
// Set the Notification Channel for the Notification Manager.
mNotificationManager.createNotificationChannel(mChannel);
}
}
@ -148,49 +107,24 @@ public class LocationUpdatesService extends Service {
removeLocationUpdates();
stopSelf();
}
// Tells the system to not try to recreate the service after it has been killed.
return START_STICKY;
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mChangingConfiguration = true;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
// Called when MainActivity comes to the foreground
// and binds with this service. The service should cease to be a foreground service
// when that happens.
Log.i(TAG, "in onBind()");
stopForeground(true);
mChangingConfiguration = false;
return mBinder;
}
@Override
public void onRebind(Intent intent) {
// Called when MainActivity returns to the foreground
// and binds once again with this service. The service should cease to be a foreground
// service when that happens.
Log.i(TAG, "in onRebind()");
stopForeground(true);
mChangingConfiguration = false;
super.onRebind(intent);
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "Last client unbound from service");
// Called when the last client (MainActivity ) unbinds from this
// service. If this method is called due to a configuration change in MainActivity, we
// do nothing. Otherwise, we make this service a foreground service.
if (!mChangingConfiguration && Utils.requestingLocationUpdates(this)) {
startForeground(NOTIFICATION_ID, getNotification());
}
return true; // Ensures onRebind() is called when a client re-binds.
return true;
}
@Override
@ -199,16 +133,19 @@ public class LocationUpdatesService extends Service {
}
public void requestLocationUpdates() {
requestInterval = Utils.getLocationUpdateIntervals(getApplicationContext());
long requestInterval = Utils.getLocationUpdateIntervals(getApplicationContext());
Log.i(TAG, "Requesting location updates. Interval is " + requestInterval);
mLocationRequest.setInterval(requestInterval);
mLocationRequest.setFastestInterval(requestInterval);
Utils.setRequestingLocationUpdates(this, true);
startService(new Intent(getApplicationContext(), LocationUpdatesService.class));
startForeground(NOTIFICATION_ID, getNotification());
try {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
} catch (SecurityException unlikely) {
//When we lost permission
Utils.setRequestingLocationUpdates(this, false);
removeLocationUpdates();
}
}
@ -216,30 +153,24 @@ public class LocationUpdatesService extends Service {
Log.i(TAG, "Removing location updates");
try {
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
Utils.setRequestingLocationUpdates(this, false);
stopSelf();
} catch (SecurityException unlikely) {
//When we lost permission
Utils.setRequestingLocationUpdates(this, true);
Log.i(TAG, "No location permission");
}
Utils.setRequestingLocationUpdates(this, false);
stopSelf();
}
/**
* Returns the {@link NotificationCompat} used as part of the foreground service.
*/
private Notification getNotification() {
Intent intent = new Intent(this, LocationUpdatesService.class);
CharSequence text = Utils.getLocationText(mLocation);
// Extra to help us figure out if we arrived in onStartCommand via the notification or not.
intent.putExtra(EXTRA_STARTED_FROM_NOTIFICATION, true);
// The PendingIntent that leads to a call to onStartCommand() in this service.
PendingIntent servicePendingIntent = PendingIntent.getService(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// The PendingIntent to launch activity.
PendingIntent activityPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
@ -252,7 +183,7 @@ public class LocationUpdatesService extends Service {
.setPriority(-1)
.setContentTitle(Utils.getLocationTitle(mLocation))
.setOngoing(true)
.setSmallIcon(R.mipmap.ic_launcher)
.setSmallIcon(R.drawable.mini_icon)
.setWhen(System.currentTimeMillis());
return builder.build();
@ -278,21 +209,12 @@ public class LocationUpdatesService extends Service {
mLocation = location;
// Notify anyone listening for broadcasts about the new location.
Intent intent = new Intent(ACTION_BROADCAST);
intent.putExtra(EXTRA_LOCATION, location);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
// Update notification content if running as a foreground service.
if (serviceIsRunningInForeground(this)) {
mNotificationManager.notify(NOTIFICATION_ID, getNotification());
}
mNotificationManager.notify(NOTIFICATION_ID, getNotification());
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
// Create the Data object:
Data locationData = new Data.Builder()
.putDouble("Lat", mLocation.getLatitude())
.putDouble("Long", mLocation.getLongitude())
@ -315,42 +237,9 @@ public class LocationUpdatesService extends Service {
.enqueueUniqueWork("SendLocationUpdate", ExistingWorkPolicy.REPLACE, uploadWorkRequest);
}
/**
* Sets the location request parameters.
*/
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(requestInterval);
mLocationRequest.setFastestInterval(requestInterval);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
/**
* Class used for the client Binder. Since this service runs in the same process as its
* clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocationUpdatesService getService() {
return LocationUpdatesService.this;
}
}
/**
* Returns true if this is a foreground service.
*
* @param context The {@link Context}.
*/
public boolean serviceIsRunningInForeground(Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(
Integer.MAX_VALUE)) {
if (getClass().getName().equals(service.service.getClassName())) {
if (service.foreground) {
return true;
}
}
}
return false;
}
}

View File

@ -20,7 +20,6 @@ import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.widget.Toast;
import io.flutter.plugin.common.MethodChannel;
@ -34,8 +33,6 @@ public class MainActivity extends FlutterActivity {
private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
private MyReceiver myReceiver;
private LocationUpdatesService mService = null;
private boolean mBound = false;
@ -87,8 +84,8 @@ public class MainActivity extends FlutterActivity {
}
break;
case "startLocationService":
if (checkPermissions()) {
requestPermissions();
if (isNoLocationPermissions()) {
requestLocationPermissions();
} else {
mService.requestLocationUpdates();
}
@ -110,12 +107,11 @@ public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myReceiver = new MyReceiver();
if (Utils.requestingLocationUpdates(this)) {
if (checkPermissions()) {
requestPermissions();
/*if (Utils.requestingLocationUpdates(this)) {
if (isNoLocationPermissions()) {
requestLocationPermissions();
}
}
}*/
}
@Override
@ -128,13 +124,10 @@ public class MainActivity extends FlutterActivity {
@Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver,
new IntentFilter(LocationUpdatesService.ACTION_BROADCAST));
}
@Override
protected void onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver);
super.onPause();
}
@ -147,12 +140,12 @@ public class MainActivity extends FlutterActivity {
super.onStop();
}
private boolean checkPermissions() {
private boolean isNoLocationPermissions() {
return PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION);
}
private void requestPermissions() {
private void requestLocationPermissions() {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_PERMISSIONS_REQUEST_CODE);
@ -168,14 +161,4 @@ public class MainActivity extends FlutterActivity {
}
}
private class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Location location = intent.getParcelableExtra(LocationUpdatesService.EXTRA_LOCATION);
if (location != null) {
//TODO looks like we need to remove this
}
}
}
}

View File

@ -120,7 +120,7 @@ public class MessagingService extends FirebaseMessagingService {
}
broadcastIntent.putExtra("actionData", data.get("action" + i + "_data"));
PendingIntent actionIntent = PendingIntent.getBroadcast(this, i, broadcastIntent, PendingIntent.FLAG_CANCEL_CURRENT);
notificationBuilder.addAction(R.drawable.mini_icon, data.get("action" + i), actionIntent);
notificationBuilder.addAction(R.drawable.blank_icon, data.get("action" + i), actionIntent);
}
}
NotificationManager notificationManager =