I am using an android fused location client for background location tracking which will run even if the app is cleared from the memory. I am using foreground service for this. It is running perfectly for most of the devices except the Samsung Galaxy devices with power saver modes. I have also added the permission for ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS on app runtime but still, the Samsung devices do not track perfectly. I am also using geofencing intent service along with a partial wake lock. This app is working fine on all other devices. Please check the code that I am using for background locations. This is not the full code.
Also when I enable location toasts then the distance is tracking perfectly even on Samsung. But when toasts are disabled then it only works for the first time in Samsung.
/**********LocationUpdatesService class********/
public class LocationUpdatesService extends Service {
#Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
onNewLocation(locationResult.getLastLocation());
}
};
createLocationRequest();
if (checkPermissions()) {
getLastLocation();
}
powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"myapp::MyWakelockTag");
wakeLock.acquire();
}
public void requestLocationUpdates() {
Log.i(TAG, "Requesting location updates");
//Utils.setRequestingLocationUpdates(this, true);
startService(new Intent(getApplicationContext(), LocationUpdatesService.class));
try {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
} catch (SecurityException unlikely) {
//Utils.setRequestingLocationUpdates(this, false);
Log.e(TAG, "Lost location permission. Could not request updates. " + unlikely);
}
}
public void removeLocationUpdates() {
Log.i(TAG, "Removing location updates");
removeActivityUpdatesButtonHandler();
try {
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
wakeLock.release();
stopForeground(true);
stopSelf();
} catch (SecurityException unlikely) {
//Utils.setRequestingLocationUpdates(this, true);
Log.e(TAG, "Lost location permission. Could not remove updates. " + unlikely);
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service started");
boolean startedFromNotification = intent.getBooleanExtra(EXTRA_STARTED_FROM_NOTIFICATION,
false);
// We got here because the user decided to remove location updates from the notification.
if (startedFromNotification) {
//removeLocationUpdates();
//stopSelf();
}
startForeground(NOTIFICATION_ID, getNotification());
// Tells the system to not try to recreate the service after it has been killed.
return START_STICKY;
}
}
I am using this Bound service in my main activity.
The above is just a sample code for anyone's reference. Please let me know if anyone knows the solution. I am just having trouble in the case of Samsung devices with a power saver. Otherwise, my service is working fine and tracking the distance perfectly.
Related
btAdapter.isDiscovering(),btAdapter.startDiscovery(); btAdapter.cancelDiscovery(); device.getName();
4four erros
Call requires permission which may be rejected by user: code should explicitly check to see if permission is available (with checkPermission) or explicitly handle a potential SecurityException
Please solve this problem
public void onClickButtonSearch(View view){
// Check if the device is already discovering
if(btAdapter.*isDiscovering()*){
*btAdapter.cancelDiscovery()*;
} else {
if (btAdapter.isEnabled()) {
*btAdapter.startDiscovery();*
btArrayAdapter.clear();
if (deviceAddressArray != null && !deviceAddressArray.isEmpty()) {
deviceAddressArray.clear();
}
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver, filter);
} else {
Toast.makeText(getApplicationContext(), "bluetooth not on", Toast.LENGTH_SHORT).show();
}
}
}
// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Discovery has found a device. Get the BluetoothDevice
// object and its info from the Intent.
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String deviceName = device.*getName();*
String deviceHardwareAddress = device.getAddress(); // MAC address
btArrayAdapter.add(deviceName);
deviceAddressArray.add(deviceHardwareAddress);
btArrayAdapter.notifyDataSetChanged();
}
}
};
protected void onDestroy() {
super.onDestroy();
// Don't forget to unregister the ACTION_FOUND receiver.
unregisterReceiver(receiver);
}
For apps targeting Android 11 or lower, calling BluetoothAdapter#startDiscovery() requires the Manifest.permission#BLUETOOTH_ADMIN permission which can be gained with a simple manifest tag.
For apps targeting API Level 31 or higher, this requires the Manifest.permission#BLUETOOTH_SCAN permission.
In addition, this requires either the Manifest.permission#ACCESS_FINE_LOCATION permission or a strong assertion that you will never derive the physical location of the device.
A permission can be gained with the following code:
getActivity().requestPermissions(new String[]{ Manifest.permission.ACCESS_FINE_LOCATION},
YOUR_REQUEST_LOCATION_PERMISSION_CODE);
For more infos: https://developer.android.com/reference/android/bluetooth/BluetoothAdapter#startDiscovery()
The addProximityAlert call stopped triggering alerts on Android 11 devices.
I call the addProximityAlert for the special locations (calculated for the user location) from the Application.onCreate method or whenever the ACCESS_FINE_LOCATION permission is granted using the following code:
mLocationManager = (LocationManager) mApplicationContext.getSystemService(Context.LOCATION_SERVICE);
if (mLocationManager != null) {
final Criteria criteria = new Criteria();
//criteria.setAccuracy(Criteria.ACCURACY_COARSE);
criteria.setAccuracy(Criteria.ACCURACY_FINE);
String provider = mLocationManager.getBestProvider(criteria, true);
if (!TextUtils.isEmpty(provider)) {
mLocationUpdatelistener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
subscribeForProximityAlert(location);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
};
final Location lastKnownLocation = mLocationManager.getLastKnownLocation(provider);
if (lastKnownLocation == null) {
try {
mLocationManager.requestSingleUpdate(criteria, mLocationUpdatelistener, Looper.getMainLooper());
} catch (Throwable e) {
e.printStackTrace();
}
} else {
subscribeForProximityAlert(lastKnownLocation);
}
}
}
The subscribeForProximityAlert function is as follows (it is called actually after the successful single location update - I've checked that):
void subscribeForProximityAlert(Location location) {
String id;
double lat;
double lng;
long radius;
// ... compute the params above using the location
final Intent intent = new Intent(ACTION_FILTER);
intent.putExtra("_id", id);
intent.putExtra("_lat", lat);
intent.putExtra("_lng", lng);
intent.putExtra("_rad", radius);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(mApplicationContext, i, intent, 0);
mPendingIntents.add(pendingIntent);
mLocationManager.addProximityAlert(
lat,
lng,
(float) radius,
24 * 60 * 60 * 1000,
pendingIntent
);
}
The ACTION_FILTER is the com.example.appname.ProximityAlert exactly the value I use in manifest to subscribe for the Proximity Alert broadcasts (com.example.appname is the package name of the app):
<application>
<receiver android:name="com.example.appname.ProximityAlertBroadcastReceiver">
<intent-filter>
<action android:name="com.example.appname.ProximityAlert" />
</intent-filter>
</receiver>
</application>
The ProximityAlertBroadcastReceiver can be as simple as:
public class ProximityAlertBroadcastReceiver extends BroadcastReceiver {
public ProximityAlertBroadcastReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
}
}
its onReceive method is never called on Android 11 devices (checked with Lod.d and Toast.makeText...show() calls). Not when the app is running, not when it's in background. Not when I'm already in the radius of specified point, not when I'm entering/exiting.
Tried to add the android.permission.ACCESS_BACKGROUND_LOCATION permission to the manifest (nothing about it in the LocationManager.addProximityAlerts docs anyway) and grant the permission in system settings for the app, but it didn't help.
Also tried to reduce the targetSdkVersion from 30 to 28, but it didn't help.
The problem happened because of the implicit intent for the broadcast receiver, which is prohibited for the app targeting Android 8+ (SDK version 26):
https://developer.android.com/about/versions/oreo/background#broadcasts
After changing the
final Intent intent = new Intent(ACTION_FILTER);
to
final Intent intent = new Intent(mApplicationContext, ProximityAlertBroadcastReceiver.class);
I started to receive the broadcasts.
UPDATE: There's a bug in recent Android versions (11, 12, maybe others) which makes Geofences unresponsive on some devices and completely non-working on other devices if no app is actively requesting location at the moment:
https://issuetracker.google.com/issues/218335535
addProximityAlert creates a geofence under the hood, so it's affected too.
I am having a problem related to Network Service Discovery.
When I start the app with wifi connected, NSD Works Totally fine discovering the service and smoothly resolving them.
But the problem arises when we connect wifi, after disabling wifi or switching the wifi from airplane mode.
It just gets stuck on DiscoveryStarted and never proceeds from there, although it establishes the connection to the wifi router after turning off airplane mode.
In code I have also ensured that the discovery will only start when the wifi connection is ensured but, no luck.
Right now I have to kill the app in order for NSD to work properly.
I am using NSD Helper from Google Gist:
https://android.googlesource.com/platform/development/+/master/samples/training/NsdChat/src/com/example/android/nsdchat/NsdHelper.java
NsdHelper helper;
BroadcastReceiver wifiReciever = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
if (intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
//do stuff
helper.stopDiscovery();
helper = new NsdHelper(context);
helper.discoverServices();
} else {
// wifi connection was lost
helper.stopDiscovery();
}
}
}
};
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
//startDiscovery();
// helper = new NsdHelper(this);
// helper.discoverServices();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
registerReceiver(wifiReciever, intentFilter);
Toast.makeText(this,"Service Started",Toast.LENGTH_SHORT).show();
}
#Override
public void onDestroy() {
// if(service!= null)
// {
// service.stop();
// helper.stopDiscovery();
// }
unregisterReceiver(wifiReciever);
//
Toast.makeText(this,"Service destroyed",Toast.LENGTH_SHORT).show();
super.onDestroy();
}
I am developing an Android application which involves showing the user a list of nearby Bluetooth devices and connecting to the device selected by them. I'm trying to use the system bluetooth device picker as shown in these posts:
How to retrieve Bluetooth device info with Android Bluetooth device picker?
Android Bluetooth Device Picker Usage
The device picker does show, but I can't find out which device was selected in my code. The toast inside the onReceive does not show, which suggests that no broadcast is being received.
Another problem I faced is that if I try to start the device picker activity inside the onRequestPermissionsResult, the device picker does not show up at all, despite clicking 'allow' in the request permission dialog. The toast inside doesn't get displayed either.
Here's the code:
//Code inside Fragment
BroadcastReceiver mReceiver;
BluetoothAdapter bluetoothAdapter;
BluetoothSocket bsock;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
myView = inflater.inflate(R.layout.controller_mode_layout,container,false);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//Get location access permission.
if (bluetoothAdapter != null) {
if (bluetoothAdapter.isEnabled()) {
ActivityCompat.requestPermissions(getActivity(),new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, reqCode);
}
}
//Receiver to get the selected device information
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
context.unregisterReceiver(this);
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Toast.makeText(context,"Device"+device.getAddress(), Toast.LENGTH_SHORT).show();
try {
bsock=device.createRfcommSocketToServiceRecord(UUID.fromString("00002415-0000-1000-8000-00805F9B34FB"));
bsock.connect();
//Send and receive data logic follows
} catch (IOException e) {
e.printStackTrace();
}
}
};
getActivity().registerReceiver(mReceiver, new IntentFilter("android.bluetooth.devicepicker.action.DEVICE_SELECTED"));
showDevicePicker();
return myView;
}
#Override
public void onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults)
{
Toast.makeText(getActivity(),"Permission result", Toast.LENGTH_SHORT).show();
if((requestCode == reqCode) && (grantResults[0] == PackageManager.PERMISSION_GRANTED))
{
//Not working
// showDevicePicker();
}
}
public void showDevicePicker()
{
//Launch built in bluetooth device picker activity
startActivity( new Intent("android.bluetooth.devicepicker.action.LAUNCH")
.putExtra("android.bluetooth.devicepicker.extra.NEED_AUTH", false)
.putExtra("android.bluetooth.devicepicker.extra.FILTER_TYPE", 0)
.putExtra("android.bluetooth.devicepicker.extra.LAUNCH_PACKAGE","com.example.ankit2.controllerapp1")
.putExtra("android.bluetooth.devicepicker.extra.DEVICE_PICKER_LAUNCH_CLASS","com.example.ankit2.controllerapp1.Fragment1")
.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS));
}
Any help will be appreciated.
Note: I tested the code on a Lenovo K3 note running Marshmallow.
The problem was in the DEVICE_PICKER_LAUNCH_CLASS, which was specified as Fragment1. The launch class must be an activity, even if the broadcast receiver is inside a fragment. In this case, changing the launch class to ControllerActivity (which contains the fragment Fragment1) fixed the problem.
I am trying to start a dream service. Currently, this is my code:
#SuppressLint("NewApi")
public class DreamLockService extends DreamService {
private static final String TAG = "DreamLockService";
public Utility utilObj = new Utility();
//private Button btnExit;
private Button btnlogin;
private EditText lgPass;
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
// Exit dream upon user touch
setInteractive(true);
// Hide system UI
setFullscreen(true);
// Set the dream layout
setContentView(R.layout.lockservice);
//setClickListener();
Toast.makeText(this, "Lock Service Created", Toast.LENGTH_LONG).show();
}
//Use this for initial setup, such as calling setContentView().
#Override
public void onDreamingStarted() {
super.onDreamingStarted();
// Exit dream upon user touch
setInteractive(true);
// Hide system UI
setFullscreen(true);
// Set the dream layout
setContentView(R.layout.lockservice);
Toast.makeText(this, "Lock Service Created", Toast.LENGTH_LONG).show();
}
//Your dream has started, so you should begin animations or other behaviors here.
public void onDreamingStopped()
{
super.onDreamingStopped();
}
//Use this to stop the things you started in onDreamingStarted().
public void onDetachedFromWindow()
{
super.onDetachedFromWindow();
}
}
I was unable to start the dream service from another activity. This is what I used:
Intent tempLock = new Intent(MainActivity.this, DreamLockService.class);
//DreamLockService test = new DreamLockService();
startService(tempLock);
I don't understand why it didn't work. How can a dream service be started from another activity?
To start a Dream service from our own app, please try this.
IBinder binder = ServiceManager.getService("dreams");
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.service.dreams.IDreamManager");
Parcel reply = Parcel.obtain();
try {
if (binder != null)
binder.transact(1, data,reply, Binder.FLAG_ONEWAY);
else
Log.e("TAG", "dreams service is not running");
} catch (RemoteException e) {
e.printStackTrace();
}
To use this, your app should be system app and should have dream permissions in the Manifest file and enable dream setting in Settings.
I tried this and it is working.
You can start the currently selected screen saver using this code:
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClassName("com.android.systemui", "com.android.systemui.Somnambulator");
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
Just need to make sure that your dream service is set and enabled.
Did you include it in your manifest and have an <intent-filter> that matches your action?
If it's ok, then try with:
startService(new Intent(this, DreamLockService.class));
An excellent Services tutorial: http://www.vogella.com/articles/AndroidServices/article.html#scheduleservice_startauto
UPDATE:
As it seems you are not sure if your service is running, you can use this solution found here:
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (MyService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}