NFCAdpater.enableReaderMode (...) не работает согласованно, если загрузка выполняется в режиме киоска - PullRequest
0 голосов
/ 10 апреля 2020

У меня есть приложение, которое запускается в режиме киоска и должно читать и реагировать на NFCTags. Он использует enableReaderMode на NFCAdapter в onResume, чтобы начать их чтение. Все работает нормально, если приложение, например, (повторно) запущено во время разработки. Однако, если я перезагружаю устройство (и действие запускается автоматически), то действие только иногда переводится в правильный режим, но часто только воспроизводит системный звук NF C, а мой handleTag не вызывается.

Из того, что я зарегистрировал, код установки NFCAdapter, который у меня есть, правильно вызывается при любых обстоятельствах

Я также пытался enableForegroundDispatch, но эффект тот же. Я также пытался периодически вспоминать enableReaderMode, но это также имеет тот же эффект.

У кого-нибудь есть идеи, что происходит?

Обновление

I я вижу это сообщение об ошибке в журналах, когда я пытаюсь установить режим считывателя в тех случаях, когда он выходит из строя

NfcService: setReaderMode: Caller is not in foreground and is not system process.

Несмотря на то, что активность отчетливо видна в забвении.

Телефон такое Google Pixel 3

Приложение является владельцем устройства через

adb shell dpm set-device-owner ...

Манифест приложения

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    android:testOnly="true">

    <!-- snip DeviceAdminReceiver -->

    <activity
        android:name=".FullscreenActivity"
        android:screenOrientation="reverseLandscape"
        android:configChanges="orientation|keyboardHidden|screenSize"
        android:label="@string/app_name"
        android:theme="@style/FullscreenTheme">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.HOME" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" />

FullscreenActivity, которая должна обрабатывать метку NF C

public class FullscreenActivity extends AppCompatActivity {
  NfcAdapter mAdapter;
  private DevicePolicyManager mDevicePolicyManager;
  private ComponentName mAdminComponentName;

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

    mDevicePolicyManager = (DevicePolicyManager) getSystemService(
            Context.DEVICE_POLICY_SERVICE);
    if (mDevicePolicyManager.isDeviceOwnerApp(getPackageName())) {
        mAdminComponentName = MyDeviceAdminReceiver.getComponentName(this);

        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MAIN);
        intentFilter.addCategory(Intent.CATEGORY_HOME);
        intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
        mDevicePolicyManager.addPersistentPreferredActivity(
                mAdminComponentName, intentFilter,
                new ComponentName(getPackageName(),
                        FullscreenActivity.class.getName()));

        mDevicePolicyManager.setLockTaskPackages(mAdminComponentName,
                new String[]{getPackageName()});

        mDevicePolicyManager.setKeyguardDisabled(mAdminComponentName, true);

    }
    startLockTask();
  }

  @Override
  public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus) {
        setFullscreenFlags();
    }
  }

  private void setFullscreenFlags() {
    getWindow().getDecorView()
            .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
  }

  @Override
  protected void onResume() {
    super.onResume();
    setFullscreenFlags();
    mAdapter = NfcAdapter.getDefaultAdapter(this);
    setupNfcAdapter();
  }

  private void setupNfcAdapter() {
    if (mAdapter == null) return;

    Bundle options = new Bundle();
    // No sure this is needed
    options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 50000);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
            new Intent(this, getClass())
                    .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
    mAdapter.enableReaderMode(this, this::handleTag,
            NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS |
                    NfcAdapter.FLAG_READER_NFC_A |
                    NfcAdapter.FLAG_READER_NFC_B |
                    NfcAdapter.FLAG_READER_NFC_F |
                    NfcAdapter.FLAG_READER_NFC_V, options);
  }

  @Override
  protected void onPause() {
    super.onPause();

    if (mAdapter != null) {
        mAdapter.disableReaderMode(this);
    }
  }

  private void handleTag(Tag tag) {
    Log.d("NFCADAPTER", "tag detected");
  }

}

Ответы [ 2 ]

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

Я нашел решение (ну, скорее, обходной путь), которое подходит для моей ситуации.

Я думаю, что случается так, что NfcService не знает, что действие выполняется на переднем плане. NfcService отслеживает активность на переднем плане через ForegroundUtils, который использует IProcessObserver.

. Я думаю, что происходит то, что моя деятельность иногда становится активностью на переднем плане до того, как этот наблюдатель процесса настроен, и поэтому NfcService считает, что моя активность не выполняется на переднем плане, что предотвращает вызов метода read.

В качестве обходного пути я получил NfcAdapter.STATE_ON изменения, зарегистрировав получателя на NfcAdapter.ACTION_ADAPTER_STATE_CHANGED в активность. Если это событие получено, это считается ситуацией, как описано выше, и я убиваю и перезапускаю приложение (см. [1]). Это теперь наблюдается ForgroundUtils, и я могу войти в режим чтения.

[1] Как программно "перезапустить" приложение Android?

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

Обновление: может быть, другое системное приложение запускается после вашего и выходит на передний план.

Я думаю, что вы можете перевести свое приложение на передний план непосредственно перед включением режима чтения? например, { ссылка }

Не знаю, что происходит, кроме как думать, что это проблема времени.

НО две вещи, которые могут помочь.

  1. Попробуйте проверить NfcAdapter.isEnabled() верно, чтобы определить, действительно ли аппаратное обеспечение NF C доступно перед вашей попыткой enableReaderMode

  2. Настройте приемник вещателя на зарегистрируйте сервисные состояния NF C и enableReaderMode, когда он будет готов, а также в onResume.

Это должно быть более надежным, чем опрос, чтобы увидеть, доступен ли адаптер позднее.

Это можно сделать с помощью следующего кода: -

protected void onCreate(Bundle savedInstanceState) {
  // All the normal onCreate Stuff

// Listen for changes NFC settings
        IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
        this.registerReceiver(mReceiver, filter);
}


private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();

            if (action != null && action.equals(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)) {
                final int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE,
                        NfcAdapter.STATE_OFF);
                switch (state) {
                    case NfcAdapter.STATE_OFF:
                        Log.d("NFCADAPTER", "Adapter Off");
                        break;
                    case NfcAdapter.STATE_TURNING_OFF:
                        Log.d("NFCADAPTER", "Adapter Turning Off");
                        break;
                    case NfcAdapter.STATE_TURNING_ON:
                        Log.d("NFCADAPTER", "Adapter Turning On"); 
                        break;
                    case NfcAdapter.STATE_ON:
                        Log.d("NFCADAPTER", "Adapter On"); 
                        setupNfcAdapter();
                        break;
                }
            }
        }
    };

...