如果以Kiosk模式进行启动,则NFCAdpater.enableReaderMode(...)无法始终如一地工作 [英] NFCAdpater.enableReaderMode(...) doesn't work consistently if booting in Kiosk mode activity

查看:126
本文介绍了如果以Kiosk模式进行启动,则NFCAdpater.enableReaderMode(...)无法始终如一地工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在Kiosk模式下启动的应用程序,应该读取NFCTag并对其做出反应.它使用onResumeNFCAdapter上的enableReaderMode开始读取它们.如果应用程序例如(重新)在开发过程中开始.但是,如果我重新启动设备(活动自动开始),则有时仅将活动置于正确的模式,但通常仅播放NFC系统声音,而不会调用我的handleTag.

I have an application which starts in Kiosk mode and should read and react on NFCTags. It's using enableReaderMode on the NFCAdapter in onResume to start reading them. Everything works fine if the app is e.g. (re-)started during development. However, if I reboot the device (and the activity gets started automatically) the activity is only sometimes put into the right mode, but often only plays the NFC system sound and my handleTag is not called.

根据我的记录,在任何情况下都可以正确调用我拥有的NFCAdapter安装代码

From what I logged, the NFCAdapter setup code I have is correctly called in all circumstances

我也尝试过enableForegroundDispatch,但是效果相同.我也尝试过定期回想enableReaderMode,但是它也有相同的效果.

I tried enableForegroundDispatch as well, but there's the same effect. I also tried periodically recalling enableReaderMode but it also has the same effect.

有人知道发生了什么事吗?

Anybody has an idea what's going on?

更新

当我尝试在失败的情况下设置阅读器模式时,我会在日志中看到此错误消息

I see this error message in the logs when I try to set the reader mode in the cases where it fails

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

尽管该活动在前人中清晰可见.

Although the activity is clearly visible in the forgreound.

电话是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" />

应处理NFC标签的FullscreenActivity

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");
  }

}

推荐答案

我找到了一种适合我情况的解决方案(很好,一种变通方法).

I found a solution (well, more a workaround) that works for my situation.

我认为发生的情况是NfcService不知道该活动在前台运行. NfcService通过利用IProcessObserverForegroundUtils跟踪前台活动.

I think what happens is that the NfcService is not aware that the activity is running in the foreground. The NfcService keeps track of the foreground activity through a ForegroundUtils which leverages an IProcessObserver.

我认为正在发生的事情是我的活动有时在设置此进程观察器之前变为前台活动,因此NfcService认为我的活动未在前台运行,从而阻止了对read方法的调用.

What I think is happening is that my activity sometimes becomes the foreground activity before this process observer is setup and therefore the NfcService thinks my activity is not runnning in the foreground, preventing the call on the read method.

作为解决方法,我所做的是通过在活动中的NfcAdapter.ACTION_ADAPTER_STATE_CHANGED上注册接收器来接收NfcAdapter.STATE_ON更改.如果收到此事件,则认为是上述情况,我将终止并重新启动该应用程序(请参阅[1]). ForgroundUtils现在可以观察到这一点,并且我可以进入阅读器模式.

What I did as a workaround is to receive NfcAdapter.STATE_ON changes by registering a receiver on NfcAdapter.ACTION_ADAPTER_STATE_CHANGED in the activity. If this event is received this is considered a situation as described above and I kill and restart the app (see [1]). This is now observed by the ForgroundUtils and I'm able to get into reader mode.

[1] 如何以编程方式重新启动"一个Android应用程序?

这篇关于如果以Kiosk模式进行启动,则NFCAdpater.enableReaderMode(...)无法始终如一地工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆