Зачем обнаруживать маяки в фоновом режиме каждые 5-8 минут и как сделать его меньше этого? Почему обнаружение маяка прекращается через 15-30 минут? ОТВЕТЫ - PullRequest
1 голос
/ 07 апреля 2020

Мой вопрос уже в заголовке, а также через 5-7 минут didExit и didEnter вызвали вместе, потому что после этого времени будет вызываться didExit, затем вызывается didEnter, как я могу это проверить, (я знаю мой Engli sh очень плохо), пожалуйста, найдите мой код ниже

примечание: я удалил импорт, потому что есть ограничение

--------------- --------- ОБНОВЛЕНО -----------------------------

MainActivity.class


public class MainActivity extends AppCompatActivity {

    private AppBarConfiguration mAppBarConfiguration;
    protected static final String TAG = "MonitoringActivity";
    private static final int PERMISSION_REQUEST_FINE_LOCATION = 1;
    private static final int PERMISSION_REQUEST_BACKGROUND_LOCATION = 2;
    Intent mServiceIntent;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view);
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        mAppBarConfiguration = new AppBarConfiguration.Builder(
                R.id.nav_home, R.id.nav_profile, R.id.nav_slideshow)
                .setDrawerLayout(drawer)
                .build();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
        NavigationUI.setupWithNavController(navigationView, navController);


        verifyBluetooth();


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    if (this.checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
                            != PackageManager.PERMISSION_GRANTED) {
                        if (!this.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
                            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                            builder.setTitle("This app needs background location access");
                            builder.setMessage("Please grant location access so this app can detect beacons in the background.");
                            builder.setPositiveButton(android.R.string.ok, null);
                            builder.setOnDismissListener(new DialogInterface.OnDismissListener() {

                                @TargetApi(23)
                                @Override
                                public void onDismiss(DialogInterface dialog) {
                                    requestPermissions(new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION},
                                            PERMISSION_REQUEST_BACKGROUND_LOCATION);
                                }

                            });
                            builder.show();
                        }
                        else {
                            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                            builder.setTitle("Functionality limited");
                            builder.setMessage("Since background location access has not been granted, this app will not be able to discover beacons in the background.  Please go to Settings -> Applications -> Permissions and grant background location access to this app.");
                            builder.setPositiveButton(android.R.string.ok, null);
                            builder.setOnDismissListener(new DialogInterface.OnDismissListener() {

                                @Override
                                public void onDismiss(DialogInterface dialog) {
                                }

                            });
                            builder.show();
                        }
                    }
                }
            } else {
                if (!this.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
                    requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
                                    Manifest.permission.ACCESS_BACKGROUND_LOCATION},
                            PERMISSION_REQUEST_FINE_LOCATION);
                }
                else {
                    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                    builder.setTitle("Functionality limited");
                    builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons.  Please go to Settings -> Applications -> Permissions and grant location access to this app.");
                    builder.setPositiveButton(android.R.string.ok, null);
                    builder.setOnDismissListener(new DialogInterface.OnDismissListener() {

                        @Override
                        public void onDismiss(DialogInterface dialog) {
                        }

                    });
                    builder.show();
                }

            }
        }

        String URL = "";
        try {
            InputStream is = this.getAssets().open("config.properties");
            Properties props = new Properties();
            props.load(is);
            URL = props.getProperty("userModule");
            is.close();
        } catch (Exception e) {
        }
        Retrofit adapter = new Retrofit.Builder()
                .baseUrl(URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        APIService api = adapter.create(APIService.class);
        SharedPreferences userDetails = this.getSharedPreferences("userDetails", 0);
        Call<Map<String,Object>> call = api.loadUserByToken(userDetails.getString("accessToken", "").toString());
        View headerView = navigationView.getHeaderView(0);
        call.enqueue(new Callback<Map<String,Object>>() {
            @Override
            public void onResponse(Call<Map<String,Object>> call, Response<Map<String,Object>> response) {
                Map<String,Object> result = response.body();
                Map<String,Object> allData = (Map<String, Object>) result.get("result");
                Log.d("result",allData.toString());
                if(allData.get("ErrorResutl") != null){
                    SharedPreferences userDetails = getSharedPreferences("userDetails", 0);
                    SharedPreferences.Editor editor = userDetails.edit();
                    editor.putString("accessToken", null);
                    editor.commit();
                    Intent intent = new Intent(MainActivity.this, LoginActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                    finish();
                }
                SharedPreferences.Editor editor = userDetails.edit();
                editor.putString("data", allData.toString() );
                editor.commit();
                TextView username = (TextView) headerView.findViewById(R.id.username);
                TextView email = (TextView) headerView.findViewById(R.id.email);
                username.setText(allData.get("firstName").toString() + " " + allData.get("lastName").toString());
                email.setText(allData.get("email").toString());
            }
            @Override
            public void onFailure(Call<Map<String,Object>> call, Throwable t) {
                Snackbar.make(findViewById(android.R.id.content), t.toString(), Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        Intent intent = new Intent(this, BeaconActivity.class);
        startActivity(intent);
        // Important:  make sure to add android:launchMode="singleInstance" in the manifest
        // to keep multiple copies of this activity from getting created if the user has
        // already manually launched the app.
    }


    private void verifyBluetooth() {

        try {
            if (!BeaconManager.getInstanceForApplication(this).checkAvailability()) {
                final AlertDialog.Builder builder = new AlertDialog.Builder(this);

                startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE),1);
            }
        } catch (RuntimeException e) {
            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("Bluetooth LE not available");
            builder.setMessage("Sorry, this device does not support Bluetooth LE.");
            builder.setPositiveButton(android.R.string.ok, null);
            builder.setOnDismissListener(new DialogInterface.OnDismissListener() {

                @Override
                public void onDismiss(DialogInterface dialog) {
                    finish();
                    System.exit(0);
                }

            });
            builder.show();

        }

    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1) {
            if (resultCode != RESULT_OK) {
                verifyBluetooth();
            }
        }
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        return NavigationUI.navigateUp(navController, mAppBarConfiguration)
                || super.onSupportNavigateUp();
    }


}


BeaconActivity.class


public class BeaconActivity extends Activity implements  BeaconConsumer  {
    protected static final String TAG = "RangingActivity";
    private BeaconManager beaconManager = BeaconManager.getInstanceForApplication(this);

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("naji","beaconactivity");
            beaconManager.bind(this);
        super.onBackPressed();

    }

    public BeaconManager getBeaconManager() {
        return beaconManager;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        beaconManager.unbind(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        beaconManager.unbind(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        beaconManager.bind(this);
    }


    @Override
    public void onBeaconServiceConnect() {

        RangeNotifier rangeNotifier = new RangeNotifier() {
            @Override
            public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
                if (beacons.size() > 0) {
                    Log.d(TAG, "didRangeBeaconsInRegion called with beacon count:  "+beacons.size());
                    for (Beacon beacon: beacons) {
                        Log.d("naji","The beacon " + beacon.toString() + " is about " + beacon.getDistance() + " meters away."+ beacon.getServiceUuid());
                        Collection<Region> monitoredRegions = beaconManager.getMonitoredRegions();
                        boolean duplicate = false;
                        for (Region monitoredRegion :monitoredRegions) {
                            if(monitoredRegion.getId1() != null && monitoredRegion.getId1().equals(beacon.getId1())){
                                duplicate = true;
                                break;
                            }
                        }
                        if(!duplicate && beacon.getId1() != null){
                            Log.d(TAG, "duplicate:  False ");
                            try {
                                beaconManager.startMonitoringBeaconsInRegion(new Region(beacon.getId1().toString(),beacon.getId1(),beacon.getId2(),beacon.getId3()));
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            }
                        } else {
                            Log.d(TAG, "duplicate:  True ");
                        }

                    }
                }
            }
        };
        try {
            beaconManager.startRangingBeaconsInRegion(new Region("myRangingUniqueId", null, null, null));
            beaconManager.addRangeNotifier(rangeNotifier);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

BeaconApplication.calss



public class BeaconApplication extends Application implements BootstrapNotifier {
    private BeaconActivity beaconActivity;
    private static final String TAG = "BeaconReferenceApp";
    private RegionBootstrap regionBootstrap;
    private BackgroundPowerSaver backgroundPowerSaver;
    private boolean haveDetectedBeaconsSinceBoot = false;
    private String cumulativeLog = "";
    BeaconManager beaconManager ;
    public void onCreate() {
        super.onCreate();
        beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
        beaconManager.setDebug(false);
        beaconManager.setEnableScheduledScanJobs(false);
        beaconManager.setBackgroundBetweenScanPeriod(0);
        beaconManager.setBackgroundScanPeriod(1100);
        beaconManager.setForegroundBetweenScanPeriod(0);
        beaconManager.setForegroundScanPeriod(1100);
        beaconManager.getBeaconParsers().add(new BeaconParser().
                setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
        Notification.Builder builder = new Notification.Builder(this);
        builder.setSmallIcon(R.drawable.ic_launcher_background);
        builder.setContentTitle("Scanning for Beacons");
        beaconManager.enableForegroundServiceScanning(builder.getNotification(),0);
        Log.d(TAG, "setting up background monitoring for beacons and power saving");
        Region region = new Region("myRangingUniqueId",
            null, null, null);
        regionBootstrap = new RegionBootstrap(this, region);
        backgroundPowerSaver = new BackgroundPowerSaver(this);

        // OneSignal Initialization
        OneSignal.startInit(this)
                .inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification)
                .unsubscribeWhenNotificationsAreDisabled(true)
                .setNotificationOpenedHandler(new ExampleNotificationOpenedHandler())
                .setNotificationReceivedHandler(new ExampleNotificationReceivedHandler())
                .autoPromptLocation(true)
                .init();

        OSPermissionSubscriptionState status = OneSignal.getPermissionSubscriptionState();
        status.getPermissionStatus().getEnabled();
        status.getSubscriptionStatus().getSubscribed();
        status.getSubscriptionStatus().getUserSubscriptionSetting();
        status.getSubscriptionStatus().getUserId();
        status.getSubscriptionStatus().getPushToken();
        Log.d(TAG, "status.getSubscriptionStatus().getUserId(); --->"+status.getSubscriptionStatus().getUserId());
        SharedPreferences userDetails = getSharedPreferences("userDetails", 0);
        SharedPreferences.Editor editor = userDetails.edit();
        editor.putString("player_id", status.getSubscriptionStatus().getUserId());
        editor.commit();


    }

    private class ExampleNotificationOpenedHandler implements OneSignal.NotificationOpenedHandler {
        private ExampleNotificationOpenedHandler() {
        }

        public void notificationOpened(OSNotificationOpenResult result) {
            Log.i("OneSignalExample", result.toString());
            OSNotificationAction.ActionType actionType = result.action.type;
            JSONObject data = result.notification.payload.additionalData;
            if (data != null) {
                String customKey = data.optString("customkey", null);
                if (customKey != null) {
                    Log.i("OneSignalExample", "customkey set with value: " + customKey);
                }
            }
            if (actionType == OSNotificationAction.ActionType.ActionTaken) {
                Log.i("OneSignalExample", "Button pressed with id: " + result.action.actionID);
            }
        }
    }

    private class ExampleNotificationReceivedHandler implements OneSignal.NotificationReceivedHandler {
        private ExampleNotificationReceivedHandler() {
        }

        @Override
        public void notificationReceived(OSNotification notification) {
            Log.i("OneSignalExample", notification.payload.additionalData.toString());
//             BeaconManager beaconManager = BeaconManager.getInstanceForApplication(beaconActivity);
//             beaconManager.bind(beaconActivity);

        }
    }

    @Override
    public void didEnterRegion(Region arg0) {
        if(arg0.getId1() != null) {
            pushNotification(arg0,"enter");
        }
//        Intent intent = new Intent(this, MainActivity.class);
//        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//        this.startActivity(intent);
    }

    @Override
    public void didExitRegion(Region region) {
        if(region.getId1() != null) {
            pushNotification(region, "exit");
        }
    }

    @Override
    public void didDetermineStateForRegion(int state, Region region) {
        Log.d(TAG,"Current region state is: " + (state == 1 ? "INSIDE" : "OUTSIDE ("+state+")"));



        RangeNotifier rangeNotifier = new RangeNotifier() {
            @Override
            public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
                if (beacons.size() > 0) {
                    Log.d(TAG, "didRangeBeaconsInRegion called with beacon count:  "+beacons.size());
                    for (Beacon beacon: beacons) {
                        Log.d("naji","The beacon " + beacon.toString() + " is about " + beacon.getDistance() + " meters away."+ beacon.getServiceUuid());
                        Collection<Region> monitoredRegions = beaconManager.getMonitoredRegions();
                        boolean duplicate = false;
                        for (Region monitoredRegion :monitoredRegions) {
                            if(monitoredRegion.getId1() != null && monitoredRegion.getId1().equals(beacon.getId1())){
                                duplicate = true;
                                break;
                            }
                        }
                        if(!duplicate && beacon.getId1() != null){
                            Log.d(TAG, "duplicate:  False ");
                            try {
                                beaconManager.startMonitoringBeaconsInRegion(new Region(beacon.getId1().toString(),beacon.getId1(),beacon.getId2(),beacon.getId3()));
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            }
                        } else {
                            Log.d(TAG, "duplicate:  True ");
                        }

                    }
                }
            }
        };
        try {
            beaconManager.startRangingBeaconsInRegion(new Region("myRangingUniqueId", null, null, null));
            beaconManager.addRangeNotifier(rangeNotifier);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }


    private void pushNotification(Region region,String action){
        String URL = "";
        try {
            InputStream is = BeaconApplication.this.getAssets().open("config.properties");
            Properties props = new Properties();
            props.load(is);
            URL = props.getProperty("hospitalModule");
            is.close();
        } catch (Exception e) {
        }
        Retrofit adapter = new Retrofit.Builder()
                .baseUrl(URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        //Creating an object of our api interface
        APIService api = adapter.create(APIService.class);
        //Defining the method
        SharedPreferences userDetails = getSharedPreferences("userDetails", 0);
        Map<String, Object> object = new LinkedHashMap<>();
        List<String> player_id = new ArrayList<>();
        player_id.add("\""+userDetails.getString("player_id", "")+"\"");
        object.put("type", action);
        object.put("player_id", player_id);
        if(region.getId1() == null){
            object.put("uuid", "no uuid");
        } else {
            object.put("uuid", region.getId1().toString());
        }
        Call<Map<String, Object>> call = api.pushNotification(userDetails.getString("accessToken", ""), object);
        call.enqueue(new Callback<Map<String, Object>>() {
            @Override
            public void onResponse(Call<Map<String, Object>> call, Response<Map<String, Object>> response) {
                Map<String, Object> result = response.body();
                Log.d("result", result.toString());
                Map<String, Object> allData = (Map<String, Object>) result.get("result");
                if (allData.get("ErrorResutl") != null) {
                    SharedPreferences userDetails = getSharedPreferences("userDetails", 0);
                    SharedPreferences.Editor editor = userDetails.edit();
                    editor.putString("accessToken", null);
                    editor.commit();
                    Intent intent = new Intent(BeaconApplication.this, LoginActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                }
            }

            @Override
            public void onFailure(Call<Map<String, Object>> call, Throwable t) {
            }
        });
    }
}

AndroidManifiets. xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.isleem.hospital">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ALLOW_BACKGROUND_LOCATION" />

<!--android:allowBackup="true" in beacon activity android:launchMode="singleTop"-->
    <application
        android:name=".application.BeaconApplication"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme.NoActionBar">
        <service android:name="org.altbeacon.beacon.service.BeaconService" tools:node="replace">
            <meta-data android:name="longScanForcingEnabled" android:value="true"/>
        </service>
        <meta-data android:name="com.onesignal.NotificationOpened.DEFAULT" android:value="DISABLE" />
        <activity android:name=".activities.MainActivity" />
        <activity android:name=".activities.BeaconActivity"   android:theme="@style/noAnimTheme"/>
        <activity
            android:name=".activities.LoginActivity"
            android:label="@string/app_name"
            android:launchMode="singleInstance"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

    </application>
</manifest>

Ответы [ 2 ]

0 голосов
/ 10 апреля 2020

Наконец-то все работает нормально, я ничего не изменил в коде, но я изменяю настройки на своем мобильном телефоне (батарея -> Запуск приложения -> отключить управление автоматами c, но в нем все параметры включены) но если кто-нибудь может сделать это программно, пожалуйста, дайте мне знать.

0 голосов
/ 08 апреля 2020

Показанный код, вероятно, не совместим с фоновыми ограничениями для Android 8+. В частности, создается пользовательская служба с именем BeaconService, которая пытается запускать BeaconActivity каждые 60 секунд. Я не верю, что это окажется надежным - операционная система убьет активность, когда она не видна, и неясно, сработают ли попытки ее воссоздания. Даже если они работают в краткосрочной перспективе, они, вероятно, не будут работать в долгосрочной перспективе.

Я предлагаю вам упростить подход и оставить весь код маяка в классе Application. (Вы можете перемещать logi c в служебные классы POJO по мере необходимости, чтобы поддерживать чистоту, но я бы не стал добавлять какие-либо новые службы для обнаружения маяков. Встроенная служба переднего плана, предоставляемая библиотекой, должна быть достаточно хорошей.) может запускать маяк в обратном вызове didDetermineStateForRegion в классе Application, что избавит вас от необходимости привязывать / отсоединять BeaconManager и реализовывать экземпляры BeaconConsumer.

Используя описанный выше упрощенный подход, если вам нужно сообщить об обнаружении маяка BeaconActivity, вы можете сделать это с помощью LocalBroadcastManager. См. здесь , как вы можете это сделать.

...