Browse Source

第一次提交

hjs 1 year ago
commit
ec849b12bf
59 changed files with 2000 additions and 0 deletions
  1. 15 0
      .gitignore
  2. 3 0
      .idea/.gitignore
  3. 1 0
      .idea/.name
  4. 6 0
      .idea/compiler.xml
  5. 20 0
      .idea/gradle.xml
  6. 21 0
      .idea/misc.xml
  7. 1 0
      app/.gitignore
  8. 63 0
      app/build.gradle
  9. BIN
      app/libs/ABCP-API-5.5.2.4-lite.aar
  10. BIN
      app/libs/Alipay_IoTSDK.aar
  11. BIN
      app/libs/aromecli-build-1.0.0.220421185143.aar
  12. BIN
      app/libs/telpo_api.jar
  13. 37 0
      app/proguard-rules.pro
  14. 55 0
      app/src/main/AndroidManifest.xml
  15. 15 0
      app/src/main/java/com/hh/arome/AutoStartReceiver.java
  16. 353 0
      app/src/main/java/com/hh/arome/MainActivity.java
  17. 22 0
      app/src/main/java/com/hh/arome/MainApplication.java
  18. 18 0
      app/src/main/java/com/hh/arome/constants/AmpeBuildConfig.java
  19. 10 0
      app/src/main/java/com/hh/arome/constants/BuildConfig.java
  20. 70 0
      app/src/main/java/com/hh/arome/http/JsonParamsBuilder.java
  21. 46 0
      app/src/main/java/com/hh/arome/http/JsonResponse.java
  22. 62 0
      app/src/main/java/com/hh/arome/http/JsonResponseParser.java
  23. 28 0
      app/src/main/java/com/hh/arome/http/params/AmpeJsonParams.java
  24. 69 0
      app/src/main/java/com/hh/arome/http/response/AmpeJsonResponse.java
  25. 135 0
      app/src/main/java/com/hh/arome/services/IDReaderService.java
  26. 90 0
      app/src/main/java/com/hh/arome/services/QrcodeScannerService.java
  27. 210 0
      app/src/main/java/com/hh/arome/util/BarcodeScannerHelper.java
  28. 47 0
      app/src/main/java/com/hh/arome/util/Utils.java
  29. BIN
      app/src/main/jniLibs/armeabi-v7a/libfingerprint.so
  30. BIN
      app/src/main/jniLibs/armeabi-v7a/libidcard.so
  31. BIN
      app/src/main/jniLibs/armeabi-v7a/libsystem_util.so
  32. BIN
      app/src/main/jniLibs/armeabi-v7a/libtelpo_serial.so
  33. BIN
      app/src/main/jniLibs/armeabi-v7a/libwlt2bmp.so
  34. BIN
      app/src/main/jniLibs/armeabi/libfingerprint.so
  35. BIN
      app/src/main/jniLibs/armeabi/libidcard.so
  36. BIN
      app/src/main/jniLibs/armeabi/libsystem_util.so
  37. BIN
      app/src/main/jniLibs/armeabi/libtelpo_serial.so
  38. BIN
      app/src/main/jniLibs/armeabi/libwlt2bmp.so
  39. 30 0
      app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  40. 170 0
      app/src/main/res/drawable/ic_launcher_background.xml
  41. 19 0
      app/src/main/res/layout/activity_main.xml
  42. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.png
  43. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.png
  44. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher.png
  45. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  46. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  47. 16 0
      app/src/main/res/values-night/themes.xml
  48. 10 0
      app/src/main/res/values/colors.xml
  49. 4 0
      app/src/main/res/values/strings.xml
  50. 16 0
      app/src/main/res/values/themes.xml
  51. 10 0
      app/src/main/res/xml/accessibility.xml
  52. 9 0
      build.gradle
  53. 21 0
      gradle.properties
  54. BIN
      gradle/wrapper/gradle-wrapper.jar
  55. 6 0
      gradle/wrapper/gradle-wrapper.properties
  56. 185 0
      gradlew
  57. 89 0
      gradlew.bat
  58. BIN
      hh-face.jks
  59. 18 0
      settings.gradle

+ 15 - 0
.gitignore

@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties

+ 3 - 0
.idea/.gitignore

@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml

+ 1 - 0
.idea/.name

@@ -0,0 +1 @@
+HH-K8-AMPE

+ 6 - 0
.idea/compiler.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <bytecodeTargetLevel target="11" />
+  </component>
+</project>

+ 20 - 0
.idea/gradle.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleMigrationSettings" migrationVersion="1" />
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="testRunner" value="GRADLE" />
+        <option name="distributionType" value="DEFAULT_WRAPPED" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/app" />
+          </set>
+        </option>
+        <option name="resolveModulePerSourceSet" value="false" />
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>

+ 21 - 0
.idea/misc.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="DesignSurface">
+    <option name="filePathToZoomLevelMap">
+      <map>
+        <entry key="..\:/workspace-app/HHK8AMPE/app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.2985" />
+        <entry key="..\:/workspace-app/HHK8AMPE/app/src/main/res/drawable/ic_launcher_background.xml" value="0.2985" />
+        <entry key="..\:/workspace-app/HHK8AMPE/app/src/main/res/layout/activity_main.xml" value="0.358695652173913" />
+        <entry key="..\:/workspace-app/HHK8AMPE/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.2985" />
+        <entry key="..\:/workspace-app/HHK8AMPE/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.2985" />
+        <entry key="..\:/workspace-app/HHK8AMPE/app/src/main/res/xml/accessibility.xml" value="0.36614583333333334" />
+      </map>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/build/classes" />
+  </component>
+  <component name="ProjectType">
+    <option name="id" value="Android" />
+  </component>
+</project>

+ 1 - 0
app/.gitignore

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

+ 63 - 0
app/build.gradle

@@ -0,0 +1,63 @@
+plugins {
+    id 'com.android.application'
+}
+
+android {
+
+    signingConfigs {
+        ampe {
+            storeFile file('D:\\航汇-人脸机sdk\\hh-face.jks')
+            storePassword 'Nqj##117521'
+            keyAlias 'hemile'
+            keyPassword 'Nqj##117521'
+        }
+    }
+
+    compileSdk 33
+    defaultConfig {
+        applicationId "com.hh.arome"
+        minSdk 21
+        targetSdk 33
+        versionCode 1
+        versionName "1.0.0"
+        multiDexEnabled true
+        ndk {
+            abiFilters "armeabi-v7a"  // 指定要ndk需要兼容的架构(这样其他依赖包里mips,x86,armeabi,arm-v8之类的so会被过滤掉)
+        }
+
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+            signingConfig signingConfigs.ampe
+            applicationVariants.all { variant ->
+                variant.outputs.all {
+                    outputFileName = "k8_v${variant.versionName}.apk"
+                }
+            }
+        }
+        debug {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+            signingConfig signingConfigs.ampe
+        }
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+}
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
+    implementation 'androidx.appcompat:appcompat:1.3.0'
+    implementation 'com.google.android.material:material:1.4.0'
+    implementation 'androidx.multidex:multidex:2.0.1'
+
+    implementation 'org.xutils:xutils:3.9.0'
+    implementation 'com.alibaba:fastjson:1.1.45@jar'
+}

BIN
app/libs/ABCP-API-5.5.2.4-lite.aar


BIN
app/libs/Alipay_IoTSDK.aar


BIN
app/libs/aromecli-build-1.0.0.220421185143.aar


BIN
app/libs/telpo_api.jar


+ 37 - 0
app/proguard-rules.pro

@@ -0,0 +1,37 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+
+-keepattributes Signature,*Annotation*
+-keep public class org.xutils.** {
+    public protected *;
+}
+-keep public interface org.xutils.** {
+    public protected *;
+}
+-keepclassmembers class * extends org.xutils.** {
+    public protected *;
+}
+-keepclassmembers @org.xutils.db.annotation.* class * {*;}
+-keepclassmembers @org.xutils.http.annotation.* class * {*;}
+-keepclassmembers class * {
+    @org.xutils.view.annotation.Event <methods>;
+}

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

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.hh.arome">
+
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+    <uses-permission android:name="android.permission.INTERNET" />
+<!--    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />-->
+
+    <application
+        android:name=".MainApplication"
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.HHK8AMPE">
+        <activity
+            android:name=".MainActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <!-- 应用自启广播接收器 -->
+        <receiver
+            android:name=".AutoStartReceiver"
+            android:enabled="true"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+        <!--    身份证读卡器service    -->
+        <service
+            android:name=".services.IDReaderService"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":idread"/>
+        <!-- 扫码枪AccessibilityService服务类 -->
+        <service
+            android:name=".services.QrcodeScannerService"
+            android:enabled="true"
+            android:exported="true"
+            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
+            <intent-filter>
+                <action android:name="android.accessibilityservice.AccessibilityService"/>
+            </intent-filter>
+            <meta-data
+                android:name="android.accessibilityservice"
+                android:resource="@xml/accessibility"/>
+        </service>
+    </application>
+
+</manifest>

+ 15 - 0
app/src/main/java/com/hh/arome/AutoStartReceiver.java

@@ -0,0 +1,15 @@
+package com.hh.arome;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class AutoStartReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        // 启动应用
+        Intent mainActivityIntent = new Intent(context, MainActivity.class);
+        mainActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(mainActivityIntent);
+    }
+}

+ 353 - 0
app/src/main/java/com/hh/arome/MainActivity.java

@@ -0,0 +1,353 @@
+package com.hh.arome;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+
+import android.app.ProgressDialog;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Toast;
+
+import com.alibaba.fastjson.JSON;
+import com.alipay.arome.aromecli.AromeInit;
+import com.alipay.arome.aromecli.AromeInitOptions;
+import com.alipay.arome.aromecli.AromeServiceInvoker;
+import com.alipay.arome.aromecli.AromeServiceTask;
+import com.alipay.arome.aromecli.requst.AromeActivateRequest;
+import com.alipay.arome.aromecli.requst.AromeLaunchAppRequest;
+import com.alipay.arome.aromecli.requst.AromeSendEventRequest;
+import com.alipay.arome.aromecli.response.AromeActivateResponse;
+import com.alipay.arome.aromecli.response.AromeLaunchAppResponse;
+import com.alipay.arome.aromecli.response.AromeResponse;
+import com.hh.arome.http.JsonResponse;
+import com.hh.arome.http.params.AmpeJsonParams;
+import com.hh.arome.http.response.AmpeJsonResponse;
+import com.hh.arome.services.IDReaderService;
+import com.hh.arome.services.QrcodeScannerService;
+import com.hh.arome.util.BarcodeScannerHelper;
+import com.hh.arome.util.Utils;
+
+import org.json.JSONException;
+import org.xutils.common.Callback;
+import org.xutils.x;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class MainActivity extends AppCompatActivity {
+
+    private static final String TAG = MainActivity.class.getSimpleName();
+    public static final int REQUEST_CODE_Accessibility = 19999;
+
+    private Handler mMainHandler = new Handler(Looper.getMainLooper());
+    private Handler mWorkerThread = null;
+    private ProgressDialog mProgressDialog;
+    private AtomicInteger mDialogToken = new AtomicInteger(0);
+
+    // 设备的配置参数
+    private AmpeJsonResponse ampeJson = null;
+
+    /**
+     * ServiceConnection代表与服务的连接,它只有两个方法,
+     * onServiceConnected和onServiceDisconnected,
+     * 前者是在操作者在连接一个服务成功时被调用,而后者是在服务崩溃或被杀死导致的连接中断时被调用
+     */
+    private ServiceConnection conn;
+    private IDReaderService mService;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        init();
+        if(initQrcodeScannerData(true)) {
+            initAmpeData();
+        }
+//        initBarcodeScanner();
+//        initService();
+    }
+
+    private void init() {
+        HandlerThread workerHandlerThread = new HandlerThread("arome_worker");
+        workerHandlerThread.start();
+        mWorkerThread = new Handler(workerHandlerThread.getLooper());
+    }
+
+    private boolean initQrcodeScannerData(boolean auto) {
+        if(!QrcodeScannerService.isAccessibilitySettingsOn(this)) {
+            if(auto) {
+                Toast.makeText(x.app(), "请开启该应用的无障碍辅助服务!", Toast.LENGTH_LONG).show();
+                startActivityForResult(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), REQUEST_CODE_Accessibility);
+            }
+            return false;
+        }
+        return true;
+    }
+
+    private void initAmpeData() {
+        final int token = showLoading("正在激活...");
+        AmpeJsonParams ampeJsonParams = new AmpeJsonParams(Utils.getIotVersion());
+        ampeJsonParams.send(new Callback.CommonCallback<JsonResponse<AmpeJsonResponse>>() {
+            @Override
+            public void onSuccess(JsonResponse<AmpeJsonResponse> result) {
+                System.out.println("onSuccess-->" + result);
+//                Toast.makeText(x.app(), result.toString(), Toast.LENGTH_LONG).show();
+                ampeJson = result.getData();
+                if(ampeJson == null || TextUtils.isEmpty(ampeJson.getAPP_ID())) {
+                    Toast.makeText(x.app(), "获取到的配置参数为空!", Toast.LENGTH_LONG).show();
+                    return;
+                }
+                initAmpe();
+            }
+
+            @Override
+            public void onError(Throwable ex, boolean isOnCallback) {
+                System.out.println("onError-->" + isOnCallback);
+//                Toast.makeText(x.app(), ex.getMessage(), Toast.LENGTH_LONG).show();
+            }
+
+            @Override
+            public void onCancelled(CancelledException cex) {
+                System.out.println("onCancelled-->");
+//                Toast.makeText(x.app(), "cancelled", Toast.LENGTH_LONG).show();
+            }
+
+            @Override
+            public void onFinished() {
+                System.out.println("onFinished-->");
+                hideLoading(token);
+            }
+        });
+    }
+
+    // 初始化扫码
+    private void initBarcodeScanner() {
+        BarcodeScannerHelper.getInstance().setScanSuccessListener(new BarcodeScannerHelper.OnScanSuccessListener() {
+            @Override
+            public void onScanSuccess(String barcode) {
+                Toast.makeText(MainActivity.this, "扫码内容:" + barcode, Toast.LENGTH_LONG).show();
+                System.out.println(TAG + "-" + barcode);
+            }
+        });
+    }
+
+    private void initService() {
+        conn = new ServiceConnection() {
+            /**
+             * 与服务器端交互的接口方法 绑定服务的时候被回调,在这个方法获取绑定Service传递过来的IBinder对象,
+             * 通过这个IBinder对象,实现宿主和Service的交互。
+             */
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                Log.d(TAG, "绑定成功调用:onServiceConnected");
+                IDReaderService.LocalBinder binder = (IDReaderService.LocalBinder) service;
+                mService = binder.getService();
+            }
+            /**
+             * 当取消绑定的时候被回调。但正常情况下是不被调用的,它的调用时机是当Service服务被意外销毁时,
+             * 例如内存的资源不足时这个方法才被自动调用。
+             */
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                mService = null;
+            }
+        };
+        Intent intent = new Intent(this, IDReaderService.class);
+        bindService(intent, conn, Service.BIND_AUTO_CREATE);
+    }
+
+    private void initAmpe() {
+        // 设备信息配置
+        Bundle deviceConfig = new Bundle();
+        deviceConfig.putString("packageName", "com.hh.arome");
+        Bundle themeConfig = new Bundle();
+        themeConfig.putBoolean("hideStatusBar", true);
+        themeConfig.putBoolean("hideNavigationBar", true);
+        themeConfig.putBoolean("hideOptionMenu", true);
+
+        AromeInit.init(new AromeInitOptions.Builder()
+                .loginMode(0)
+                .hardwareType(0)
+                .hardwareName("杭州航汇数字YX08政务刷脸自助机")
+                .deviceConfig(deviceConfig)
+                .themeConfig(themeConfig)
+                .build(), new AromeInit.Callback() {
+            @Override
+            public void postInit(boolean success, int errorCode, String errorMsg) {
+                if(success) {
+                    activateDevice(null);
+                } else {
+                    Toast.makeText(MainActivity.this, "失败:" + errorMsg, Toast.LENGTH_LONG).show();
+                }
+            }
+            @Override
+            public void serverDied() {
+
+            }
+        });
+    }
+
+    public void activateDevice(View view) {
+        final int token = showLoading("正在加载...");
+        mWorkerThread.post(new Runnable() {
+            @Override
+            public void run() {
+                AromeActivateRequest request = new AromeActivateRequest();
+                request.hostAppId = ampeJson.getHOST_APP_ID();
+                request.deviceId = ampeJson.getDEVICE_ID();
+                request.signature = ampeJson.getSignature();
+                try{
+                    request.productId = Integer.parseInt(ampeJson.getPRODUCT_ID());
+                } catch (Exception e) {
+                    throw new NullPointerException("productId不能为空");
+                }
+                AromeServiceInvoker.invoke(request, new AromeServiceTask.Callback<AromeActivateResponse>() {
+                    @Override
+                    public void onCallback(final AromeActivateResponse response) {
+                        mMainHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                if(response.success) {
+                                    launchApp();
+                                } else {
+                                    Toast.makeText(MainActivity.this, "激活失败:" + response.message, Toast.LENGTH_LONG).show();
+                                }
+                            }
+                        });
+                    }
+                });
+                hideLoading(token);
+            }
+        });
+    }
+
+    private void launchApp() {
+        final int token = showLoading("正在启动...");
+        mWorkerThread.post(new Runnable() {
+            @Override
+            public void run() {
+                AromeLaunchAppRequest request = new AromeLaunchAppRequest();
+                // 指定启动 appId
+                request.appId = ampeJson.getAPP_ID();
+                request.closeAllApp = true;
+
+                // 指定启动的显示类型 showType
+                // 指定启动时小程序主体的显示宽度 launchWidth
+                Bundle themeConfig = new Bundle();
+                request.themeConfig = themeConfig;
+
+                AromeServiceInvoker.invoke(request, new AromeServiceTask.Callback<AromeLaunchAppResponse>() {
+                    @Override
+                    public void onCallback(final AromeLaunchAppResponse response) {
+                        mMainHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                if(response.success) {
+//                                    Toast.makeText(MainActivity.this, "小程序启动成功:", Toast.LENGTH_LONG).show();
+                                } else {
+                                    Toast.makeText(MainActivity.this, "启动失败:" + response.message, Toast.LENGTH_LONG).show();
+                                }
+                            }
+                        });
+                    }
+                });
+                hideLoading(token);
+            }
+        });
+    }
+
+    // 用户手动离开当前activity,会调用该方法,比如用户主动切换任务,短按home进入桌面等。系统自动切换activity不会调用此方法,如来电,灭屏等。
+    @Override
+    protected void onUserLeaveHint() {
+        System.out.println("---->onUserLeaveHint---->");
+        super.onUserLeaveHint();
+    }
+
+    // activity在分发各种事件的时候会调用该方法,注意:启动另一个activity,onUserInteraction()会被调用两次,一次是activity捕获到事件,另一次是调用Activity#onUserLeaveHint()之前会调用Activity#onUserInteraction()。
+    @Override
+    public void onUserInteraction() {
+        System.out.println("---->onUserInteraction---->");
+        super.onUserInteraction();
+    }
+
+    private int showLoading(final String text) {
+        Utils.runOnMain(new Runnable() {
+            @Override
+            public void run() {
+                if (mProgressDialog != null) {
+                    mProgressDialog.dismiss();
+                    mProgressDialog = null;
+                }
+                mProgressDialog = ProgressDialog.show(MainActivity.this, "", text, true, true);
+            }
+        });
+        return mDialogToken.addAndGet(1);
+    }
+
+    private void hideLoading(final int token) {
+        Utils.runOnMain(new Runnable() {
+            @Override
+            public void run() {
+                // 防止dismiss串后续dialog
+                if (token != mDialogToken.get()) {
+                    return;
+                }
+                if (mProgressDialog != null) {
+                    mProgressDialog.dismiss();
+                    mProgressDialog = null;
+                }
+            }
+        }, 500);
+    }
+
+//    @Override
+//    public boolean dispatchKeyEvent(KeyEvent event) {
+//        if(BarcodeScannerHelper.getInstance().dispatchKeyEvent(event)) {
+//            return true;
+//        }
+//        return super.dispatchKeyEvent(event);
+//    }
+
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+        if (requestCode == REQUEST_CODE_Accessibility) {
+            // 检查权限是否已经被授权
+            boolean success = initQrcodeScannerData(false);
+            if(!success) {
+                Toast.makeText(x.app(), "未无障碍辅助服务,将不能使用扫码服务!", Toast.LENGTH_LONG).show();
+            }
+            initAmpeData();
+        }
+        super.onActivityResult(requestCode, resultCode, data);
+    }
+
+    @Override
+    protected void onDestroy() {
+        if(BarcodeScannerHelper.getInstance() != null) {
+            BarcodeScannerHelper.getInstance().removeScanSuccessListener();
+        }
+        // 解除绑定
+        if(mService != null) {
+            mService = null;
+            unbindService(conn);
+        }
+        super.onDestroy();
+    }
+}

+ 22 - 0
app/src/main/java/com/hh/arome/MainApplication.java

@@ -0,0 +1,22 @@
+package com.hh.arome;
+
+import android.app.Application;
+import android.content.Context;
+
+import androidx.multidex.MultiDex;
+
+import com.alipay.arome.aromecli.AromeInit;
+import com.hh.arome.constants.BuildConfig;
+
+import org.xutils.x;
+
+public class MainApplication extends Application {
+    @Override
+    protected void attachBaseContext(Context context) {
+        super.attachBaseContext(context);
+        MultiDex.install(this);
+        AromeInit.attachApplicationContext(context);
+        x.Ext.init(this);
+        x.Ext.setDebug(BuildConfig.isDebug); // 是否输出debug日志, 开启debug会影响性能.
+    }
+}

+ 18 - 0
app/src/main/java/com/hh/arome/constants/AmpeBuildConfig.java

@@ -0,0 +1,18 @@
+package com.hh.arome.constants;
+
+public class AmpeBuildConfig {
+
+    // iot平台的产品productId
+    public final static long PRODUCT_ID = 9705850;
+    // iot平台关联设备的设备编号
+//    public final static String DEVICE_ID = "137K008000200001";  // 江西人社k8设备
+    public final static String DEVICE_ID = "133K008000100016";  // 公司k8测试机
+    // 开放平台的移动应用AppId
+    public final static String HOST_APP_ID = "2021004108608975";
+    // 启动的小程序AppId, 需要在iot平台,在移动应用管理中绑定该小程序AppId
+//    public final static String APP_ID = "2021004108673948";   // 江西人社
+    public final static String APP_ID = "2021004113634033"; // K8访客小程序
+    // productId + "_" + deviceId 获取签名
+    public final static String signature = "VpbWmib2R6nONDmSgrrIrNQrv+Z6A4FKQz2NH53joFzm1ivoqAo4RMEiy6AHAVaMf+xZ+IxDmPwmuvYJUK4XYMoI2XidZeZOGrabyj6+m80gALnegy7XlIauEv+V3uX2jVX4gklgv0OvqdheT/+pKIBYjgNJ7daqK4bH6APWoLybLJIB+yWjuBa9syV6b3Pvwa8lPOec6izwxLrZrIBp1FCTeprpytqJ4RzPxGQ7lsJrkfHaovkoQodALiRR+6utVCrCWfU+CB3M7HsVbZ6vji6G4QvPY5q14pAnuMgwvhOceLmROyopjVjo/dgFpOdLrhY5lmLIcUCj+3GE8O2cQg==";
+
+}

+ 10 - 0
app/src/main/java/com/hh/arome/constants/BuildConfig.java

@@ -0,0 +1,10 @@
+package com.hh.arome.constants;
+
+public class BuildConfig {
+
+    // 是否为debug模式
+    public final static Boolean isDebug = true;
+
+    public static final String BASE_URL = "https://tx.hz-hanghui.com:8088/yx-fyzd/alipay/api/v1/open/";
+    public static final String BASE_URL_DEBUG = "https://tx.hz-hanghui.com:8088/yx-fyzd/alipay/api/v1/open/";
+}

+ 70 - 0
app/src/main/java/com/hh/arome/http/JsonParamsBuilder.java

@@ -0,0 +1,70 @@
+package com.hh.arome.http;
+
+import static com.hh.arome.constants.BuildConfig.BASE_URL;
+import static com.hh.arome.constants.BuildConfig.BASE_URL_DEBUG;
+
+import android.text.TextUtils;
+
+import org.xutils.http.HttpMethod;
+import org.xutils.http.RequestParams;
+import org.xutils.http.annotation.HttpRequest;
+import org.xutils.http.app.ParamsBuilder;
+import org.xutils.x;
+
+import java.util.HashMap;
+
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Created by wyouflf on 16/1/23.
+ * 添加在params对象的注解参数中.
+ */
+public class JsonParamsBuilder implements ParamsBuilder {
+
+    @Override
+    public String buildUri(RequestParams params, HttpRequest httpRequest) {
+        String url = x.isDebug() ? BASE_URL_DEBUG : BASE_URL;
+         url += httpRequest.path();
+        return url;
+    }
+
+    @Override
+    public String buildCacheKey(RequestParams params, String[] cacheKeys) {
+        return null;
+    }
+
+    @Override
+    public SSLSocketFactory getSSLSocketFactory() {
+        return null;
+    }
+
+    @Override
+    public void buildParams(RequestParams params) throws Throwable {
+        // 添加额外公共参数
+//        params.addParameter("common_a", "xxxx");
+//        params.addParameter("common_b", "xxxx");
+
+        // 将post请求的body参数以json形式提交
+         params.setAsJsonContent(true);
+
+        // 或者query参数和body参数都json形式
+//        String json = params.toJSONString();
+//        params.clearParams();// 清空参数
+//        if (params.getMethod() == HttpMethod.GET) {
+//            params.addQueryStringParameter("wd", json);
+//        } else {
+//            params.setBodyContent(json);
+//        }
+
+        // 也可以将参数对象转为pb
+        //byte[] pbData = convertPbData(pbFiled);
+        //params.setMultipart(false);
+        // 非multipart表单,key被忽略,只上传pbData
+        //params.addBodyParameter("data", pbData, "application/octet-stream");
+    }
+
+    @Override
+    public void buildSign(RequestParams params, String[] signs) {
+        // params.addHeader("xxx_sign", "xxxx");
+    }
+}

+ 46 - 0
app/src/main/java/com/hh/arome/http/JsonResponse.java

@@ -0,0 +1,46 @@
+package com.hh.arome.http;
+
+import org.xutils.http.annotation.HttpResponse;
+
+/**
+ * ampe平台配置参数
+ */
+@HttpResponse(parser = JsonResponseParser.class)
+public class JsonResponse<T> {
+    private int code;
+    private T data;
+    private String msg;
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    @Override
+    public String toString() {
+        return "JsonResponse{" +
+                "code=" + code +
+                ", data=" + data +
+                ", msg='" + msg + '\'' +
+                '}';
+    }
+}

+ 62 - 0
app/src/main/java/com/hh/arome/http/JsonResponseParser.java

@@ -0,0 +1,62 @@
+package com.hh.arome.http;
+
+import com.alibaba.fastjson.JSON;
+
+import org.xutils.common.util.LogUtil;
+import org.xutils.common.util.ParameterizedTypeUtil;
+import org.xutils.http.app.ResponseParser;
+import org.xutils.http.request.UriRequest;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by wyouflf on 15/11/5.
+ * 添加在params对象的注解参数中.
+ * 如果泛型为 byte[] 或 InputStream, 可以方便的转换protobuf对象.
+ */
+public class JsonResponseParser implements ResponseParser<String> {
+
+    @Override
+    public void beforeRequest(UriRequest request) throws Throwable {
+        // custom check params?
+        LogUtil.d(request.getParams().toString());
+    }
+
+    @Override
+    public void afterRequest(UriRequest request) throws Throwable {
+        // custom check response Headers?
+        LogUtil.d("response code:" + request.getResponseCode());
+    }
+
+    /**
+     * 转换result为resultType类型的对象
+     *
+     * @param resultType  返回值类型(可能带有泛型信息)
+     * @param resultClass 返回值类型
+     * @param result      网络返回数据(支持String, byte[], JSONObject, JSONArray, InputStream)
+     * @return 请求结果, 类型为resultType
+     */
+    @Override
+    public Object parse(Type resultType, Class<?> resultClass, String result) throws Throwable {
+        // TODO: json to java bean
+        if (resultClass == List.class) {
+            // 这里只是个示例, 不做json转换.
+//            List<JsonDemoResponse> list = new ArrayList<JsonDemoResponse>();
+//            JsonDemoResponse baiduResponse = new JsonDemoResponse();
+//            baiduResponse.setTest(result);
+//            list.add(baiduResponse);
+//            return list;
+            // fastJson 解析示例:
+             return JSON.parseArray(result, (Class<?>) ParameterizedTypeUtil.getParameterizedType(resultType, List.class, 0));
+        } else {
+            // 这里只是个示例, 不做json转换.
+//            JsonDemoResponse baiduResponse = new JsonDemoResponse();
+//            baiduResponse.setTest(result);
+//            return baiduResponse;
+            // fastjson 解析示例:
+             return JSON.parseObject(result, resultType);
+        }
+    }
+}

+ 28 - 0
app/src/main/java/com/hh/arome/http/params/AmpeJsonParams.java

@@ -0,0 +1,28 @@
+package com.hh.arome.http.params;
+
+import com.hh.arome.http.JsonParamsBuilder;
+import com.hh.arome.http.JsonResponse;
+import com.hh.arome.http.response.AmpeJsonResponse;
+
+import org.xutils.common.Callback;
+import org.xutils.http.RequestParams;
+import org.xutils.http.annotation.HttpRequest;
+import org.xutils.x;
+
+@HttpRequest(
+    path = "ampe/sign",
+    builder = JsonParamsBuilder.class
+)
+public class AmpeJsonParams extends RequestParams {
+
+    private String deviceId;
+
+    public AmpeJsonParams(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public Callback.Cancelable send(Callback.CommonCallback<JsonResponse<AmpeJsonResponse>> callback) {
+        return x.http().post(this, callback);
+    }
+
+}

+ 69 - 0
app/src/main/java/com/hh/arome/http/response/AmpeJsonResponse.java

@@ -0,0 +1,69 @@
+package com.hh.arome.http.response;
+
+/**
+ * ampe平台配置参数
+ */
+public class AmpeJsonResponse {
+
+    // iot平台的产品productId
+    private String PRODUCT_ID;
+    // iot平台关联设备的设备编号
+    private String DEVICE_ID;
+    // 开放平台的移动应用AppId
+    private String HOST_APP_ID;
+    // 启动的支付宝小程序AppId, 需要在ampe平台,在移动应用管理中绑定该小程序AppId
+    private String APP_ID;
+    // ampe平台,激活设备需要的签名,由productId + "_" + deviceId 获取签名
+    private String signature;
+
+    public String getPRODUCT_ID() {
+        return PRODUCT_ID;
+    }
+
+    public void setPRODUCT_ID(String PRODUCT_ID) {
+        this.PRODUCT_ID = PRODUCT_ID;
+    }
+
+    public String getDEVICE_ID() {
+        return DEVICE_ID;
+    }
+
+    public void setDEVICE_ID(String DEVICE_ID) {
+        this.DEVICE_ID = DEVICE_ID;
+    }
+
+    public String getHOST_APP_ID() {
+        return HOST_APP_ID;
+    }
+
+    public void setHOST_APP_ID(String HOST_APP_ID) {
+        this.HOST_APP_ID = HOST_APP_ID;
+    }
+
+    public String getAPP_ID() {
+        return APP_ID;
+    }
+
+    public void setAPP_ID(String APP_ID) {
+        this.APP_ID = APP_ID;
+    }
+
+    public String getSignature() {
+        return signature;
+    }
+
+    public void setSignature(String signature) {
+        this.signature = signature;
+    }
+
+    @Override
+    public String toString() {
+        return "AmpeJsonResponse{" +
+                "PRODUCT_ID='" + PRODUCT_ID + '\'' +
+                ", DEVICE_ID='" + DEVICE_ID + '\'' +
+                ", HOST_APP_ID='" + HOST_APP_ID + '\'' +
+                ", APP_ID='" + APP_ID + '\'' +
+                ", signature='" + signature + '\'' +
+                '}';
+    }
+}

+ 135 - 0
app/src/main/java/com/hh/arome/services/IDReaderService.java

@@ -0,0 +1,135 @@
+package com.hh.arome.services;
+
+import android.app.Service;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import com.telpo.tps550.api.idcard.IdentityMsg;
+import com.telpo.tps550.api.idcard.T2OReader;
+import com.telpo.tps550.api.util.ReaderUtils;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * 身份证读卡service
+ */
+public class IDReaderService extends Service {
+
+    private final static String TAG = "IDReaderService";
+    // 读取状态
+    private boolean reading = false;
+    private T2OReader t2oReader;
+    private CountDownLatch countDownLatch = null;
+
+    private LocalBinder binder = new LocalBinder();
+
+    /**
+     * 创建Binder对象,返回给客户端即Activity使用,提供数据交换的接口
+     */
+    public class LocalBinder extends Binder {
+        // 声明一个方法,getService。(提供给客户端调用)
+        public IDReaderService getService() {
+            // 返回当前对象LocalService,这样我们就可在客户端端调用Service的公共方法了
+            return IDReaderService.this;
+        }
+    }
+
+    /**
+     * 绑定服务时才会调用
+     * 必须要实现的方法, 把Binder类返回给客户端
+     * @param intent
+     * @return
+     */
+    @Nullable
+    @Override
+    public IBinder onBind(Intent intent) {
+        return binder;
+    }
+
+    /**
+     * 解除绑定时调用
+     * @return
+     */
+    @Override
+    public boolean onUnbind(Intent intent) {
+        Log.i(TAG, "Service is invoke onUnbind");
+        return super.onUnbind(intent);
+    }
+
+    /**
+     * 首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。
+     * 如果服务已在运行,则不会调用此方法。该方法只被调用一次
+     */
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.i(TAG, "Service is invoke Created");
+        t2oReader = new T2OReader();
+        countDownLatch = new CountDownLatch(1);
+        read();
+    }
+
+    private void read() {
+        if(t2oReader.isUSBReader(this)){
+            t2oReader.openReader(this);
+        }
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                reading = true;
+                while(reading) {
+                    try {
+                        Thread.sleep(500);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                    IdentityMsg msg = t2oReader.checkIDCard();
+                    if(msg != null){
+                        Bitmap bitmap = t2oReader.decodeIDImage(msg.getHead_photo());
+                        String name = msg.getName();
+                        String sex = msg.getSex();
+                        String nation = msg.getNation();
+                        String born = msg.getBorn();
+                        String address = msg.getAddress();
+                        String apartment = msg.getApartment();
+                        String period = msg.getPeriod();
+                        String no = msg.getNo();
+                        String finger = ReaderUtils.get_finger_info(IDReaderService.this, t2oReader.getIDFinger(msg));
+
+                    }
+                }
+                countDownLatch.countDown();
+            }
+        }).start();
+    }
+
+    /**
+     * 每次通过startService()方法启动Service时都会被回调。
+     * @param intent
+     * @param flags
+     * @param startId
+     * @return
+     */
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.i(TAG, "onStartCommand invoke");
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    /**
+     * 服务销毁时的回调
+     */
+    @Override
+    public void onDestroy() {
+        Log.i(TAG, "Service is invoke Destroyed");
+        reading = false;
+        t2oReader.closeReader();
+        super.onDestroy();
+    }
+
+}

+ 90 - 0
app/src/main/java/com/hh/arome/services/QrcodeScannerService.java

@@ -0,0 +1,90 @@
+package com.hh.arome.services;
+
+import android.accessibilityservice.AccessibilityService;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.view.KeyEvent;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.Toast;
+
+import com.hh.arome.MainActivity;
+import com.hh.arome.util.BarcodeScannerHelper;
+
+/**
+ * 扫码枪的 AccessibilityService
+ */
+public class QrcodeScannerService extends AccessibilityService {
+
+    @Override
+    protected void onServiceConnected() {
+        super.onServiceConnected();
+        initBarcodeScanner();
+    }
+
+    @Override
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+
+    }
+
+    @Override
+    protected boolean onKeyEvent(KeyEvent event) {
+        if(BarcodeScannerHelper.getInstance().dispatchKeyEvent(event)) {
+            return true;
+        }
+        return super.onKeyEvent(event);
+    }
+
+    @Override
+    public void onInterrupt() {
+
+    }
+
+    /**
+     * 初始化扫码
+     */
+    private void initBarcodeScanner() {
+        BarcodeScannerHelper.getInstance().setScanSuccessListener(new BarcodeScannerHelper.OnScanSuccessListener() {
+            @Override
+            public void onScanSuccess(String barcode) {
+                Toast.makeText(QrcodeScannerService.this.getApplicationContext(), "--->扫码内容:" + barcode, Toast.LENGTH_LONG).show();
+                System.out.println("--->扫码内容:" + barcode);
+            }
+        });
+    }
+
+    /**
+     * 判断当前应用的辅助功能在设置中是否打开
+     * @param context
+     * @return true辅助功能开 false辅助功能关
+     */
+    public static boolean isAccessibilitySettingsOn(Context context) {
+        int accessibilityEnabled = 0;
+        final String service = context.getPackageName() + "/" + QrcodeScannerService.class.getCanonicalName();
+        System.out.println("--->isAccessibilitySettingsOn:" + service);
+        try {
+            // 获取setting里辅助功能的开启状态
+            accessibilityEnabled = Settings.Secure.getInt(context.getApplicationContext().getContentResolver(), android.provider.Settings.Secure.ACCESSIBILITY_ENABLED);
+        } catch (Settings.SettingNotFoundException e) {
+        }
+        TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');
+        if (accessibilityEnabled == 1) {
+            // 获取辅助功能里所有开启的服务 包名列表
+            String settingValue = Settings.Secure.getString(context.getApplicationContext().getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+            if (settingValue != null) {
+                // 转换程集合
+                mStringColonSplitter.setString(settingValue);
+                while (mStringColonSplitter.hasNext()) {
+                    String accessibilityService = mStringColonSplitter.next();
+                    //判断当前包名是否在服务集合里
+                    if (accessibilityService.equalsIgnoreCase(service)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+}

+ 210 - 0
app/src/main/java/com/hh/arome/util/BarcodeScannerHelper.java

@@ -0,0 +1,210 @@
+package com.hh.arome.util;
+
+import android.view.KeyEvent;
+
+import java.util.ArrayList;
+
+/**
+ * 扫码枪帮助类
+ */
+public class BarcodeScannerHelper {
+
+    private final static String TAG = BarcodeScannerHelper.class.getSimpleName();
+    private static volatile BarcodeScannerHelper mInstance = null;
+
+    private ArrayList<Integer> scannedCodes = new ArrayList<>();
+    private OnScanSuccessListener mOnScanSuccessListener;
+
+    private BarcodeScannerHelper() {}
+
+    public static BarcodeScannerHelper getInstance() {
+        if (mInstance == null) {
+            synchronized(BarcodeScannerHelper.class) {
+                if (mInstance == null) {
+                    mInstance = new BarcodeScannerHelper();
+                }
+            }
+        }
+        return mInstance;
+    }
+
+    // 获取扫描内容
+    private String keyCodeToChar(int code, boolean isShift) {
+        switch (code) {
+            case KeyEvent.KEYCODE_SHIFT_LEFT:
+            case KeyEvent.KEYCODE_SHIFT_RIGHT:
+            case KeyEvent.KEYCODE_SPACE:
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+            case KeyEvent.KEYCODE_DPAD_UP:
+                return "";
+
+            case KeyEvent.KEYCODE_0:
+                return isShift ? ")" : "0";
+            case KeyEvent.KEYCODE_1:
+                return isShift ? "!" : "1";
+            case KeyEvent.KEYCODE_2:
+                return isShift ? "@" : "2";
+            case KeyEvent.KEYCODE_3:
+                return isShift ? "#" : "3";
+            case KeyEvent.KEYCODE_4:
+                return isShift ? "$" : "4";
+            case KeyEvent.KEYCODE_5:
+                return isShift ? "%" : "5";
+            case KeyEvent.KEYCODE_6:
+                return isShift ? "^" : "6";
+            case KeyEvent.KEYCODE_7:
+                return isShift ? "&" : "7";
+            case KeyEvent.KEYCODE_8:
+                return isShift ? "*" : "8";
+            case KeyEvent.KEYCODE_9:
+                return isShift ? "(" : "9";
+
+            case KeyEvent.KEYCODE_A:
+                return isShift ? "A" : "a";
+            case KeyEvent.KEYCODE_B:
+                return isShift ? "B" : "b";
+            case KeyEvent.KEYCODE_C:
+                return isShift ? "C" : "c";
+            case KeyEvent.KEYCODE_D:
+                return isShift ? "D" : "d";
+            case KeyEvent.KEYCODE_E:
+                return isShift ? "E" : "e";
+            case KeyEvent.KEYCODE_F:
+                return isShift ? "F" : "f";
+            case KeyEvent.KEYCODE_G:
+                return isShift ? "G" : "g";
+            case KeyEvent.KEYCODE_H:
+                return isShift ? "H" : "h";
+            case KeyEvent.KEYCODE_I:
+                return isShift ? "I" : "i";
+            case KeyEvent.KEYCODE_J:
+                return isShift ? "J" : "j";
+            case KeyEvent.KEYCODE_K:
+                return isShift ? "K" : "k";
+            case KeyEvent.KEYCODE_L:
+                return isShift ? "L" : "l";
+            case KeyEvent.KEYCODE_M:
+                return isShift ? "M" : "m";
+            case KeyEvent.KEYCODE_N:
+                return isShift ? "N" : "n";
+            case KeyEvent.KEYCODE_O:
+                return isShift ? "O" : "o";
+            case KeyEvent.KEYCODE_P:
+                return isShift ? "P" : "p";
+            case KeyEvent.KEYCODE_Q:
+                return isShift ? "Q" : "q";
+            case KeyEvent.KEYCODE_R:
+                return isShift ? "R" : "r";
+            case KeyEvent.KEYCODE_S:
+                return isShift ? "S" : "s";
+            case KeyEvent.KEYCODE_T:
+                return isShift ? "T" : "t";
+            case KeyEvent.KEYCODE_U:
+                return isShift ? "U" : "u";
+            case KeyEvent.KEYCODE_V:
+                return isShift ? "V" : "v";
+            case KeyEvent.KEYCODE_W:
+                return isShift ? "W" : "w";
+            case KeyEvent.KEYCODE_X:
+                return isShift ? "X" : "x";
+            case KeyEvent.KEYCODE_Y:
+                return isShift ? "Y" : "y";
+            case KeyEvent.KEYCODE_Z:
+                return isShift ? "Z" : "z";
+
+            case KeyEvent.KEYCODE_COMMA:
+                return isShift ? "<" : ",";
+            case KeyEvent.KEYCODE_PERIOD:
+                return isShift ? ">" : ".";
+            case KeyEvent.KEYCODE_SLASH:
+                return isShift ? "?" : "/";
+            case KeyEvent.KEYCODE_BACKSLASH:
+                return isShift ? "|" : "\\";
+            case KeyEvent.KEYCODE_APOSTROPHE:
+                return isShift ? "\"" : "'";
+            case KeyEvent.KEYCODE_SEMICOLON:
+                return isShift ? ":" : ";";
+            case KeyEvent.KEYCODE_LEFT_BRACKET:
+                return isShift ? "{" : "[";
+            case KeyEvent.KEYCODE_RIGHT_BRACKET:
+                return isShift ? "}" : "]";
+            case KeyEvent.KEYCODE_GRAVE:
+                return isShift ? "~" : "`";
+            case KeyEvent.KEYCODE_EQUALS:
+                return isShift ? "+" : "=";
+            case KeyEvent.KEYCODE_MINUS:
+                return isShift ? "_" : "-";
+            case KeyEvent.KEYCODE_NUMPAD_SUBTRACT:
+                return "-";
+            case KeyEvent.KEYCODE_NUMPAD_DIVIDE:
+                return "/";
+            case KeyEvent.KEYCODE_NUMPAD_MULTIPLY:
+                return "*";
+            case KeyEvent.KEYCODE_NUMPAD_DOT:
+                return ".";
+            case KeyEvent.KEYCODE_NUMPAD_ADD:
+                return "+";
+            case KeyEvent.KEYCODE_NUMPAD_COMMA:
+                return ",";
+            case KeyEvent.KEYCODE_NUMPAD_EQUALS:
+                return "=";
+            case KeyEvent.KEYCODE_NUMPAD_LEFT_PAREN:
+                return "(";
+            case KeyEvent.KEYCODE_NUMPAD_RIGHT_PAREN:
+                return ")";
+            default:
+                return "";
+        }
+    }
+
+    /**
+     * 处理输入事件
+     * @param event
+     * @return  true 表示消费掉,拦截不在传递, false 不管
+     */
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        // 系统的软键盘  按下去是 -1, 不管,不拦截
+        if (event.getDeviceId() == -1) {
+            return false;
+        }
+        if(event.getAction() == KeyEvent.ACTION_DOWN) {
+            if (event.getKeyCode() != KeyEvent.KEYCODE_ENTER) {
+                scannedCodes.add(event.getKeyCode());
+            } else {
+                handleKeyCodes();
+            }
+        }
+        return true;
+    }
+
+    private void handleKeyCodes() {
+        int count = scannedCodes.size();
+        if (count <= 0) {
+            return;
+        }
+        StringBuilder result = new StringBuilder();
+        boolean hasShift = false;
+        for (int i = 0; i < scannedCodes.size(); i++) {
+            int keyCode = scannedCodes.get(i);
+            result.append(keyCodeToChar(keyCode, hasShift));
+            hasShift = (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT || keyCode == KeyEvent.KEYCODE_SHIFT_LEFT);
+        }
+        if (result.length() > 0 && mOnScanSuccessListener != null) {
+            mOnScanSuccessListener.onScanSuccess(result.toString());
+        }
+        scannedCodes.clear();
+    }
+
+    public void setScanSuccessListener(OnScanSuccessListener onScanSuccessListener) {
+        mOnScanSuccessListener = onScanSuccessListener;
+    }
+
+    public void removeScanSuccessListener() {
+        mOnScanSuccessListener = null;
+    }
+
+    public interface OnScanSuccessListener {
+        void onScanSuccess(String barcode);
+    }
+
+}

+ 47 - 0
app/src/main/java/com/hh/arome/util/Utils.java

@@ -0,0 +1,47 @@
+package com.hh.arome.util;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import java.lang.reflect.Method;
+
+public class Utils {
+
+    private static Handler sMainHandler = new Handler(Looper.getMainLooper());
+
+    public static void runOnMain(Runnable runnable) {
+        if (Looper.myLooper() == Looper.getMainLooper()) {
+            runnable.run();
+        } else {
+            sMainHandler.post(runnable);
+        }
+    }
+
+    public static void runOnMain(Runnable runnable, long delay) {
+        if (Looper.myLooper() == Looper.getMainLooper() && delay == 0) {
+            runnable.run();
+        } else {
+            sMainHandler.postDelayed(runnable, delay);
+        }
+    }
+
+    public static int parseInt(String value, int defaultValue) {
+        try {
+            return Integer.parseInt(value);
+        } catch (Throwable t) {
+            return defaultValue;
+        }
+    }
+
+    public static String getIotVersion() {
+        String serial = null;
+        try {
+            Class<?> c = Class.forName("android.os.SystemProperties");
+            Method get = c.getMethod("get", String.class);
+            serial = (String) get.invoke(c, "ro.serialno");
+        } catch (Exception ignored) {
+
+        }
+        return serial;
+    }
+}

BIN
app/src/main/jniLibs/armeabi-v7a/libfingerprint.so


BIN
app/src/main/jniLibs/armeabi-v7a/libidcard.so


BIN
app/src/main/jniLibs/armeabi-v7a/libsystem_util.so


BIN
app/src/main/jniLibs/armeabi-v7a/libtelpo_serial.so


BIN
app/src/main/jniLibs/armeabi-v7a/libwlt2bmp.so


BIN
app/src/main/jniLibs/armeabi/libfingerprint.so


BIN
app/src/main/jniLibs/armeabi/libidcard.so


BIN
app/src/main/jniLibs/armeabi/libsystem_util.so


BIN
app/src/main/jniLibs/armeabi/libtelpo_serial.so


BIN
app/src/main/jniLibs/armeabi/libwlt2bmp.so


+ 30 - 0
app/src/main/res/drawable-v24/ic_launcher_foreground.xml

@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="85.84757"
+                android:endY="92.4963"
+                android:startX="42.9492"
+                android:startY="49.59793"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0" />
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0" />
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000" />
+</vector>

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

@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillColor="#3DDC84"
+        android:pathData="M0,0h108v108h-108z" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M9,0L9,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,0L19,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,0L29,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,0L39,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,0L49,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,0L59,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,0L69,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,0L79,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M89,0L89,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M99,0L99,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,9L108,9"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,19L108,19"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,29L108,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,39L108,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,49L108,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,59L108,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,69L108,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,79L108,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,89L108,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,99L108,99"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,29L89,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,39L89,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,49L89,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,59L89,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,69L89,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,79L89,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,19L29,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,19L39,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,19L49,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,19L59,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,19L69,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,19L79,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+</vector>

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

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".MainActivity">
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:visibility="gone"
+        android:text="启动小程序"
+        android:layout_marginTop="150dp"
+        android:onClick="activateDevice"/>
+
+</LinearLayout>

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


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


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


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


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


+ 16 - 0
app/src/main/res/values-night/themes.xml

@@ -0,0 +1,16 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Base application theme. -->
+    <style name="Theme.HHK8AMPE" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+        <!-- Primary brand color. -->
+        <item name="colorPrimary">@color/purple_200</item>
+        <item name="colorPrimaryVariant">@color/purple_700</item>
+        <item name="colorOnPrimary">@color/black</item>
+        <!-- Secondary brand color. -->
+        <item name="colorSecondary">@color/teal_200</item>
+        <item name="colorSecondaryVariant">@color/teal_200</item>
+        <item name="colorOnSecondary">@color/black</item>
+        <!-- Status bar color. -->
+        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
+        <!-- Customize your theme here. -->
+    </style>
+</resources>

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

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="purple_200">#FFBB86FC</color>
+    <color name="purple_500">#FF6200EE</color>
+    <color name="purple_700">#FF3700B3</color>
+    <color name="teal_200">#FF03DAC5</color>
+    <color name="teal_700">#FF018786</color>
+    <color name="black">#FF000000</color>
+    <color name="white">#FFFFFFFF</color>
+</resources>

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

@@ -0,0 +1,4 @@
+<resources>
+    <string name="app_name">航汇就业</string>
+    <string name="accessibility_description">获取设备扫码枪的内容</string>
+</resources>

+ 16 - 0
app/src/main/res/values/themes.xml

@@ -0,0 +1,16 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Base application theme. -->
+    <style name="Theme.HHK8AMPE" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+        <!-- Primary brand color. -->
+        <item name="colorPrimary">@color/purple_500</item>
+        <item name="colorPrimaryVariant">@color/purple_700</item>
+        <item name="colorOnPrimary">@color/white</item>
+        <!-- Secondary brand color. -->
+        <item name="colorSecondary">@color/teal_200</item>
+        <item name="colorSecondaryVariant">@color/teal_700</item>
+        <item name="colorOnSecondary">@color/black</item>
+        <!-- Status bar color. -->
+        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
+        <!-- Customize your theme here. -->
+    </style>
+</resources>

+ 10 - 0
app/src/main/res/xml/accessibility.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accessibilityEventTypes="typeAllMask"
+    android:accessibilityFeedbackType="feedbackGeneric"
+    android:accessibilityFlags="flagRequestFilterKeyEvents"
+    android:canRetrieveWindowContent="true"
+    android:notificationTimeout="100"
+    android:canRequestFilterKeyEvents="true"
+    android:description="@string/accessibility_description"
+    android:packageNames="com.hh.arome" />

+ 9 - 0
build.gradle

@@ -0,0 +1,9 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+    id 'com.android.application' version '7.1.1' apply false
+    id 'com.android.library' version '7.1.1' apply false
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}

+ 21 - 0
gradle.properties

@@ -0,0 +1,21 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app"s APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true

BIN
gradle/wrapper/gradle-wrapper.jar


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

@@ -0,0 +1,6 @@
+#Tue Aug 29 16:54:18 CST 2023
+distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME

+ 185 - 0
gradlew

@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=`expr $i + 1`
+    done
+    case $i in
+        0) set -- ;;
+        1) set -- "$args0" ;;
+        2) set -- "$args0" "$args1" ;;
+        3) set -- "$args0" "$args1" "$args2" ;;
+        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"

+ 89 - 0
gradlew.bat

@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega

BIN
hh-face.jks


+ 18 - 0
settings.gradle

@@ -0,0 +1,18 @@
+pluginManagement {
+    repositories {
+        gradlePluginPortal()
+        google()
+        jcenter()
+        mavenCentral()
+    }
+}
+dependencyResolutionManagement {
+    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+    repositories {
+        google()
+        jcenter()
+        mavenCentral()
+    }
+}
+rootProject.name = "HH-K8-AMPE"
+include ':app'