Автозапуск на Eddystone-UID в пределах 1 метра

Я хочу автоматически запускать свою активность, когда маяк находится в пределах 1 метра. Этот вопрос был задан ранее , но я не могу заставить свою работать, используя/изменив его код.

Как и в этом посте, я выполнил те же действия с библиотекой маяков Android через altbeacon. github, но до сих пор не увенчались успехом.

У меня также есть «скомпилировать» org.altbeacon: android-beacon-library: 2.7+ «» в файле build.gradle.

AndroidManifest.xml:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.communionchapelefca.ccsatx" android:versionCode="1" android:versionName="1.0">
    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23"/>
    <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_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    "android.hardware.bluetooth_le" android:required="false"/>
    <uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>

    <application 
android:allowBackup="true" 
android:icon="@mipmap/ic_launcher" 
android:label="@string/app_name" 
android:theme="@style/AppTheme">
    <activity 
android:name="org.communionchapelefca.ccsatx.SplashScreen" android:label="@string/app_name" 
android:launchMode="singleInstance">
    <intent-filter>
    <action android:name="android.intent.action.MAIN"/>
    <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
    </activity>
    <activity 
android:name="org.communionchapelefca.ccsatx.MainActivity" android:label="@string/app_name" 
android:launchMode="singleInstance">
    <intent-filter>
    <action android:name="org.communionchapelefca.ccsatx.MAINACTIVITY"/>
    <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
    </activity>
    </application>
    </manifest>

MainActivity.java

import android.Manifest;
        import android.app.Activity;
        import android.app.AlertDialog;
        import android.app.Application;
        import android.content.DialogInterface;
        import android.content.Intent;
        import android.content.pm.PackageManager;
        import android.graphics.Bitmap;
        import android.os.Build;
        import android.os.Bundle;
        import android.os.RemoteException;
        import android.util.Log;
        import android.view.KeyEvent;
        import android.view.Menu;
        import android.view.MenuItem;
        import android.webkit.WebSettings;
        import android.webkit.WebView;
        import android.webkit.WebViewClient;
        import android.widget.ProgressBar;

        import org.altbeacon.beacon.Beacon;
        import org.altbeacon.beacon.BeaconManager;
        import org.altbeacon.beacon.BeaconParser;
        import org.altbeacon.beacon.RangeNotifier;
        import org.altbeacon.beacon.Region;
        import org.altbeacon.beacon.powersave.BackgroundPowerSaver;
        import org.altbeacon.beacon.startup.BootstrapNotifier;
        import org.altbeacon.beacon.startup.RegionBootstrap;

        import java.util.Collection;


public class MainActivity extends Activity implements BootstrapNotifier, RangeNotifier {
    public static final String TAG = "MainActivityCCSATX";
    private WebView mWebView;
    ProgressBar progressBar;
        private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;


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

                setContentView(R.layout.activity_main);

                mWebView = (WebView) findViewById(R.id.activity_main_webview);

                progressBar = (ProgressBar) findViewById(R.id.progressBar1);

                WebSettings webSettings = mWebView.getSettings();
                webSettings.setJavaScriptEnabled(true);
                mWebView.loadUrl("http://communionchapelefca.org/edy-home");
                mWebView.setWebViewClient(new HelloWebViewClient());

                // begin code for bluetooth permission for android 6
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    // Android M Permission check

                    if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                        builder.setTitle("This app needs location access to find Communion Chapel beacons");
                        builder.setMessage("Please grant location access so this app can detect Communion Chapel beacons.");
                        builder.setPositiveButton(android.R.string.ok, null);
                        builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
                            @Override
                            public void onDismiss(DialogInterface dialog) {
                                requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
                            }
                        });
                        builder.show();
                    }
                }

                mAllBeaconsRegion = new Region("all beacons", null, null, null);
                mBeaconManager = BeaconManager.getInstanceForApplication(this);
                mBackgroundPowerSaver = new BackgroundPowerSaver(this);
                mRegionBootstrap = new RegionBootstrap(this, mAllBeaconsRegion);

                // By default the AndroidBeaconLibrary will only find AltBeacons.  If you wish to make it
                // find a different type of beacon, you must specify the byte layout for that beacon's
                // advertisement with a line like below.  The example shows how to find a beacon with the
                // same byte layout as AltBeacon but with a beaconTypeCode of 0xaabb
                //
                Log.d(TAG, " region.  starting ranging");

                mBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
                mBeaconManager.setBackgroundScanPeriod(11000l);

            }

            @Override
            public void onRequestPermissionsResult(int requestCode,
                                                   String permissions[], int[] grantResults) {
                switch (requestCode) {
                    case PERMISSION_REQUEST_COARSE_LOCATION: {
                        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                            Log.d(TAG, "coarse location permission granted");
                        } 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 when in the background.");
                            builder.setPositiveButton(android.R.string.ok, null);
                            builder.setOnDismissListener(new DialogInterface.OnDismissListener() {

                                @Override
                                public void onDismiss(DialogInterface dialog) {
                                }

                            });
                            builder.show();
                        }
                        return;
                    }
                }
            }

        // end code for bluetooth permission for android 6



    private class HelloWebViewClient extends WebViewClient{


        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            // TODO Auto-generated method stub
            super.onPageStarted(view, url, favicon);
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView webView, String url)
        {
            webView.loadUrl(url);
            return true;
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            // TODO Auto-generated method stub
            super.onPageFinished(view, url);

            progressBar.setVisibility(view.GONE);
        }

    }


    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event)
    { //if back key is pressed
        if((keyCode == KeyEvent.KEYCODE_BACK)&& mWebView.canGoBack())
        {
            mWebView.goBack();
            return true;

        }

        return super.onKeyDown(keyCode, event);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public void onBackPressed() {
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
                MainActivity.this);

        // set title
        alertDialogBuilder.setTitle("Exit");

        // set dialog message
        alertDialogBuilder
                .setMessage("Do you really want to exit?")
                .setCancelable(false)
                .setPositiveButton("Yes",new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog,int id) {
                        // if this button is clicked, close
                        // current activity
                        MainActivity.this.finish();
                    }
                })
                .setNegativeButton("No",new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog,int id) {
                        // if this button is clicked, just close
                        // the dialog box and do nothing
                        dialog.cancel();
                    }
                });

        // create alert dialog
        AlertDialog alertDialog = alertDialogBuilder.create();

        // show it
        alertDialog.show();
    }


    private RegionBootstrap regionBootstrap;
    private BeaconManager mBeaconManager;
    private Region region;
    private Region mAllBeaconsRegion;
    private BackgroundPowerSaver mBackgroundPowerSaver;
    private RegionBootstrap mRegionBootstrap;

    @Override
    public void didDetermineStateForRegion(int arg0, Region arg1) {
        // Don't care
    }

    @Override
    public void didEnterRegion(Region arg0) {

        mRegionBootstrap.disable();
        // This call to disable will make it so the activity below only gets launched the first time a beacon is seen (until the next time the app is launched)
        // if you want the Activity to launch every single time beacons come into view, remove this call.
        try {

            mBeaconManager.startRangingBeaconsInRegion(new Region("all beacons", null, null, null));
            mBeaconManager.setRangeNotifier(this);
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        Log.d(TAG, "Got a didEnterRegion call");

    }

    @Override
    public void didExitRegion(Region arg0) {
        // Don't care
    }

    @Override
    public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
        // TODO Auto-generated method stub
        if (beacons.size() > 0) {

            for (Beacon beacon: beacons) {
                Log.d(TAG, "Found a beacon, getting distance");
                if(beacon.getDistance()<1)
                {
                    Log.d(TAG, "within 1 minute call");
                    Intent intent = new Intent(this, MainActivity.class);
                    // IMPORTANT: in the AndroidManifest.xml definition of this activity, you must set android:launchMode="singleInstance" or you will get two instances
                    // created when a user launches the activity manually and it gets launched from here.
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    this.startActivity(intent);
                }

            }

        }
    }
}

LogCat от фатальной ошибки:

01-28 17:23:38.819  6549  6724 D MainActivityCCSATX: Got a didEnterRegion call
01-28 17:23:38.824  6549  6549 D BluetoothAdapter: STATE_ON
01-28 17:23:38.824  6549  6549 D BluetoothLeScanner: could not find callback wrapper
01-28 17:23:38.824  6549  6549 D BluetoothAdapter: STATE_ON
01-28 17:23:38.824  6549  6549 D BluetoothLeScanner: could not find callback wrapper
01-28 17:23:39.444  6549  6549 W cr_BindingManager: Cannot call determinedVisibility() - never saw a connection for the pid: 6549
01-28 17:23:40.023  6549  6549 W cr_BindingManager: Cannot call determinedVisibility() - never saw a connection for the pid: 6549

person Greg Williams    schedule 25.01.2016    source источник
comment
Не могли бы вы уточнить, почему вы потерпели неудачу? Попадает ли код внутрь блока if (beacons.size() › 0)`? Попадает ли он внутрь блока if(beacon.getDistance()<1)?   -  person davidgyoung    schedule 26.01.2016
comment
Вот в чем дело; Не знаю, почему неудачно. У меня подключен маяк (Eddy-UID) и идет трансляция (подтверждено с помощью RadBeacon). Однако всякий раз, когда мое устройство с установленным приложением (которое было открыто и запущено хотя бы один раз) оказывается на расстоянии менее 1 метра от маяка, оно не открывает приложение (ни на переднем, ни на заднем плане). Мой код неправильный? Как я могу проверить то, что вы предложили?   -  person Greg Williams    schedule 26.01.2016


Ответы (2)


Несколько советов:

  1. Попробуйте добавить строку отладки Log.d("Distance:"+beacon.get Distance()); перед проверкой Distance ‹ 1. Затем запустите приложение, наблюдая за выводом LogCat в поисках этой строки журнала.

  2. Имейте в виду, что если у вас Android 4.x, для обнаружения в фоновом режиме может потребоваться до пяти минут.

  3. Всегда проще сначала заставить приложения работать на переднем плане, а затем добавлять фоновые возможности. Убедитесь, что вы можете написать код для обнаружения вашего маяка на переднем плане.

person davidgyoung    schedule 26.01.2016
comment
Спасибо за помощь, я использую Android 6 на Nexus 9. В сети радиуса другие приложения могут увидеть маяк менее чем за 5 секунд. Я запустил logcat и получил огромный файл. Я приложил вывод в ОП, так как мне не хватает места в этом поле. - person Greg Williams; 27.01.2016
comment
Я также посмотрел дальше в файле logcat и обнаружил, что он нашел маяк и начал синтаксический анализ, но затем выдает предупреждение о ModelSpecificDistanceCalculator. Я читал где-то в Интернете, что это проблема синтаксического анализа, но разве мой код не очищает маяк? - person Greg Williams; 27.01.2016
comment
Проведя дополнительные исследования, я считаю, что это ошибка Android6. Marshmellow требует разрешения ACCESS_COURSE_LOCATION или ACCESS_FINE_LOCATION, а также запроса пользователя на разрешение этого разрешения. Я добавил код разрешения среды выполнения отсюда: developer.radiusnetworks.com/2015/09/29/ @davidgyoung, можете ли вы взглянуть на мой пересмотренный файл MyApplication.java выше? Я импортировал все классы, но requestPermission и PERMISSION_REQUEST_COARSE_LOCATION не позволяют импортировать класс. Есть идеи, почему? - person Greg Williams; 28.01.2016
comment
Код показывает два метода onCreate. Это опечатка? Вы говорите, что не можете импортировать PERMISSION_REQUEST_COARSE_LOCATION? Вы ориентируетесь на SDK 23 в студии Android? Вы должны сделать это, чтобы обнаружить в фоновом режиме на Android 6+. - person davidgyoung; 28.01.2016
comment
@daviggyoung я увидел, что вы сказали в своем комментарии, и поправил. У меня минимальный SDK 19 и цель 23. Я провожу весь день, работая над этим, этим и этим. Я почти начал с нуля, чтобы попытаться заставить это работать, и я думаю, что я близок к этому. Я объединил MyApplicationName с классом MainActivity. Это позволило мне успешно запросить разрешения для COURSE_LOCATION, и это дало мне возможность обнаруживать маяки, анализировать их, а затем видеть, как они входят в регион. В логарифме выше он выдает BluetoothLeScanner: не удалось найти ошибку оболочки обратного вызова; я что-то пропустил? - person Greg Williams; 29.01.2016
comment
Вы можете игнорировать эту строку журнала о том, что не удалось найти оболочку обратного вызова. Вы когда-нибудь видели Найденный маяк, находящийся на расстоянии? - person davidgyoung; 29.01.2016

С помощью кода davidgyoung, размещенного на github, я смог решить проблему.

person Greg Williams    schedule 30.01.2016