NFCAdpater.enableReaderMode(…)如果以Kiosk模式活动启动,将无法一致工作

问题描述 投票:0回答:1

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

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

我也尝试过enableForegroundDispatch,但效果相同。我也尝试过定期召回enableReaderMode,但它也有相同的效果。

任何人都知道发生了什么事吗?

更新

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

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" />

应该处理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");
  }

}

android nfc kiosk-mode
1个回答
0
投票

更新:可能是另一个系统应用程序正在您的应用程序中启动并占据前台。

我认为您可以在启用阅读器模式之前将您的应用强制到Foreground吗?例如https://stackoverflow.com/a/10019332/2373819

不知道发生了什么,除了认为这是时间问题。

但有两点可能会有所帮助。

  1. 尝试检查NfcAdapter.isEnabled()是否为真,以帮助您在尝试enableReaderMode之前确定NFC硬件是否实际可用

  2. 设置广播者接收器以记录NFC服务状态,并在就绪时以及在enableReaderMode中记录onResume。]

  3. 这应该比轮询更可靠,以便以后查看适配器是否可用。

    这可以通过以下代码完成:-

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

© www.soinside.com 2019 - 2024. All rights reserved.