WifiManager.startScan() not calling onReceive() on a phone - android

I need to connect to a device via wi-fi and I am using WifiManager.startScan() for this. In theory onReceive() should be called back, but this doesn't happen. The code just keeps waiting for the callback.
The thing is that this code actually works fine on a Samsung tablet with Android 8.1, but it doesn't on any phones that I have tried (Huawei Android 8.0 and Samsung Android 9).
Here is the relevant code:
public void Init()
{
try {
mainWifiObj = (WifiManager) act.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiScanReceiver wifiReceiver = new WifiScanReceiver(act, logger, mainWifiObj);
act.getApplicationContext().registerReceiver(wifiReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
mainWifiObj.startScan();
}
catch (Exception ex)
{
...
}
}
public class WifiScanReceiver extends BroadcastReceiver {
...
public void onReceive(Context c, Intent intent) {
try {
...// doesn't get here
}
} catch (Exception e) {
...
}
...
}
And here are the all important manifest permissions I used:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
The code doesn't generate any errors, it just silently fails to perform the callback.

Yes I found the answer. For a reason logical only to Android designers, you must enable Location Based Services for it to work. So it's not enough to give all the needed permissions to your app, but also go to settings and enable LBS.
The reason why it worked on the tablet is that LBS were enabled on it...but how is one supposed to keep all these dependencies under control?

Another thing to check is that you're not registering the broadcast receiver using
LocalBroadcastManager.getInstance(mContext).registerReceiver(broadcastReceiver, intentFilter);
use:
mContext.registerReceiver(broadcastReceiver, intentFilter);

Related

Service not running in Background when app terminated on Oreo

I have developed small app to detect changes in network like on, off or connection change Wifi to Ethernet, whenever app closed or running in all cases.
Provided code working for me upto Nuget 7, when testing app in Oreo 8 background services not working when app terminated.
How can I get it work in Oreo?
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
Intent vpnServiceIntent = new Intent(getBaseContext(), MyService.class);
startForegroundService(vpnServiceIntent);}}
WifiReceiver.java file
public class WifiReceiver extends BroadcastReceiver {
static final String CONNECTIVITY_CHANGE_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (CONNECTIVITY_CHANGE_ACTION.equals(action)) {
if (!isConnected()) {
if (context != null) {
Toast.makeText(context," Not connected...",Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(context,"connected...",Toast.LENGTH_LONG).show();
}
}
}
}
MySevice.java file
public class MyService extends Service
{
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
IntentFilter filter = new IntentFilter();
filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
WifiReceiver receiver =new WifiReceiver();
registerReceiver(receiver,filter);
return START_STICKY;
}
}
Manifest.xml file
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
<receiver android:name=".WifiReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<service android:name=".MyService" />
</application>
Note: If I call startForeground(101, notification); in onCreate of MyService class, my above code is working but showing permanent notification icon on top most status bar, that I don't want at all.
since Android 8.0 (API level 26) it is basically impossible to run background service while app is not visible because of Battery optimizations and security reasons.
It sucks, many useful apps can not run and work normally.
They recommend to use ForegroundService which requires to show notification.
It would be almost okay, but these ForegroundServices also gets killed after some time.
To avoid killing them you need to make BatteryOptimization prompt so user would let service running in background without killing.
But it is not over yet... Services is still being killed on most of Manufactures like Samsung, Huawei and so on because they has they own badly implemented BatteryOptimizations running parallel with native one... and if user want some app avoid to be killed while running in background it has to go long way to settings find provider specific settings and let app run....
here is an example how to change these provider specific settings on Slack
I think it is worst thing that happened to Android.....

Network Changed Broadcast Receiver does not execute in One Plus Phones

I have a BroadcastReciever name NetworkReciver.java that executes when Internet is Connected or Disconnected. And it is working well.
But when app is closed from recent apps, then NetworkReciver.java does not executes in One Plus 6 Phone while it works proper in Samsung Phones.
I am not getting why the behavior is different in One Plus Device
My Code:
Manifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<receiver android:name=".NetworkReciever" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
NetworkReciever.java:
public class NetworkReciever extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.i("TAG", "Network REceiver Executed");
}
}
Problem:
NetworkReciever does not execute when app is closed from recent apps in One Plus Device.
Starting in Android N, the system does not send CONNECTIVITY_ACTION broadcasts to manifest receivers of applications targeting N+.
Explicit BroadcastReceivers registered via Context.registerReceiver() continue to receive these broadcasts.
Solution: See ConnectivityManager.CONNECTIVITY_ACTION deprecated
Apps targeting Android 7.0+ do not receive CONNECTIVITY_ACTION broadcasts if they register to receive them in their manifest, and processes that depend on this broadcast will not start.
So, if you want to do some work when internet connection is available. You can use Job scheduler or work manager.
For example, here is sample code for job scheduler.
public static final int MY_BACKGROUND_JOB = 0;
...
public static void scheduleJob(Context context) {
JobScheduler js =
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo job = new JobInfo.Builder(
MY_BACKGROUND_JOB,
new ComponentName(context, MyJobService.class))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setRequiresCharging(true)
.build();
js.schedule(job);
}
When the conditions for your job are met, your app receives a callback to run the onStartJob() method in the specified JobService.class
Android JobScheduler Sample
Also, registering broadcasts in the activity's onCreate and unregistering it in onDestroy will not work for your case as you will not receive the broadcast after the app is killed.
In Android Nougat, Android does not broadcast for network changes to manifest registered BroadcastReceiver.
From the Android Nogout Changes & Also mentioned in ConnectivityManager
Monitor for changes in connectivity
Apps targeting Android 7.0 (API level 24) and higher do not receive
CONNECTIVITY_ACTION broadcasts if they declare the broadcast receiver
in their manifest. Apps will still receive CONNECTIVITY_ACTION
broadcasts if they register their BroadcastReceiver with
Context.registerReceiver() and that context is still valid.
Solution
NetworkReciever does not execute when app is closed from recent apps
I don't know why you want to get network changes after the app is closed. But in this case you have to make some periodic task with WorkManager or JobScheduler. I suggest you use WorkManager because it will work for all devices. whether JobScheduler is available only for devices >= 21 version. Here is a good example for WorkManager (It is quite easy).
Background solution (execute when only you need)
public class MyWorker extends Worker {
#Override
public Worker.Result doWork() {
// get online status
boolean isOnline = isOnline(getApplicationContext());
// Indicate success or failure with your return value:
return Result.SUCCESS;
// (Returning RETRY tells WorkManager to try this task again
// later; FAILURE says not to try again.)
}
public boolean isOnline(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
//should check null because in airplane mode it will be null
return (netInfo != null && netInfo.isConnected());
}
}
and schedule this Work at app start.
public static void scheduleWork() {
int TIME_INTERVAL_IN_SECONDS = 15;
PeriodicWorkRequest.Builder photoCheckBuilder = new PeriodicWorkRequest.Builder(MyWorker .class, TIME_INTERVAL_IN_SECONDS, TimeUnit.SECONDS);
PeriodicWorkRequest photoCheckWork = photoCheckBuilder.build();
WorkManager instance = WorkManager.getInstance();
if (instance != null) {
instance.enqueueUniquePeriodicWork("TAG", ExistingPeriodicWorkPolicy.KEEP, photoCheckWork);
}
}
Foreground solution (recommended)
Or if you just want to receive network changes when you app is live. You can below solution.
Register this receiver in your BaseActivity. or create one if you don't have yet any BaseActivity.
Register on onStart() and unregister on onStop(). Because you may not want to invoke your UI after onStop().
Here is BaseActivity.java
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
/**
* Created by KHEMRAJ on 9/5/2018.
*/
public class BaseActivity extends AppCompatActivity {
NetworkReceiver receiver;
public boolean isOnline;
#Override
protected void onStart() {
super.onStart();
isOnline = isOnline(this);
// register network change receiver
receiver = new NetworkReceiver();
registerReceiver(receiver, new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"));
}
#Override
protected void onStop() {
super.onStop();
// unregister network change receiver
unregisterReceiver(receiver);
receiver = null;
}
public class NetworkReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
isOnline = isOnline(context);
Log.i("TAG", "Network REceiver Executed");
}
}
public boolean isOnline(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
//should check null because in airplane mode it will be null
return (netInfo != null && netInfo.isConnected());
}
}
I suggested you WorkManger only, because I created a sample earlier
days with JobScheduler, EvernoteJobs,
AlarmManager, [JobService][7], and WorkManager. In which I started periodic task of 15 minutes with each of these. and
wrote logs of each in separate file when invoked.
Conclusion of this test was that. WorkManager and EvernoteJobs were
most efficient to do jobs. Now because EvernoteJobs will use
WorkManager from next version. So I came up with WorkManager.
Root cause:
From Android N OnePlus introduced a feature similar to Mi devices which prevent certain apps from auto-starting after reboot. I suspect that same feature is preventing your app to receive BroadcastReceiver as well.
Solution
Use AccessibilityService service in your app and ask user to turn on AccessibilityService for your app from Settings and boing doing this BroadcastReceiver in your app will work as expected.
Since AccessibilityService is a system level service, so by registering your own service you are passing the certain filter applied by these manufacturers and as soon as your custom AccessibilityService gets triggered by the OS, your app becomes active in receiving the eligible BroadcastReceiver that you had registered.
Here is how you can register your own AccessibilityService.
Create your custom AccessibilityService
public class MyAccessibilityService extends AccessibilityService {
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {//do nothing }
#Override
public void onInterrupt() { //do nothing}
}
Create configuration file my_accessibility_service.xml and add below code:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityFeedbackType="feedbackSpoken"
android:description="#string/service_desc"
android:notificationTimeout="100"/>
Add permission to AndroidManifest.xml file:
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"/>
Add your AccessibilityService in AndroidManifest.xml file:
<service
android:name=".MyAccessibilityService"
android:label="#string/app_name"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="#xml/my_accessibility_service"/>
</service>
You done!
Below is method to check status of AccessibilityService:
private static final int ACCESSIBILITY_ENABLED = 1;
public static boolean isAccessibilitySettingsOn(Context context) {
int accessibilityEnabled = 0;
final String service = context.getPackageName() + "/" + MyAccessibilityService.class.getCanonicalName();
try {
accessibilityEnabled = Settings.Secure.getInt(
context.getApplicationContext().getContentResolver(),
android.provider.Settings.Secure.ACCESSIBILITY_ENABLED);
} catch (Settings.SettingNotFoundException e) {
Log.e("AU", "Error finding setting, default accessibility to not found: "
+ e.getMessage());
}
TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');
if (accessibilityEnabled == ACCESSIBILITY_ENABLED) {
String settingValue = Settings.Secure.getString(
context.getApplicationContext().getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (settingValue != null) {
mStringColonSplitter.setString(settingValue);
while (mStringColonSplitter.hasNext()) {
String accessibilityService = mStringColonSplitter.next();
if (accessibilityService.equalsIgnoreCase(service)) {
return true;
}
}
}
}
return false;
}
Note: I have not tried but it may help.
Broadcast Receiver is not supported in Oreo as manifest tag, you must have to register it as a Service/ Activity with context.registerReceiver(). Or you use the WorkManager to schedule something for specific network conditions.
use this code in OnCreate
NetworkReciever receiver = NetworkReciever ()
IntentFilter filter = new IntentFilter();
filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
registerReceiver(receiver, filter);
don't forget to unregister it in onDestroy
#Override
protected void onDestroy() {
if (receiver != null) {
unregisterReceiver(receiver);
receiver = null;
}
super.onDestroy();
}
and delete this from Manifest
<receiver android:name=".NetworkReciever" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>

BluetoothLeScanner.startScan with Android 6.0 does not discover devices

I'm trying to use the function BluatoothLeScanner.startScan instead of the deprecated one BluetoothAdapter.startLeScan.
Yesterday I updated my Nexus 5 to Android 6.0 and since that moment my app does not work anymore.
I firstly add the preferences required ACCESS_COARSE_LOCATION as found here, https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id.
Then I added the permission as described here: https://developer.android.com/training/permissions/requesting.html.
But at the end it seems not working, it does not send back the ble devices.
This is my code:
manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.stm.sensitronapp">
<uses-sdk android:maxSdkVersion="23"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>`
DeviceScanActivity
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED){
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_COARSE_LOCATION)) {
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
MY_PERMISSIONS_REQUEST_ACCESS_COARSE);
}
}
// Device scan callback.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
mLeDeviceListAdapter.addDevice(result.getDevice());
mLeDeviceListAdapter.notifyDataSetChanged();
}
};
}
}
}
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
mSwipeRefreshLayout.setRefreshing(true);
mLeDeviceListAdapter.clear();
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
if(ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION ) == PackageManager.PERMISSION_GRANTED) {
mBluetoothLeScanner.startScan(mScanCallback);
}
}
EDIT: to solve this problem I only turned on the GPS. It is easy to do it programmatically in this way.
if permissions granted, have a try: turn ON the GPS.
Is you app prompting for Location permission on startup? If it's not, handle the code somewhere else so that it is being prompted.
Also you can check this to test if your app is working fine:
Open Settings > Apps > YourApplication > Permissions
and enable Location and then try to scan for results.
Location will be listed under permissions only if you have provided ACCESS_COARSE_LOCATION on manifest.
Using the solutions provided above works but the side effect is that you have to have location services turned on for something that doesn't need it. An ugly and unsatisfying work around is to specify the target version in your manifest to
android:targetSdkVersion="21"
It allows scanning on my Nexus 7 even though the installed version is 6.0.1. I do not know what the side effects are of targeting a lower version than the installed version but at least scanning works. Might be the only solution for GPS-less devices (if such devices exist).
Google should be crucified for this.
One - not perfect answer, is that you can still use the same old method BT scan method, once you have the new runtime Location permission enabled.
mBluetoothAdapter.startDiscovery();
.......
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = (BluetoothDevice) intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
mDeviceList.add(device);
}
}
};
It's an old question, but I will answer to help someone.
Unfortunately, the combination of ACCESS_COARSE_LOCATION and targetSdkVersion 22 does not work on some devices.This is not a good method, but I have solved it in the following way without using runtime permissions (ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION)
Set your 'targetSdkVersion' to 19 (I think maybe api19 ~ api22 will be possible)
Add the following permission to your manifest file
<uses-permission android:name="android.permission.READ_OWNER_DATA" />
<uses-permission android:name="android.permission.WRITE_OWNER_DATA" />
tested to Android 4.4 ~ 7.1.1
Set your 'minSdkVersion' to 18
targetSdkVersion 22

Android: Set Bluetooth Discoverability Unbounded

I have spent the last couple of days trying to make an app that keeps my Samsung Galaxy S3 mini (Android 2.1.4) discoverable for an "infinite" amount of time. My code looks currently as follows:
package com.example.downtoone;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.widget.Toast;
import com.example.downtoone.*;
import android.bluetooth.*;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
public class MainActivity extends Activity {
private BluetoothAdapter mBluetoothAdapter = null;
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
private static final int REQUEST_ENABLE_DSC = 3;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
}
#Override
public void onStart() {
super.onStart();
if (!mBluetoothAdapter.isEnabled()) {
Intent MDisc = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
MDisc.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,0);
startActivityForResult(MDisc, REQUEST_ENABLE_DSC);
}
}
#Override
public void onRestart(){
super.onRestart();
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onStop() {
super.onStop();
}
#Override
public void onDestroy() {
super.onDestroy();
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CONNECT_DEVICE:
if (resultCode == Activity.RESULT_OK) {
}
break;
case REQUEST_ENABLE_BT:
if (resultCode == Activity.RESULT_CANCELED) {
Toast.makeText(this, "BLUETOOTH NEEDS TO BE ENABLED AND DISCOVERABLE", Toast.LENGTH_SHORT).show();
finish();
}
break;
case REQUEST_ENABLE_DSC:
if (resultCode == Activity.RESULT_CANCELED) {
Toast.makeText(this, "BLUETOOTH NEEDS TO BE ENABLED AND DISCOVERABLE", Toast.LENGTH_SHORT).show();
//finish();
}
break;
}
}
public void finishBTsetup(){
}
}
Despite the fact that I am setting the time to '0', discoverability only runs for 2minutes. This is rather frustrating since I know the device can handle to be discoverable for an indefinite amount of time! ( I could manually access the bluetooth settings and set Bluetooth Visibility to 'Never Time Out'!)
I've looked all over for an answer without success... many posts give what (for a relative unskilled programmer such as me) look like arcane solutions that are either too vague(*), confusing(**) or downright wrong. A simple straightforward answer solving this issue (if it exists of course!) would be greatly appreciated!
(*)
Make Bluetooth on Android 2.1 discoverable indefinitely
(**)
Extend Android Bluetooth Discoverability
Android Application Bluetooth visibility duration (answer section)
MANIFEST:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.downtoone"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="14" />
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<application
android:allowBackup="true"
android:icon="#drawable/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>
</application>
</manifest>
EDIT:
To give people a little context, one of the goals of this application is to try and be DISCOVERABLE to all nearby Bluetooth devices so that it can directly talk to them. Since most smartphones are discoverable for short amounts of time (2min usually*) and only so when the user directly enables discoverability (= visibility), apps that scan for devices and automatically exchange data are impossible to implement. (* The user can usually set the visibility to 'No Time Out', but that requires the user to set that option directly under Bluetooth Settings of their smartphone, which is not a very elegant solution...)
I come to the same conclusion on three devices I have.
ANDROID v 4.3 and higher : EXTRA_DISCOVERABLE_DURATION 0 works no limit
ANDROIND v 4.1 : EXTRA_DISCOVERABLE_DURATION 0 is max 1 hour. Have to change manually to no limit in parameters.
above api level 14 EXTRA_DISCOVERABLE_DURATION 0 works with infinite limit but below this it works for max 1 hour.
This code works for me
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);
startActivityForResult(intent, Utils.REQUEST_DEVICE_DISCOVERABLE);
According to Android documentation, the maximum time for being discoverable is capped at 300seconds. You cannot make the BT discoverable forever.
Please see:
http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#ACTION_REQUEST_DISCOVERABLE
In order to get the 300second maximum period, you need to change one line of code as:
MDisc.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300)
Im not sure if this would suit your application or if theres some other reason why you don't want to do this but why not just discover for the default time then restart discovery when it times out? this way it will technically be an unlimited discovery, which will only trigger a VERY slight pause in between, I used this method in my application using a broadcast receiver.
I put startDiscovery() in the onStart() method to trigger discovery on activity start, then listen to ACTION_DISCOVERY_FINISHED in your broadcast receiver's onReceive() method, here place another call to startDiscovery().
this will loop the discovery forever, if you want to stop when you find a device then call cancelDiscovery() in you receiver's ACTION_FOUND listener, you can also place some checking here if you need to find a particular device - again in my case i was checking for a particular device's mac address so the discovery would continue until this was found.
not sure if this is any use but if you need more detail let me know.
I've arrived to the conclusion that it can't be done, unless the user goes to Bluetooth > Settings > Visibility timeout and sets the timeout accordingly.
Peace.
Works to me.
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
enableBtIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);
startActivityForResult(enableBtIntent, Utils.REQUEST_DEVICE_DISCOVERABLE);
Disable manually your Bluetooth and then run the code. It will works, yes.

Android bluetooth ACTION_DISCOVERY_FINISHED not working

I have written my first Android app and everything is working really well, except...in the routine, below, the ACTION_DISCOVERY_FINISHED never seems to get called (or broadcast or received or whatever). No matter what the block of code in that "else if" is not working.
I have only tested on my Motorola Atrix, so I am wondering if that is the issue. Since I am testing bluetooth functionality, I don't think I can use the Android emulator for effective testing.
Thoughts?
private BluetoothAdapter mBtAdapter;
mBtAdapter.startDiscovery();
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
//do something
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
//do something else
}
}
}
2 possibles solutions:
Instead of creating an annonymous receiver, subclass BroadcastReceiver with just the same implementation, then declare it in your project manifest (Remember to declare that your receiver receives these actions you want).
Dynamically register it from your activity/service, this way:
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
I'm not sure if you have to unregister it when registering it from an activity/service (I know you have to when registering from app's context) so check it out.
You need to add the line
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
to your manifest

Categories

Resources