如果以Kiosk模式进行启动,则NFCAdpater.enableReaderMode(...)无法始终如一地工作 [英] NFCAdpater.enableReaderMode(...) doesn't work consistently if booting in Kiosk mode activity
问题描述
我有一个在Kiosk模式下启动的应用程序,应该读取NFCTag并对其做出反应.它使用onResume
中NFCAdapter
上的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
通过利用IProcessObserver
的ForegroundUtils
跟踪前台活动.
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屋!