├── .gitignore ├── Available_School.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wolfaonliu │ │ └── cardreader │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── java │ │ └── com │ │ │ └── wolfaonliu │ │ │ └── cardreader │ │ │ ├── AboutActivity.java │ │ │ ├── AboutAdapter.java │ │ │ ├── CardInfo.java │ │ │ ├── CardReader.java │ │ │ ├── DealAdapter.java │ │ │ ├── ItemDivider.java │ │ │ ├── MainActivity.java │ │ │ ├── TradingRecordInfo.java │ │ │ ├── Util.java │ │ │ ├── e.java │ │ │ ├── fInts.java │ │ │ └── g.java │ └── res │ │ ├── drawable │ │ ├── ic_menu_info.xml │ │ ├── ic_menu_nfc.xml │ │ ├── ic_menu_share.xml │ │ └── side_nav_bar.xml │ │ ├── font │ │ └── noto_sans.ttf │ │ ├── layout │ │ ├── about_item.xml │ │ ├── activity_about.xml │ │ ├── activity_main.xml │ │ ├── app_bar_about.xml │ │ ├── app_bar_main.xml │ │ ├── content_about.xml │ │ ├── content_main.xml │ │ ├── nav_header_main.xml │ │ └── view_item.xml │ │ ├── menu │ │ └── activity_main_drawer.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── values-en │ │ └── strings.xml │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-zh │ │ └── strings.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── ic_launcher_background.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── nfc_tech_filter.xml │ └── test │ └── java │ └── com │ └── wolfaonliu │ └── cardreader │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /Available_School.md: -------------------------------------------------------------------------------- 1 | ## 确认支持的学校 2 | - 东北大学 NEU 3 | 4 | 5 | ## 确认不支持的学校 6 | - 四川大学 SCU 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NewcapecCardReader 2 | A NFC card reader for Newcapec card 3 | 4 | ## Download 5 | [Release](https://github.com/liuyanyi/NeuCardReader/releases) 6 | 7 | ## Available school 8 | See [Available_School.md](/Available_School.md) 9 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | defaultConfig { 6 | applicationId "com.wolfaonliu.cardreader" 7 | minSdkVersion 23 8 | targetSdkVersion 26 9 | versionCode 1 10 | versionName "1.3.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled true 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | 20 | android.applicationVariants.all { 21 | variant -> 22 | variant.outputs.all { 23 | outputFileName = "NCR_${variant.name}_v${variant.versionName}.apk" 24 | } 25 | } 26 | } 27 | 28 | dependencies { 29 | implementation fileTree(dir: 'libs', include: ['*.jar']) 30 | implementation 'com.android.support:appcompat-v7:26.1.0' 31 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 32 | implementation 'com.android.support:design:26.1.0' 33 | implementation 'com.android.support:support-v4:26.1.0' 34 | testImplementation 'junit:junit:4.12' 35 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 36 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 37 | implementation 'com.android.support:cardview-v7:26.1.0' 38 | } 39 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/wolfaonliu/cardreader/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.wolfaonliu.cardreader; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.mogician.nfctest", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/java/com/wolfaonliu/cardreader/AboutActivity.java: -------------------------------------------------------------------------------- 1 | package com.wolfaonliu.cardreader; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.DialogInterface; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.support.v7.widget.Toolbar; 11 | import android.view.View; 12 | import android.widget.AdapterView; 13 | import android.widget.ListView; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | 18 | public class AboutActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { 19 | 20 | Toolbar toolbar; 21 | 22 | 23 | private ListView mView; 24 | 25 | private AboutAdapter mAdapter; 26 | 27 | private RecyclerView.LayoutManager mLayoutManager; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_about); 33 | 34 | toolbar = findViewById(R.id.about_toolbar); 35 | setSupportActionBar(toolbar); 36 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 37 | toolbar.setNavigationOnClickListener(new View.OnClickListener() { 38 | @Override 39 | public void onClick(View v) { 40 | finish(); 41 | } 42 | }); 43 | initData(); 44 | initView(); 45 | } 46 | 47 | 48 | private void initData() { 49 | mAdapter = new AboutAdapter(getSet(), this); 50 | } 51 | 52 | private ArrayList getSet() { 53 | ArrayList settings = new ArrayList<>(); 54 | String[][] s = new String[4][2]; 55 | s[0][0] = getString(R.string.version); 56 | s[0][1] = Util.getVersion(this.getApplicationContext()); 57 | s[1][0] = getString(R.string.developer); 58 | s[1][1] = "wolfaonliu"; 59 | s[2][0] = getString(R.string.contact); 60 | s[2][1] = "wolfaonliu@gmail.com"; 61 | s[3][0] = getString(R.string.github); 62 | s[3][1] = "https://github.com/liuyanyi/NewcapecCardReader"; 63 | settings.addAll(Arrays.asList(s)); 64 | return settings; 65 | } 66 | 67 | private void initView() { 68 | mView = findViewById(R.id.set_list); 69 | // 设置adapter 70 | mView.setAdapter(mAdapter); 71 | mView.setOnItemClickListener(this); 72 | } 73 | 74 | @Override 75 | public void onItemClick(AdapterView parent, View view, int position, long id) { 76 | Uri uri; 77 | Intent intent; 78 | switch (position) { 79 | case 2: 80 | // uri = Uri.parse("wolfaonliu@gmail.com"); 81 | // intent = new Intent(Intent.ACTION_SENDTO, uri); 82 | //// intent.putExtra(Intent.EXTRA_SUBJECT, "Newcapec Card Reader Report"); 83 | // startActivity(intent); 84 | showEmailDialog(); 85 | break; 86 | case 3: 87 | uri = Uri.parse("https://github.com/liuyanyi/NewcapecCardReader"); 88 | intent = new Intent(Intent.ACTION_VIEW, uri); 89 | startActivity(intent); 90 | break; 91 | default: 92 | break; 93 | } 94 | // Toast.makeText(this, "你点击了第" + position + "项", Toast.LENGTH_SHORT).show(); 95 | } 96 | 97 | 98 | private void showEmailDialog() { 99 | AlertDialog.Builder builder = new AlertDialog.Builder(this); 100 | builder.setTitle(R.string.Report) 101 | .setMessage(R.string.report_atten); 102 | builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { 103 | @Override 104 | public void onClick(DialogInterface dialog, int which) { 105 | Intent email = new Intent(Intent.ACTION_SEND); 106 | email.setType("message/rfc822"); 107 | email.putExtra(Intent.EXTRA_EMAIL, new String[]{"wolfaonliu@gmail.com"}); 108 | email.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.app_name) + getString(R.string.report)); 109 | startActivity(Intent.createChooser(email, getString(R.string.email_clint))); 110 | } 111 | }); 112 | builder.setNegativeButton(R.string.no, null); 113 | 114 | builder.show(); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /app/src/main/java/com/wolfaonliu/cardreader/AboutAdapter.java: -------------------------------------------------------------------------------- 1 | package com.wolfaonliu.cardreader; 2 | 3 | import android.app.Activity; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | 10 | import java.util.ArrayList; 11 | 12 | /** 13 | * Created by Mogician on 2018/3/14. 14 | */ 15 | 16 | public class AboutAdapter extends BaseAdapter { 17 | 18 | private ArrayList mData; 19 | private Activity activity; 20 | 21 | private TextView setting; 22 | private TextView settingsub; 23 | 24 | 25 | public AboutAdapter(ArrayList data, Activity activity) { 26 | this.mData = data; 27 | this.activity = activity; 28 | } 29 | 30 | @Override 31 | public int getCount() { 32 | return mData.size(); 33 | } 34 | 35 | @Override 36 | public Object getItem(int position) { 37 | return null; 38 | } 39 | 40 | @Override 41 | public long getItemId(int position) { 42 | return position; 43 | } 44 | 45 | @Override 46 | public View getView(int position, View convertView, ViewGroup parent) { 47 | convertView = LayoutInflater.from(activity).inflate(R.layout.about_item, parent, false); 48 | 49 | setting = convertView.findViewById(R.id.setting); 50 | settingsub = convertView.findViewById(R.id.settingsub); 51 | 52 | // 53 | setting.setText(mData.get(position)[0]); 54 | settingsub.setText(mData.get(position)[1]); 55 | return convertView; 56 | 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/wolfaonliu/cardreader/CardInfo.java: -------------------------------------------------------------------------------- 1 | package com.wolfaonliu.cardreader; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Color; 5 | import android.support.v7.widget.CardView; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.util.Log; 9 | import android.view.View; 10 | import android.widget.ImageView; 11 | import android.widget.ProgressBar; 12 | import android.widget.TextView; 13 | 14 | import java.util.ArrayList; 15 | 16 | /** 17 | * Created by Mogician on 2018/3/12. 18 | */ 19 | 20 | public class CardInfo { 21 | 22 | private Activity mainActivity; 23 | 24 | private String hardwareId = ""; 25 | private String studentId = ""; 26 | private String studentName = ""; 27 | private String cardBalance = ""; 28 | private String studentDept = ""; 29 | private String personId = ""; 30 | 31 | private ArrayList tradeList = new ArrayList<>(); 32 | 33 | private boolean isNewcapecCard = false; 34 | 35 | private TextView name; 36 | private TextView id; 37 | private TextView balance; 38 | private TextView hardware; 39 | private TextView dept; 40 | private TextView isCard; 41 | private TextView pId; 42 | private ImageView pgI; 43 | private TextView atten; 44 | private ProgressBar pgBar; 45 | private CardView dealCard; 46 | private RecyclerView mRecyclerView; 47 | private RecyclerView.Adapter mAdapter; 48 | private RecyclerView.LayoutManager mLayoutManager; 49 | 50 | public ArrayList getTradeList() { 51 | return tradeList; 52 | } 53 | 54 | CardInfo(Activity m) { 55 | this.mainActivity = m; 56 | this.isCard = mainActivity.findViewById(R.id.isNewcapec); 57 | this.name = mainActivity.findViewById(R.id.Name); 58 | this.id = mainActivity.findViewById(R.id.Id); 59 | this.balance = mainActivity.findViewById(R.id.Balance); 60 | this.hardware = mainActivity.findViewById(R.id.Hardware); 61 | this.dept = mainActivity.findViewById(R.id.Dept); 62 | this.pId = mainActivity.findViewById(R.id.personId); 63 | this.pgI = mainActivity.findViewById(R.id.pgImg); 64 | this.pgBar = mainActivity.findViewById(R.id.pgBar); 65 | this.atten = mainActivity.findViewById(R.id.attention); 66 | this.dealCard = mainActivity.findViewById(R.id.dealCard); 67 | 68 | this.mLayoutManager = new LinearLayoutManager(mainActivity, LinearLayoutManager.VERTICAL, false); 69 | this.mRecyclerView = mainActivity.findViewById(R.id.dealList); 70 | // 设置布局管理器 71 | this.mRecyclerView.setLayoutManager(mLayoutManager); 72 | 73 | } 74 | 75 | public void setHardwareId(String hardwareId) { 76 | this.hardwareId = hardwareId; 77 | } 78 | 79 | public void setStudentId(String studentId) { 80 | this.studentId = studentId; 81 | if (studentId != null) 82 | isNewcapecCard = true; 83 | } 84 | 85 | public void setStudentName(String studentName) { 86 | this.studentName = studentName; 87 | if (studentName != null) 88 | isNewcapecCard = true; 89 | } 90 | 91 | public void setPersonId(String personId) { 92 | this.personId = personId; 93 | } 94 | 95 | public void setCardBalance(String cardBalance) { 96 | if (cardBalance != null) 97 | isNewcapecCard = true; 98 | this.cardBalance = cardBalance + mainActivity.getString(R.string.yuan); 99 | } 100 | 101 | public void setStudentDept(String studentDept) { 102 | this.studentDept = studentDept; 103 | } 104 | 105 | 106 | public void onStart() { 107 | pgI.setVisibility(View.GONE); 108 | pgBar.setVisibility(View.VISIBLE); 109 | atten.setText("读取中"); 110 | } 111 | 112 | public void onFinish(boolean isFull) { 113 | pgI.setVisibility(View.VISIBLE); 114 | pgBar.setVisibility(View.GONE); 115 | if (!isFull) { 116 | //未能复现…… 117 | atten.setText(mainActivity.getString(R.string.reading_alert)); 118 | pgI.setColorFilter(Color.parseColor("#259b24")); 119 | } else if (isNewcapecCard) { 120 | atten.setText(mainActivity.getString(R.string.success)); 121 | pgI.setColorFilter(Color.parseColor("#259b24")); 122 | } else { 123 | atten.setText(mainActivity.getString(R.string.failed)); 124 | pgI.setColorFilter(Color.parseColor("#e51c23")); 125 | } 126 | } 127 | 128 | public void addDeal(TradingRecordInfo tradingRecordInfo) { 129 | tradeList.add(tradingRecordInfo); 130 | } 131 | 132 | public void showInLog() { 133 | if (isNewcapecCard) { 134 | Log.d("姓名", studentName); 135 | Log.d("学号", studentId); 136 | Log.d("余额", cardBalance); 137 | if (studentDept != null) 138 | Log.d("学院", studentDept); 139 | Log.d("卡ID", hardwareId); 140 | Log.d("身份证", personId); 141 | } else { 142 | Log.d("ERROR", "非校园卡"); 143 | Log.d("卡ID", hardwareId); 144 | } 145 | } 146 | 147 | public boolean show() { 148 | if (isNewcapecCard) { 149 | isCard.setText(mainActivity.getString(R.string.isStuCard)); 150 | 151 | name.setText(studentName); 152 | 153 | id.setText(studentId); 154 | 155 | balance.setText(cardBalance); 156 | 157 | hardware.setText(hardwareId); 158 | 159 | dept.setText(studentDept); 160 | 161 | pId.setText(personId); 162 | 163 | if (!getTradeList().isEmpty()) { 164 | 165 | dealCard.setVisibility(View.VISIBLE); 166 | // 设置adapter 167 | mAdapter = new DealAdapter(getTradeList(), mainActivity); 168 | mRecyclerView.setAdapter(mAdapter); 169 | mRecyclerView.addItemDecoration(new ItemDivider(mainActivity, LinearLayoutManager.VERTICAL)); 170 | } 171 | 172 | if (studentName.isEmpty() || studentId.isEmpty() || cardBalance.isEmpty()) 173 | return false; 174 | 175 | } else { 176 | isCard.setText(mainActivity.getString(R.string.unsupport)); 177 | 178 | hardware.setText(hardwareId); 179 | 180 | name.setText(""); 181 | id.setText(""); 182 | balance.setText(""); 183 | dept.setText(""); 184 | pId.setText(""); 185 | dealCard.setVisibility(View.GONE); 186 | 187 | } 188 | return true; 189 | 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /app/src/main/java/com/wolfaonliu/cardreader/CardReader.java: -------------------------------------------------------------------------------- 1 | package com.wolfaonliu.cardreader; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.nfc.NfcAdapter; 6 | import android.nfc.Tag; 7 | import android.nfc.tech.IsoDep; 8 | import android.util.Log; 9 | 10 | import java.io.IOException; 11 | 12 | /** 13 | * Created by Mogician on 2018/3/14. 14 | */ 15 | 16 | public class CardReader { 17 | 18 | 19 | public static CardInfo readCard(Activity activity, Intent intent) { 20 | //TODO 拆分成多个方法 21 | CardInfo card = new CardInfo(activity); 22 | 23 | Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 24 | if (tagFromIntent == null) 25 | return null; 26 | card.setHardwareId(Util.byteToHex(tagFromIntent.getId())); 27 | 28 | 29 | String action = intent.getAction(); 30 | if (!"android.nfc.action.TAG_DISCOVERED".equals(action) && !"android.nfc.action.TECH_DISCOVERED".equals(action) && !"android.nfc.action.NDEF_DISCOVERED".equals(action)) { 31 | return null; 32 | } 33 | 34 | IsoDep isoDep = IsoDep.get((Tag) intent.getParcelableExtra("android.nfc.extra.TAG")); 35 | if (isoDep == null) { 36 | // extraID(); 37 | // a(this.NfcMainfare); 38 | return null; 39 | } 40 | 41 | 42 | try { 43 | 44 | isoDep.connect(); 45 | // a(this.NfcMainfare); 46 | // extraID(); 47 | isoDep.transceive(g.a(fInts.a)); 48 | byte[] transceive = isoDep.transceive(g.a(fInts.c)); 49 | if (transceive != null && g.c(transceive)) { 50 | transceive = isoDep.transceive(g.a(fInts.d)); 51 | if (transceive == null || !g.c(transceive)) { 52 | Util.aToast(activity.getString(R.string.read_failed), activity); 53 | } else { 54 | byte[] a; 55 | 56 | 57 | transceive = isoDep.transceive(g.a(fInts.j)); 58 | //名字 59 | if (transceive != null && g.c(transceive)) { 60 | a = g.a(transceive); 61 | g.a(a, 0, transceive, 0, transceive.length - 2); 62 | action = g.a(a, 0, a.length, "GB18030").trim(); 63 | // Log.d("名字", action); 64 | if (Util.g(action)) { 65 | card.setStudentName(action); 66 | // Log.d("名字", action); 67 | // aToast(action); 68 | // Log.d("名字","r1"); 69 | } 70 | } 71 | 72 | transceive = isoDep.transceive(g.a(fInts.h)); 73 | //卡号 74 | if (transceive != null && g.c(transceive)) { 75 | a = g.a(transceive); 76 | g.a(a, 0, transceive, 0, transceive.length - 2); 77 | action = g.a(a, 0, a.length, "GB18030").trim(); 78 | // Log.d("卡号", action); 79 | card.setStudentId(action); 80 | } 81 | 82 | transceive = isoDep.transceive(g.a(fInts.personId)); 83 | //身份证 84 | if (transceive != null && g.c(transceive)) { 85 | a = g.a(transceive); 86 | g.a(a, 0, transceive, 0, transceive.length - 2); 87 | action = g.a(a, 0, a.length, "GB18030").trim(); 88 | // Log.d("卡号", action); 89 | card.setPersonId(action); 90 | } 91 | 92 | 93 | transceive = isoDep.transceive(g.a(fInts.g)); 94 | //学院 95 | if (transceive != null && g.c(transceive)) { 96 | a = g.a(transceive); 97 | g.a(a, 0, transceive, 0, transceive.length - 2); 98 | action = g.a(a, 0, a.length, "GB18030").trim(); 99 | // Log.d("***", action); 100 | if (Util.d(action) || Util.a(action) || action.contains("000000")) { 101 | // bVar.d(action); 102 | // Log.d("学院******", action); 103 | } else { 104 | // bVar.c(action); 105 | // Log.d("学院***", action); 106 | card.setStudentDept(action); 107 | } 108 | } 109 | 110 | int intValue; 111 | transceive = isoDep.transceive(g.a(fInts.e)); 112 | //余额 113 | if (transceive != null && g.c(transceive)) { 114 | transceive = isoDep.transceive(g.a(fInts.n)); 115 | if (transceive != null && g.c(transceive)) { 116 | transceive = g.a(transceive); 117 | intValue = Integer.valueOf(g.a(transceive, transceive.length), 16); 118 | action = (intValue / 100) + "." + (intValue % 100); 119 | 120 | // bVar.e(action); 121 | // Log.d("余额", action); 122 | card.setCardBalance(action); 123 | } 124 | } 125 | 126 | 127 | ReadTrade(isoDep, card); 128 | 129 | //测试部分,用于遍历卡内储存地址 130 | // 131 | // for(int j=0;j { 17 | 18 | private ArrayList mData; 19 | private Activity activity; 20 | 21 | public DealAdapter(ArrayList data, Activity activity) { 22 | this.mData = data; 23 | this.activity = activity; 24 | } 25 | 26 | public void updateData(ArrayList data) { 27 | this.mData = data; 28 | notifyDataSetChanged(); 29 | } 30 | 31 | @Override 32 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 33 | // 实例化展示的view 34 | View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_item, parent, false); 35 | // 实例化viewholder 36 | return new ViewHolder(v); 37 | } 38 | 39 | @Override 40 | public void onBindViewHolder(ViewHolder holder, int position) { 41 | // 绑定数据 42 | String m = mData.get(position).getTradingMoney(); 43 | int t = mData.get(position).getTradingType(); 44 | holder.time.setText(mData.get(position).getTradingDateTime()); 45 | holder.money.setText(m); 46 | switch (t) { 47 | case 2: 48 | holder.type.setText(activity.getString(R.string.recharge)); 49 | break; 50 | case 6: 51 | holder.type.setText(activity.getString(R.string.consumption)); 52 | break; 53 | default: 54 | holder.type.setText(t); 55 | break; 56 | } 57 | } 58 | 59 | @Override 60 | public int getItemCount() { 61 | return mData == null ? 0 : mData.size(); 62 | } 63 | 64 | public static class ViewHolder extends RecyclerView.ViewHolder { 65 | 66 | TextView time; 67 | TextView money; 68 | TextView type; 69 | 70 | public ViewHolder(View itemView) { 71 | super(itemView); 72 | type = itemView.findViewById(R.id.type); 73 | money = itemView.findViewById(R.id.deal); 74 | time = itemView.findViewById(R.id.time); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/wolfaonliu/cardreader/ItemDivider.java: -------------------------------------------------------------------------------- 1 | package com.wolfaonliu.cardreader; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Rect; 7 | import android.graphics.drawable.Drawable; 8 | import android.support.v4.view.ViewCompat; 9 | import android.support.v7.widget.LinearLayoutManager; 10 | import android.support.v7.widget.RecyclerView; 11 | import android.view.View; 12 | 13 | /** 14 | * Created by Mogician on 2018/3/14. 15 | */ 16 | 17 | 18 | public class ItemDivider extends RecyclerView.ItemDecoration { 19 | 20 | private static final int[] ATTRS = new int[]{ 21 | android.R.attr.listDivider 22 | }; 23 | public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; 24 | public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; 25 | /** 26 | * 用于绘制间隔样式 27 | */ 28 | private Drawable mDivider; 29 | /** 30 | * 列表的方向,水平/竖直 31 | */ 32 | private int mOrientation; 33 | 34 | 35 | public ItemDivider(Context context, int orientation) { 36 | // 获取默认主题的属性 37 | final TypedArray a = context.obtainStyledAttributes(ATTRS); 38 | mDivider = a.getDrawable(0); 39 | a.recycle(); 40 | setOrientation(orientation); 41 | } 42 | 43 | @Override 44 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 45 | // 绘制间隔 46 | if (mOrientation == VERTICAL_LIST) { 47 | drawVertical(c, parent); 48 | } else { 49 | drawHorizontal(c, parent); 50 | } 51 | } 52 | 53 | @Override 54 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 55 | if (mOrientation == VERTICAL_LIST) { 56 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); 57 | } else { 58 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); 59 | } 60 | } 61 | 62 | private void setOrientation(int orientation) { 63 | if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { 64 | throw new IllegalArgumentException("invalid orientation"); 65 | } 66 | mOrientation = orientation; 67 | } 68 | 69 | /** 70 | * 绘制间隔 71 | */ 72 | private void drawVertical(Canvas c, RecyclerView parent) { 73 | final int left = parent.getPaddingLeft(); 74 | final int right = parent.getWidth() - parent.getPaddingRight(); 75 | final int childCount = parent.getChildCount(); 76 | for (int i = 0; i < childCount; i++) { 77 | final View child = parent.getChildAt(i); 78 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 79 | .getLayoutParams(); 80 | final int top = child.getBottom() + params.bottomMargin + 81 | Math.round(ViewCompat.getTranslationY(child)); 82 | final int bottom = top + mDivider.getIntrinsicHeight(); 83 | mDivider.setBounds(left, top, right, bottom); 84 | mDivider.draw(c); 85 | } 86 | } 87 | 88 | /** 89 | * 绘制间隔 90 | */ 91 | private void drawHorizontal(Canvas c, RecyclerView parent) { 92 | final int top = parent.getPaddingTop(); 93 | final int bottom = parent.getHeight() - parent.getPaddingBottom(); 94 | final int childCount = parent.getChildCount(); 95 | for (int i = 0; i < childCount; i++) { 96 | final View child = parent.getChildAt(i); 97 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 98 | .getLayoutParams(); 99 | final int left = child.getRight() + params.rightMargin + 100 | Math.round(ViewCompat.getTranslationX(child)); 101 | final int right = left + mDivider.getIntrinsicHeight(); 102 | mDivider.setBounds(left, top, right, bottom); 103 | mDivider.draw(c); 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wolfaonliu/cardreader/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.wolfaonliu.cardreader; 2 | 3 | import android.app.PendingIntent; 4 | import android.content.Intent; 5 | import android.nfc.NfcAdapter; 6 | import android.os.Bundle; 7 | import android.support.annotation.NonNull; 8 | import android.support.design.widget.NavigationView; 9 | import android.support.v4.view.GravityCompat; 10 | import android.support.v4.widget.DrawerLayout; 11 | import android.support.v7.app.ActionBarDrawerToggle; 12 | import android.support.v7.app.AppCompatActivity; 13 | import android.support.v7.widget.RecyclerView; 14 | import android.support.v7.widget.Toolbar; 15 | import android.view.MenuItem; 16 | 17 | 18 | //TODO 代码优化,预计大部分都可以去掉 19 | public class MainActivity extends AppCompatActivity 20 | implements NavigationView.OnNavigationItemSelectedListener { 21 | 22 | private NfcAdapter nfcAdapter; 23 | private RecyclerView mRecyclerView; 24 | private RecyclerView.Adapter mAdapter; 25 | private RecyclerView.LayoutManager mLayoutManager; 26 | private PendingIntent pi; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_main); 32 | 33 | viewInit(); 34 | 35 | nfcAdapter = NfcAdapter.getDefaultAdapter(this); 36 | 37 | if (this.nfcAdapter != null) { 38 | pi = PendingIntent.getActivity(this, 0, 39 | new Intent(this, getClass()) 40 | .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); 41 | processIntent(this.getIntent()); 42 | } 43 | 44 | 45 | } 46 | 47 | private void viewInit() { 48 | Toolbar toolbar = findViewById(R.id.toolbar); 49 | setSupportActionBar(toolbar); 50 | 51 | DrawerLayout drawer = findViewById(R.id.drawer_layout); 52 | ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( 53 | this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); 54 | drawer.addDrawerListener(toggle); 55 | toggle.syncState(); 56 | 57 | NavigationView navigationView = findViewById(R.id.nav_view); 58 | navigationView.setNavigationItemSelectedListener(this); 59 | 60 | } 61 | 62 | 63 | @SuppressWarnings("StatementWithEmptyBody") 64 | @Override 65 | public boolean onNavigationItemSelected(@NonNull MenuItem item) { 66 | // Handle navigation view item clicks here. 67 | int id = item.getItemId(); 68 | 69 | if (id == R.id.nav_nfc) { 70 | 71 | } else if (id == R.id.nav_share) { 72 | Intent textIntent = new Intent(Intent.ACTION_SEND); 73 | textIntent.setType("text/plain"); 74 | textIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.app_name) + " : https://www.coolapk.com/apk/com.wolfaonliu.cardreader"); 75 | startActivity(Intent.createChooser(textIntent, getString(R.string.share) + getString(R.string.app_name))); 76 | } else if (id == R.id.nav_about) { 77 | Intent intent = new Intent(MainActivity.this, AboutActivity.class); 78 | startActivity(intent); 79 | } 80 | 81 | DrawerLayout drawer = findViewById(R.id.drawer_layout); 82 | drawer.closeDrawer(GravityCompat.START); 83 | return true; 84 | } 85 | 86 | 87 | @Override 88 | public void onBackPressed() { 89 | DrawerLayout drawer = findViewById(R.id.drawer_layout); 90 | if (drawer.isDrawerOpen(GravityCompat.START)) { 91 | drawer.closeDrawer(GravityCompat.START); 92 | } else { 93 | super.onBackPressed(); 94 | } 95 | } 96 | 97 | @Override 98 | protected void onNewIntent(Intent intent) { 99 | super.onNewIntent(intent); 100 | // 当前app正在前端界面运行,这个时候有intent发送过来,那么系统就会调用onNewIntent回调方法,将intent传送过来 101 | // 我们只需要在这里检验这个intent是否是NFC相关的intent,如果是,就调用处理方法 102 | if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { 103 | processIntent(intent); 104 | } 105 | } 106 | 107 | @Override 108 | protected void onResume() { 109 | super.onResume(); 110 | if (nfcAdapter != null) { 111 | nfcAdapter.enableForegroundDispatch(this, pi, null, null); 112 | } 113 | } 114 | 115 | /** 116 | * Parses the NDEF Message from the intent and prints to the TextView 117 | */ 118 | private void processIntent(Intent intent) { 119 | //取出封装在intent中的TAG 120 | CardInfo card = CardReader.readCard(this, intent); 121 | if (card != null) { 122 | 123 | boolean isFull = card.show(); 124 | card.onFinish(isFull); 125 | //card.showInLog(); 126 | } 127 | } 128 | 129 | public void onPause() { 130 | super.onPause(); 131 | if (nfcAdapter != null) { 132 | nfcAdapter.disableForegroundDispatch(this); 133 | } 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /app/src/main/java/com/wolfaonliu/cardreader/TradingRecordInfo.java: -------------------------------------------------------------------------------- 1 | package com.wolfaonliu.cardreader; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import java.io.Serializable; 6 | import java.util.Locale; 7 | 8 | 9 | //TODO 单个交易记录类 10 | public class TradingRecordInfo implements Serializable, Comparable { 11 | private static final long serialVersionUID = -6533154177080647539L; 12 | private String tradingDateTime; 13 | private String tradingMoney; 14 | private int tradingType; 15 | 16 | public int compareTo(@NonNull TradingRecordInfo tradingRecordInfo) { 17 | return tradingRecordInfo.getTradingDateTime().compareTo(this.tradingDateTime); 18 | } 19 | 20 | public String getTradingDateTime() { 21 | return this.tradingDateTime; 22 | } 23 | 24 | public String getTradingMoney() { 25 | return this.tradingMoney; 26 | } 27 | 28 | public int getTradingType() { 29 | return this.tradingType; 30 | } 31 | 32 | public void setTradingDateTime(String str) { 33 | this.tradingDateTime = str.substring(0, 4) + "." + str.substring(4, 6) + "." + str.substring(6, 8) + " " + str.substring(8, 10) + ":" + str.substring(10, 12); 34 | } 35 | 36 | public void setTradingMoney(long j) { 37 | this.tradingMoney = String.format(Locale.getDefault(), "%.2f", j / 100.0); 38 | } 39 | 40 | public void setTradingType(int i) { 41 | 42 | this.tradingType = i; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/wolfaonliu/cardreader/Util.java: -------------------------------------------------------------------------------- 1 | package com.wolfaonliu.cardreader; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.pm.PackageInfo; 6 | import android.content.pm.PackageManager; 7 | import android.widget.Toast; 8 | 9 | import java.util.regex.Pattern; 10 | 11 | /** 12 | * Created by Mogician on 2018/3/14. 13 | */ 14 | 15 | public class Util { 16 | 17 | public static void aToast(String string, Activity activity) { 18 | Toast.makeText(activity, string, Toast.LENGTH_SHORT).show(); 19 | } 20 | 21 | public static String byteToHex(byte[] bArr) { 22 | int i = 0; 23 | String[] strArr = new String[]{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; 24 | StringBuilder str = new StringBuilder(); 25 | while (i < bArr.length) { 26 | int i2 = bArr[i] & 255; 27 | str = new StringBuilder((str + strArr[(i2 >> 4) & 15]) + strArr[i2 & 15]); 28 | i++; 29 | } 30 | return str.toString(); 31 | } 32 | 33 | //错误提示 34 | public static void ErrorToast(int i, Activity activity) { 35 | switch (i) { 36 | case 1: 37 | Util.aToast("Authentication Failed ", activity); 38 | break; 39 | case 2: 40 | Util.aToast("Failed reading ", activity); 41 | break; 42 | case 3: 43 | Util.aToast("Failed reading 0", activity); 44 | break; 45 | case 4: 46 | Util.aToast("Tag reading error", activity); 47 | break; 48 | case 5: 49 | Util.aToast("不是Mifare卡", activity); 50 | break; 51 | case 6: 52 | Util.aToast("不是CPU卡", activity); 53 | break; 54 | case 7: 55 | Util.aToast("未找到卡", activity); 56 | break; 57 | case 8: 58 | Util.aToast("tag类型不对", activity); 59 | break; 60 | } 61 | } 62 | 63 | public static boolean a(String str) { 64 | char[] toCharArray = Pattern.compile("\\s*|\t*|\r*|\n*").matcher(str).replaceAll("").replaceAll("\\p{P}", "").trim().toCharArray(); 65 | float length = (float) toCharArray.length; 66 | float f = 0.0f; 67 | for (char c : toCharArray) { 68 | if (!(Character.isLetterOrDigit(c) || a(c))) { 69 | f += 1.0f; 70 | } 71 | } 72 | return ((double) (f / length)) > 0.4d; 73 | } 74 | 75 | public static boolean a(char c) { 76 | Character.UnicodeBlock of = Character.UnicodeBlock.of(c); 77 | return of == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || of == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS || of == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || of == Character.UnicodeBlock.GENERAL_PUNCTUATION || of == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || of == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS; 78 | } 79 | 80 | public static boolean d(String str) { 81 | return str == null || str.trim().equals(""); 82 | } 83 | 84 | public static boolean g(String str) { 85 | return !(str == null || str.trim().equals("") || str.equalsIgnoreCase("null")); 86 | } 87 | 88 | public static String getVersion(Context context) { 89 | String ver = ""; 90 | try { 91 | PackageManager packageManager = context.getPackageManager(); 92 | PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); 93 | ver = packageInfo.versionName; 94 | if (ver == "" || ver.length() <= 0) { 95 | return ""; 96 | } 97 | } catch (PackageManager.NameNotFoundException e) { 98 | e.printStackTrace(); 99 | } 100 | return ver; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/java/com/wolfaonliu/cardreader/e.java: -------------------------------------------------------------------------------- 1 | package com.wolfaonliu.cardreader; 2 | 3 | //TODO 工具类更名+整理 4 | public class e { 5 | private static byte a(char c) { 6 | return (byte) "0123456789ABCDEF".indexOf(c); 7 | } 8 | 9 | public static final String a(byte[] bArr, boolean z) { 10 | StringBuilder stringBuilder = new StringBuilder(bArr.length); 11 | for (byte b : bArr) { 12 | String toHexString = Integer.toHexString(b & 255); 13 | if (toHexString.length() < 2) { 14 | stringBuilder.append(0); 15 | } 16 | stringBuilder.append(toHexString.toUpperCase()); 17 | if (z) { 18 | stringBuilder.append(" "); 19 | } 20 | } 21 | return stringBuilder.toString(); 22 | } 23 | 24 | public static final String b(byte[] bArr) { 25 | return a(bArr, false); 26 | } 27 | 28 | 29 | public static String d(byte[] bArr) { 30 | StringBuilder stringBuilder = new StringBuilder(bArr.length * 2); 31 | for (byte aBArr : bArr) { 32 | stringBuilder.append((byte) ((aBArr & 240) >>> 4)); 33 | stringBuilder.append((byte) (aBArr & 15)); 34 | } 35 | return stringBuilder.toString().substring(0, 1).equalsIgnoreCase("0") ? stringBuilder.toString().substring(1) : stringBuilder.toString(); 36 | } 37 | 38 | 39 | public static String e1(byte[] bArr, int i) { 40 | byte[] bArr2 = new byte[7]; 41 | g.a(bArr, i, bArr2, 0, 7); 42 | return d(bArr2); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/wolfaonliu/cardreader/fInts.java: -------------------------------------------------------------------------------- 1 | package com.wolfaonliu.cardreader; 2 | 3 | /** 4 | * Created by Mogician on 2018/3/12. 5 | */ 6 | 7 | public class fInts { 8 | public static final String a = "00A404000E4E432E65436172642E4444463031"; 9 | public static final String b = "00A40400104E432E436F6D70616E792E4E46433031"; 10 | public static final String c = "00A40000023F00"; 11 | public static final String d = "00A4000002EC01"; 12 | public static final String e = "00A4000002EC11"; 13 | public static final String f = "00A4000002EC12"; 14 | public static final String g = "00B0962F3E"; 15 | public static final String h = "00B0968414"; 16 | public static final String i = "00B0962F3E"; 17 | public static final String j = "00B0960214"; 18 | public static final String k = "00B0950A0A"; 19 | public static final String l = "0084000004"; 20 | public static final String m = "0084000008"; 21 | public static final String n = "805C000204"; 22 | public static final String o = "0020000003000000"; 23 | public static final String p = "805001020B0100000000000000000000"; 24 | public static final String q = "805401000F000000000000000000000000000000"; 25 | public static final String r = "805000020B0100000000000000000000"; 26 | public static final String s = "805200000B0000000000000000000000"; 27 | public static final String t = "00B201C417"; 28 | public static final String personId = "00B0961612"; 29 | 30 | // public static String[] tt = {d}; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/wolfaonliu/cardreader/g.java: -------------------------------------------------------------------------------- 1 | package com.wolfaonliu.cardreader; 2 | 3 | 4 | //TODO 工具类更名 5 | public class g { 6 | private static final byte[] a = new byte[]{(byte) 48, (byte) 49, (byte) 50, (byte) 51, (byte) 52, (byte) 53, (byte) 54, (byte) 55, (byte) 56, (byte) 57, (byte) 65, (byte) 66, (byte) 67, (byte) 68, (byte) 69, (byte) 70}; 7 | 8 | private static byte a(char c) { 9 | return (byte) "0123456789ABCDEF".indexOf(c); 10 | } 11 | 12 | public static String a(byte[] bArr, int i) { 13 | int i2 = 0; 14 | byte[] bArr2 = new byte[(i * 2)]; 15 | int length = bArr.length; 16 | int i3 = 0; 17 | int i4 = 0; 18 | while (i2 < length) { 19 | byte b = bArr[i2]; 20 | if (i3 >= i) { 21 | break; 22 | } 23 | i3++; 24 | int i5 = b & 255; 25 | int i6 = i4 + 1; 26 | bArr2[i4] = a[i5 >>> 4]; 27 | i4 = i6 + 1; 28 | bArr2[i6] = a[i5 & 15]; 29 | i2++; 30 | } 31 | return new String(bArr2); 32 | } 33 | 34 | public static String a(byte[] bArr, int i, int i2, String str) { 35 | try { 36 | // String str2 = ""; 37 | byte[] bArr2 = new byte[i2]; 38 | a(bArr, i, bArr2, 0, i2); 39 | return new String(bArr2, str); 40 | } catch (Exception e) { 41 | e.printStackTrace(); 42 | return null; 43 | } 44 | } 45 | 46 | public static void a(byte[] bArr, int i, byte[] bArr2, int i2, int i3) { 47 | if (i2 + i3 > bArr2.length) { 48 | throw new RuntimeException("目标字节数组所分配的长度不够"); 49 | } else if (i + i3 > bArr.length) { 50 | throw new RuntimeException("源字节数组的长度与要求复制的长度不符"); 51 | } else { 52 | System.arraycopy(bArr, i, bArr2, i2, i3); 53 | // for (int i4 = 0; i4 < i3; i4++) { 54 | // bArr2[i2 + i4] = bArr[i + i4]; 55 | // } 56 | //AS自动优化 57 | } 58 | } 59 | 60 | public static byte[] a(String str) { 61 | int length = str.length() / 2; 62 | byte[] bArr = new byte[length]; 63 | char[] toCharArray = str.toCharArray(); 64 | for (int i = 0; i < length; i++) { 65 | int i2 = i * 2; 66 | bArr[i] = (byte) (a(toCharArray[i2 + 1]) | (a(toCharArray[i2]) << 4)); 67 | } 68 | return bArr; 69 | } 70 | 71 | public static byte[] a(byte[] bArr) { 72 | byte[] obj = new byte[(bArr.length - 2)]; 73 | System.arraycopy(bArr, 0, obj, 0, obj.length); 74 | return obj; 75 | } 76 | 77 | public static boolean c(byte[] bArr) { 78 | byte[] obj = new byte[2]; 79 | System.arraycopy(bArr, bArr.length - 2, obj, 0, obj.length); 80 | return a(obj, obj.length).equals("9000"); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_info.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_nfc.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_share.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/side_nav_bar.xml: -------------------------------------------------------------------------------- 1 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/font/noto_sans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/font/noto_sans.ttf -------------------------------------------------------------------------------- /app/src/main/res/layout/about_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 16 | 17 | 25 | 26 | 34 | 35 | 36 | 37 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/app_bar_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/app_bar_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 27 | 28 | 35 | 36 | 42 | 43 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 70 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 29 | 30 | 34 | 35 | 42 | 43 | 52 | 53 | 60 | 61 | 72 | 73 | 74 | 79 | 80 | 89 | 90 | 98 | 99 | 109 | 110 | 124 | 125 | 135 | 136 | 150 | 151 | 161 | 162 | 172 | 173 | 187 | 188 | 189 | 190 | 198 | 199 | 207 | 208 | 220 | 221 | 229 | 230 | 242 | 243 | 251 | 252 | 260 | 261 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 294 | 295 | 299 | 300 | 313 | 314 | 318 | 319 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | -------------------------------------------------------------------------------- /app/src/main/res/layout/nav_header_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 22 | 23 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 22 | 23 | 33 | 34 | 35 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/menu/activity_main_drawer.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 13 | 14 | 15 | 16 | 17 | 21 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liuyanyi/NeuCardReader/5c3c95cf005b8f6e891a90db385fcd76408e0f1f/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values-en/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Newcapec Card Reader 4 | Newcapec Card Reader 5 | Place the card in the reader area 6 | Category 7 | Name 8 | Stu ID 9 | Balance 10 | Hardware ID 11 | Department 12 | Preson ID 13 | Deal list 14 | Type 15 | Time 16 | Deal 17 | background 18 | NFC_Icon 19 | Open navigation drawer 20 | Close navigation drawer 21 | Failed! 22 | Warning, please re-place the card 23 | Success 24 | Failed,unsupported card 25 | Newcapec Card 26 | Unsupported card 27 | yuan 28 | Consumption 29 | Recharge 30 | Share 31 | Read Card 32 | About 33 | Other 34 | About 35 | Version 36 | Developer 37 | Github 38 | Contact 39 | Email Report 40 | Feedback can be provided to developers via email, which will evoke email application. 41 | Yes 42 | No 43 | Choose an Email Client 44 | " Report" 45 | In theory, it applies to all campus cards provided by the Newcapec Company. 46 | Only tested on campus card of NEU. 47 | Donate 48 | -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Open navigation drawer 5 | Close navigation drawer 6 | 7 | background 8 | NFC_Icon 9 | 10 | 新开普读卡器 11 | 新开普读卡器 12 | 将卡片放置到读卡区 13 | 卡类型 14 | 姓名 15 | 学号 16 | 余额 17 | 硬件ID 18 | 学院 19 | 身份证号 20 | 交易记录 21 | Type 22 | Time 23 | Deal 24 | 读卡失败! 25 | 警告,请重新放置卡片 26 | 失败,不支持的卡片 27 | 成功 28 | 校园卡 29 | 不支持的卡片 30 | 31 | 消费 32 | 充值 33 | 分享 34 | 读卡 35 | 关于 36 | 其他 37 | 关于 38 | 版本号 39 | 开发者 40 | Github 41 | 捐赠 42 | 联系方式 43 | 邮件反馈 44 | 可以通过邮件向开发者反馈,该操作会唤起邮件应用。 45 | 46 | 47 | 选择邮件客户端 48 | 反馈 49 | 理论上适用于所有新开普公司提供的校园卡 50 | 目前仅在东北大学校园卡测试通过 51 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 8dp 6 | 176dp 7 | 16dp 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 新开普读卡器 3 | 4 | Open navigation drawer 5 | Close navigation drawer 6 | 7 | 新开普读卡器 8 | background 9 | NFC_Icon 10 | 将卡片放置到读卡区 11 | 卡类型 12 | 姓名 13 | 学号 14 | 余额 15 | 硬件ID 16 | 学院 17 | 身份证号 18 | 交易记录 19 | Type 20 | Time 21 | Deal 22 | 读卡失败! 23 | 警告,请重新放置卡片 24 | 成功 25 | 失败,不支持的卡片 26 | 校园卡 27 | 不支持的卡片 28 | 29 | 消费 30 | 充值 31 | 分享 32 | 读卡 33 | 关于 34 | 关于 35 | 36 | 其他 37 | 版本号 38 | 开发者 39 | Github 40 | 捐赠 41 | 联系方式 42 | 邮件反馈 43 | 可以通过邮件向开发者反馈,该操作会唤起邮件应用。 44 | 45 | 46 | 选择邮件客户端 47 | 反馈 48 | 理论上适用于所有新开普公司提供的校园卡。 49 | 目前仅在东北大学校园卡测试通过。 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 |