Browse Source

首次提交

mq 4 years ago
commit
4816659ded
49 changed files with 2281 additions and 0 deletions
  1. 16 0
      .gitignore
  2. 155 0
      .idea/codeStyles/Project.xml
  3. 456 0
      .idea/dbnavigator.xml
  4. 4 0
      .idea/encodings.xml
  5. 21 0
      .idea/gradle.xml
  6. 25 0
      .idea/jarRepositories.xml
  7. 14 0
      .idea/misc.xml
  8. 12 0
      .idea/runConfigurations.xml
  9. 6 0
      .idea/vcs.xml
  10. 1 0
      README.md
  11. 1 0
      app/.gitignore
  12. 28 0
      app/build.gradle
  13. 21 0
      app/proguard-rules.pro
  14. 26 0
      app/src/androidTest/java/com/mq/nfctool/ExampleInstrumentedTest.java
  15. 47 0
      app/src/main/AndroidManifest.xml
  16. 48 0
      app/src/main/java/com/mq/nfctool/BaseActivity.java
  17. 165 0
      app/src/main/java/com/mq/nfctool/M1CardUtils.java
  18. 27 0
      app/src/main/java/com/mq/nfctool/MainActivity.java
  19. 389 0
      app/src/main/java/com/mq/nfctool/NFCActivity.java
  20. 185 0
      app/src/main/java/com/mq/nfctool/NfcUtils.java
  21. 34 0
      app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  22. 170 0
      app/src/main/res/drawable/ic_launcher_background.xml
  23. 18 0
      app/src/main/res/layout/activity_main.xml
  24. 47 0
      app/src/main/res/layout/activity_nfc.xml
  25. 5 0
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  26. 5 0
      app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  27. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.png
  28. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher_round.png
  29. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.png
  30. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher_round.png
  31. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher.png
  32. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
  33. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  34. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
  35. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  36. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
  37. 6 0
      app/src/main/res/values/colors.xml
  38. 3 0
      app/src/main/res/values/strings.xml
  39. 11 0
      app/src/main/res/values/styles.xml
  40. 13 0
      app/src/main/res/xml/nfc.xml
  41. 17 0
      app/src/test/java/com/mq/nfctool/ExampleUnitTest.java
  42. 27 0
      build.gradle
  43. 15 0
      gradle.properties
  44. BIN
      gradle/wrapper/gradle-wrapper.jar
  45. 6 0
      gradle/wrapper/gradle-wrapper.properties
  46. 172 0
      gradlew
  47. 84 0
      gradlew.bat
  48. BIN
      nfctool.jks
  49. 1 0
      settings.gradle

+ 16 - 0
.gitignore

@@ -0,0 +1,16 @@
1
+*.iml
2
+.gradle
3
+/local.properties
4
+/.idea/caches
5
+/.idea/libraries
6
+/.idea/modules.xml
7
+/.idea/workspace.xml
8
+/.idea/navEditor.xml
9
+/.idea/assetWizardSettings.xml
10
+.DS_Store
11
+/build
12
+/captures
13
+.externalNativeBuild
14
+/app/release/*.apk
15
+/app/release
16
+/app/debug

+ 155 - 0
.idea/codeStyles/Project.xml

@@ -0,0 +1,155 @@
1
+<component name="ProjectCodeStyleConfiguration">
2
+  <code_scheme name="Project" version="173">
3
+    <DBN-PSQL>
4
+      <case-options enabled="true">
5
+        <option name="KEYWORD_CASE" value="lower" />
6
+        <option name="FUNCTION_CASE" value="lower" />
7
+        <option name="PARAMETER_CASE" value="lower" />
8
+        <option name="DATATYPE_CASE" value="lower" />
9
+        <option name="OBJECT_CASE" value="preserve" />
10
+      </case-options>
11
+      <formatting-settings enabled="false" />
12
+    </DBN-PSQL>
13
+    <DBN-SQL>
14
+      <case-options enabled="true">
15
+        <option name="KEYWORD_CASE" value="lower" />
16
+        <option name="FUNCTION_CASE" value="lower" />
17
+        <option name="PARAMETER_CASE" value="lower" />
18
+        <option name="DATATYPE_CASE" value="lower" />
19
+        <option name="OBJECT_CASE" value="preserve" />
20
+      </case-options>
21
+      <formatting-settings enabled="false">
22
+        <option name="STATEMENT_SPACING" value="one_line" />
23
+        <option name="CLAUSE_CHOP_DOWN" value="chop_down_if_statement_long" />
24
+        <option name="ITERATION_ELEMENTS_WRAPPING" value="chop_down_if_not_single" />
25
+      </formatting-settings>
26
+    </DBN-SQL>
27
+    <JetCodeStyleSettings>
28
+      <option name="PACKAGES_TO_USE_STAR_IMPORTS">
29
+        <value>
30
+          <package name="java.util" alias="false" withSubpackages="false" />
31
+          <package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
32
+          <package name="io.ktor" alias="false" withSubpackages="true" />
33
+        </value>
34
+      </option>
35
+      <option name="PACKAGES_IMPORT_LAYOUT">
36
+        <value>
37
+          <package name="" alias="false" withSubpackages="true" />
38
+          <package name="java" alias="false" withSubpackages="true" />
39
+          <package name="javax" alias="false" withSubpackages="true" />
40
+          <package name="kotlin" alias="false" withSubpackages="true" />
41
+          <package name="" alias="true" withSubpackages="true" />
42
+        </value>
43
+      </option>
44
+    </JetCodeStyleSettings>
45
+    <codeStyleSettings language="XML">
46
+      <arrangement>
47
+        <rules>
48
+          <section>
49
+            <rule>
50
+              <match>
51
+                <AND>
52
+                  <NAME>xmlns:android</NAME>
53
+                  <XML_ATTRIBUTE />
54
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
55
+                </AND>
56
+              </match>
57
+            </rule>
58
+          </section>
59
+          <section>
60
+            <rule>
61
+              <match>
62
+                <AND>
63
+                  <NAME>xmlns:.*</NAME>
64
+                  <XML_ATTRIBUTE />
65
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
66
+                </AND>
67
+              </match>
68
+              <order>BY_NAME</order>
69
+            </rule>
70
+          </section>
71
+          <section>
72
+            <rule>
73
+              <match>
74
+                <AND>
75
+                  <NAME>.*:id</NAME>
76
+                  <XML_ATTRIBUTE />
77
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
78
+                </AND>
79
+              </match>
80
+            </rule>
81
+          </section>
82
+          <section>
83
+            <rule>
84
+              <match>
85
+                <AND>
86
+                  <NAME>.*:name</NAME>
87
+                  <XML_ATTRIBUTE />
88
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
89
+                </AND>
90
+              </match>
91
+            </rule>
92
+          </section>
93
+          <section>
94
+            <rule>
95
+              <match>
96
+                <AND>
97
+                  <NAME>name</NAME>
98
+                  <XML_ATTRIBUTE />
99
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
100
+                </AND>
101
+              </match>
102
+            </rule>
103
+          </section>
104
+          <section>
105
+            <rule>
106
+              <match>
107
+                <AND>
108
+                  <NAME>style</NAME>
109
+                  <XML_ATTRIBUTE />
110
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
111
+                </AND>
112
+              </match>
113
+            </rule>
114
+          </section>
115
+          <section>
116
+            <rule>
117
+              <match>
118
+                <AND>
119
+                  <NAME>.*</NAME>
120
+                  <XML_ATTRIBUTE />
121
+                  <XML_NAMESPACE>^$</XML_NAMESPACE>
122
+                </AND>
123
+              </match>
124
+              <order>BY_NAME</order>
125
+            </rule>
126
+          </section>
127
+          <section>
128
+            <rule>
129
+              <match>
130
+                <AND>
131
+                  <NAME>.*</NAME>
132
+                  <XML_ATTRIBUTE />
133
+                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
134
+                </AND>
135
+              </match>
136
+              <order>ANDROID_ATTRIBUTE_ORDER</order>
137
+            </rule>
138
+          </section>
139
+          <section>
140
+            <rule>
141
+              <match>
142
+                <AND>
143
+                  <NAME>.*</NAME>
144
+                  <XML_ATTRIBUTE />
145
+                  <XML_NAMESPACE>.*</XML_NAMESPACE>
146
+                </AND>
147
+              </match>
148
+              <order>BY_NAME</order>
149
+            </rule>
150
+          </section>
151
+        </rules>
152
+      </arrangement>
153
+    </codeStyleSettings>
154
+  </code_scheme>
155
+</component>

+ 456 - 0
.idea/dbnavigator.xml

@@ -0,0 +1,456 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="DBNavigator.Project.DataEditorManager">
4
+    <record-view-column-sorting-type value="BY_INDEX" />
5
+    <value-preview-text-wrapping value="true" />
6
+    <value-preview-pinned value="false" />
7
+  </component>
8
+  <component name="DBNavigator.Project.DataExportManager">
9
+    <export-instructions>
10
+      <create-header value="true" />
11
+      <quote-values-containing-separator value="true" />
12
+      <quote-all-values value="false" />
13
+      <value-separator value="" />
14
+      <file-name value="" />
15
+      <file-location value="" />
16
+      <scope value="GLOBAL" />
17
+      <destination value="FILE" />
18
+      <format value="EXCEL" />
19
+      <charset value="GBK" />
20
+    </export-instructions>
21
+  </component>
22
+  <component name="DBNavigator.Project.DatabaseBrowserManager">
23
+    <autoscroll-to-editor value="false" />
24
+    <autoscroll-from-editor value="true" />
25
+    <show-object-properties value="true" />
26
+    <loaded-nodes />
27
+  </component>
28
+  <component name="DBNavigator.Project.DatabaseFileManager">
29
+    <open-files />
30
+  </component>
31
+  <component name="DBNavigator.Project.EditorStateManager">
32
+    <last-used-providers />
33
+  </component>
34
+  <component name="DBNavigator.Project.MethodExecutionManager">
35
+    <method-browser />
36
+    <execution-history>
37
+      <group-entries value="true" />
38
+      <execution-inputs />
39
+    </execution-history>
40
+    <argument-values-cache />
41
+  </component>
42
+  <component name="DBNavigator.Project.ObjectDependencyManager">
43
+    <last-used-dependency-type value="INCOMING" />
44
+  </component>
45
+  <component name="DBNavigator.Project.ObjectQuickFilterManager">
46
+    <last-used-operator value="EQUAL" />
47
+    <filters />
48
+  </component>
49
+  <component name="DBNavigator.Project.ScriptExecutionManager" clear-outputs="true">
50
+    <recently-used-interfaces />
51
+  </component>
52
+  <component name="DBNavigator.Project.Settings">
53
+    <connections />
54
+    <browser-settings>
55
+      <general>
56
+        <display-mode value="TABBED" />
57
+        <navigation-history-size value="100" />
58
+        <show-object-details value="false" />
59
+      </general>
60
+      <filters>
61
+        <object-type-filter>
62
+          <object-type name="SCHEMA" enabled="true" />
63
+          <object-type name="USER" enabled="true" />
64
+          <object-type name="ROLE" enabled="true" />
65
+          <object-type name="PRIVILEGE" enabled="true" />
66
+          <object-type name="CHARSET" enabled="true" />
67
+          <object-type name="TABLE" enabled="true" />
68
+          <object-type name="VIEW" enabled="true" />
69
+          <object-type name="MATERIALIZED_VIEW" enabled="true" />
70
+          <object-type name="NESTED_TABLE" enabled="true" />
71
+          <object-type name="COLUMN" enabled="true" />
72
+          <object-type name="INDEX" enabled="true" />
73
+          <object-type name="CONSTRAINT" enabled="true" />
74
+          <object-type name="DATASET_TRIGGER" enabled="true" />
75
+          <object-type name="DATABASE_TRIGGER" enabled="true" />
76
+          <object-type name="SYNONYM" enabled="true" />
77
+          <object-type name="SEQUENCE" enabled="true" />
78
+          <object-type name="PROCEDURE" enabled="true" />
79
+          <object-type name="FUNCTION" enabled="true" />
80
+          <object-type name="PACKAGE" enabled="true" />
81
+          <object-type name="TYPE" enabled="true" />
82
+          <object-type name="TYPE_ATTRIBUTE" enabled="true" />
83
+          <object-type name="ARGUMENT" enabled="true" />
84
+          <object-type name="DIMENSION" enabled="true" />
85
+          <object-type name="CLUSTER" enabled="true" />
86
+          <object-type name="DBLINK" enabled="true" />
87
+        </object-type-filter>
88
+      </filters>
89
+      <sorting>
90
+        <object-type name="COLUMN" sorting-type="NAME" />
91
+        <object-type name="FUNCTION" sorting-type="NAME" />
92
+        <object-type name="PROCEDURE" sorting-type="NAME" />
93
+        <object-type name="ARGUMENT" sorting-type="POSITION" />
94
+      </sorting>
95
+      <default-editors>
96
+        <object-type name="VIEW" editor-type="SELECTION" />
97
+        <object-type name="PACKAGE" editor-type="SELECTION" />
98
+        <object-type name="TYPE" editor-type="SELECTION" />
99
+      </default-editors>
100
+    </browser-settings>
101
+    <navigation-settings>
102
+      <lookup-filters>
103
+        <lookup-objects>
104
+          <object-type name="SCHEMA" enabled="true" />
105
+          <object-type name="USER" enabled="false" />
106
+          <object-type name="ROLE" enabled="false" />
107
+          <object-type name="PRIVILEGE" enabled="false" />
108
+          <object-type name="CHARSET" enabled="false" />
109
+          <object-type name="TABLE" enabled="true" />
110
+          <object-type name="VIEW" enabled="true" />
111
+          <object-type name="MATERIALIZED VIEW" enabled="true" />
112
+          <object-type name="NESTED TABLE" enabled="false" />
113
+          <object-type name="COLUMN" enabled="false" />
114
+          <object-type name="INDEX" enabled="true" />
115
+          <object-type name="CONSTRAINT" enabled="true" />
116
+          <object-type name="DATASET TRIGGER" enabled="true" />
117
+          <object-type name="DATABASE TRIGGER" enabled="true" />
118
+          <object-type name="SYNONYM" enabled="false" />
119
+          <object-type name="SEQUENCE" enabled="true" />
120
+          <object-type name="PROCEDURE" enabled="true" />
121
+          <object-type name="FUNCTION" enabled="true" />
122
+          <object-type name="PACKAGE" enabled="true" />
123
+          <object-type name="TYPE" enabled="true" />
124
+          <object-type name="TYPE ATTRIBUTE" enabled="false" />
125
+          <object-type name="ARGUMENT" enabled="false" />
126
+          <object-type name="DIMENSION" enabled="false" />
127
+          <object-type name="CLUSTER" enabled="false" />
128
+          <object-type name="DBLINK" enabled="true" />
129
+        </lookup-objects>
130
+        <force-database-load value="false" />
131
+        <prompt-connection-selection value="true" />
132
+        <prompt-schema-selection value="true" />
133
+      </lookup-filters>
134
+    </navigation-settings>
135
+    <dataset-grid-settings>
136
+      <general>
137
+        <enable-zooming value="true" />
138
+        <enable-column-tooltip value="true" />
139
+      </general>
140
+      <sorting>
141
+        <nulls-first value="true" />
142
+        <max-sorting-columns value="4" />
143
+      </sorting>
144
+      <tracking-columns>
145
+        <columnNames value="" />
146
+        <visible value="true" />
147
+        <editable value="false" />
148
+      </tracking-columns>
149
+    </dataset-grid-settings>
150
+    <dataset-editor-settings>
151
+      <text-editor-popup>
152
+        <active value="false" />
153
+        <active-if-empty value="false" />
154
+        <data-length-threshold value="100" />
155
+        <popup-delay value="1000" />
156
+      </text-editor-popup>
157
+      <values-actions-popup>
158
+        <show-popup-button value="true" />
159
+        <element-count-threshold value="1000" />
160
+        <data-length-threshold value="250" />
161
+      </values-actions-popup>
162
+      <general>
163
+        <fetch-block-size value="100" />
164
+        <fetch-timeout value="30" />
165
+        <trim-whitespaces value="true" />
166
+        <convert-empty-strings-to-null value="true" />
167
+        <select-content-on-cell-edit value="true" />
168
+        <large-value-preview-active value="true" />
169
+      </general>
170
+      <filters>
171
+        <prompt-filter-dialog value="true" />
172
+        <default-filter-type value="BASIC" />
173
+      </filters>
174
+      <qualified-text-editor text-length-threshold="300">
175
+        <content-types>
176
+          <content-type name="Text" enabled="true" />
177
+          <content-type name="Properties" enabled="true" />
178
+          <content-type name="XML" enabled="true" />
179
+          <content-type name="DTD" enabled="true" />
180
+          <content-type name="HTML" enabled="true" />
181
+          <content-type name="XHTML" enabled="true" />
182
+          <content-type name="Java" enabled="true" />
183
+          <content-type name="SQL" enabled="true" />
184
+          <content-type name="PL/SQL" enabled="true" />
185
+          <content-type name="Groovy" enabled="true" />
186
+          <content-type name="AIDL" enabled="true" />
187
+          <content-type name="YAML" enabled="true" />
188
+          <content-type name="Manifest" enabled="true" />
189
+        </content-types>
190
+      </qualified-text-editor>
191
+      <record-navigation>
192
+        <navigation-target value="VIEWER" />
193
+      </record-navigation>
194
+    </dataset-editor-settings>
195
+    <code-editor-settings>
196
+      <general>
197
+        <show-object-navigation-gutter value="false" />
198
+        <show-spec-declaration-navigation-gutter value="true" />
199
+        <enable-spellchecking value="true" />
200
+        <enable-reference-spellchecking value="false" />
201
+      </general>
202
+      <confirmations>
203
+        <save-changes value="false" />
204
+        <revert-changes value="true" />
205
+      </confirmations>
206
+    </code-editor-settings>
207
+    <code-completion-settings>
208
+      <filters>
209
+        <basic-filter>
210
+          <filter-element type="RESERVED_WORD" id="keyword" selected="true" />
211
+          <filter-element type="RESERVED_WORD" id="function" selected="true" />
212
+          <filter-element type="RESERVED_WORD" id="parameter" selected="true" />
213
+          <filter-element type="RESERVED_WORD" id="datatype" selected="true" />
214
+          <filter-element type="RESERVED_WORD" id="exception" selected="true" />
215
+          <filter-element type="OBJECT" id="schema" selected="true" />
216
+          <filter-element type="OBJECT" id="role" selected="true" />
217
+          <filter-element type="OBJECT" id="user" selected="true" />
218
+          <filter-element type="OBJECT" id="privilege" selected="true" />
219
+          <user-schema>
220
+            <filter-element type="OBJECT" id="table" selected="true" />
221
+            <filter-element type="OBJECT" id="view" selected="true" />
222
+            <filter-element type="OBJECT" id="materialized view" selected="true" />
223
+            <filter-element type="OBJECT" id="index" selected="true" />
224
+            <filter-element type="OBJECT" id="constraint" selected="true" />
225
+            <filter-element type="OBJECT" id="trigger" selected="true" />
226
+            <filter-element type="OBJECT" id="synonym" selected="false" />
227
+            <filter-element type="OBJECT" id="sequence" selected="true" />
228
+            <filter-element type="OBJECT" id="procedure" selected="true" />
229
+            <filter-element type="OBJECT" id="function" selected="true" />
230
+            <filter-element type="OBJECT" id="package" selected="true" />
231
+            <filter-element type="OBJECT" id="type" selected="true" />
232
+            <filter-element type="OBJECT" id="dimension" selected="true" />
233
+            <filter-element type="OBJECT" id="cluster" selected="true" />
234
+            <filter-element type="OBJECT" id="dblink" selected="true" />
235
+          </user-schema>
236
+          <public-schema>
237
+            <filter-element type="OBJECT" id="table" selected="false" />
238
+            <filter-element type="OBJECT" id="view" selected="false" />
239
+            <filter-element type="OBJECT" id="materialized view" selected="false" />
240
+            <filter-element type="OBJECT" id="index" selected="false" />
241
+            <filter-element type="OBJECT" id="constraint" selected="false" />
242
+            <filter-element type="OBJECT" id="trigger" selected="false" />
243
+            <filter-element type="OBJECT" id="synonym" selected="false" />
244
+            <filter-element type="OBJECT" id="sequence" selected="false" />
245
+            <filter-element type="OBJECT" id="procedure" selected="false" />
246
+            <filter-element type="OBJECT" id="function" selected="false" />
247
+            <filter-element type="OBJECT" id="package" selected="false" />
248
+            <filter-element type="OBJECT" id="type" selected="false" />
249
+            <filter-element type="OBJECT" id="dimension" selected="false" />
250
+            <filter-element type="OBJECT" id="cluster" selected="false" />
251
+            <filter-element type="OBJECT" id="dblink" selected="false" />
252
+          </public-schema>
253
+          <any-schema>
254
+            <filter-element type="OBJECT" id="table" selected="true" />
255
+            <filter-element type="OBJECT" id="view" selected="true" />
256
+            <filter-element type="OBJECT" id="materialized view" selected="true" />
257
+            <filter-element type="OBJECT" id="index" selected="true" />
258
+            <filter-element type="OBJECT" id="constraint" selected="true" />
259
+            <filter-element type="OBJECT" id="trigger" selected="true" />
260
+            <filter-element type="OBJECT" id="synonym" selected="true" />
261
+            <filter-element type="OBJECT" id="sequence" selected="true" />
262
+            <filter-element type="OBJECT" id="procedure" selected="true" />
263
+            <filter-element type="OBJECT" id="function" selected="true" />
264
+            <filter-element type="OBJECT" id="package" selected="true" />
265
+            <filter-element type="OBJECT" id="type" selected="true" />
266
+            <filter-element type="OBJECT" id="dimension" selected="true" />
267
+            <filter-element type="OBJECT" id="cluster" selected="true" />
268
+            <filter-element type="OBJECT" id="dblink" selected="true" />
269
+          </any-schema>
270
+        </basic-filter>
271
+        <extended-filter>
272
+          <filter-element type="RESERVED_WORD" id="keyword" selected="true" />
273
+          <filter-element type="RESERVED_WORD" id="function" selected="true" />
274
+          <filter-element type="RESERVED_WORD" id="parameter" selected="true" />
275
+          <filter-element type="RESERVED_WORD" id="datatype" selected="true" />
276
+          <filter-element type="RESERVED_WORD" id="exception" selected="true" />
277
+          <filter-element type="OBJECT" id="schema" selected="true" />
278
+          <filter-element type="OBJECT" id="user" selected="true" />
279
+          <filter-element type="OBJECT" id="role" selected="true" />
280
+          <filter-element type="OBJECT" id="privilege" selected="true" />
281
+          <user-schema>
282
+            <filter-element type="OBJECT" id="table" selected="true" />
283
+            <filter-element type="OBJECT" id="view" selected="true" />
284
+            <filter-element type="OBJECT" id="materialized view" selected="true" />
285
+            <filter-element type="OBJECT" id="index" selected="true" />
286
+            <filter-element type="OBJECT" id="constraint" selected="true" />
287
+            <filter-element type="OBJECT" id="trigger" selected="true" />
288
+            <filter-element type="OBJECT" id="synonym" selected="true" />
289
+            <filter-element type="OBJECT" id="sequence" selected="true" />
290
+            <filter-element type="OBJECT" id="procedure" selected="true" />
291
+            <filter-element type="OBJECT" id="function" selected="true" />
292
+            <filter-element type="OBJECT" id="package" selected="true" />
293
+            <filter-element type="OBJECT" id="type" selected="true" />
294
+            <filter-element type="OBJECT" id="dimension" selected="true" />
295
+            <filter-element type="OBJECT" id="cluster" selected="true" />
296
+            <filter-element type="OBJECT" id="dblink" selected="true" />
297
+          </user-schema>
298
+          <public-schema>
299
+            <filter-element type="OBJECT" id="table" selected="true" />
300
+            <filter-element type="OBJECT" id="view" selected="true" />
301
+            <filter-element type="OBJECT" id="materialized view" selected="true" />
302
+            <filter-element type="OBJECT" id="index" selected="true" />
303
+            <filter-element type="OBJECT" id="constraint" selected="true" />
304
+            <filter-element type="OBJECT" id="trigger" selected="true" />
305
+            <filter-element type="OBJECT" id="synonym" selected="true" />
306
+            <filter-element type="OBJECT" id="sequence" selected="true" />
307
+            <filter-element type="OBJECT" id="procedure" selected="true" />
308
+            <filter-element type="OBJECT" id="function" selected="true" />
309
+            <filter-element type="OBJECT" id="package" selected="true" />
310
+            <filter-element type="OBJECT" id="type" selected="true" />
311
+            <filter-element type="OBJECT" id="dimension" selected="true" />
312
+            <filter-element type="OBJECT" id="cluster" selected="true" />
313
+            <filter-element type="OBJECT" id="dblink" selected="true" />
314
+          </public-schema>
315
+          <any-schema>
316
+            <filter-element type="OBJECT" id="table" selected="true" />
317
+            <filter-element type="OBJECT" id="view" selected="true" />
318
+            <filter-element type="OBJECT" id="materialized view" selected="true" />
319
+            <filter-element type="OBJECT" id="index" selected="true" />
320
+            <filter-element type="OBJECT" id="constraint" selected="true" />
321
+            <filter-element type="OBJECT" id="trigger" selected="true" />
322
+            <filter-element type="OBJECT" id="synonym" selected="true" />
323
+            <filter-element type="OBJECT" id="sequence" selected="true" />
324
+            <filter-element type="OBJECT" id="procedure" selected="true" />
325
+            <filter-element type="OBJECT" id="function" selected="true" />
326
+            <filter-element type="OBJECT" id="package" selected="true" />
327
+            <filter-element type="OBJECT" id="type" selected="true" />
328
+            <filter-element type="OBJECT" id="dimension" selected="true" />
329
+            <filter-element type="OBJECT" id="cluster" selected="true" />
330
+            <filter-element type="OBJECT" id="dblink" selected="true" />
331
+          </any-schema>
332
+        </extended-filter>
333
+      </filters>
334
+      <sorting enabled="true">
335
+        <sorting-element type="RESERVED_WORD" id="keyword" />
336
+        <sorting-element type="RESERVED_WORD" id="datatype" />
337
+        <sorting-element type="OBJECT" id="column" />
338
+        <sorting-element type="OBJECT" id="table" />
339
+        <sorting-element type="OBJECT" id="view" />
340
+        <sorting-element type="OBJECT" id="materialized view" />
341
+        <sorting-element type="OBJECT" id="index" />
342
+        <sorting-element type="OBJECT" id="constraint" />
343
+        <sorting-element type="OBJECT" id="trigger" />
344
+        <sorting-element type="OBJECT" id="synonym" />
345
+        <sorting-element type="OBJECT" id="sequence" />
346
+        <sorting-element type="OBJECT" id="procedure" />
347
+        <sorting-element type="OBJECT" id="function" />
348
+        <sorting-element type="OBJECT" id="package" />
349
+        <sorting-element type="OBJECT" id="type" />
350
+        <sorting-element type="OBJECT" id="dimension" />
351
+        <sorting-element type="OBJECT" id="cluster" />
352
+        <sorting-element type="OBJECT" id="dblink" />
353
+        <sorting-element type="OBJECT" id="schema" />
354
+        <sorting-element type="OBJECT" id="role" />
355
+        <sorting-element type="OBJECT" id="user" />
356
+        <sorting-element type="RESERVED_WORD" id="function" />
357
+        <sorting-element type="RESERVED_WORD" id="parameter" />
358
+      </sorting>
359
+      <format>
360
+        <enforce-code-style-case value="true" />
361
+      </format>
362
+    </code-completion-settings>
363
+    <execution-engine-settings>
364
+      <statement-execution>
365
+        <fetch-block-size value="100" />
366
+        <execution-timeout value="20" />
367
+        <debug-execution-timeout value="600" />
368
+        <focus-result value="false" />
369
+        <prompt-execution value="false" />
370
+      </statement-execution>
371
+      <script-execution>
372
+        <command-line-interfaces />
373
+        <execution-timeout value="300" />
374
+      </script-execution>
375
+      <method-execution>
376
+        <execution-timeout value="30" />
377
+        <debug-execution-timeout value="600" />
378
+        <parameter-history-size value="10" />
379
+      </method-execution>
380
+    </execution-engine-settings>
381
+    <operation-settings>
382
+      <transactions>
383
+        <uncommitted-changes>
384
+          <on-project-close value="ASK" />
385
+          <on-disconnect value="ASK" />
386
+          <on-autocommit-toggle value="ASK" />
387
+        </uncommitted-changes>
388
+        <multiple-uncommitted-changes>
389
+          <on-commit value="ASK" />
390
+          <on-rollback value="ASK" />
391
+        </multiple-uncommitted-changes>
392
+      </transactions>
393
+      <session-browser>
394
+        <disconnect-session value="ASK" />
395
+        <kill-session value="ASK" />
396
+        <reload-on-filter-change value="false" />
397
+      </session-browser>
398
+      <compiler>
399
+        <compile-type value="KEEP" />
400
+        <compile-dependencies value="ASK" />
401
+        <always-show-controls value="false" />
402
+      </compiler>
403
+      <debugger>
404
+        <debugger-type value="ASK" />
405
+        <use-generic-runners value="true" />
406
+      </debugger>
407
+    </operation-settings>
408
+    <ddl-file-settings>
409
+      <extensions>
410
+        <mapping file-type-id="VIEW" extensions="vw" />
411
+        <mapping file-type-id="TRIGGER" extensions="trg" />
412
+        <mapping file-type-id="PROCEDURE" extensions="prc" />
413
+        <mapping file-type-id="FUNCTION" extensions="fnc" />
414
+        <mapping file-type-id="PACKAGE" extensions="pkg" />
415
+        <mapping file-type-id="PACKAGE_SPEC" extensions="pks" />
416
+        <mapping file-type-id="PACKAGE_BODY" extensions="pkb" />
417
+        <mapping file-type-id="TYPE" extensions="tpe" />
418
+        <mapping file-type-id="TYPE_SPEC" extensions="tps" />
419
+        <mapping file-type-id="TYPE_BODY" extensions="tpb" />
420
+      </extensions>
421
+      <general>
422
+        <lookup-ddl-files value="true" />
423
+        <create-ddl-files value="false" />
424
+        <synchronize-ddl-files value="true" />
425
+        <use-qualified-names value="false" />
426
+        <make-scripts-rerunnable value="true" />
427
+      </general>
428
+    </ddl-file-settings>
429
+    <general-settings>
430
+      <regional-settings>
431
+        <date-format value="MEDIUM" />
432
+        <number-format value="UNGROUPED" />
433
+        <locale value="SYSTEM_DEFAULT" />
434
+        <use-custom-formats value="false" />
435
+      </regional-settings>
436
+      <environment>
437
+        <environment-types>
438
+          <environment-type id="development" name="Development" description="Development environment" color="-2430209/-12296320" readonly-code="false" readonly-data="false" />
439
+          <environment-type id="integration" name="Integration" description="Integration environment" color="-2621494/-12163514" readonly-code="true" readonly-data="false" />
440
+          <environment-type id="production" name="Production" description="Productive environment" color="-11574/-10271420" readonly-code="true" readonly-data="true" />
441
+          <environment-type id="other" name="Other" description="" color="-1576/-10724543" readonly-code="false" readonly-data="false" />
442
+        </environment-types>
443
+        <visibility-settings>
444
+          <connection-tabs value="true" />
445
+          <dialog-headers value="true" />
446
+          <object-editor-tabs value="true" />
447
+          <script-editor-tabs value="false" />
448
+          <execution-result-tabs value="true" />
449
+        </visibility-settings>
450
+      </environment>
451
+    </general-settings>
452
+  </component>
453
+  <component name="DBNavigator.Project.StatementExecutionManager">
454
+    <execution-variables />
455
+  </component>
456
+</project>

+ 4 - 0
.idea/encodings.xml

@@ -0,0 +1,4 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="Encoding" addBOMForNewFiles="with NO BOM" />
4
+</project>

+ 21 - 0
.idea/gradle.xml

@@ -0,0 +1,21 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="GradleMigrationSettings" migrationVersion="1" />
4
+  <component name="GradleSettings">
5
+    <option name="linkedExternalProjectsSettings">
6
+      <GradleProjectSettings>
7
+        <option name="delegatedBuild" value="true" />
8
+        <option name="testRunner" value="PLATFORM" />
9
+        <option name="distributionType" value="DEFAULT_WRAPPED" />
10
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
11
+        <option name="modules">
12
+          <set>
13
+            <option value="$PROJECT_DIR$" />
14
+            <option value="$PROJECT_DIR$/app" />
15
+          </set>
16
+        </option>
17
+        <option name="resolveModulePerSourceSet" value="false" />
18
+      </GradleProjectSettings>
19
+    </option>
20
+  </component>
21
+</project>

+ 25 - 0
.idea/jarRepositories.xml

@@ -0,0 +1,25 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="RemoteRepositoriesConfiguration">
4
+    <remote-repository>
5
+      <option name="id" value="central" />
6
+      <option name="name" value="Maven Central repository" />
7
+      <option name="url" value="https://repo1.maven.org/maven2" />
8
+    </remote-repository>
9
+    <remote-repository>
10
+      <option name="id" value="jboss.community" />
11
+      <option name="name" value="JBoss Community repository" />
12
+      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
13
+    </remote-repository>
14
+    <remote-repository>
15
+      <option name="id" value="BintrayJCenter" />
16
+      <option name="name" value="BintrayJCenter" />
17
+      <option name="url" value="https://jcenter.bintray.com/" />
18
+    </remote-repository>
19
+    <remote-repository>
20
+      <option name="id" value="Google" />
21
+      <option name="name" value="Google" />
22
+      <option name="url" value="https://dl.google.com/dl/android/maven2/" />
23
+    </remote-repository>
24
+  </component>
25
+</project>

+ 14 - 0
.idea/misc.xml

@@ -0,0 +1,14 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="CMakeSettings">
4
+    <configurations>
5
+      <configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
6
+    </configurations>
7
+  </component>
8
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="JDK" project-jdk-type="JavaSDK">
9
+    <output url="file://$PROJECT_DIR$/build/classes" />
10
+  </component>
11
+  <component name="ProjectType">
12
+    <option name="id" value="Android" />
13
+  </component>
14
+</project>

+ 12 - 0
.idea/runConfigurations.xml

@@ -0,0 +1,12 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="RunConfigurationProducerService">
4
+    <option name="ignoredProducers">
5
+      <set>
6
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
7
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
8
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
9
+      </set>
10
+    </option>
11
+  </component>
12
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project version="4">
3
+  <component name="VcsDirectoryMappings">
4
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+  </component>
6
+</project>

+ 1 - 0
README.md

@@ -0,0 +1 @@
1
+# NFC测试工具

+ 1 - 0
app/.gitignore

@@ -0,0 +1 @@
1
+/build

+ 28 - 0
app/build.gradle

@@ -0,0 +1,28 @@
1
+apply plugin: 'com.android.application'
2
+
3
+android {
4
+    compileSdkVersion 28
5
+    defaultConfig {
6
+        applicationId "com.mq.nfctool"
7
+        minSdkVersion 15
8
+        targetSdkVersion 28
9
+        versionCode 1
10
+        versionName "1.0"
11
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12
+    }
13
+    buildTypes {
14
+        release {
15
+            minifyEnabled false
16
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
17
+        }
18
+    }
19
+}
20
+
21
+dependencies {
22
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
23
+    implementation 'com.android.support:appcompat-v7:28.0.0'
24
+    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
25
+    testImplementation 'junit:junit:4.12'
26
+    androidTestImplementation 'com.android.support.test:runner:1.0.2'
27
+    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
28
+}

+ 21 - 0
app/proguard-rules.pro

@@ -0,0 +1,21 @@
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

+ 26 - 0
app/src/androidTest/java/com/mq/nfctool/ExampleInstrumentedTest.java

@@ -0,0 +1,26 @@
1
+package com.mq.nfctool;
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.*;
11
+
12
+/**
13
+ * Instrumented test, which will execute on an Android device.
14
+ *
15
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
16
+ */
17
+@RunWith(AndroidJUnit4.class)
18
+public class ExampleInstrumentedTest {
19
+    @Test
20
+    public void useAppContext() {
21
+        // Context of the app under test.
22
+        Context appContext = InstrumentationRegistry.getTargetContext();
23
+
24
+        assertEquals("com.mq.nfctool", appContext.getPackageName());
25
+    }
26
+}

+ 47 - 0
app/src/main/AndroidManifest.xml

@@ -0,0 +1,47 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+    xmlns:tools="http://schemas.android.com/tools"
4
+    package="com.mq.nfctool">
5
+    <!-- NFC 相关权限 -->
6
+    <!-- 描述所需硬件特性 -->
7
+    <uses-feature
8
+        android:name="android.hardware.nfc"
9
+        android:required="true" />
10
+
11
+    <uses-permission android:name="android.permission.NFC" />
12
+
13
+    <application
14
+        android:allowBackup="true"
15
+        android:icon="@mipmap/ic_launcher"
16
+        android:label="@string/app_name"
17
+        android:roundIcon="@mipmap/ic_launcher_round"
18
+        android:supportsRtl="true"
19
+        android:theme="@style/AppTheme"
20
+        tools:ignore="GoogleAppIndexingWarning">
21
+
22
+        <activity
23
+            android:name=".NFCActivity"
24
+            android:launchMode="singleTop">
25
+            <intent-filter>
26
+                <action android:name="android.intent.action.MAIN" />
27
+                <category android:name="android.intent.category.LAUNCHER" />
28
+            </intent-filter>
29
+            <intent-filter>
30
+                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
31
+            </intent-filter>
32
+            <intent-filter>
33
+                <action android:name="android.nfc.action.TAG_DISCOVERED" />
34
+                <category android:name="android.intent.category.DEFAULT" />
35
+            </intent-filter>
36
+            <intent-filter>
37
+                <action android:name="android.nfc.action.TECH_DISCOVERED" />
38
+            </intent-filter>
39
+        </activity>
40
+
41
+        <activity android:name=".MainActivity">
42
+
43
+        </activity>
44
+
45
+    </application>
46
+
47
+</manifest>

+ 48 - 0
app/src/main/java/com/mq/nfctool/BaseActivity.java

@@ -0,0 +1,48 @@
1
+package com.mq.nfctool;
2
+
3
+import android.app.PendingIntent;
4
+import android.content.Intent;
5
+import android.nfc.NfcAdapter;
6
+import android.support.v7.app.AppCompatActivity;
7
+
8
+/**
9
+ * 创建人 mQ
10
+ * 创建时间 2019/6/24 0024 16:46
11
+ * 文件名称 BaseActivity
12
+ * 说明:
13
+ **/
14
+public class BaseActivity extends AppCompatActivity {
15
+
16
+    private NfcAdapter mNfcAdapter;
17
+    private PendingIntent mPendingIntent;
18
+    /**
19
+     * 启动Activity,界面可见时
20
+     */
21
+    @Override
22
+    protected void onStart() {
23
+        super.onStart();
24
+        mNfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
25
+        //一旦截获NFC消息,就会通过PendingIntent调用窗口
26
+        mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0);
27
+    }
28
+    /**
29
+     * 获得焦点,按钮可以点击
30
+     */
31
+    @Override
32
+    public void onResume() {
33
+        super.onResume();
34
+        //设置处理优于所有其他NFC的处理
35
+        if (mNfcAdapter != null)
36
+            mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
37
+    }
38
+    /**
39
+     * 暂停Activity,界面获取焦点,按钮可以点击
40
+     */
41
+    @Override
42
+    public void onPause() {
43
+        super.onPause();
44
+        //恢复默认状态
45
+        if (mNfcAdapter != null)
46
+            mNfcAdapter.disableForegroundDispatch(this);
47
+    }
48
+}

+ 165 - 0
app/src/main/java/com/mq/nfctool/M1CardUtils.java

@@ -0,0 +1,165 @@
1
+package com.mq.nfctool;
2
+
3
+import android.app.Activity;
4
+import android.app.PendingIntent;
5
+import android.nfc.NfcAdapter;
6
+import android.nfc.Tag;
7
+import android.nfc.tech.MifareClassic;
8
+import android.util.Log;
9
+import android.widget.Toast;
10
+
11
+import java.io.IOException;
12
+
13
+/**
14
+ * 创建人 mQ
15
+ * 创建时间 2019/6/24 0024 17:30
16
+ * 文件名称 M1CardUtils
17
+ * 说明:
18
+ **/
19
+public class M1CardUtils {
20
+    private static PendingIntent pendingIntent;
21
+    public static PendingIntent getPendingIntent(){
22
+        return pendingIntent;
23
+    }
24
+
25
+    public static void setPendingIntent(PendingIntent pendingIntent){
26
+        M1CardUtils.pendingIntent = pendingIntent;
27
+    }
28
+
29
+    /**
30
+     * 判断是否支持NFC
31
+     * @return
32
+     */
33
+    public static NfcAdapter isNfcAble(Activity mContext){
34
+        NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext);
35
+        if (mNfcAdapter == null) {
36
+            Toast.makeText(mContext, "设备不支持NFC!", Toast.LENGTH_LONG).show();
37
+        }
38
+        if (!mNfcAdapter.isEnabled()) {
39
+            Toast.makeText(mContext, "请在系统设置中先启用NFC功能!", Toast.LENGTH_LONG).show();
40
+        }
41
+        return mNfcAdapter;
42
+    }
43
+
44
+    /**
45
+     * 监测是否支持MifareClassic
46
+     * @param tag
47
+     * @param activity
48
+     * @return
49
+     */
50
+    public static boolean isMifareClassic(Tag tag, Activity activity){
51
+        String[] techList = tag.getTechList();
52
+        boolean haveMifareUltralight = false;
53
+        for (String tech : techList) {
54
+            if (tech.contains("MifareClassic")) {
55
+                haveMifareUltralight = true;
56
+                break;
57
+            }
58
+        }
59
+        if (!haveMifareUltralight) {
60
+            Toast.makeText(activity, "不支持MifareClassic", Toast.LENGTH_LONG).show();
61
+            return false;
62
+        }
63
+        return true;
64
+    }
65
+
66
+    /**
67
+     * 读取卡片信息
68
+     * @return
69
+     */
70
+    public static String[][] readCard(Tag tag)  throws IOException{
71
+        MifareClassic mifareClassic = MifareClassic.get(tag);
72
+        try {
73
+            mifareClassic.connect();
74
+            String[][] metaInfo = new String[16][4];
75
+            // 获取TAG中包含的扇区数
76
+            int sectorCount = mifareClassic.getSectorCount();
77
+            for (int j = 0; j < sectorCount; j++) {
78
+                int bCount;//当前扇区的块数
79
+                int bIndex;//当前扇区第一块
80
+                if (m1Auth(mifareClassic,j)) {
81
+                    bCount = mifareClassic.getBlockCountInSector(j);
82
+                    bIndex = mifareClassic.sectorToBlock(j);
83
+                    for (int i = 0; i < bCount; i++) {
84
+                        byte[] data = mifareClassic.readBlock(bIndex);
85
+                        String dataString = bytesToHexString(data);
86
+                        metaInfo[j][i] = dataString;
87
+                        Log.e("获取到信息",dataString);
88
+                        bIndex++;
89
+                    }
90
+                } else {
91
+                    Log.e("readCard","密码校验失败");
92
+                }
93
+            }
94
+            return metaInfo;
95
+        } catch (IOException e){
96
+            throw new IOException(e);
97
+        } finally {
98
+            try {
99
+                mifareClassic.close();
100
+            }catch (IOException e){
101
+                throw new IOException(e);
102
+            }
103
+        }
104
+    }
105
+
106
+    /**
107
+     * 改写数据
108
+     * @param block
109
+     * @param blockbyte
110
+     */
111
+    public static boolean writeBlock(Tag tag, int block, byte[] blockbyte) throws IOException {
112
+        MifareClassic mifareClassic = MifareClassic.get(tag);
113
+        try {
114
+            mifareClassic.connect();
115
+            if (m1Auth(mifareClassic,block/4)) {
116
+                mifareClassic.writeBlock(block, blockbyte);
117
+                Log.e("writeBlock","写入成功");
118
+            } else {
119
+                Log.e("密码是", "没有找到密码");
120
+                return false;
121
+            }
122
+        } catch (IOException e){
123
+            throw new IOException(e);
124
+        } finally {
125
+            try {
126
+                mifareClassic.close();
127
+            }catch (IOException e){
128
+                throw new IOException(e);
129
+            }
130
+        }
131
+        return true;
132
+
133
+    }
134
+
135
+    /**
136
+     * 密码校验
137
+     * @param mTag
138
+     * @param position
139
+     * @return
140
+     * @throws IOException
141
+     */
142
+    public static boolean m1Auth(MifareClassic mTag, int position) throws IOException {
143
+        if (mTag.authenticateSectorWithKeyA(position, MifareClassic.KEY_DEFAULT)) {
144
+            return true;
145
+        } else if (mTag.authenticateSectorWithKeyB(position, MifareClassic.KEY_DEFAULT)) {
146
+            return true;
147
+        }
148
+        return false;
149
+    }
150
+
151
+    private static String bytesToHexString(byte[] src) {
152
+        StringBuilder stringBuilder = new StringBuilder();
153
+        if (src == null || src.length <= 0) {
154
+            return null;
155
+        }
156
+        char[] buffer = new char[2];
157
+        for (int i = 0; i < src.length; i++) {
158
+            buffer[0] = Character.forDigit((src[i] >>> 4) & 0x0F, 16);
159
+            buffer[1] = Character.forDigit(src[i] & 0x0F, 16);
160
+            System.out.println(buffer);
161
+            stringBuilder.append(buffer);
162
+        }
163
+        return stringBuilder.toString();
164
+    }
165
+}

+ 27 - 0
app/src/main/java/com/mq/nfctool/MainActivity.java

@@ -0,0 +1,27 @@
1
+package com.mq.nfctool;
2
+
3
+import android.content.Intent;
4
+import android.nfc.FormatException;
5
+import android.nfc.NdefMessage;
6
+import android.nfc.NdefRecord;
7
+import android.nfc.NfcAdapter;
8
+import android.os.Parcelable;
9
+import android.support.v7.app.AppCompatActivity;
10
+import android.os.Bundle;
11
+import android.util.Log;
12
+import android.widget.Toast;
13
+
14
+import java.io.IOException;
15
+import java.io.UnsupportedEncodingException;
16
+
17
+public class MainActivity extends AppCompatActivity {
18
+
19
+    @Override
20
+    protected void onCreate(Bundle savedInstanceState) {
21
+        super.onCreate(savedInstanceState);
22
+        setContentView(R.layout.activity_main);
23
+        startActivity(new Intent(this, NFCActivity.class));
24
+    }
25
+
26
+
27
+}

+ 389 - 0
app/src/main/java/com/mq/nfctool/NFCActivity.java

@@ -0,0 +1,389 @@
1
+package com.mq.nfctool;
2
+
3
+import android.app.PendingIntent;
4
+import android.content.Intent;
5
+import android.nfc.FormatException;
6
+import android.nfc.NdefMessage;
7
+import android.nfc.NdefRecord;
8
+import android.nfc.NfcAdapter;
9
+import android.nfc.Tag;
10
+import android.nfc.tech.MifareClassic;
11
+import android.nfc.tech.Ndef;
12
+import android.os.Parcelable;
13
+import android.provider.Settings;
14
+import android.support.v7.app.AppCompatActivity;
15
+import android.os.Bundle;
16
+import android.util.Base64;
17
+import android.util.Log;
18
+import android.view.View;
19
+import android.widget.EditText;
20
+import android.widget.TextView;
21
+import android.widget.Toast;
22
+
23
+import java.io.IOException;
24
+import java.io.UnsupportedEncodingException;
25
+import java.util.ArrayList;
26
+import java.util.Arrays;
27
+import java.util.HashMap;
28
+import java.util.List;
29
+import java.util.Map;
30
+
31
+public class NFCActivity extends AppCompatActivity {
32
+    private static final String TAG = "NFCActivity";
33
+
34
+    private String mTagText;
35
+    private EditText mTvContent;
36
+    private TextView mTvMsg;
37
+    private NfcAdapter mNfcAdapter;
38
+    private PendingIntent mPendingIntent;
39
+
40
+    @Override
41
+    protected void onCreate(Bundle savedInstanceState) {
42
+        super.onCreate(savedInstanceState);
43
+        setContentView(R.layout.activity_nfc);
44
+        mTvContent = findViewById(R.id.tv_content);
45
+        mTvMsg = findViewById(R.id.tv_msg);
46
+    }
47
+
48
+    @Override
49
+    protected void onStart() {
50
+        super.onStart();
51
+        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
52
+        //一旦截获NFC消息,就会通过PendingIntent调用窗口
53
+        mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0);
54
+    }
55
+
56
+    @Override
57
+    protected void onResume() {
58
+        super.onResume();
59
+        //设置处理优于所有其他NFC的处理
60
+        if (mNfcAdapter != null)
61
+            mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
62
+    }
63
+
64
+//    @Override
65
+//    protected void onNewIntent(Intent intent) {
66
+//        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
67
+//            mTvMsg.setText("读卡中");
68
+//
69
+//            StringBuffer sb = new StringBuffer();
70
+//            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
71
+//            sb.append("可用技术: \n");
72
+//            for (String tech : tag.getTechList()) {
73
+//                sb.append(tech);
74
+//                sb.append("\n");
75
+//            }
76
+//            sb.append("\n------------------------\n");
77
+//            MifareClassic mc = MifareClassic.get(tag);
78
+//            try {
79
+//                mc.connect();
80
+//                int type = mc.getType();//获取TAG的类型
81
+//                int sectorCount = mc.getSectorCount();//获取扇区数
82
+//                sb.append("\n卡片连接成功")
83
+//                        .append("\n卡片类型:");
84
+//                switch (type) {
85
+//                    case MifareClassic.TYPE_CLASSIC:
86
+//                        sb.append("TYPE_CLASSIC");
87
+//                        break;
88
+//                    case MifareClassic.TYPE_PLUS:
89
+//                        sb.append("TYPE_PLUS");
90
+//                        break;
91
+//                    case MifareClassic.TYPE_PRO:
92
+//                        sb.append("TYPE_PRO");
93
+//                        break;
94
+//                    case MifareClassic.TYPE_UNKNOWN:
95
+//                        sb.append("TYPE_UNKNOWN");
96
+//                        break;
97
+//                }
98
+//                sb.append("\n共")
99
+//                        .append(sectorCount)
100
+//                        .append("个扇区\n共")
101
+//                        .append(mc.getBlockCount())
102
+//                        .append("个块\n存储空间: ")
103
+//                        .append(mc.getSize())
104
+//                        .append("B\n");
105
+//                sb.append("\n------------------------\n");
106
+//
107
+//                StringBuffer sbResult = new StringBuffer();
108
+//
109
+//                for (int i = 0; i < sectorCount; i++) {
110
+//                    //验证扇区
111
+//                    boolean auth = mc.authenticateSectorWithKeyA(i, MifareClassic.KEY_DEFAULT);
112
+//                    if (auth) {
113
+//                        //获取扇区中的块数
114
+//                        int blockCount = mc.getBlockCountInSector(i);
115
+//                        sb.append("\n")
116
+//                                .append(i)
117
+//                                .append("扇区验证通过,共")
118
+//                                .append(blockCount)
119
+//                                .append("个块\n");
120
+//
121
+//                        int blockIndex = mc.sectorToBlock(i);
122
+//                        for (int j = 0; j < blockCount; j++) {
123
+//                            byte[] data = mc.readBlock(blockIndex);//读取块中的字节
124
+//
125
+//                            String strRead = new String(data, "gb2312");
126
+//                            String result = "";
127
+//                            if (i != 0 || j != 0)
128
+//                                if (j < blockCount - 1)
129
+//                                    sbResult.append(strRead);
130
+//
131
+//                            //数据解析
132
+//                            try {
133
+//                                if (strRead.contains("*")) {
134
+//                                    //*代表结尾, 截取结尾前的数据,转换成字符串
135
+//                                    String substring = strRead.substring(0, strRead.indexOf("*"));
136
+//                                    result = new String(Base64.decode(substring.getBytes(), Base64.DEFAULT), "gb2312");
137
+//                                } else if ("0000000000000000".equals(strRead)) {
138
+//                                    //0000000000000000 无数据,直接赋值
139
+//                                    result = strRead;
140
+//                                } else {
141
+//                                    result = new String(Base64.decode(strRead.getBytes(), Base64.DEFAULT), "gb2312");
142
+//                                }
143
+//                            } catch (Exception e) {
144
+//                                //解析失败直接赋值
145
+//                                result = strRead;
146
+//                            }
147
+//                            sb.append(i)
148
+//                                    .append("扇区, ")
149
+//                                    .append(j)
150
+//                                    .append("块,数据: ")
151
+//                                    .append(result)
152
+//                                    .append("\n");
153
+//                            blockIndex++;
154
+//                        }
155
+//
156
+//                    } else {
157
+//                        sb.append(i + "区验证失败");
158
+//                    }
159
+//                }
160
+//                String debugStr = sbResult.toString();
161
+//                String debugStrResult = null;
162
+//                if (debugStr.contains("*")) {
163
+//                    debugStrResult = debugStr.substring(0, debugStr.indexOf("*"));
164
+//                } else {
165
+//                    debugStrResult = debugStr;
166
+//                }
167
+//                byte[] debugBytes = Base64.decode(debugStrResult.getBytes(), Base64.DEFAULT);
168
+//                String gb2312 = new String(debugBytes, "gb2312");
169
+//                StringBuffer buffer = new StringBuffer();
170
+//                String[] split = gb2312.split("\\|");
171
+//                buffer.append("字段数:")
172
+//                        .append(split.length)
173
+//                        .append("\n");
174
+//                for (int i = 0; i < split.length; i++) {
175
+//                    buffer.append(split[i])
176
+//                            .append("\n");
177
+//                }
178
+//                sb.append("\n------------------------\n")
179
+//                        .append("所需数据解析:\n")
180
+//                        .append(buffer.toString());
181
+//            } catch (Exception e) {
182
+//                e.printStackTrace();
183
+//                Log.e(TAG, "NFC读取异常: " + e);
184
+//            } finally {
185
+//                try {
186
+//                    mc.close();
187
+//                } catch (Exception e) {
188
+//                    e.printStackTrace();
189
+//                }
190
+//            }
191
+//            mTvContent.setText(sb.toString());
192
+//        }
193
+//        mTvMsg.setText("读卡结束");
194
+//    }
195
+
196
+
197
+    @Override
198
+    protected void onNewIntent(Intent intent) {
199
+        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
200
+
201
+            mTvMsg.setText("读卡中");
202
+
203
+            StringBuffer sb = new StringBuffer();
204
+            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
205
+            sb.append("可用技术: \n");
206
+            for (String tech : tag.getTechList()) {
207
+                sb.append(tech).append("\n");
208
+            }
209
+            sb.append("\n------------------------\n");
210
+            MifareClassic mc = MifareClassic.get(tag);
211
+            try {
212
+                mc.connect();
213
+                if (!mc.isConnected()) {
214
+                    sb.append("卡片连接失败")
215
+                            .append("\n");
216
+                    mTvContent.setText(sb.toString());
217
+                    mTvMsg.setText("读卡结束");
218
+                    return;
219
+                }
220
+                int type = mc.getType();//获取TAG的类型
221
+                int sectorCount = mc.getSectorCount();//获取扇区数
222
+                sb.append("卡片连接成功")
223
+                        .append("\n")
224
+                        .append("卡片类型:");
225
+                switch (type) {
226
+                    case MifareClassic.TYPE_CLASSIC:
227
+                        sb.append("TYPE_CLASSIC");
228
+                        break;
229
+                    case MifareClassic.TYPE_PLUS:
230
+                        sb.append("TYPE_PLUS");
231
+                        break;
232
+                    case MifareClassic.TYPE_PRO:
233
+                        sb.append("TYPE_PRO");
234
+                        break;
235
+                    case MifareClassic.TYPE_UNKNOWN:
236
+                        sb.append("TYPE_UNKNOWN");
237
+                        break;
238
+                }
239
+                sb.append("\n扇区:")
240
+                        .append(sectorCount)
241
+                        .append("\n块:")
242
+                        .append(mc.getBlockCount())
243
+                        .append("\n存储空间: ")
244
+                        .append(mc.getSize())
245
+                        .append("B");
246
+                sb.append("\n------------------------\n");
247
+
248
+                StringBuffer sbResult = new StringBuffer();
249
+
250
+                List<byte[]> byteList = new ArrayList<>();
251
+
252
+                for (int i = 0; i < sectorCount; i++) {
253
+                    //验证扇区
254
+                    boolean auth = false;
255
+                    if (mc.authenticateSectorWithKeyA(i, MifareClassic.KEY_MIFARE_APPLICATION_DIRECTORY)) {
256
+                        auth = true;
257
+                    } else if (mc.authenticateSectorWithKeyA(i, MifareClassic.KEY_DEFAULT)) {
258
+                        auth = true;
259
+                    } else if (mc.authenticateSectorWithKeyA(i, MifareClassic.KEY_NFC_FORUM)) {
260
+                        auth = true;
261
+                    } else {
262
+                        Log.d("TAG", "Authorization denied ");
263
+                    }
264
+                    if (!auth) {
265
+                        sb.append(i).append("扇区验证失败")
266
+                                .append("\n");
267
+                        mTvContent.setText(sb.toString());
268
+                        mTvMsg.setText("读卡结束");
269
+                        return;
270
+                    }
271
+
272
+                    //获取扇区中的块数
273
+                    int blockCount = mc.getBlockCountInSector(i);
274
+                    sb.append("\n")
275
+                            .append(i)
276
+                            .append("扇区验证通过,共")
277
+                            .append(blockCount)
278
+                            .append("个块\n");
279
+
280
+                    int blockIndex = mc.sectorToBlock(i);
281
+                    for (int j = 0; j < blockCount; j++) {
282
+                        byte[] data = mc.readBlock(blockIndex);//读取块中的字节
283
+
284
+                        String strRead = new String(data, "gb2312");
285
+//                        String result = "";
286
+                        if (i != 0 || j != 0)
287
+                            if (j < blockCount - 1) {
288
+                                sbResult.append(strRead);
289
+                                byteList.add(data);
290
+                            }
291
+
292
+//                            //数据解析
293
+//                            try {
294
+//                                if (strRead.contains("*")) {
295
+//                                    //*代表结尾, 截取结尾前的数据,转换成字符串
296
+//                                    String substring = strRead.substring(0, strRead.indexOf("*"));
297
+//                                    result = new String(substring.getBytes(), "gb2312");
298
+//                                } else if ("0000000000000000".equals(strRead)) {
299
+//                                    //0000000000000000 无数据,直接赋值
300
+//                                    result = strRead;
301
+//                                } else {
302
+//                                    result = new String(strRead.getBytes(), "gb2312");
303
+//                                }
304
+//                            } catch (Exception e) {
305
+//                                //解析失败直接赋值
306
+//                                result = strRead;
307
+//                            }
308
+//                        sb.append(i)
309
+//                                .append("扇区, ")
310
+//                                .append(j)
311
+//                                .append("块,数据: ")
312
+//                                .append(strRead)
313
+//                                .append("\n");
314
+                        blockIndex++;
315
+                    }
316
+                }
317
+                mc.close();
318
+
319
+                sb.append("读取结果:\n").append(sbResult.toString());
320
+                int count = 0;
321
+                for (byte[] bytes : byteList) {
322
+                    count += bytes.length;
323
+                }
324
+                sb.append("读取字节总数:")
325
+                        .append(count)
326
+                        .append("\n");
327
+                byte[] byteResult = new byte[count];
328
+                int index = 0;
329
+                for (byte[] bytes : byteList) {
330
+                    for (byte b : bytes) {
331
+                        byteResult[index] = b;
332
+                        index++;
333
+                    }
334
+                }
335
+                String result = new String(byteResult, "gb2312");
336
+                sb.append("读取结果:")
337
+                        .append(result)
338
+                        .append("\n");
339
+//                String debugStr = sbResult.toString();
340
+                String debugStrResult = null;
341
+                if (result.contains("*")) {
342
+                    debugStrResult = result.substring(0, result.indexOf("*"));
343
+                } else {
344
+                    debugStrResult = result;
345
+                }
346
+//                byte[] debugBytes = debugStrResult.getBytes();
347
+//                String gb2312 = new String(debugBytes, "gb2312");
348
+                StringBuffer buffer = new StringBuffer();
349
+                String[] split = debugStrResult.split("\\|");
350
+                buffer.append("字段数:")
351
+                        .append(split.length)
352
+                        .append("\n");
353
+
354
+                for (int i = 0; i < split.length; i++) {
355
+                    buffer.append(split[i])
356
+                            .append("\n");
357
+                }
358
+                sb.append("\n------------------------\n")
359
+                        .append("所需数据解析:\n")
360
+                        .append(buffer.toString());
361
+
362
+            } catch (Exception e) {
363
+                e.printStackTrace();
364
+                Log.e(TAG, "NFC读取异常: " + e);
365
+                sb.append("NFC读取异常:\n");
366
+                sb.append(e.toString());
367
+            }
368
+            mTvContent.setText(sb.toString());
369
+        }
370
+        mTvMsg.setText("读卡结束");
371
+
372
+    }
373
+
374
+    /**
375
+     * 暂停Activity,界面获取焦点
376
+     */
377
+    @Override
378
+    public void onPause() {
379
+        super.onPause();
380
+        //恢复默认状态
381
+        if (mNfcAdapter != null)
382
+            mNfcAdapter.disableForegroundDispatch(this);
383
+    }
384
+
385
+    public void onClick(View view) {
386
+        mTvContent.setText("");
387
+        mTvMsg.setText("请重新放卡");
388
+    }
389
+}

+ 185 - 0
app/src/main/java/com/mq/nfctool/NfcUtils.java

@@ -0,0 +1,185 @@
1
+package com.mq.nfctool;
2
+
3
+import android.app.Activity;
4
+import android.app.PendingIntent;
5
+import android.content.DialogInterface;
6
+import android.content.Intent;
7
+import android.content.IntentFilter;
8
+import android.nfc.FormatException;
9
+import android.nfc.NdefMessage;
10
+import android.nfc.NdefRecord;
11
+import android.nfc.NfcAdapter;
12
+import android.nfc.Tag;
13
+import android.nfc.tech.MifareClassic;
14
+import android.nfc.tech.Ndef;
15
+import android.nfc.tech.NfcA;
16
+import android.os.Build;
17
+import android.os.Parcelable;
18
+import android.provider.Settings;
19
+import android.support.v7.app.AlertDialog;
20
+import android.widget.Toast;
21
+
22
+import java.io.IOException;
23
+import java.io.UnsupportedEncodingException;
24
+
25
+/**
26
+ * 创建人 mQ
27
+ * 创建时间 2019/6/24 0024 16:29
28
+ * 文件名称 NfcUtils
29
+ * 说明:
30
+ **/
31
+public class NfcUtils {
32
+
33
+    //nfc
34
+    public static NfcAdapter mNfcAdapter;
35
+    public static IntentFilter[] mIntentFilter = null;
36
+    public static PendingIntent mPendingIntent = null;
37
+    public static String[][] mTechList = null;
38
+
39
+    public NfcUtils(Activity activity) {
40
+        mNfcAdapter = NfcCheck(activity);
41
+        NfcInit(activity);
42
+    }
43
+
44
+    /**
45
+     * 检查NFC是否打开
46
+     */
47
+    public static NfcAdapter NfcCheck(Activity activity) {
48
+        NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(activity);
49
+        if (mNfcAdapter == null) {
50
+            Toast.makeText(activity, "设备不支持NFC功能!", Toast.LENGTH_SHORT).show();
51
+            return null;
52
+        } else {
53
+            if (!mNfcAdapter.isEnabled()) {
54
+                IsToSet(activity);
55
+            } else {
56
+                Toast.makeText(activity, "NFC功能已打开!", Toast.LENGTH_SHORT).show();
57
+            }
58
+        }
59
+        return mNfcAdapter;
60
+    }
61
+
62
+    /**
63
+     * 初始化nfc设置
64
+     */
65
+    public static void NfcInit(Activity activity) {
66
+        Intent intent = new Intent(activity, activity.getClass());
67
+        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
68
+        mPendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
69
+        //做一个IntentFilter过滤你想要的action 这里过滤的是ndef
70
+        IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
71
+        //如果你对action的定义有更高的要求,比如data的要求,你可以使用如下的代码来定义intentFilter
72
+        //        IntentFilter filter2 = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
73
+        //        try {
74
+        //            filter.addDataType("*/*");
75
+        //        } catch (IntentFilter.MalformedMimeTypeException e) {
76
+        //            e.printStackTrace();
77
+        //        }
78
+        //        mIntentFilter = new IntentFilter[]{filter, filter2};
79
+        //        mTechList = null;
80
+        try {
81
+            filter.addDataType("*/*");
82
+        } catch (IntentFilter.MalformedMimeTypeException e) {
83
+            e.printStackTrace();
84
+        }
85
+        mTechList = new String[][]{{MifareClassic.class.getName()},
86
+                {NfcA.class.getName()}};
87
+        //生成intentFilter
88
+        mIntentFilter = new IntentFilter[]{filter};
89
+    }
90
+
91
+
92
+    /**
93
+     * 读取NFC的数据
94
+     */
95
+    public static String readNFCFromTag(Intent intent) throws UnsupportedEncodingException {
96
+        Parcelable[] rawArray = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
97
+        if (rawArray != null) {
98
+            NdefMessage mNdefMsg = (NdefMessage) rawArray[0];
99
+            NdefRecord mNdefRecord = mNdefMsg.getRecords()[0];
100
+            if (mNdefRecord != null) {
101
+                String readResult = new String(mNdefRecord.getPayload(), "UTF-8");
102
+                return readResult;
103
+            }
104
+        }
105
+        return "";
106
+    }
107
+
108
+
109
+    /**
110
+     * 往nfc写入数据
111
+     */
112
+    public static void writeNFCToTag(String data, Intent intent) throws IOException, FormatException {
113
+        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
114
+        Ndef ndef = Ndef.get(tag);
115
+        ndef.connect();
116
+        NdefRecord ndefRecord = null;
117
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
118
+            ndefRecord = NdefRecord.createTextRecord(null, data);
119
+        }
120
+        NdefRecord[] records = {ndefRecord};
121
+        NdefMessage ndefMessage = new NdefMessage(records);
122
+        ndef.writeNdefMessage(ndefMessage);
123
+    }
124
+
125
+    /**
126
+     * 读取nfcID
127
+     */
128
+    public static String readNFCId(Intent intent) throws UnsupportedEncodingException {
129
+        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
130
+        String id = ByteArrayToHexString(tag.getId());
131
+        return id;
132
+    }
133
+
134
+    /**
135
+     * 将字节数组转换为字符串
136
+     */
137
+    private static String ByteArrayToHexString(byte[] inarray) {
138
+        int i, j, in;
139
+        String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
140
+        String out = "";
141
+
142
+        for (j = 0; j < inarray.length; ++j) {
143
+            in = (int) inarray[j] & 0xff;
144
+            i = (in >> 4) & 0x0f;
145
+            out += hex[i];
146
+            i = in & 0x0f;
147
+            out += hex[i];
148
+        }
149
+        return out;
150
+    }
151
+
152
+    private static void IsToSet(final Activity activity) {
153
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
154
+        builder.setMessage("是否跳转到设置页面打开NFC功能");
155
+//        builder.setTitle("提示");
156
+        builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
157
+            @Override
158
+            public void onClick(DialogInterface dialog, int which) {
159
+                goToSet(activity);
160
+                dialog.dismiss();
161
+            }
162
+        });
163
+        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
164
+            @Override
165
+            public void onClick(DialogInterface dialog, int which) {
166
+                dialog.dismiss();
167
+            }
168
+        });
169
+        builder.create().show();
170
+    }
171
+
172
+    private static void goToSet(Activity activity) {
173
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BASE) {
174
+            // 进入设置系统应用权限界面
175
+            Intent intent = new Intent(Settings.ACTION_SETTINGS);
176
+            activity.startActivity(intent);
177
+            return;
178
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {// 运行系统在5.x环境使用
179
+            // 进入设置系统应用权限界面
180
+            Intent intent = new Intent(Settings.ACTION_SETTINGS);
181
+            activity.startActivity(intent);
182
+            return;
183
+        }
184
+    }
185
+}

File diff suppressed because it is too large
+ 34 - 0
app/src/main/res/drawable-v24/ic_launcher_foreground.xml


+ 170 - 0
app/src/main/res/drawable/ic_launcher_background.xml

@@ -0,0 +1,170 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
3
+    android:width="108dp"
4
+    android:height="108dp"
5
+    android:viewportWidth="108"
6
+    android:viewportHeight="108">
7
+    <path
8
+        android:fillColor="#008577"
9
+        android:pathData="M0,0h108v108h-108z" />
10
+    <path
11
+        android:fillColor="#00000000"
12
+        android:pathData="M9,0L9,108"
13
+        android:strokeWidth="0.8"
14
+        android:strokeColor="#33FFFFFF" />
15
+    <path
16
+        android:fillColor="#00000000"
17
+        android:pathData="M19,0L19,108"
18
+        android:strokeWidth="0.8"
19
+        android:strokeColor="#33FFFFFF" />
20
+    <path
21
+        android:fillColor="#00000000"
22
+        android:pathData="M29,0L29,108"
23
+        android:strokeWidth="0.8"
24
+        android:strokeColor="#33FFFFFF" />
25
+    <path
26
+        android:fillColor="#00000000"
27
+        android:pathData="M39,0L39,108"
28
+        android:strokeWidth="0.8"
29
+        android:strokeColor="#33FFFFFF" />
30
+    <path
31
+        android:fillColor="#00000000"
32
+        android:pathData="M49,0L49,108"
33
+        android:strokeWidth="0.8"
34
+        android:strokeColor="#33FFFFFF" />
35
+    <path
36
+        android:fillColor="#00000000"
37
+        android:pathData="M59,0L59,108"
38
+        android:strokeWidth="0.8"
39
+        android:strokeColor="#33FFFFFF" />
40
+    <path
41
+        android:fillColor="#00000000"
42
+        android:pathData="M69,0L69,108"
43
+        android:strokeWidth="0.8"
44
+        android:strokeColor="#33FFFFFF" />
45
+    <path
46
+        android:fillColor="#00000000"
47
+        android:pathData="M79,0L79,108"
48
+        android:strokeWidth="0.8"
49
+        android:strokeColor="#33FFFFFF" />
50
+    <path
51
+        android:fillColor="#00000000"
52
+        android:pathData="M89,0L89,108"
53
+        android:strokeWidth="0.8"
54
+        android:strokeColor="#33FFFFFF" />
55
+    <path
56
+        android:fillColor="#00000000"
57
+        android:pathData="M99,0L99,108"
58
+        android:strokeWidth="0.8"
59
+        android:strokeColor="#33FFFFFF" />
60
+    <path
61
+        android:fillColor="#00000000"
62
+        android:pathData="M0,9L108,9"
63
+        android:strokeWidth="0.8"
64
+        android:strokeColor="#33FFFFFF" />
65
+    <path
66
+        android:fillColor="#00000000"
67
+        android:pathData="M0,19L108,19"
68
+        android:strokeWidth="0.8"
69
+        android:strokeColor="#33FFFFFF" />
70
+    <path
71
+        android:fillColor="#00000000"
72
+        android:pathData="M0,29L108,29"
73
+        android:strokeWidth="0.8"
74
+        android:strokeColor="#33FFFFFF" />
75
+    <path
76
+        android:fillColor="#00000000"
77
+        android:pathData="M0,39L108,39"
78
+        android:strokeWidth="0.8"
79
+        android:strokeColor="#33FFFFFF" />
80
+    <path
81
+        android:fillColor="#00000000"
82
+        android:pathData="M0,49L108,49"
83
+        android:strokeWidth="0.8"
84
+        android:strokeColor="#33FFFFFF" />
85
+    <path
86
+        android:fillColor="#00000000"
87
+        android:pathData="M0,59L108,59"
88
+        android:strokeWidth="0.8"
89
+        android:strokeColor="#33FFFFFF" />
90
+    <path
91
+        android:fillColor="#00000000"
92
+        android:pathData="M0,69L108,69"
93
+        android:strokeWidth="0.8"
94
+        android:strokeColor="#33FFFFFF" />
95
+    <path
96
+        android:fillColor="#00000000"
97
+        android:pathData="M0,79L108,79"
98
+        android:strokeWidth="0.8"
99
+        android:strokeColor="#33FFFFFF" />
100
+    <path
101
+        android:fillColor="#00000000"
102
+        android:pathData="M0,89L108,89"
103
+        android:strokeWidth="0.8"
104
+        android:strokeColor="#33FFFFFF" />
105
+    <path
106
+        android:fillColor="#00000000"
107
+        android:pathData="M0,99L108,99"
108
+        android:strokeWidth="0.8"
109
+        android:strokeColor="#33FFFFFF" />
110
+    <path
111
+        android:fillColor="#00000000"
112
+        android:pathData="M19,29L89,29"
113
+        android:strokeWidth="0.8"
114
+        android:strokeColor="#33FFFFFF" />
115
+    <path
116
+        android:fillColor="#00000000"
117
+        android:pathData="M19,39L89,39"
118
+        android:strokeWidth="0.8"
119
+        android:strokeColor="#33FFFFFF" />
120
+    <path
121
+        android:fillColor="#00000000"
122
+        android:pathData="M19,49L89,49"
123
+        android:strokeWidth="0.8"
124
+        android:strokeColor="#33FFFFFF" />
125
+    <path
126
+        android:fillColor="#00000000"
127
+        android:pathData="M19,59L89,59"
128
+        android:strokeWidth="0.8"
129
+        android:strokeColor="#33FFFFFF" />
130
+    <path
131
+        android:fillColor="#00000000"
132
+        android:pathData="M19,69L89,69"
133
+        android:strokeWidth="0.8"
134
+        android:strokeColor="#33FFFFFF" />
135
+    <path
136
+        android:fillColor="#00000000"
137
+        android:pathData="M19,79L89,79"
138
+        android:strokeWidth="0.8"
139
+        android:strokeColor="#33FFFFFF" />
140
+    <path
141
+        android:fillColor="#00000000"
142
+        android:pathData="M29,19L29,89"
143
+        android:strokeWidth="0.8"
144
+        android:strokeColor="#33FFFFFF" />
145
+    <path
146
+        android:fillColor="#00000000"
147
+        android:pathData="M39,19L39,89"
148
+        android:strokeWidth="0.8"
149
+        android:strokeColor="#33FFFFFF" />
150
+    <path
151
+        android:fillColor="#00000000"
152
+        android:pathData="M49,19L49,89"
153
+        android:strokeWidth="0.8"
154
+        android:strokeColor="#33FFFFFF" />
155
+    <path
156
+        android:fillColor="#00000000"
157
+        android:pathData="M59,19L59,89"
158
+        android:strokeWidth="0.8"
159
+        android:strokeColor="#33FFFFFF" />
160
+    <path
161
+        android:fillColor="#00000000"
162
+        android:pathData="M69,19L69,89"
163
+        android:strokeWidth="0.8"
164
+        android:strokeColor="#33FFFFFF" />
165
+    <path
166
+        android:fillColor="#00000000"
167
+        android:pathData="M79,19L79,89"
168
+        android:strokeWidth="0.8"
169
+        android:strokeColor="#33FFFFFF" />
170
+</vector>

+ 18 - 0
app/src/main/res/layout/activity_main.xml

@@ -0,0 +1,18 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
+    xmlns:app="http://schemas.android.com/apk/res-auto"
4
+    xmlns:tools="http://schemas.android.com/tools"
5
+    android:layout_width="match_parent"
6
+    android:layout_height="match_parent"
7
+    tools:context=".MainActivity">
8
+
9
+    <TextView
10
+        android:layout_width="wrap_content"
11
+        android:layout_height="wrap_content"
12
+        android:text="Hello World!"
13
+        app:layout_constraintBottom_toBottomOf="parent"
14
+        app:layout_constraintLeft_toLeftOf="parent"
15
+        app:layout_constraintRight_toRightOf="parent"
16
+        app:layout_constraintTop_toTopOf="parent" />
17
+
18
+</android.support.constraint.ConstraintLayout>

+ 47 - 0
app/src/main/res/layout/activity_nfc.xml

@@ -0,0 +1,47 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
3
+    xmlns:app="http://schemas.android.com/apk/res-auto"
4
+    xmlns:tools="http://schemas.android.com/tools"
5
+    android:layout_width="match_parent"
6
+    android:layout_height="match_parent"
7
+    tools:context=".NFCActivity">
8
+
9
+    <LinearLayout
10
+        android:layout_width="match_parent"
11
+        android:layout_height="match_parent"
12
+        android:orientation="vertical">
13
+
14
+        <LinearLayout
15
+            android:layout_width="match_parent"
16
+            android:layout_height="wrap_content">
17
+
18
+            <Button
19
+                android:layout_width="wrap_content"
20
+                android:layout_height="wrap_content"
21
+                android:onClick="onClick"
22
+                android:text="清空" />
23
+
24
+            <TextView
25
+                android:id="@+id/tv_msg"
26
+                android:layout_width="match_parent"
27
+                android:layout_height="wrap_content"
28
+                android:gravity="center"
29
+                android:text="请放卡"
30
+                android:textColor="@android:color/black"
31
+                android:textSize="16sp" />
32
+
33
+        </LinearLayout>
34
+
35
+
36
+        <EditText
37
+            android:id="@+id/tv_content"
38
+            android:layout_width="match_parent"
39
+            android:layout_height="wrap_content"
40
+            android:gravity="center"
41
+            android:padding="8dp"
42
+            android:textSize="12sp"
43
+            android:textColor="@android:color/black" />
44
+    </LinearLayout>
45
+
46
+
47
+</android.support.v4.widget.NestedScrollView>

+ 5 - 0
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@@ -0,0 +1,5 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
3
+    <background android:drawable="@drawable/ic_launcher_background" />
4
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
5
+</adaptive-icon>

+ 5 - 0
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@@ -0,0 +1,5 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
3
+    <background android:drawable="@drawable/ic_launcher_background" />
4
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
5
+</adaptive-icon>

BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png


+ 6 - 0
app/src/main/res/values/colors.xml

@@ -0,0 +1,6 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<resources>
3
+    <color name="colorPrimary">#008577</color>
4
+    <color name="colorPrimaryDark">#00574B</color>
5
+    <color name="colorAccent">#D81B60</color>
6
+</resources>

+ 3 - 0
app/src/main/res/values/strings.xml

@@ -0,0 +1,3 @@
1
+<resources>
2
+    <string name="app_name">NFCTool</string>
3
+</resources>

+ 11 - 0
app/src/main/res/values/styles.xml

@@ -0,0 +1,11 @@
1
+<resources>
2
+
3
+    <!-- Base application theme. -->
4
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
5
+        <!-- Customize your theme here. -->
6
+        <item name="colorPrimary">@color/colorPrimary</item>
7
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
8
+        <item name="colorAccent">@color/colorAccent</item>
9
+    </style>
10
+
11
+</resources>

+ 13 - 0
app/src/main/res/xml/nfc.xml

@@ -0,0 +1,13 @@
1
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
2
+    <tech-list>
3
+        <tech>android.nfc.tech.IsoDep</tech>
4
+        <tech>android.nfc.tech.NfcA</tech>
5
+        <tech>android.nfc.tech.NfcB</tech>
6
+        <tech>android.nfc.tech.NfcF</tech>
7
+        <tech>android.nfc.tech.NfcV</tech>
8
+        <tech>android.nfc.tech.Ndef</tech>
9
+        <tech>android.nfc.tech.NdefFormatable</tech>
10
+        <tech>android.nfc.tech.MifareClassic</tech>
11
+        <tech>android.nfc.tech.MifareUltralight</tech>
12
+    </tech-list>
13
+</resources>

+ 17 - 0
app/src/test/java/com/mq/nfctool/ExampleUnitTest.java

@@ -0,0 +1,17 @@
1
+package com.mq.nfctool;
2
+
3
+import org.junit.Test;
4
+
5
+import static org.junit.Assert.*;
6
+
7
+/**
8
+ * Example local unit test, which will execute on the development machine (host).
9
+ *
10
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
11
+ */
12
+public class ExampleUnitTest {
13
+    @Test
14
+    public void addition_isCorrect() {
15
+        assertEquals(4, 2 + 2);
16
+    }
17
+}

+ 27 - 0
build.gradle

@@ -0,0 +1,27 @@
1
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
2
+
3
+buildscript {
4
+    repositories {
5
+        google()
6
+        jcenter()
7
+        
8
+    }
9
+    dependencies {
10
+        classpath 'com.android.tools.build:gradle:3.4.1'
11
+        
12
+        // NOTE: Do not place your application dependencies here; they belong
13
+        // in the individual module build.gradle files
14
+    }
15
+}
16
+
17
+allprojects {
18
+    repositories {
19
+        google()
20
+        jcenter()
21
+        
22
+    }
23
+}
24
+
25
+task clean(type: Delete) {
26
+    delete rootProject.buildDir
27
+}

+ 15 - 0
gradle.properties

@@ -0,0 +1,15 @@
1
+# Project-wide Gradle settings.
2
+# IDE (e.g. Android Studio) users:
3
+# Gradle settings configured through the IDE *will override*
4
+# any settings specified in this file.
5
+# For more details on how to configure your build environment visit
6
+# http://www.gradle.org/docs/current/userguide/build_environment.html
7
+# Specifies the JVM arguments used for the daemon process.
8
+# The setting is particularly useful for tweaking memory settings.
9
+org.gradle.jvmargs=-Xmx1536m
10
+# When configured, Gradle will run in incubating parallel mode.
11
+# This option should only be used with decoupled projects. More details, visit
12
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13
+# org.gradle.parallel=true
14
+
15
+

BIN
gradle/wrapper/gradle-wrapper.jar


+ 6 - 0
gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,6 @@
1
+#Mon Jun 24 16:26:39 CST 2019
2
+distributionBase=GRADLE_USER_HOME
3
+distributionPath=wrapper/dists
4
+zipStoreBase=GRADLE_USER_HOME
5
+zipStorePath=wrapper/dists
6
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip

+ 172 - 0
gradlew

@@ -0,0 +1,172 @@
1
+#!/usr/bin/env sh
2
+
3
+##############################################################################
4
+##
5
+##  Gradle start up script for UN*X
6
+##
7
+##############################################################################
8
+
9
+# Attempt to set APP_HOME
10
+# Resolve links: $0 may be a link
11
+PRG="$0"
12
+# Need this for relative symlinks.
13
+while [ -h "$PRG" ] ; do
14
+    ls=`ls -ld "$PRG"`
15
+    link=`expr "$ls" : '.*-> \(.*\)$'`
16
+    if expr "$link" : '/.*' > /dev/null; then
17
+        PRG="$link"
18
+    else
19
+        PRG=`dirname "$PRG"`"/$link"
20
+    fi
21
+done
22
+SAVED="`pwd`"
23
+cd "`dirname \"$PRG\"`/" >/dev/null
24
+APP_HOME="`pwd -P`"
25
+cd "$SAVED" >/dev/null
26
+
27
+APP_NAME="Gradle"
28
+APP_BASE_NAME=`basename "$0"`
29
+
30
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31
+DEFAULT_JVM_OPTS=""
32
+
33
+# Use the maximum available, or set MAX_FD != -1 to use that value.
34
+MAX_FD="maximum"
35
+
36
+warn () {
37
+    echo "$*"
38
+}
39
+
40
+die () {
41
+    echo
42
+    echo "$*"
43
+    echo
44
+    exit 1
45
+}
46
+
47
+# OS specific support (must be 'true' or 'false').
48
+cygwin=false
49
+msys=false
50
+darwin=false
51
+nonstop=false
52
+case "`uname`" in
53
+  CYGWIN* )
54
+    cygwin=true
55
+    ;;
56
+  Darwin* )
57
+    darwin=true
58
+    ;;
59
+  MINGW* )
60
+    msys=true
61
+    ;;
62
+  NONSTOP* )
63
+    nonstop=true
64
+    ;;
65
+esac
66
+
67
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68
+
69
+# Determine the Java command to use to start the JVM.
70
+if [ -n "$JAVA_HOME" ] ; then
71
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72
+        # IBM's JDK on AIX uses strange locations for the executables
73
+        JAVACMD="$JAVA_HOME/jre/sh/java"
74
+    else
75
+        JAVACMD="$JAVA_HOME/bin/java"
76
+    fi
77
+    if [ ! -x "$JAVACMD" ] ; then
78
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79
+
80
+Please set the JAVA_HOME variable in your environment to match the
81
+location of your Java installation."
82
+    fi
83
+else
84
+    JAVACMD="java"
85
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86
+
87
+Please set the JAVA_HOME variable in your environment to match the
88
+location of your Java installation."
89
+fi
90
+
91
+# Increase the maximum file descriptors if we can.
92
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93
+    MAX_FD_LIMIT=`ulimit -H -n`
94
+    if [ $? -eq 0 ] ; then
95
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96
+            MAX_FD="$MAX_FD_LIMIT"
97
+        fi
98
+        ulimit -n $MAX_FD
99
+        if [ $? -ne 0 ] ; then
100
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
101
+        fi
102
+    else
103
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104
+    fi
105
+fi
106
+
107
+# For Darwin, add options to specify how the application appears in the dock
108
+if $darwin; then
109
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110
+fi
111
+
112
+# For Cygwin, switch paths to Windows format before running java
113
+if $cygwin ; then
114
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116
+    JAVACMD=`cygpath --unix "$JAVACMD"`
117
+
118
+    # We build the pattern for arguments to be converted via cygpath
119
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120
+    SEP=""
121
+    for dir in $ROOTDIRSRAW ; do
122
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
123
+        SEP="|"
124
+    done
125
+    OURCYGPATTERN="(^($ROOTDIRS))"
126
+    # Add a user-defined pattern to the cygpath arguments
127
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129
+    fi
130
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
131
+    i=0
132
+    for arg in "$@" ; do
133
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
135
+
136
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
137
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138
+        else
139
+            eval `echo args$i`="\"$arg\""
140
+        fi
141
+        i=$((i+1))
142
+    done
143
+    case $i in
144
+        (0) set -- ;;
145
+        (1) set -- "$args0" ;;
146
+        (2) set -- "$args0" "$args1" ;;
147
+        (3) set -- "$args0" "$args1" "$args2" ;;
148
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154
+    esac
155
+fi
156
+
157
+# Escape application args
158
+save () {
159
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160
+    echo " "
161
+}
162
+APP_ARGS=$(save "$@")
163
+
164
+# Collect all arguments for the java command, following the shell quoting and substitution rules
165
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166
+
167
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169
+  cd "$(dirname "$0")"
170
+fi
171
+
172
+exec "$JAVACMD" "$@"

+ 84 - 0
gradlew.bat

@@ -0,0 +1,84 @@
1
+@if "%DEBUG%" == "" @echo off
2
+@rem ##########################################################################
3
+@rem
4
+@rem  Gradle startup script for Windows
5
+@rem
6
+@rem ##########################################################################
7
+
8
+@rem Set local scope for the variables with windows NT shell
9
+if "%OS%"=="Windows_NT" setlocal
10
+
11
+set DIRNAME=%~dp0
12
+if "%DIRNAME%" == "" set DIRNAME=.
13
+set APP_BASE_NAME=%~n0
14
+set APP_HOME=%DIRNAME%
15
+
16
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17
+set DEFAULT_JVM_OPTS=
18
+
19
+@rem Find java.exe
20
+if defined JAVA_HOME goto findJavaFromJavaHome
21
+
22
+set JAVA_EXE=java.exe
23
+%JAVA_EXE% -version >NUL 2>&1
24
+if "%ERRORLEVEL%" == "0" goto init
25
+
26
+echo.
27
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28
+echo.
29
+echo Please set the JAVA_HOME variable in your environment to match the
30
+echo location of your Java installation.
31
+
32
+goto fail
33
+
34
+:findJavaFromJavaHome
35
+set JAVA_HOME=%JAVA_HOME:"=%
36
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37
+
38
+if exist "%JAVA_EXE%" goto init
39
+
40
+echo.
41
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42
+echo.
43
+echo Please set the JAVA_HOME variable in your environment to match the
44
+echo location of your Java installation.
45
+
46
+goto fail
47
+
48
+:init
49
+@rem Get command-line arguments, handling Windows variants
50
+
51
+if not "%OS%" == "Windows_NT" goto win9xME_args
52
+
53
+:win9xME_args
54
+@rem Slurp the command line arguments.
55
+set CMD_LINE_ARGS=
56
+set _SKIP=2
57
+
58
+:win9xME_args_slurp
59
+if "x%~1" == "x" goto execute
60
+
61
+set CMD_LINE_ARGS=%*
62
+
63
+:execute
64
+@rem Setup the command line
65
+
66
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67
+
68
+@rem Execute Gradle
69
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70
+
71
+:end
72
+@rem End local scope for the variables with windows NT shell
73
+if "%ERRORLEVEL%"=="0" goto mainEnd
74
+
75
+:fail
76
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77
+rem the _cmd.exe /c_ return code!
78
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79
+exit /b 1
80
+
81
+:mainEnd
82
+if "%OS%"=="Windows_NT" endlocal
83
+
84
+:omega

BIN
nfctool.jks


+ 1 - 0
settings.gradle

@@ -0,0 +1 @@
1
+include ':app'