├── .github
└── dependabot.yml
├── .gitignore
├── .idea
└── vcs.xml
├── .project
├── DeviceIdentifiersWrapper
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── zebra
│ │ └── deviceidentifierswrapper
│ │ ├── DICommandBase.java
│ │ ├── DICommandBaseSettings.java
│ │ ├── DIHelper.java
│ │ ├── DIProfileManagerCommand.java
│ │ ├── EMessageType.java
│ │ ├── ExecutorTask.java
│ │ ├── IDIResultCallbacks.java
│ │ └── RetrieveOEMInfoTask.java
│ └── res
│ └── values
│ └── strings.xml
├── LICENSE
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 |
7 | version: 2
8 | updates:
9 | - package-ecosystem: "" # See documentation for possible values
10 | directory: "/" # Location of package manifests
11 | schedule:
12 | interval: "weekly"
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 | *.aab
5 |
6 | # Files for the ART/Dalvik VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 | out/
16 | release/
17 |
18 | # Gradle files
19 | .gradle/
20 | build/
21 |
22 | # Local configuration file (sdk path, etc)
23 | local.properties
24 |
25 | # Proguard folder generated by Eclipse
26 | proguard/
27 |
28 | # Log Files
29 | *.log
30 |
31 | # Android Studio Navigation editor temp files
32 | .navigation/
33 |
34 | # Android Studio captures folder
35 | captures/
36 |
37 | # IntelliJ
38 | *.iml
39 | .idea/workspace.xml
40 | .idea/tasks.xml
41 | .idea/gradle.xml
42 | .idea/assetWizardSettings.xml
43 | .idea/dictionaries
44 | .idea/libraries
45 | # Android Studio 3 in .gitignore file.
46 | .idea/caches
47 | .idea/modules.xml
48 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
49 | .idea/navEditor.xml
50 |
51 | # Keystore files
52 | # Uncomment the following lines if you do not want to check your keystore files in.
53 | #*.jks
54 | #*.keystore
55 |
56 | # External native build folder generated in Android Studio 2.2 and later
57 | .externalNativeBuild
58 |
59 | # Google Services (e.g. APIs or Firebase)
60 | # google-services.json
61 |
62 | # Freeline
63 | freeline.py
64 | freeline/
65 | freeline_project_description.json
66 |
67 | # fastlane
68 | fastlane/report.xml
69 | fastlane/Preview.html
70 | fastlane/screenshots
71 | fastlane/test_output
72 | fastlane/readme.md
73 |
74 | # Version control
75 | vcs.xml
76 |
77 | # lint
78 | lint/intermediates/
79 | lint/generated/
80 | lint/outputs/
81 | lint/tmp/
82 | # lint/reports/
83 | .idea/
84 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | EMDK-DeviceIdentifiers-Sample
4 | Project EMDK-DeviceIdentifiers-Sample created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.buildship.core.gradleprojectbuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.buildship.core.gradleprojectnature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/DeviceIdentifiersWrapper/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/DeviceIdentifiersWrapper/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | }
4 |
5 | android {
6 | compileSdkVersion 34
7 |
8 | defaultConfig {
9 | minSdkVersion 19
10 | targetSdkVersion 34
11 | versionCode 120
12 | versionName "0.12.0"
13 |
14 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | compileOptions {
25 | sourceCompatibility JavaVersion.VERSION_1_8
26 | targetCompatibility JavaVersion.VERSION_1_8
27 | }
28 |
29 | }
30 |
31 | dependencies {
32 | implementation fileTree(dir: 'libs', include: ['*.jar'])
33 | implementation 'androidx.appcompat:appcompat:1.0.0'
34 | testImplementation 'junit:junit:4.13'
35 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
36 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
37 | compileOnly 'com.symbol:emdk:9.1.1'
38 | }
39 |
--------------------------------------------------------------------------------
/DeviceIdentifiersWrapper/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/DeviceIdentifiersWrapper/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/DeviceIdentifiersWrapper/src/main/java/com/zebra/deviceidentifierswrapper/DICommandBase.java:
--------------------------------------------------------------------------------
1 | package com.zebra.deviceidentifierswrapper;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.os.Parcel;
6 | import android.os.ResultReceiver;
7 |
8 | /**
9 | * Created by Trudu Laurent on 2020/08/11.
10 | */
11 |
12 | abstract class DICommandBase {
13 | /*
14 | A TAG if we want to log something
15 | */
16 | protected static String TAG = "DIWrapperMX";
17 |
18 | /*
19 | A context to work with intents
20 | */
21 | protected Context mContext = null;
22 |
23 | protected DICommandBaseSettings mSettings = null;
24 |
25 | /*
26 | A handler that will be used by the derived
27 | class to prevent waiting to loong for DW in case
28 | of problem
29 | */
30 | protected Handler mTimeOutHandler;
31 |
32 | /*
33 | What will be done at the end of the TimeOut
34 | */
35 | protected Runnable mTimeOutRunnable = new Runnable() {
36 | @Override
37 | public void run() {
38 | onTimeOut(mSettings);
39 | }
40 | };
41 |
42 |
43 | public DICommandBase(Context aContext)
44 | {
45 | mContext = aContext;
46 | mTimeOutHandler = new Handler(mContext.getMainLooper());
47 | }
48 |
49 |
50 | protected void execute(DICommandBaseSettings settings)
51 | {
52 | mSettings = settings;
53 | /*
54 | Start time out mechanism
55 | Enabled by default in DWProfileBaseSettings
56 | */
57 | if(settings.mEnableTimeOutMechanism) {
58 | mTimeOutHandler.postDelayed(mTimeOutRunnable,
59 | mSettings.mTimeOutMS);
60 | }
61 | }
62 |
63 | protected void onTimeOut(DICommandBaseSettings settings)
64 | {
65 | cleanAll();
66 | }
67 |
68 | protected void cleanAll()
69 | {
70 | if(mTimeOutHandler != null)
71 | {
72 | mTimeOutHandler.removeCallbacks(mTimeOutRunnable);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/DeviceIdentifiersWrapper/src/main/java/com/zebra/deviceidentifierswrapper/DICommandBaseSettings.java:
--------------------------------------------------------------------------------
1 | package com.zebra.deviceidentifierswrapper;
2 |
3 | class DICommandBaseSettings
4 | {
5 | /*
6 | Use this to track the source of the intent
7 | */
8 | public String mCommandId = "";
9 |
10 | /*
11 | Some method return only errors (StartScan, StopScan)
12 | We do not need a time out for them
13 | */
14 | public boolean mEnableTimeOutMechanism = true;
15 |
16 | /*
17 | A time out, in case we don't receive an answer
18 | from PrintConnect
19 | */
20 | public long mTimeOutMS = 5000;
21 | }
22 |
--------------------------------------------------------------------------------
/DeviceIdentifiersWrapper/src/main/java/com/zebra/deviceidentifierswrapper/DIHelper.java:
--------------------------------------------------------------------------------
1 | package com.zebra.deviceidentifierswrapper;
2 |
3 | import android.Manifest.permission;
4 | import android.annotation.SuppressLint;
5 | import android.bluetooth.BluetoothAdapter;
6 | import android.content.Context;
7 | import android.content.pm.PackageInfo;
8 | import android.content.pm.PackageManager;
9 | import android.content.pm.Signature;
10 | import android.database.Cursor;
11 | import android.net.Uri;
12 | import android.os.AsyncTask;
13 | import android.os.Build;
14 | import android.telephony.TelephonyManager;
15 | import android.util.Log;
16 |
17 | import androidx.core.content.ContextCompat;
18 | import java.util.Base64;
19 |
20 | public class DIHelper {
21 |
22 | // Placeholder for custom certificate
23 | // Otherwise, the app will use the first certificate found with the method:
24 | // final Signature[] arrSignatures = packageInfo.signingInfo.getApkContentsSigners();
25 | // TODO: Put your custom certificate in the apkCertificate member for MX AccessMgr registering (only if necessary and if you know what you are doing)
26 | public static Signature apkCertificate = null;
27 |
28 | protected static String sIMEI = null;
29 | protected static String sSerialNumber = null;
30 | protected static String sBtMacAddress = null;
31 | protected static String sProductModel = null;
32 | protected static String sIdentityDeviceID = null;
33 | protected static String sWifiMac = null;
34 | protected static String sWifiAPMac = null;
35 | protected static String sWifiSSID= null;
36 | protected static String sEthernetMac = null;
37 |
38 |
39 | public static final long SEC_IN_MS = 1000;
40 | public static final long MIN_IN_MS = SEC_IN_MS * 60;
41 | public static long MAX_EMDK_TIMEOUT_IN_MS = 10 * MIN_IN_MS; // 10 minutes
42 | public static long WAIT_PERIOD_BEFORE_RETRY_EMDK_RETRIEVAL_IN_MS = 2 * SEC_IN_MS; // 2 seconds
43 |
44 | public static void resetCachedValues()
45 | {
46 | sIMEI = null;
47 | sSerialNumber = null;
48 | }
49 |
50 | // This method will return the serial number in the string passed through the onSuccess method
51 | public static void getSerialNumber(Context context, IDIResultCallbacks callbackInterface)
52 | {
53 | if(sSerialNumber != null)
54 | {
55 | if(callbackInterface != null)
56 | {
57 | callbackInterface.onDebugStatus("Serial number already in cache.");
58 | }
59 | callbackInterface.onSuccess(sSerialNumber);
60 | return;
61 | }
62 | if (android.os.Build.VERSION.SDK_INT < 29) {
63 | returnSerialUsingAndroidAPIs(context, callbackInterface);
64 | } else {
65 | returnSerialUsingZebraAPIs(context, callbackInterface);
66 | }
67 | }
68 |
69 | @SuppressLint({"MissingPermission", "ObsoleteSdkInt", "HardwareIds"})
70 | private static void returnSerialUsingAndroidAPIs(Context context, IDIResultCallbacks callbackInterface) {
71 | if (android.os.Build.VERSION.SDK_INT < 26) {
72 | sSerialNumber = Build.SERIAL;
73 | callbackInterface.onSuccess(Build.SERIAL);
74 | } else {
75 | if (ContextCompat.checkSelfPermission(context, permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
76 | sSerialNumber = Build.getSerial();
77 | callbackInterface.onSuccess(Build.getSerial());
78 | } else {
79 | callbackInterface.onError("Please grant READ_PHONE_STATE permission");
80 | }
81 | }
82 | }
83 |
84 | private static void returnSerialUsingZebraAPIs(Context context, final IDIResultCallbacks callbackInterface) {
85 | IDIResultCallbacks tempCallbackInterface = new IDIResultCallbacks() {
86 | @Override
87 | public void onSuccess(String message) {
88 | sSerialNumber = message;
89 | callbackInterface.onSuccess(message);
90 | }
91 |
92 | @Override
93 | public void onError(String message) {
94 | callbackInterface.onError(message);
95 | }
96 |
97 | @Override
98 | public void onDebugStatus(String message) {
99 | callbackInterface.onDebugStatus(message);
100 | }
101 | };
102 |
103 | new RetrieveOEMInfoTask()
104 | .executeAsync(context, Uri.parse("content://oem_info/oem.zebra.secure/build_serial"),
105 | tempCallbackInterface);
106 | }
107 |
108 | // This method will return the imei number in the string passed through the onSuccess method
109 | public static void getIMEINumber(Context context, IDIResultCallbacks callbackInterface)
110 | {
111 | if(sIMEI != null)
112 | {
113 | if(callbackInterface != null)
114 | {
115 | callbackInterface.onDebugStatus("IMEI number already in cache.");
116 | }
117 | callbackInterface.onSuccess(sIMEI);
118 | return;
119 | }
120 | if (android.os.Build.VERSION.SDK_INT < 29) {
121 | returnImeiUsingAndroidAPIs(context, callbackInterface);
122 | } else {
123 | returnImeiUsingZebraAPIs(context, callbackInterface);
124 | }
125 | }
126 |
127 | @SuppressLint({"MissingPermission", "ObsoleteSdkInt", "HardwareIds" })
128 | private static void returnImeiUsingAndroidAPIs(Context context, IDIResultCallbacks callbackInterface) {
129 | TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
130 | if (android.os.Build.VERSION.SDK_INT < 26) {String imei = telephonyManager.getDeviceId();
131 | if (imei != null && !imei.isEmpty()) {
132 | sIMEI = imei;
133 | callbackInterface.onSuccess(imei);
134 | } else {
135 | callbackInterface.onError("Could not get IMEI number");
136 | }
137 | } else {
138 | if (ContextCompat.checkSelfPermission(context, permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
139 | String imei = telephonyManager.getImei();
140 | if (imei != null && !imei.isEmpty()) {
141 | sIMEI = imei;
142 | callbackInterface.onSuccess(imei);
143 | } else {
144 | callbackInterface.onError("Could not get IMEI number");
145 | }
146 | } else {
147 | callbackInterface.onError("Please grant READ_PHONE_STATE permission");
148 | }
149 | }
150 | }
151 |
152 | private static void returnImeiUsingZebraAPIs(Context context, final IDIResultCallbacks callbackInterface) {
153 | IDIResultCallbacks tempCallbackInterface = new IDIResultCallbacks() {
154 | @Override
155 | public void onSuccess(String message) {
156 | sIMEI = message;
157 | callbackInterface.onSuccess(message);
158 | }
159 |
160 | @Override
161 | public void onError(String message) {
162 | callbackInterface.onError(message);
163 | }
164 |
165 | @Override
166 | public void onDebugStatus(String message) {
167 | callbackInterface.onDebugStatus(message);
168 | }
169 | };
170 |
171 | new RetrieveOEMInfoTask().executeAsync(context, Uri.parse("content://oem_info/wan/imei"),
172 | tempCallbackInterface);
173 | }
174 |
175 | public static void getBtMacAddress(Context context, IDIResultCallbacks callbackInterface)
176 | {
177 | if(sBtMacAddress != null)
178 | {
179 | if(callbackInterface != null)
180 | {
181 | callbackInterface.onDebugStatus("BT Mac address already in cache.");
182 | }
183 | callbackInterface.onSuccess(sBtMacAddress);
184 | return;
185 | }
186 | if (android.os.Build.VERSION.SDK_INT < 23) {
187 | returnBtMacAddressUsingAndroidAPIs(context, callbackInterface);
188 | } else {
189 | returnBtMacAddressUsingZebraAPIs(context, callbackInterface);
190 | }
191 | }
192 |
193 | private static void returnBtMacAddressUsingZebraAPIs(Context context, IDIResultCallbacks callbackInterface) {
194 | IDIResultCallbacks tempCallbackInterface = new IDIResultCallbacks() {
195 | @Override
196 | public void onSuccess(String message) {
197 | sBtMacAddress = message;
198 | callbackInterface.onSuccess(message);
199 | }
200 |
201 | @Override
202 | public void onError(String message) {
203 | callbackInterface.onError(message);
204 | }
205 |
206 | @Override
207 | public void onDebugStatus(String message) {
208 | callbackInterface.onDebugStatus(message);
209 | }
210 | };
211 |
212 | new RetrieveOEMInfoTask().executeAsync(context, Uri.parse("content://oem_info/oem.zebra.secure/bt_mac"),
213 | tempCallbackInterface);
214 | }
215 |
216 | private static void returnBtMacAddressUsingAndroidAPIs(Context context, IDIResultCallbacks callbackInterface) {
217 | BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
218 | String macAddress = mBluetoothAdapter.getAddress();
219 | if(callbackInterface != null)
220 | {
221 | callbackInterface.onSuccess(macAddress);
222 | }
223 | }
224 |
225 | public static void getProductModel(Context context, IDIResultCallbacks callbackInterface)
226 | {
227 | if(sProductModel != null)
228 | {
229 | if(callbackInterface != null)
230 | {
231 | callbackInterface.onDebugStatus("Product Model already in cache.");
232 | }
233 | callbackInterface.onSuccess(sProductModel);
234 | return;
235 | }
236 |
237 | IDIResultCallbacks tempCallbackInterface = new IDIResultCallbacks() {
238 | @Override
239 | public void onSuccess(String message) {
240 | sProductModel = message;
241 | callbackInterface.onSuccess(message);
242 | }
243 |
244 | @Override
245 | public void onError(String message) {
246 | callbackInterface.onError(message);
247 | }
248 |
249 | @Override
250 | public void onDebugStatus(String message) {
251 | callbackInterface.onDebugStatus(message);
252 | }
253 | };
254 |
255 | new RetrieveOEMInfoTask().executeAsync(context, Uri.parse("content://oem_info/oem.zebra.secure/ro_product_model"),
256 | tempCallbackInterface);
257 |
258 | }
259 |
260 | public static void getIdentityDeviceID(Context context, IDIResultCallbacks callbackInterface)
261 | {
262 | if(sIdentityDeviceID != null)
263 | {
264 | if(callbackInterface != null)
265 | {
266 | callbackInterface.onDebugStatus("IdentityDeviceID already in cache.");
267 | }
268 | callbackInterface.onSuccess(sIdentityDeviceID);
269 | return;
270 | }
271 |
272 | IDIResultCallbacks tempCallbackInterface = new IDIResultCallbacks() {
273 | @Override
274 | public void onSuccess(String message) {
275 | sIdentityDeviceID = message;
276 | callbackInterface.onSuccess(message);
277 | }
278 |
279 | @Override
280 | public void onError(String message) {
281 | callbackInterface.onError(message);
282 | }
283 |
284 | @Override
285 | public void onDebugStatus(String message) {
286 | callbackInterface.onDebugStatus(message);
287 | }
288 | };
289 |
290 | new RetrieveOEMInfoTask().executeAsync(context, Uri.parse("content://oem_info/oem.zebra.secure/identity_device_id"),
291 | tempCallbackInterface);
292 |
293 | }
294 |
295 | public static void getWifiMacAddress(Context context, IDIResultCallbacks callbackInterface)
296 | {
297 | if(sWifiMac != null)
298 | {
299 | if(callbackInterface != null)
300 | {
301 | callbackInterface.onDebugStatus("Wifi Mac Address already in cache.");
302 | }
303 | callbackInterface.onSuccess(sWifiMac);
304 | return;
305 | }
306 |
307 | IDIResultCallbacks tempCallbackInterface = new IDIResultCallbacks() {
308 | @Override
309 | public void onSuccess(String message) {
310 | sWifiMac = message;
311 | callbackInterface.onSuccess(message);
312 | }
313 |
314 | @Override
315 | public void onError(String message) {
316 | callbackInterface.onError(message);
317 | }
318 |
319 | @Override
320 | public void onDebugStatus(String message) {
321 | callbackInterface.onDebugStatus(message);
322 | }
323 | };
324 |
325 | new RetrieveOEMInfoTask().executeAsync(context, Uri.parse("content://oem_info/oem.zebra.secure/wifi_mac"),
326 | tempCallbackInterface);
327 |
328 | }
329 |
330 | public static void getWifiAPMacAddress(Context context, IDIResultCallbacks callbackInterface)
331 | {
332 | if(sWifiAPMac != null)
333 | {
334 | if(callbackInterface != null)
335 | {
336 | callbackInterface.onDebugStatus("Wifi AP Mac Address already in cache.");
337 | }
338 | callbackInterface.onSuccess(sWifiAPMac);
339 | return;
340 | }
341 |
342 | IDIResultCallbacks tempCallbackInterface = new IDIResultCallbacks() {
343 | @Override
344 | public void onSuccess(String message) {
345 | sWifiAPMac = message;
346 | callbackInterface.onSuccess(message);
347 | }
348 |
349 | @Override
350 | public void onError(String message) {
351 | callbackInterface.onError(message);
352 | }
353 |
354 | @Override
355 | public void onDebugStatus(String message) {
356 | callbackInterface.onDebugStatus(message);
357 | }
358 | };
359 |
360 | new RetrieveOEMInfoTask().executeAsync(context, Uri.parse("content://oem_info/oem.zebra.secure/wifi_ap_mac"),
361 | tempCallbackInterface);
362 | }
363 |
364 | public static void getWifiSSID(Context context, IDIResultCallbacks callbackInterface)
365 | {
366 | if(sWifiSSID != null)
367 | {
368 | if(callbackInterface != null)
369 | {
370 | callbackInterface.onDebugStatus("Wifi SSID already in cache.");
371 | }
372 | callbackInterface.onSuccess(sWifiSSID);
373 | return;
374 | }
375 |
376 | IDIResultCallbacks tempCallbackInterface = new IDIResultCallbacks() {
377 | @Override
378 | public void onSuccess(String message) {
379 | sWifiSSID = message;
380 | callbackInterface.onSuccess(message);
381 | }
382 |
383 | @Override
384 | public void onError(String message) {
385 | callbackInterface.onError(message);
386 | }
387 |
388 | @Override
389 | public void onDebugStatus(String message) {
390 | callbackInterface.onDebugStatus(message);
391 | }
392 | };
393 |
394 | new RetrieveOEMInfoTask().executeAsync(context, Uri.parse("content://oem_info/oem.zebra.secure/wifi_ssid"),
395 | tempCallbackInterface);
396 | }
397 |
398 | public static void getEthernetMacAddress(Context context, IDIResultCallbacks callbackInterface)
399 | {
400 | if(sEthernetMac != null)
401 | {
402 | if(callbackInterface != null)
403 | {
404 | callbackInterface.onDebugStatus("Ethernet Mac Address already in cache.");
405 | }
406 | callbackInterface.onSuccess(sEthernetMac);
407 | return;
408 | }
409 |
410 | IDIResultCallbacks tempCallbackInterface = new IDIResultCallbacks() {
411 | @Override
412 | public void onSuccess(String message) {
413 | sEthernetMac = message;
414 | callbackInterface.onSuccess(message);
415 | }
416 |
417 | @Override
418 | public void onError(String message) {
419 | callbackInterface.onError(message);
420 | }
421 |
422 | @Override
423 | public void onDebugStatus(String message) {
424 | callbackInterface.onDebugStatus(message);
425 | }
426 | };
427 |
428 | new RetrieveOEMInfoTask().executeAsync(context, Uri.parse("content://oem_info/oem.zebra.secure/ethernet_mac"),
429 | tempCallbackInterface);
430 | }
431 |
432 |
433 | }
434 |
--------------------------------------------------------------------------------
/DeviceIdentifiersWrapper/src/main/java/com/zebra/deviceidentifierswrapper/DIProfileManagerCommand.java:
--------------------------------------------------------------------------------
1 | package com.zebra.deviceidentifierswrapper;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 | import android.os.Build;
6 | import android.text.TextUtils;
7 | import android.util.Log;
8 | import android.util.Xml;
9 |
10 | import com.symbol.emdk.EMDKBase;
11 | import com.symbol.emdk.EMDKException;
12 | import com.symbol.emdk.EMDKManager;
13 | import com.symbol.emdk.EMDKResults;
14 | import com.symbol.emdk.ProfileManager;
15 |
16 | import org.xmlpull.v1.XmlPullParser;
17 | import org.xmlpull.v1.XmlPullParserException;
18 |
19 | import java.io.StringReader;
20 | import java.util.ArrayList;
21 | import java.util.Date;
22 |
23 | class DIProfileManagerCommand extends DICommandBase {
24 | public class ErrorHolder
25 | {
26 | // Provides the error type for characteristic-error
27 | public String sErrorType = "";
28 |
29 | // Provides the parm name for parm-error
30 | public String sParmName = "";
31 |
32 | // Provides error description
33 | public String sErrorDescription = "";
34 | }
35 |
36 | // Membres
37 | private String TAG = "DIWrapperMX";
38 |
39 | // Callback interface to get the hand back when the profile has been executed
40 | private IDIResultCallbacks idiProfileManagerCommandResult = null;
41 |
42 | // Profile content in XML
43 | private String msProfileData = "";
44 |
45 | // Profile name to execute
46 | private String msProfileName = "";
47 |
48 | //Declare a variable to store ProfileManager object
49 | private ProfileManager mProfileManager = null;
50 |
51 | //Declare a variable to store EMDKManager object
52 | private EMDKManager mEMDKManager = null;
53 |
54 | // An ArrayList that will contains errors if we find some
55 | private ArrayList mErrors = new ArrayList<>();
56 |
57 | // Provides full error description string
58 | public String msErrorString = "";
59 |
60 | // To prevent multiple initializations at the same time
61 | private boolean bInitializing = false;
62 |
63 | // Status Listener implementation (ensure that we retrieve the profile manager asynchronously
64 | EMDKManager.StatusListener mStatusListener = new EMDKManager.StatusListener() {
65 | @Override
66 | public void onStatus(EMDKManager.StatusData statusData, EMDKBase emdkBase) {
67 | if(statusData.getResult() == EMDKResults.STATUS_CODE.SUCCESS)
68 | {
69 | logMessage("Profile manager retrieved.", EMessageType.DEBUG);
70 | onProfileManagerInitialized((ProfileManager)emdkBase);
71 | }
72 | else
73 | {
74 | String errorMessage = "Error when trying to retrieve ProfileManager: " + getResultCode(statusData.getResult());
75 | logMessage(errorMessage, EMessageType.ERROR);
76 | }
77 | }
78 | };
79 |
80 | // EMDKListener implementation
81 | EMDKManager.EMDKListener mEMDKListener = new EMDKManager.EMDKListener() {
82 | @Override
83 | public void onOpened(EMDKManager emdkManager) {
84 | logMessage("EMDKManager.EMDKListener.onOpened", EMessageType.DEBUG);
85 | onEMDKManagerRetrieved(emdkManager);
86 | }
87 |
88 | @Override
89 | public void onClosed() {
90 | logMessage("EMDKManager.EMDKListener.onClosed", EMessageType.DEBUG);
91 | onEMDKManagerClosed();
92 | }
93 | };
94 |
95 |
96 | public DIProfileManagerCommand(Context aContext) {
97 | super(aContext);
98 | mSettings = new DICommandBaseSettings(){{
99 | mTimeOutMS = 20000;
100 | mEnableTimeOutMechanism = true;
101 | mCommandId = "DWProfileManagerCommand";
102 | }};
103 | }
104 |
105 | @Override
106 | protected void onTimeOut(DICommandBaseSettings settings) {
107 | super.onTimeOut(settings);
108 | onEMDKManagerClosed();
109 | }
110 |
111 | public void execute(String mxProfile, String mxProfileName, IDIResultCallbacks resutCallback)
112 | {
113 | // Let's start the timeout mechanism
114 | super.execute(mSettings);
115 | idiProfileManagerCommandResult = resutCallback;
116 | msProfileData = mxProfile;
117 | msProfileName = mxProfileName;
118 | initializeEMDK();
119 | }
120 |
121 | private void initializeEMDK()
122 | {
123 | if(bInitializing)
124 | return;
125 | bInitializing = true;
126 | if(mEMDKManager == null)
127 | {
128 | EMDKResults results = null;
129 | try
130 | {
131 | //The EMDKManager object will be created and returned in the callback.
132 | results = EMDKManager.getEMDKManager(mContext.getApplicationContext(), mEMDKListener);
133 | }
134 | catch(Exception e)
135 | {
136 | logMessage("Error while requesting EMDKManager.\n" + e.getLocalizedMessage(), EMessageType.ERROR);
137 | e.printStackTrace();
138 | waitForEMDK();
139 | return;
140 | }
141 |
142 | //Check the return status of EMDKManager object creation.
143 | if(results.statusCode == EMDKResults.STATUS_CODE.SUCCESS) {
144 | logMessage("EMDKManager request command issued with success", EMessageType.DEBUG);
145 | }else {
146 | logMessage("EMDKManager request command error", EMessageType.ERROR);
147 | waitForEMDK();
148 | }
149 | }
150 | else
151 | {
152 | onEMDKManagerRetrieved(mEMDKManager);
153 | }
154 | }
155 |
156 | private void waitForEMDK()
157 | {
158 | logMessage("EMDKManager error, this could be a BOOT_COMPLETED issue.", EMessageType.DEBUG);
159 | logMessage("Starting watcher thread to wait for EMDK initialization.", EMessageType.DEBUG);
160 | Thread t = new Thread(new Runnable() {
161 | @Override
162 | public void run() {
163 | long startDate = new Date().getTime();
164 | long delta = 0;
165 | while(mEMDKManager == null || delta < DIHelper.MAX_EMDK_TIMEOUT_IN_MS ) {
166 | // Try to initialize EMDK
167 | logMessage("Calling EMDK Initialization method", EMessageType.DEBUG);
168 | initializeEMDK();
169 | try {
170 | logMessage("Waiting " + DIHelper.WAIT_PERIOD_BEFORE_RETRY_EMDK_RETRIEVAL_IN_MS + " milliseconds before retrying.", EMessageType.DEBUG);
171 | Thread.sleep(DIHelper.WAIT_PERIOD_BEFORE_RETRY_EMDK_RETRIEVAL_IN_MS);
172 | } catch (InterruptedException e) {
173 | e.printStackTrace();
174 | }
175 | delta = new Date().getTime() - startDate;
176 | logMessage("Delta in ms since first EMDK retrieval try: " + delta + "ms stops at " + DIHelper.MAX_EMDK_TIMEOUT_IN_MS + "ms", EMessageType.DEBUG);
177 | }
178 | bInitializing = false;
179 | logMessage("Could not retrieve EMDK Manager after waiting " + DIHelper.WAIT_PERIOD_BEFORE_RETRY_EMDK_RETRIEVAL_IN_MS/DIHelper.SEC_IN_MS + " seconds. Please contact your administrator or check logcat for any EMDK related error.", EMessageType.ERROR);
180 | }
181 | });
182 | t.setPriority(Thread.MIN_PRIORITY);
183 | t.start();
184 | }
185 |
186 | private void onEMDKManagerRetrieved(EMDKManager emdkManager)
187 | {
188 | mEMDKManager = emdkManager;
189 | logMessage("EMDK Manager retrieved.", EMessageType.DEBUG);
190 | if(mProfileManager == null)
191 | {
192 | try {
193 | logMessage("Requesting profile manager.", EMessageType.DEBUG);
194 | logMessage("Current API version: " + android.os.Build.VERSION.SDK_INT, EMessageType.VERBOSE);
195 | if(android.os.Build.VERSION.SDK_INT < 33) {
196 | logMessage("Requesting profile manager Asynchonously", EMessageType.DEBUG);
197 | emdkManager.getInstanceAsync(EMDKManager.FEATURE_TYPE.PROFILE, mStatusListener);
198 | }
199 | else
200 | {
201 | logMessage("Requesting profile manager synchronized", EMessageType.DEBUG);
202 | ProfileManager profileManager = (ProfileManager) emdkManager.getInstance(EMDKManager.FEATURE_TYPE.PROFILE);
203 | if(profileManager != null)
204 | {
205 | onProfileManagerInitialized(profileManager);
206 | }
207 | }
208 | } catch (EMDKException e) {
209 | logMessage("Error when trying to retrieve profile manager: " + e.getMessage(), EMessageType.ERROR);
210 | }
211 | }
212 | else
213 | {
214 | logMessage("EMDK Manager already initialized.", EMessageType.DEBUG);
215 | onProfileManagerInitialized(mProfileManager);
216 | }
217 | }
218 |
219 | private void onEMDKManagerClosed()
220 | {
221 | releaseManagers();
222 | }
223 |
224 | private void releaseManagers()
225 | {
226 | if(mProfileManager != null)
227 | {
228 | mProfileManager = null;
229 | logMessage("Profile Manager reseted.", EMessageType.DEBUG);
230 | }
231 |
232 | //This callback will be issued when the EMDK closes unexpectedly.
233 | if (mEMDKManager != null) {
234 | mEMDKManager.release();
235 | logMessage("EMDKManager released.", EMessageType.DEBUG);
236 | mEMDKManager = null;
237 | logMessage("EMDKManager reseted.", EMessageType.DEBUG);
238 | }
239 | }
240 |
241 | private void onProfileManagerInitialized(ProfileManager profileManager)
242 | {
243 | mProfileManager = profileManager;
244 | bInitializing = false;
245 | logMessage("Processing MX Content", EMessageType.DEBUG);
246 | processMXContent();
247 | }
248 |
249 | private void onProfileExecutedWithSuccess()
250 | {
251 | releaseManagers();
252 | if(idiProfileManagerCommandResult != null)
253 | {
254 | idiProfileManagerCommandResult.onSuccess("Success applying profile:" + msProfileName + "\nProfileData:" + msProfileData);
255 | }
256 |
257 | }
258 |
259 | private void onProfileExecutedError(String message)
260 | {
261 | releaseManagers();
262 | if(idiProfileManagerCommandResult != null)
263 | {
264 | idiProfileManagerCommandResult.onError("Error on profile: " + msProfileName + "\nError:" + message + "\nProfileData:" + msProfileData);
265 | }
266 |
267 | }
268 |
269 | private void onProfileExecutedStatusChanged(String message)
270 | {
271 | if(idiProfileManagerCommandResult != null)
272 | {
273 | idiProfileManagerCommandResult.onDebugStatus(message);
274 | }
275 | }
276 |
277 | private void processMXContent()
278 | {
279 | String[] params = new String[1];
280 | params[0] = msProfileData;
281 |
282 | logMessage("Processing profile :" + msProfileData, EMessageType.VERBOSE);
283 | EMDKResults results = mProfileManager.processProfile(msProfileName, ProfileManager.PROFILE_FLAG.SET, params);
284 |
285 | //Check the return status of processProfile
286 | if(results.statusCode == EMDKResults.STATUS_CODE.CHECK_XML) {
287 |
288 | // Get XML response as a String
289 | String statusXMLResponse = results.getStatusString();
290 |
291 | try {
292 | // Empty Error Holder Array List if it already exists
293 | mErrors.clear();
294 |
295 | // Create instance of XML Pull Parser to parse the response
296 | XmlPullParser parser = Xml.newPullParser();
297 | // Provide the string response to the String Reader that reads
298 | // for the parser
299 | parser.setInput(new StringReader(statusXMLResponse));
300 | // Call method to parse the response
301 | parseXML(parser);
302 |
303 | if ( mErrors.size() == 0 ) {
304 |
305 | logMessage("Profile executed with success: " + msProfileName, EMessageType.SUCCESS);
306 | onProfileExecutedWithSuccess();
307 | }
308 | else {
309 | String errorMessage = "";
310 | for(ErrorHolder error : mErrors)
311 | {
312 | errorMessage += "Profile processing error.\t" + "Type:" + error.sErrorType + "\tParamName:" + error.sParmName + "\tDescription:" + error.sErrorDescription;
313 | }
314 | logMessage(errorMessage, EMessageType.ERROR);
315 | onProfileExecutedError(errorMessage);
316 | return;
317 | }
318 |
319 | } catch (XmlPullParserException e) {
320 | String errorMessage = "Error while trying to parse ProfileManager XML Response: " + e.getLocalizedMessage();
321 | logMessage(errorMessage, EMessageType.ERROR);
322 | onProfileExecutedError(errorMessage);
323 | return;
324 | }
325 | }
326 | else if(results.statusCode == EMDKResults.STATUS_CODE.SUCCESS)
327 | {
328 | logMessage("Profile executed with success: " + msProfileName, EMessageType.DEBUG);
329 | onProfileExecutedWithSuccess();
330 | return;
331 | }
332 | else
333 | {
334 | String errorMessage = "Profile update failed." + getResultCode(results.statusCode) + "\nProfil:\n" + msProfileName;
335 | logMessage(errorMessage, EMessageType.ERROR);
336 | onProfileExecutedError(errorMessage);
337 | return;
338 | }
339 | }
340 |
341 | // Method to parse the XML response using XML Pull Parser
342 | private void parseXML(XmlPullParser myParser) {
343 | int event;
344 | try {
345 | // Retrieve error details if parm-error/characteristic-error in the response XML
346 | event = myParser.getEventType();
347 | // An object that will store a temporary error holder if an error characteristic is found
348 | ErrorHolder tempErrorHolder = null;
349 | //logMessage("XML document", EMessageType.VERBOSE);
350 | while (event != XmlPullParser.END_DOCUMENT) {
351 | String name = myParser.getName();
352 | switch (event) {
353 | case XmlPullParser.START_TAG:
354 | //logMessage("XML Element:<" + myParser.getText()+">", EMessageType.VERBOSE);
355 | if (name.equals("characteristic-error"))
356 | {
357 | if(tempErrorHolder == null)
358 | tempErrorHolder = new ErrorHolder();
359 | tempErrorHolder.sErrorType = myParser.getAttributeValue(null, "type");
360 | if(tempErrorHolder.sParmName != null && TextUtils.isEmpty(tempErrorHolder.sParmName) == false)
361 | {
362 | msErrorString += "Nom: " + tempErrorHolder.sParmName + "\nType: " + tempErrorHolder.sErrorType + "\nDescription: " + tempErrorHolder.sErrorDescription + ")";
363 | mErrors.add(tempErrorHolder);
364 | tempErrorHolder = null;
365 | }
366 | }
367 | else if (name.equals("parm-error"))
368 | {
369 | if(tempErrorHolder == null)
370 | tempErrorHolder = new ErrorHolder();
371 | tempErrorHolder.sParmName = myParser.getAttributeValue(null, "name");
372 | tempErrorHolder.sErrorDescription = myParser.getAttributeValue(null, "desc");
373 | if(tempErrorHolder.sErrorType != null && TextUtils.isEmpty(tempErrorHolder.sErrorType) == false)
374 | {
375 | msErrorString += "Nom: " + tempErrorHolder.sParmName + "\nType: " + tempErrorHolder.sErrorType + "\nDescription: " + tempErrorHolder.sErrorDescription + ")";
376 | mErrors.add(tempErrorHolder);
377 | tempErrorHolder = null;
378 | }
379 | }
380 | break;
381 | case XmlPullParser.END_TAG:
382 | //logMessage("XML Element:/" + myParser.getText()+">", EMessageType.VERBOSE);
383 | break;
384 | }
385 | event = myParser.next();
386 | }
387 |
388 | } catch (Exception e) {
389 | e.printStackTrace();
390 | }
391 | }
392 |
393 | private void logMessage(String message, EMessageType messageType)
394 | {
395 | switch(messageType)
396 | {
397 | case ERROR:
398 | Log.e(TAG, message);
399 | onProfileExecutedStatusChanged("ERROR:" + message);
400 | break;
401 | case SUCCESS:
402 | Log.v(TAG, message);
403 | onProfileExecutedStatusChanged("SUCCESS:" + message);
404 | break;
405 | case VERBOSE:
406 | Log.v(TAG, message);
407 | onProfileExecutedStatusChanged("VERBOSE:" + message);
408 | break;
409 | case WARNING:
410 | Log.w(TAG, message);
411 | onProfileExecutedStatusChanged("WARNING:" + message);
412 | break;
413 | case DEBUG:
414 | Log.d(TAG,message);
415 | onProfileExecutedStatusChanged("DEBUG:" + message);
416 | }
417 | }
418 |
419 | private String getResultCode(EMDKResults.STATUS_CODE aStatusCode)
420 | {
421 | switch (aStatusCode)
422 | {
423 | case FAILURE:
424 | return "FAILURE";
425 | case NULL_POINTER:
426 | return "NULL_POINTER";
427 | case EMPTY_PROFILENAME:
428 | return "EMPTY_PROFILENAME";
429 | case EMDK_NOT_OPENED:
430 | return "EMDK_NOT_OPENED";
431 | case CHECK_XML:
432 | return "CHECK_XML";
433 | case PREVIOUS_REQUEST_IN_PROGRESS:
434 | return "PREVIOUS_REQUEST_IN_PROGRESS";
435 | case PROCESSING:
436 | return "PROCESSING";
437 | case NO_DATA_LISTENER:
438 | return "NO_DATA_LISTENER";
439 | case FEATURE_NOT_READY_TO_USE:
440 | return "FEATURE_NOT_READY_TO_USE";
441 | case FEATURE_NOT_SUPPORTED:
442 | return "FEATURE_NOT_SUPPORTED";
443 | case UNKNOWN:
444 | default:
445 | return "UNKNOWN";
446 | }
447 | }
448 |
449 | }
450 |
--------------------------------------------------------------------------------
/DeviceIdentifiersWrapper/src/main/java/com/zebra/deviceidentifierswrapper/EMessageType.java:
--------------------------------------------------------------------------------
1 | package com.zebra.deviceidentifierswrapper;
2 |
3 | enum EMessageType {
4 | VERBOSE,
5 | WARNING,
6 | ERROR,
7 | SUCCESS,
8 | DEBUG
9 | }
10 |
--------------------------------------------------------------------------------
/DeviceIdentifiersWrapper/src/main/java/com/zebra/deviceidentifierswrapper/ExecutorTask.java:
--------------------------------------------------------------------------------
1 | package com.zebra.deviceidentifierswrapper;
2 |
3 | // Inspiration from Vitality answer : https://stackoverflow.com/a/68395429
4 |
5 | import android.os.Handler;
6 | import android.os.Looper;
7 | import android.util.Log;
8 |
9 | import java.util.concurrent.Executor;
10 | import java.util.concurrent.LinkedBlockingQueue;
11 | import java.util.concurrent.ThreadPoolExecutor;
12 | import java.util.concurrent.TimeUnit;
13 |
14 | public abstract class ExecutorTask {
15 | public static final String TAG = "ExecutorTask";
16 |
17 | private static final Executor THREAD_POOL_EXECUTOR =
18 | new ThreadPoolExecutor(5, 128, 1,
19 | TimeUnit.SECONDS, new LinkedBlockingQueue());
20 |
21 | private final Handler mHandler = new Handler(Looper.getMainLooper());
22 | private boolean mIsInterrupted = false;
23 |
24 | protected void onPreExecute(){}
25 | protected abstract Result doInBackground(Params... params);
26 | protected void onPostExecute(Result result){}
27 |
28 | protected void onProgressUpdate(Progress... values) {
29 | }
30 | protected void onCancelled() {}
31 |
32 | @SafeVarargs
33 | public final void executeAsync(Params... params) {
34 | THREAD_POOL_EXECUTOR.execute(() -> {
35 | try {
36 | checkInterrupted();
37 | mHandler.post(this::onPreExecute);
38 |
39 | checkInterrupted();
40 | final Result results = doInBackground(params);
41 |
42 | checkInterrupted();
43 | mHandler.post(new Runnable() {
44 | @Override
45 | public void run() {
46 | onPostExecute(results);
47 | }
48 | });
49 | } catch (InterruptedException ex) {
50 | mHandler.post(this::onCancelled);
51 | } catch (Exception ex) {
52 | Log.e(TAG, "executeAsync: " + ex.getMessage() + "\n" + ex.getStackTrace());
53 |
54 | }
55 | });
56 | }
57 |
58 | private void checkInterrupted() throws InterruptedException {
59 | if (isInterrupted()){
60 | throw new InterruptedException();
61 | }
62 | }
63 |
64 | public void cancel(boolean mayInterruptIfRunning){
65 | setInterrupted(mayInterruptIfRunning);
66 | }
67 |
68 | public boolean isInterrupted() {
69 | return mIsInterrupted;
70 | }
71 |
72 | public void setInterrupted(boolean interrupted) {
73 | mIsInterrupted = interrupted;
74 | }
75 | }
--------------------------------------------------------------------------------
/DeviceIdentifiersWrapper/src/main/java/com/zebra/deviceidentifierswrapper/IDIResultCallbacks.java:
--------------------------------------------------------------------------------
1 | package com.zebra.deviceidentifierswrapper;
2 |
3 | public interface IDIResultCallbacks {
4 | void onSuccess(final String message);
5 | void onError(final String message);
6 | void onDebugStatus(final String message);
7 | }
8 |
--------------------------------------------------------------------------------
/DeviceIdentifiersWrapper/src/main/java/com/zebra/deviceidentifierswrapper/RetrieveOEMInfoTask.java:
--------------------------------------------------------------------------------
1 | package com.zebra.deviceidentifierswrapper;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.pm.PackageInfo;
6 | import android.content.pm.PackageManager;
7 | import android.content.pm.Signature;
8 | import android.database.Cursor;
9 | import android.net.Uri;
10 | import android.os.AsyncTask;
11 |
12 | import java.util.Base64;
13 |
14 | /**
15 | * Device Identifiers Sample
16 | *
17 | * Original Device Identifier Sample Code:
18 | * - Darryn Campbell
19 | * - https://github.com/darryncampbell/EMDK-DeviceIdentifiers-Sample
20 | *
21 | * Wrapper Code:
22 | * - Trudu Laurent
23 | * - https://github.com/ltrudu/DeviceIdentifiersWrapper-Sample
24 | *
25 | * (c) Zebra 2020
26 | */
27 |
28 | class RetrieveOEMInfoTask extends ExecutorTask