Cannot able run Bluetooth Scanning in Foreground service more than 10 - 15 secs even though Notification is provided

£可爱£侵袭症+ 提交于 2021-02-11 06:25:39

问题


I have used Service to keep my scan for android mobiles even when the app is closed. I used Broadcast receiver to restart my service when killed. It restarts the scanning and it works only for some 15 seconds and then stops When i click button1 in {MainActivity} I started the service and have called startdiscovery() in startCommand method in {ExampleService} Please Help me in running the app in background

MainActivity.java

import android.Manifest;
import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.bluetooth.le.ScanResult;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.ResolvableApiException;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResponse;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.FirebaseFirestore;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class MainActivity extends AppCompatActivity {
   ListView scanListView;
    ArrayList<String> stringArrayList = new ArrayList<String>();
    ArrayAdapter<String> arrayAdapter;
    static BluetoothAdapter myAdapter = BluetoothAdapter.getDefaultAdapter();
    FirebaseFirestore db = FirebaseFirestore.getInstance();

    static int count=0;
    ScanResult sc;
    String Uuid;
    Date currentTime;
    private LocationSettingsRequest.Builder builder;
    private final int REQUEST_CHECK_CODE=8989;
    public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
    LocationManager locationm;
    String provider;
    Button button1;
    BluetoothAdapter bluetoothAdapter;
    Intent btEnablingIntent;
    int requestCodeForEnable;
    Button button;
    Button scanButton1;
    RegisterActivity registerActivity=new RegisterActivity();
    String email ;
    String phone ;

///
Intent discoverableIntenet = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
Intent mServiceIntent;

    private ExampleService mYourService;
    Context ctx;
    public Context getCtx() {
        return ctx;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);



   currentTime = Calendar.getInstance().getTime();
        setContentView(R.layout.activity_main);

        checkLocationPermission();

        btEnablingIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        requestCodeForEnable=1;
        discoverableIntenet.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 3000);
        startActivity(discoverableIntenet);
        button=(Button) findViewById(R.id.button4);
        Intent intent = new Intent(MainActivity.this,ble.class);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Intent intent = new Intent(MainActivity.this,ble.class);
                MainActivity.this.startActivity(intent);
            }
        });
        button=(Button) findViewById(R.id.button6);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                open(view);
            }
        });
        button=(Button) findViewById(R.id.button3);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                pdfs(view);
            }
        });
        button=(Button) findViewById(R.id.button5);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myths(view);
            }
        });


        button1=(Button) findViewById(R.id.button2);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                analytics(view);
            }
        });
        scanListView = (ListView) findViewById(R.id.scannedListView);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        scanButton1=(Button) findViewById(R.id.Button1);
        scanButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("disc","discoveeery!");
                Log.i("hiiiiiii", String.valueOf(myAdapter.isDiscovering()));
                Intent serviceIntent = new Intent(MainActivity.this, ExampleService.class);
                serviceIntent.putExtra("inputExtra", "hi");
//                startService( serviceIntent);

                mYourService = new ExampleService();
                mServiceIntent = new Intent(MainActivity.this, mYourService.getClass());
                if (!isMyServiceRunning(mYourService.getClass())) {
                    startService(mServiceIntent);
                }

            }
        });
        bluetoothOnMethod();
        BluetoothFunctions();


   }
    public void BluetoothFunctions(){


        Log.d("disc", "discovery!");
        IntentFilter intentFilter;
        intentFilter=new IntentFilter(BluetoothDevice.ACTION_FOUND);
        registerReceiver(myreceiver, intentFilter);
        intentFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        registerReceiver(myreceiver, intentFilter);
        arrayAdapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, stringArrayList);
        scanListView.setAdapter(arrayAdapter);
        Uuid="02.020202.020.02";
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == requestCodeForEnable) {
            if (resultCode == RESULT_OK) {
                Toast.makeText(getApplicationContext(), "Bluetooth is enabled", Toast.LENGTH_LONG).show();
            }
            else if(resultCode==RESULT_CANCELED) {
                Toast.makeText(getApplicationContext(), "Bluetooth enabling cancelled", Toast.LENGTH_LONG).show();
            }
        }
    }


    final BroadcastReceiver myreceiver = new BroadcastReceiver() {

        @RequiresApi(api = Build.VERSION_CODES.O)
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (device.getName() == null) {
                    return;
                }
                String address = device.getName();
                int N = 2;
                float type = intent.getFloatExtra((BluetoothDevice.EXTRA_UUID),Float.MIN_VALUE);
                int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
                String rssi_val = String.valueOf(rssi);
                String data = device.getAddress() + "   " + rssi_val;
                Vibrator v1 = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                stringArrayList.add(data);
                if (rssi >= -50) {
                   v1.vibrate(VibrationEffect.createOneShot(1000, VibrationEffect.DEFAULT_AMPLITUDE));
                    count++;
                    if (device.getAddress() != null) {
                        Firebasepush(device.getAddress(), rssi_val);
                    }
                }
                Log.i("lll", device.getAddress());
                Log.i("lll", device.getName());
                Log.i("+>>>>>>>>>>>>>", BluetoothDevice.EXTRA_UUID);
                Log.i("lll", rssi_val);
                arrayAdapter.notifyDataSetChanged();
                //  Toast.makeText(getApplicationContext(),"  TX power: " +sc.getTxPower() + "dBm", Toast.LENGTH_SHORT).show();
                //startThread();
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                Log.v("ggggggggg", "Entered the Finished ");
                myAdapter.startDiscovery();
            }
        }
    };

public void Firebasepush(String uuid,String rrsi){
    Map<String, Object> updateMap = new HashMap();
    updateMap.put("RSSI", rrsi);
    updateMap.put("time", currentTime);
    Map<String, Object> countMap = new HashMap();
    countMap.put("Count", count);
    countMap.put("time", currentTime);
    countMap.put("Name",registerActivity.NameString);
    countMap.put("Email",registerActivity.EmailId);
   countMap.put("Phone Number",registerActivity.PhoneNumber);
// Add a new document with a generated ID
    db.collection("users").document(Uuid).collection("contacts").document(uuid)
            .set(updateMap);
    db.collection("users").document(Uuid).
            set(countMap);
}
    void bluetoothOnMethod() {
        if(bluetoothAdapter==null){
            Toast.makeText(getApplicationContext(), "Bluetooth does not support ",Toast.LENGTH_LONG).show();
        }
        else {
            if(!bluetoothAdapter.isEnabled()){
                startActivityForResult(btEnablingIntent,requestCodeForEnable);
            }
        }
    }
    public boolean checkLocationPermission() {
        LocationRequest request = new LocationRequest()
                .setFastestInterval(1500)
                .setInterval(3000)
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        builder = new LocationSettingsRequest.Builder()
                .addLocationRequest(request);
        Task<LocationSettingsResponse> result = LocationServices.getSettingsClient( this).checkLocationSettings(builder.build());
        result.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() {
            @Override
            public void onComplete(@NonNull Task<LocationSettingsResponse> task) {
                try{
                    task.getResult(ApiException.class);
                }catch (ApiException e){
                    switch (e.getStatusCode())
                    {
                        case LocationSettingsStatusCodes
                                .RESOLUTION_REQUIRED:
                            try {
                                ResolvableApiException resolvableApiException= (ResolvableApiException) e;
                                resolvableApiException.startResolutionForResult(MainActivity.this,REQUEST_CHECK_CODE);
                            } catch (IntentSender.SendIntentException ex) {
                                ex.printStackTrace();
                            }catch (ClassCastException ex){
                            }break;
                        case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                        { break;}
                    }
                }
            }
        });
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.ACCESS_FINE_LOCATION)) {
                // Show an explanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission.
                new AlertDialog.Builder(this)
                        .setTitle(R.string.title_location_permission)
                        .setMessage(R.string.text_location_permission)
                        .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                //Prompt the user once explanation has been shown
                                ActivityCompat.requestPermissions(MainActivity.this,
                                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                        MY_PERMISSIONS_REQUEST_LOCATION);
                            }
                        })
                        .create()
                        .show();
            } else {
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                        MY_PERMISSIONS_REQUEST_LOCATION);
            }
            return false;
        } else {
            return true;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,String permissions[], int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    // permission was granted, yay! Do the
                    // location-related task you need to do.
                    if (ContextCompat.checkSelfPermission(this,
                            Manifest.permission.ACCESS_FINE_LOCATION)
                            == PackageManager.PERMISSION_GRANTED) {
                        //Request location updates:
                        //  locationm.requestLocationUpdates(provider, 400, 1,this);
                    }
                } else {
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                }
                return;
            }

        }
    }

    private boolean isMyServiceRunning(Class<?> serviceClass) {
        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (serviceClass.getName().equals(service.service.getClassName())) {
                Log.i ("Service status", "Running");
                return true;
            }
        }
        Log.i ("Service status", "Not running");
        return false;
    }


    @Override
    protected void onDestroy() {

        Intent broadcastIntent = new Intent();
        broadcastIntent.setAction("restartservice");
        broadcastIntent.setClass(this, Restarter.class);
        this.sendBroadcast(broadcastIntent);
        super.onDestroy();

        // Don't forget to unregister the ACTION_FOUND receiver.
    //    unregisterReceiver(myreceiver);
    }
    public void openservices(){
        Intent intnt=new Intent(this ,Services.class);
        startActivity(intnt);
    }
    public void open(View view)
    {
        Intent browserIntent=new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.hogist.com/#/"));
        startActivity(browserIntent);
    }
    public void pdfs(View view)
    {
        Intent browserIntent=new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.mohfw.gov.in/pdf/Illustrativeguidelineupdate.pdf"));
        startActivity(browserIntent);
    }
    public void myths(View view)
    {
        Intent browserIntent=new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.mohfw.gov.in/pdf/Illustrativeguidelineupdate.pdf"));
        startActivity(browserIntent);
    }
    public void analytics(View view){
        final Intent intent1 = new Intent(MainActivity.this, Analytics.class);
        startActivity(intent1);
    }

}

ExampleService.java

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;

import java.util.Timer;
import java.util.TimerTask;

public class ExampleService extends Service {
      BluetoothAdapter myAdapter = BluetoothAdapter.getDefaultAdapter();
      MainActivity mainActivity=new MainActivity();
    public int counter=0;

    @Override
    public void onCreate() {
        super.onCreate();
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
            startMyOwnForeground();
        else
            startForeground(1, new Notification());
    }

    @RequiresApi(Build.VERSION_CODES.O)
    private void startMyOwnForeground()
    {
        String NOTIFICATION_CHANNEL_ID = "example.permanence";
        String channelName = "Background Service";
        NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
        chan.setLightColor(Color.BLUE);
        chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);

        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        assert manager != null;
        manager.createNotificationChannel(chan);

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
        Notification notification = notificationBuilder.setOngoing(true)
                .setContentTitle("App is running in background")
                .setPriority(NotificationManager.IMPORTANCE_MIN)
                .setCategory(Notification.CATEGORY_SERVICE)
                .build();
        startForeground(2, notification);
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
    //    startTimer();
        myAdapter.startDiscovery();
        return START_STICKY;
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
       // stoptimertask();
myAdapter.cancelDiscovery();
        Intent broadcastIntent = new Intent();
        broadcastIntent.setAction("restartservice");
        broadcastIntent.setClass(this, Restarter.class);
        this.sendBroadcast(broadcastIntent);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

}```

Restarter.java


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;

public class Restarter extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("Broadcast Listened", "Service tried to stop");
        Toast.makeText(context, "Service restarted", Toast.LENGTH_SHORT).show();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            Log.i(Restarter.class.getSimpleName(), "Service Stops! Oooooooooooooppppssssss!!!!");
            context.startForegroundService(new Intent(context, ExampleService.class));
        } else {
            context.startService(new Intent(context, ExampleService.class));

        }
    }
}

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.hogist_social_distancing">

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <application
        android:name=".App"
        android:fullBackupContent="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=".Analytics"
            android:screenOrientation="portrait" />
        <activity
            android:name=".Services"
            android:screenOrientation="portrait" />
        <activity
            android:name=".Permissions"
            android:screenOrientation="portrait" />
        <activity
            android:name=".MainActivity"
            android:screenOrientation="portrait" />
        <activity android:name=".RegisterActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".OTPActivity" />
        <activity android:name=".ble" />

        <service
            android:name=".ExampleService"
            android:enabled="true" />

        <receiver
            android:name="Restarter"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="restartservice" />
            </intent-filter>
        </receiver>

    </application>

</manifest>```

回答1:


Android strives to save the battery, so it's expected that your service is stopped, especially if it runs battery draining operations such as Bluetooth scans.

Also, bare in mind that starting from Android 7, an app cannot start the BLE scan more than 5 times per 30 seconds, as mentioned here. Other issues related to BLE scanning are listed here.

If you do want to run Bluetooth scans in the background, I suggest you use a JobIntentService, in which you start BLE scan for a few seconds.

JobIntentService is very similar to IntentService but with few benefits like holding a wake lock which prevents the CPU to go to sleep

Also, this type of service does not require displaying a notification to your user. For more info: https://developer.android.com/reference/androidx/core/app/JobIntentService




回答2:


  1. are you sure your bluetooth code can work well on activity (without service)?
  2. you can not restart your service by call Broadcast when you service was killed, because when your service was killed by OS system, it will kill your application process so your broadcast will not work. When you call return START_STICKY; it means system will automatic restart your service when it have available resource


来源:https://stackoverflow.com/questions/63513734/cannot-able-run-bluetooth-scanning-in-foreground-service-more-than-10-15-secs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!