如何在onNewIntent执行之前拦截NFC标签

时间:2015-03-04 16:52:45

标签: android nfc

我有一个可以捕获NFC标签的应用。我过去遇到的问题是用户以不稳定的方式悬停在标签上,导致NFC适配器触发两次。

我做了一些事情来对付这件事。

清单:

<activity
    android:name=".NfcActivity"
    android:screenOrientation="portrait"
    android:launchMode="singleTask" 
    android:noHistory="true"
    android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation">

    <intent-filter>


        <action android:name="android.nfc.action.NDEF_DISCOVERED" />

        <category android:name="android.intent.category.DEFAULT" />

        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

这将NFC捕获活动设置为堆栈中唯一的实例,并且没有历史记录。我已经覆盖了所有可以停止并重新启动此活动的配置更改,后者可能会导致意图数据重新传递到活动,使其看起来像重复扫描。

在Activity本身中,我已经覆盖了onNewIntent,除了显示一个糟糕的扫描屏幕之外什么都不做。我也理解onNewIntent应该从功能角度镜像onCreate,但是因为以前版本的应用程序已经向下一个Activity发送了2次扫描,我只想在一个地方使用NFC捕获代码onCreate。

在onCreate中我做了进一步的测试,以防止悬停在标签上并创建错误的扫描。

  • 我在intent中检查已启动的表单历史记录标志。 Android可以在内存不足时杀死应用,并在以后重新启动时重新启动原始意图。这可能会导致重复扫描。
  • 在onCreate中,我检查用户STILL是否已将手机连接到标签。这证明用户没有使用ndefTag.connect();
  • 悬停在标记上

该应用程序似乎工作正常,但在一个特定的手机(三星Galaxy Young 2),如果用户将手机放在标签上几秒钟,NFC适配器似乎连续几次点火。< / p>

发生这种情况时,原始扫描将被取消。这样做的原因是oncreate处理标签,但是当后续扫描发生时(通过偶然的悬停),onPause - &gt; onNewIntent运行。因此,Activity跳出onCreate并停止处理标记。 onNewIntent显示失败的扫描屏幕并启动菜单屏幕。

上述问题不是太大,因为用户必须重新扫描标签。

我想要发生的是:

当onCreate运行时,无论如何处理标记,即使onNewintent执行也是如此。有没有办法可以在到达onNewintent和onPause之前拦截意图?

也许有一个我可以使用的全局标志,可以首先检查onCreate是否仍然在运行而onNewIntent不应该,或者更重要的是onPause不会被称为onCreate停止运行。

import java.util.List;
import java.util.concurrent.ExecutionException;

import org.ndeftools.Message;
import org.ndeftools.Record;

import android.app.Activity;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.os.Vibrator;
import android.util.Log;
import android.widget.Toast;

public class NfcActivity extends Activity {

    private static final String TAG = NfcActivity.class.getName();

    protected NfcAdapter nfcAdapter;
    protected PendingIntent nfcPendingIntent;

    Handler handler;
    Runnable runnable;

    Handler failHandler;
    Runnable failRunnable;

    Parcelable[] messages;

    Intent i;

    Tag tag;
    String tagId;

    boolean nfcConnected;

    ProgressDialog progressDialog;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.nfcactivitylayout);
        Log.e(TAG, "oncreate");
        nfcConnected = false;

        // initialize NFC
        nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        nfcPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, this.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);

        tag = null;
        tagId = null;

        i = getIntent();

        if ((i.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {

            //check to see if Android has previously killed the app and relaunched it from History
            //and delivered the original intent.
            //if it has do not process and launch the menu screen
                Intent processPayloadIntent = new Intent(NfcActivity.this, NfcscannerActivity.class);
                processPayloadIntent.setAction("QRCODE_ACTION"); 
                processPayloadIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(processPayloadIntent);

            }else{



        tag = i.getParcelableExtra(NfcAdapter.EXTRA_TAG);

        tagId = bytesToHexString(tag.getId());

        Log.e(TAG, "tagID = " + tagId);

        Log.e(TAG, "oncreate intent action = " + i.getAction());




        //The activity has captured tag data, prove the user is not hovering over the tag and is doing a good scan
        //hovering can trigger the adapter twice

        AsyncNfcConnect asnc = new AsyncNfcConnect();
        try {
            asnc.execute().get();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }




        Log.e(TAG, "nfcConnected!!!!!!!!!!!!!!!!!!!!!!!!! = " + nfcConnected);

        if(nfcConnected == true){


            int buildVersionSdk = Build.VERSION.SDK_INT;
            int buildVersionCodes = Build.VERSION_CODES.GINGERBREAD;

            Log.e(TAG, "buildVersionSdk = " + buildVersionSdk
                    + "buildVersionCodes = " + buildVersionCodes);

            int themeVersion;
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD) {

                themeVersion = 2;

            } else {

                themeVersion = 1;
            }

            try{

            progressDialog = new ProgressDialog(this, themeVersion);
            progressDialog.setTitle("NFC Tag Scanned");
            progressDialog.setMessage("Processing tag...");
            progressDialog.setIndeterminate(true);
            progressDialog.show();

            }catch(Exception e){        }




        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(i.getAction()) || NfcAdapter.ACTION_TAG_DISCOVERED.equals(i.getAction())) {            

            if(NfcScannerApplication.isCanScanNfcTag()){

            messages = i.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
            if (messages != null) {


                //setContentView(R.layout.successfulnfc);

                NfcScannerApplication.startNfcTimer();
                //Toast.makeText(this, "NFC timer set", Toast.LENGTH_LONG).show();

                Log.e(TAG, "Found " + messages.length + " NDEF messages"); // is almost always just one

                vibrate(); // signal found messages :-)



                initHandler();
                handler.postDelayed(runnable,  2000);

      }else{

          Toast.makeText(this, "Data on tag was not correct", Toast.LENGTH_LONG).show();

              try{

                handler.removeCallbacks(runnable);
                Log.e(TAG, "just removed callback to runnable that reads nfc tag data");

                }catch(Exception e){

                }




                initFailHandler();
                failHandler.postDelayed(failRunnable,  1);



      }

            }else{


                try{

                    handler.removeCallbacks(runnable);
                    Log.e(TAG, "just removed callback to runnable that reads nfc tag data");

                    }catch(Exception e){

                    }




                    initFailHandler();
                    failHandler.postDelayed(failRunnable,  1);


            }



        } else {

            Toast.makeText(this, "Tag not recognized correctly", Toast.LENGTH_LONG).show();

                try{

                handler.removeCallbacks(runnable);
                Log.e(TAG, "just removed callback to runnable that reads nfc tag data");

                }catch(Exception e){

                }




                initFailHandler();
                failHandler.postDelayed(failRunnable,  1);

        }


        }else{


            try{

                Toast.makeText(this, "Phone wasn't connected to Tag", Toast.LENGTH_LONG).show();

                handler.removeCallbacks(runnable);
                Log.e(TAG, "just removed callback to runnable that reads nfc tag data");

                }catch(Exception e){

                }




                initFailHandler();
                failHandler.postDelayed(failRunnable,  1);



        }//end of NFC connect test


        }//end of launched from history check


    }//end of onCreate





    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "onStart");
    }





    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "onStop");
    }





    @Override
    public void onNewIntent(Intent intent) {
        Log.e(TAG, "onNewIntent");

                            Toast.makeText(this, "Bad scan!!!", Toast.LENGTH_LONG).show();



                            initFailHandler();
                            failHandler.postDelayed(failRunnable, 1);



    }//end of onNewIntent






    public void enableForegroundMode() {
        Log.e(TAG, "enableForegroundMode");

        IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); // filter for all
        IntentFilter[] writeTagFilters = new IntentFilter[] {tagDetected};
        nfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null);
    }

    public void disableForegroundMode() {
        Log.e(TAG, "disableForegroundMode");

        nfcAdapter.disableForegroundDispatch(this);
    }





    @Override
    protected void onResume() {
     super.onResume();
     Log.e(TAG, "onResume");

        enableForegroundMode();
    }

    @Override
    protected void onPause() {
        Log.e(TAG, "onPause");

        super.onPause();

        disableForegroundMode();

        if(handler != null){
            handler.removeCallbacks(runnable);
        }


    }

    private void vibrate() {
        Log.e(TAG, "vibrate");

        Vibrator vibe = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE) ;
        vibe.vibrate(500);
    }


    public void initHandler(){

          handler = new Handler();
          runnable = new Runnable() {
                public void run() {
                    processTag();

                }

                private void processTag() {
                    Log.e(TAG, "about to process tag");

                    try{
                        progressDialog.dismiss();

                    }catch(Exception e){

                        //do nothing
                    }

                    // parse to records
                    for (int i = 0; i < messages.length; i++) {
                        try {
                            List<Record> records = new Message((NdefMessage)messages[i]);

                            Log.e(TAG, "Found " + records.size() + " records in message " + i);

                            for(int k = 0; k < records.size(); k++) {
                                Log.e(TAG, " Record #" + k + " is of class " + records.get(k).getClass().getSimpleName());

                                Record record = records.get(k);

                                NdefRecord ndefRecord = record.getNdefRecord();

                                byte[] arr = ndefRecord.getPayload();

                                String payload = new String(arr);


                                if(payload.length() > 0){

                                payload = payload.substring(3, payload.length());

                                Log.e(TAG, "payload = " + payload);

                                String[] splitPayload = payload.split(",");

                                String tagType = splitPayload[0];
                                String tagCompany = splitPayload[1];
                                String tagClientID = splitPayload[2];
                                String tagClientName = splitPayload[3];

                                if(! tagClientID.equalsIgnoreCase("0") && tagClientID.length() > 0){

                                    handler.post(new Runnable(){
                                        public void run() {

                                            setContentView(R.layout.successfulnfc);

                                          }
                                        });






                                Intent processPayloadIntent = new Intent(NfcActivity.this, NfcscannerActivity.class);
                                processPayloadIntent.putExtra("payload", payload);
                                processPayloadIntent.putExtra("tagid", tagId);
                                processPayloadIntent.setAction("NFC"); 
                                processPayloadIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                                //processPayloadIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_NEW_TASK);
                                startActivity(processPayloadIntent);
                                finish();
                                overridePendingTransition(0, R.anim.activity_animation_zoom_in);





                                    }else{
                                        Toast.makeText(NfcActivity.this, "Tag data problem/Scan problem.", Toast.LENGTH_LONG).show();

                                        initFailHandler();
                                        failHandler.postDelayed(failRunnable, 1);


                                    }

                                }else{
                                    Toast.makeText(NfcActivity.this, "Tag data problem/Scan problem.", Toast.LENGTH_LONG).show();

                                    initFailHandler();
                                    failHandler.postDelayed(failRunnable, 1);

                                }



                            }
                        } catch (Exception e) {
                            Log.e(TAG, "Problem parsing message", e);
                        }

                    }

                }
            };

        }





    public void initFailHandler(){

          failHandler = new Handler();
          failRunnable = new Runnable() {
                public void run() {

                    returnToMainMenu();

                }

                private void returnToMainMenu() {
                    //Log.e(TAG, "about to return to main menu");

                    try{
                        progressDialog.dismiss();

                    }catch(Exception e){

                        //do nothing
                    }

                    Toast.makeText(NfcActivity.this, "Please check your scanning technique.\nPlease do not hover over tag or swipe...", Toast.LENGTH_LONG).show();

                    failHandler.post(new Runnable(){
                        public void run() {

                            setContentView(R.layout.nfcfail);

                          }
                        });






                    //onBackPressed();
                    Intent processPayloadIntent = new Intent(NfcActivity.this, NfcscannerActivity.class);
                    processPayloadIntent.setAction("QRCODE_ACTION"); 
                    processPayloadIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    startActivity(processPayloadIntent);
                    finish();
                    //overridePendingTransition(0, R.anim.activity_animation_zoom_in);

                }
            };

        }




    private String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("0x");
        if (src == null || src.length <= 0) {
            return null;
        }

        char[] buffer = new char[2];
        for (int i = 0; i < src.length; i++) {
            buffer[0] = Character.forDigit((src[i] >>> 4) & 0x0F, 16);
            buffer[1] = Character.forDigit(src[i] & 0x0F, 16);
            System.out.println(buffer);
            stringBuilder.append(buffer);
        }

        return stringBuilder.toString();
    }



private class AsyncNfcConnect extends AsyncTask<String, Void, String> {






        @Override
        protected String doInBackground(String... params) {

            NfcActivity.this.nfcConnected = false;
            String result;
            Ndef ndefTag = Ndef.get(tag);

            try {
                Log.e(TAG, "about to test connect()********************************************");
                ndefTag.connect();  // this should already perform an IO operation and should therefore fail if there is no tag
                Log.e(TAG, "Ndef.connect() connected!********************************************");
                NdefMessage ndefMsg = ndefTag.getNdefMessage();  // this reads the current NDEF message from the tag and consequently causes an IO operation

                NfcActivity.this.nfcConnected = true;
                result = "OK";
                return result;

            } catch (Exception e) {
                // there is no tag or communication with tag dropped
                Log.e(TAG, "There a problem with connecting to the tag using Ndef.connect(");
                NfcActivity.this.nfcConnected = false;
                result = "NOTOK";
                return result;
            } finally {
                try {
                    ndefTag.close();
                } catch (Exception e) {
                }
            }


        }



    }//end of Async


}

1 个答案:

答案 0 :(得分:1)

您似乎坚持不在onNewIntent()处理NFC意图。我建议onCreate()onNewIntent()都调用扫描标记的常用过程。这样,两个入口点都将遵循相同的代码路径。

您声称应用程序跳出了创建&#34;可能只是一种比喻?会发生什么情况是您的标记扫描AsyncNfcConnect在单独的线程上作为后台任务运行(应该如此)。该任务在onCreate()中创建,并在onCreate()完成后继续运行(您可以在Log末尾添加onCreate()语句进行检查)。当以某种方式丢失与标记的连接并重新发现标记时,正如您所观察到的那样调用onNewIntent()

在任何情况下都无法阻止这种情况发生,因此您的应用必须能够处理它。要检测并处理它,您可以在活动中设置一些标志,以指示您的后台任务正在运行或已运行。您还可以存储是否发生异常的信息,并在重新发现时再次尝试再次扫描标记(这可能需要您实施我上面提出的建议)。如果您想让您的应用程序更加失败,您还可以存储最后扫描的标签的ID,以便在成功扫描(或不扫描)后重新发现它时再次识别它。当异常持续发生在同一标签上时,您可以在一定次数后向用户指明他(例如,通过建议设备与标签的位置不同)。