Repository: lunan0320/Pioneer Branch: main Commit: 107369941b2e Files: 258 Total size: 672.7 KB Directory structure: gitextract_i2vhfrty/ ├── Android_apk/ │ └── appAndroid.apk ├── Android_app/ │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── ABC/ │ │ │ └── pioneer/ │ │ │ └── app/ │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets/ │ │ │ │ ├── Pioneer.keystore │ │ │ │ └── server.p12 │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── ABC/ │ │ │ │ └── pioneer/ │ │ │ │ └── app/ │ │ │ │ ├── AppDelegate.java │ │ │ │ ├── LoginActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── RegisterActivity.java │ │ │ │ ├── SplashActivity.java │ │ │ │ ├── Target.java │ │ │ │ ├── TargetListAdapter.java │ │ │ │ ├── TokenActivity.java │ │ │ │ ├── fragment/ │ │ │ │ │ ├── FragmentActivity1.java │ │ │ │ │ ├── FragmentActivity2.java │ │ │ │ │ └── FragmentActivity3.java │ │ │ │ └── ignoreBatteryOpt.java │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── border_input_box.xml │ │ │ │ ├── button_background.xml │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ └── token_background.xml │ │ │ ├── drawable-v24/ │ │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── layout/ │ │ │ │ ├── activity_bluetooth.xml │ │ │ │ ├── activity_bottom_bar.xml │ │ │ │ ├── activity_login.xml │ │ │ │ ├── activity_payload.xml │ │ │ │ ├── activity_register.xml │ │ │ │ ├── activity_splash.xml │ │ │ │ ├── activity_token.xml │ │ │ │ ├── activity_token_pre.xml │ │ │ │ ├── activity_user.xml │ │ │ │ ├── custom_notification.xml │ │ │ │ └── listview_targets_row.xml │ │ │ ├── mipmap-anydpi-v26/ │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ └── values/ │ │ │ ├── colors.xml │ │ │ ├── ic_launcher_background.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── ABC/ │ │ └── pioneer/ │ │ └── app/ │ │ └── ExampleUnitTest.java │ ├── build.gradle │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ ├── local.properties │ ├── pioneer/ │ │ ├── .gitignore │ │ ├── BuildConfig.java │ │ ├── app/ │ │ │ └── BuildConfig.java │ │ ├── build.gradle │ │ ├── consumer-rules.pro │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── ABC/ │ │ │ └── pioneer/ │ │ │ └── sensor/ │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── ABC/ │ │ │ └── pioneer/ │ │ │ └── sensor/ │ │ │ ├── DefaultSensorDelegate.java │ │ │ ├── Device.java │ │ │ ├── PayloadSupplier.java │ │ │ ├── Sensor.java │ │ │ ├── SensorArray.java │ │ │ ├── SensorDelegate.java │ │ │ ├── analysis/ │ │ │ │ └── Sample.java │ │ │ ├── ble/ │ │ │ │ ├── BLEDatabaseDelegate.java │ │ │ │ ├── BLEDevice.java │ │ │ │ ├── BLESensor.java │ │ │ │ ├── BluetoothStateManager.java │ │ │ │ ├── BluetoothStateManagerDelegate.java │ │ │ │ ├── Configurations.java │ │ │ │ ├── Database.java │ │ │ │ ├── DeviceAttribute.java │ │ │ │ ├── DeviceDelegate.java │ │ │ │ ├── DeviceOperatingSystem.java │ │ │ │ ├── DeviceState.java │ │ │ │ ├── DeviceUpdatedComparator.java │ │ │ │ ├── Receiver.java │ │ │ │ ├── SpecificBLESensor.java │ │ │ │ ├── SpecificBluetoothStateManager.java │ │ │ │ ├── SpecificDatabase.java │ │ │ │ ├── SpecificReceiver.java │ │ │ │ ├── SpecificTransmitter.java │ │ │ │ ├── Timer.java │ │ │ │ ├── TimerDelegate.java │ │ │ │ ├── Transmitter.java │ │ │ │ ├── TxPower.java │ │ │ │ └── filter/ │ │ │ │ ├── BLEAppleManuSeg.java │ │ │ │ ├── BLEDeviceFilter.java │ │ │ │ ├── BLEManuData.java │ │ │ │ ├── BLEParser.java │ │ │ │ ├── BLEScanResponseData.java │ │ │ │ ├── BLESeg.java │ │ │ │ ├── BLESegType.java │ │ │ │ └── BLEServiceData.java │ │ │ ├── client/ │ │ │ │ └── controller/ │ │ │ │ └── PioneerClient.java │ │ │ ├── data/ │ │ │ │ ├── BatteryLog.java │ │ │ │ ├── CalibrationLog.java │ │ │ │ ├── ConcretePayloadDataFormatter.java │ │ │ │ ├── ContactLog.java │ │ │ │ ├── DetectionLog.java │ │ │ │ ├── EventTimeIntervalLog.java │ │ │ │ ├── PayloadDataFormatter.java │ │ │ │ ├── StatisticsLog.java │ │ │ │ └── TextFile.java │ │ │ ├── datatype/ │ │ │ │ ├── Base64.java │ │ │ │ ├── BluetoothState.java │ │ │ │ ├── Calibration.java │ │ │ │ ├── CalibrationMeasurementUnit.java │ │ │ │ ├── Callback.java │ │ │ │ ├── Data.java │ │ │ │ ├── Encounter.java │ │ │ │ ├── Float16.java │ │ │ │ ├── ImmediateSendData.java │ │ │ │ ├── InertiaLocationReference.java │ │ │ │ ├── Int16.java │ │ │ │ ├── Int32.java │ │ │ │ ├── Int64.java │ │ │ │ ├── Int8.java │ │ │ │ ├── LegacyPayload.java │ │ │ │ ├── Location.java │ │ │ │ ├── LocationReference.java │ │ │ │ ├── PayloadData.java │ │ │ │ ├── PayloadSharingData.java │ │ │ │ ├── PayloadTimestamp.java │ │ │ │ ├── PlacenameLocationReference.java │ │ │ │ ├── Proximity.java │ │ │ │ ├── ProximityMeasurementUnit.java │ │ │ │ ├── PseudoDeviceAddress.java │ │ │ │ ├── RSSI.java │ │ │ │ ├── RandomSource.java │ │ │ │ ├── SensorState.java │ │ │ │ ├── SensorType.java │ │ │ │ ├── SignalCharacteristicData.java │ │ │ │ ├── SignalCharacteristicDataType.java │ │ │ │ ├── TargetIdentifier.java │ │ │ │ ├── TimeInterval.java │ │ │ │ ├── Triple.java │ │ │ │ ├── Tuple.java │ │ │ │ ├── UInt16.java │ │ │ │ ├── UInt32.java │ │ │ │ ├── UInt64.java │ │ │ │ └── UInt8.java │ │ │ ├── motion/ │ │ │ │ ├── ConcreteInertiaSensor.java │ │ │ │ └── InertiaSensor.java │ │ │ ├── payload/ │ │ │ │ ├── Crypto/ │ │ │ │ │ ├── BasicFunc.java │ │ │ │ │ ├── CipherParameters.java │ │ │ │ │ ├── ContactIdentifier.java │ │ │ │ │ ├── ContactKey.java │ │ │ │ │ ├── ContactKeySeed.java │ │ │ │ │ ├── Digest.java │ │ │ │ │ ├── DigestRandomGenerator.java │ │ │ │ │ ├── ExtendedDigest.java │ │ │ │ │ ├── GeneralDigest.java │ │ │ │ │ ├── GenerateKey.java │ │ │ │ │ ├── HMACSHA256.java │ │ │ │ │ ├── HMac.java │ │ │ │ │ ├── KeyParameter.java │ │ │ │ │ ├── Mac.java │ │ │ │ │ ├── MatchingKey.java │ │ │ │ │ ├── MatchingKeySeed.java │ │ │ │ │ ├── Memoable.java │ │ │ │ │ ├── PioneerHMac.java │ │ │ │ │ ├── PioneerHash.java │ │ │ │ │ ├── PioneerPRG.java │ │ │ │ │ ├── RandomGenerator.java │ │ │ │ │ ├── SM3Digest.java │ │ │ │ │ ├── SecretKey.java │ │ │ │ │ ├── SpecificUsePayloadSupplier.java │ │ │ │ │ ├── UsePayloadSupplier.java │ │ │ │ │ └── Util.java │ │ │ │ ├── DefaultPayloadSupplier.java │ │ │ │ ├── DigitalSignature.java │ │ │ │ └── extended/ │ │ │ │ ├── ConcreteExtendedDataSectionV1.java │ │ │ │ ├── ConcreteExtendedDataV1.java │ │ │ │ └── ExtendedData.java │ │ │ └── service/ │ │ │ ├── AlarmReceiver.java │ │ │ ├── Connection.java │ │ │ ├── CustomTimer.java │ │ │ ├── ForegroundService.java │ │ │ ├── MatchDelegate.java │ │ │ ├── NotificationService.java │ │ │ └── PioneerDb.java │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── ABC/ │ │ └── pioneer/ │ │ └── sensor/ │ │ └── ExampleUnitTest.java │ └── settings.gradle ├── IOS_app/ │ └── Pioneer_ios/ │ └── Pioneer Framework/ │ ├── Certificate/ │ │ ├── client.p12 │ │ └── server.cer │ ├── Pioneer/ │ │ ├── ContactLogData/ │ │ │ └── ContactLog.xcdatamodeld/ │ │ │ ├── .xccurrentversion │ │ │ └── ContactLog.xcdatamodel/ │ │ │ └── contents │ │ ├── Crypto/ │ │ │ ├── CipherParameters.swift │ │ │ ├── Crypto.swift │ │ │ ├── Digest.swift │ │ │ ├── DigestRandomNumber.swift │ │ │ ├── ExtendedDigest.swift │ │ │ ├── GeneralDigest.swift │ │ │ ├── HMAC.swift │ │ │ ├── KeyParameter.swift │ │ │ ├── MAC.swift │ │ │ ├── Memoable.swift │ │ │ ├── PioneerHMac.swift │ │ │ ├── PioneerHash.swift │ │ │ ├── RandomGenerator.swift │ │ │ ├── SM3Digest.swift │ │ │ └── Util.swift │ │ ├── Info.plist │ │ ├── Manager/ │ │ │ ├── Connection.swift │ │ │ ├── GlobalConfiguration.swift │ │ │ ├── KeyManager.swift │ │ │ ├── ManagerDelegate.swift │ │ │ ├── Register.swift │ │ │ └── UploadManager.swift │ │ ├── Pioneer.h │ │ └── Sensor/ │ │ ├── BLE/ │ │ │ ├── BLEDatabase.swift │ │ │ ├── BLEReceiver.swift │ │ │ ├── BLESensor.swift │ │ │ ├── BLETransmitter.swift │ │ │ └── BLEUtilities.swift │ │ ├── Data/ │ │ │ ├── BatteryLog.swift │ │ │ └── SensorLogger.swift │ │ ├── Device.swift │ │ ├── Extensions/ │ │ │ ├── DataExtensions.swift │ │ │ └── DateExtensions.swift │ │ ├── Location/ │ │ │ └── LocationSensor.swift │ │ ├── Payload/ │ │ │ ├── PayloadDataMatcher.swift │ │ │ ├── PayloadDataSupplier.swift │ │ │ └── SpecificImplement/ │ │ │ ├── SpecificPayloadDataMatcher.swift │ │ │ └── SpecificPayloadDataSupplier.swift │ │ ├── Sensor.swift │ │ ├── SensorArray.swift │ │ └── SensorDelegate.swift │ ├── Pioneer.xcodeproj/ │ │ ├── project.pbxproj │ │ ├── project.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ ├── xcshareddata/ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ └── xcuserdata/ │ │ │ └── Beh.xcuserdatad/ │ │ │ └── UserInterfaceState.xcuserstate │ │ └── xcuserdata/ │ │ └── Beh.xcuserdatad/ │ │ └── xcschemes/ │ │ └── xcschememanagement.plist │ └── PioneerTests/ │ ├── Info.plist │ └── PioneerTests.swift ├── README.md ├── Server/ │ ├── bin/ │ │ ├── db.properties │ │ └── lib/ │ │ └── mysql-connector-java-5.1.49-bin.jar │ └── src/ │ ├── com/ │ │ ├── bean/ │ │ │ ├── User.java │ │ │ └── UserMessage.java │ │ ├── controller/ │ │ │ ├── PioneerClient.java │ │ │ └── PioneerServer.java │ │ ├── dao/ │ │ │ ├── RandomGenerator.java │ │ │ ├── TaskThread.java │ │ │ ├── UserDao.java │ │ │ └── UserDao_Imp.java │ │ └── jdbc/ │ │ └── JDBCUtils.java │ ├── db.properties │ └── lib/ │ └── mysql-connector-java-5.1.49-bin.jar ├── Server_jar/ │ ├── META-INF/ │ │ └── MANIFEST.MF │ ├── db.properties │ ├── mysql-connector-java-5.1.49-bin.jar │ ├── org.hamcrest.core_1.3.0.v20180420-1519.jar │ └── org.junit_4.13.0.v20200204-1500.jar └── Test/ ├── Contribution.md └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: Android_app/app/.gitignore ================================================ /build ================================================ FILE: Android_app/app/build.gradle ================================================ plugins { id 'com.android.application' } android { compileSdkVersion 30 buildToolsVersion "30.0.3" defaultConfig { applicationId "com.sdu.pioneer.app" minSdkVersion 26 targetSdkVersion 30 versionCode 1 versionName "1.2.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } lintOptions { checkReleaseBuilds false abortOnError false } packagingOptions { exclude 'classes.dex' exclude '**.**' } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation project(path: ':pioneer') testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' } ================================================ FILE: Android_app/app/proguard-rules.pro ================================================ # 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 ================================================ FILE: Android_app/app/src/androidTest/java/com/ABC/pioneer/app/ExampleInstrumentedTest.java ================================================ package com.ABC.pioneer.app; import android.content.Context; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumented test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() { // Context of the app under test. Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); assertEquals("com.sdu.pioneer.app", appContext.getPackageName()); } } ================================================ FILE: Android_app/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: Android_app/app/src/main/java/com/ABC/pioneer/app/AppDelegate.java ================================================ package com.ABC.pioneer.app; import android.app.Application; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Build; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; import com.ABC.pioneer.sensor.Sensor; import com.ABC.pioneer.sensor.SensorArray; import com.ABC.pioneer.sensor.SensorDelegate; import com.ABC.pioneer.sensor.datatype.Data; import com.ABC.pioneer.sensor.datatype.ImmediateSendData; import com.ABC.pioneer.sensor.datatype.PayloadData; import com.ABC.pioneer.sensor.datatype.Proximity; import com.ABC.pioneer.sensor.datatype.SensorType; import com.ABC.pioneer.sensor.datatype.TargetIdentifier; import com.ABC.pioneer.sensor.payload.Crypto.SpecificUsePayloadSupplier; import com.ABC.pioneer.sensor.payload.Crypto.GenerateKey; import com.ABC.pioneer.sensor.payload.Crypto.SecretKey; import com.ABC.pioneer.sensor.service.NotificationService; import java.util.List; public class AppDelegate extends Application implements SensorDelegate { private final static String tag =AppDelegate.class.getName(); private final static String NOTIFICATION_CHANNEL_ID = "PIONEER_NOTIFICATION_CHANNEL_ID"; private final static int NOTIFICATION_ID = NOTIFICATION_CHANNEL_ID.hashCode(); private static AppDelegate appDelegate = null; public static SecretKey secretKey; private static AppDelegate instance; /// 生成唯一一致的设备标识符以测试检测和跟踪 private int identifier() { final String text = Build.MODEL + ":" + Build.BRAND; return text.hashCode(); } // 接近检测传感器 static SensorArray sensor = null; public static int getNotificationId() { return NOTIFICATION_ID; } public static String getNotificationChannelId(){ return NOTIFICATION_CHANNEL_ID; } @Override public PackageManager getPackageManager() { return super.getPackageManager(); } @Override public void onCreate() { super.onCreate(); final SharedPreferences sp_SecretKey = getSharedPreferences("SecretKey",MODE_PRIVATE); appDelegate = this; // 初始化前台服务以使应用程序在后台运行 this.createNotificationChannel(); NotificationService.shared(this).startForegroundService(this.getForegroundNotification(), NOTIFICATION_ID); // 初始化传感器序列,用于给定的有效负载数据 if(sp_SecretKey.getString("SecretKey","").equals("")){ SharedPreferences.Editor edit_key = sp_SecretKey.edit(); secretKey = GenerateKey.secretKey(); edit_key.putString("SecretKey",secretKey.base64EncodedString()); edit_key.apply(); } else { final Data secretkeyData = new Data(sp_SecretKey.getString("SecretKey","")); secretKey = new SecretKey(secretkeyData.value); System.out.println(secretKey); } final SpecificUsePayloadSupplier payloadDataSupplier = new SpecificUsePayloadSupplier(secretKey); sensor = new SensorArray(getApplicationContext(), payloadDataSupplier); // 将appDelegate添加为侦听器,以记录和启动传感器的检测事件 sensor.add(this); // 效率功能记录 // 测试 //PayloadData payloadData = sensor.payloadData(); // if (BuildConfig.DEBUG) { // sensor.add(new ContactLog(this, "contacts.csv")); // sensor.add(new StatisticsLog(this, "statistics.csv",payloadData)); // sensor.add(new DetectionLog(this,"detection.csv", payloadData)); // new BatteryLog(this, "battery.csv"); // if (Configurations.payloadDataUpdateTimeInterval != TimeInterval.never) { // sensor.add(new EventTimeIntervalLog(this, "statistics_didRead.csv", payloadData, EventTimeIntervalLog.EventType.read)); // } // } // 传感器将通过UI开关(默认为ON)和蓝牙状态启动和停止 } public static AppDelegate getInstance(){ return instance; } @Override public void onTerminate() { sensor.stop(); super.onTerminate(); } // 获取应用程序委托 public static AppDelegate getAppDelegate() { return appDelegate; } // 获取传感器 public Sensor sensor() { return sensor; } private Notification getForegroundNotification() { Intent intent = new Intent(this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); final PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0); final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) .setContentTitle(this.getString(R.string.notification_content_title)) .setContentText(this.getString(R.string.notification_content_text)) .setContentIntent(pendingIntent) .setAutoCancel(true) .setPriority(NotificationCompat.PRIORITY_DEFAULT); final Notification notification = builder.build(); return notification; } // SensorDelegate用于记录接近检测到的事件 private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { final int importance = NotificationManager.IMPORTANCE_DEFAULT; final NotificationChannel channel = new NotificationChannel( NOTIFICATION_CHANNEL_ID, this.getString(R.string.notification_channel_name), importance); channel.setDescription(this.getString(R.string.notification_channel_description)); final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.createNotificationChannel(channel); } } @Override public void sensor(SensorType sensor, TargetIdentifier didDetect) { } @Override public void sensor(SensorType sensor, PayloadData didRead, TargetIdentifier fromTarget) { } @Override public void sensor(SensorType sensor, ImmediateSendData didReceive, TargetIdentifier fromTarget) { } @Override public void sensor(SensorType sensor, List didShare, TargetIdentifier fromTarget) { } @Override public void sensor(SensorType sensor, Proximity didMeasure, TargetIdentifier fromTarget) { } } ================================================ FILE: Android_app/app/src/main/java/com/ABC/pioneer/app/LoginActivity.java ================================================ package com.ABC.pioneer.app; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; //登陆界面 public class LoginActivity extends AppCompatActivity { // 本地变量 private SharedPreferences sp; private SharedPreferences.Editor edit; private Button loginbtn; private Button regisbtn_jump; private EditText et_phone; @Override protected void onCreate(Bundle savedInstanceState) { // 检查已有登录状态 checkAutoLogin(); super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); // 初始化视图 initViews(); // 设置登录按钮事件 setupLoginButton(); // 设置注册跳转按钮事件 setupRegisterButton(); } /** * 检查是否已登录,如果是则自动跳转 */ private void checkAutoLogin() { sp = getSharedPreferences("PhoneNumber", MODE_PRIVATE); String savedPhone = sp.getString("PhoneNumber", ""); if (!savedPhone.isEmpty()) { jumpToMainActivity(getApplication()); finish(); } } /** * 初始化所有视图组件 */ private void initViews() { loginbtn = (Button) findViewById(R.id.btn_login); regisbtn_jump = (Button) findViewById(R.id.btn_register_jump); et_phone = (EditText) findViewById(R.id.et_phone); } /** * 设置登录按钮点击事件 */ private void setupLoginButton() { loginbtn.setOnClickListener(v -> { String phone = et_phone.getText().toString().trim(); if (!isValidPhone(phone)) { showToast("请输入正确的手机号"); return; } handleLoginLogic(phone); }); } /** * 设置注册跳转按钮点击事件 */ private void setupRegisterButton() { regisbtn_jump.setOnClickListener(v -> { Intent it = new Intent(getApplicationContext(), RegisterActivity.class); startActivity(it); }); } /** * 验证手机号格式 */ private boolean isValidPhone(String phone) { return phone != null && phone.length() == 11; } /** * 处理登录逻辑 */ private void handleLoginLogic(String phone) { // 测试账号直接登录 if ("12345678901".equals(phone)) { jumpToMainActivity(LoginActivity.this); finish(); return; } String savedPhone = sp.getString("PhoneNumber", ""); if (savedPhone.isEmpty()) { showToast("此电话号码未在本机注册过,请先注册"); } else if (!savedPhone.equals(phone)) { showToast("此电话号码不是本机注册号码"); } else { jumpToMainActivity(getApplicationContext()); finish(); } } /** * 跳转到主界面 */ private void jumpToMainActivity(Context context) { Intent intent = new Intent(context, MainActivity.class); startActivity(intent); } /** * 显示Toast提示 */ private void showToast(String message) { Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); } } ================================================ FILE: Android_app/app/src/main/java/com/ABC/pioneer/app/MainActivity.java ================================================ package com.ABC.pioneer.app; import android.Manifest; import android.annotation.SuppressLint; import android.app.Notification; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Intent; import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; import com.ABC.pioneer.app.fragment.FragmentActivity1; import com.ABC.pioneer.app.fragment.FragmentActivity2; import com.ABC.pioneer.app.fragment.FragmentActivity3; import com.ABC.pioneer.sensor.Sensor; import com.ABC.pioneer.sensor.datatype.PayloadData; import com.ABC.pioneer.sensor.datatype.TargetIdentifier; import com.ABC.pioneer.sensor.service.AlarmReceiver; import com.ABC.pioneer.sensor.service.CustomTimer; import com.ABC.pioneer.sensor.service.MatchDelegate; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import static android.content.pm.PackageManager.PERMISSION_GRANTED; public class MainActivity extends AppCompatActivity implements View.OnClickListener,MatchDelegate { private final static int permissionRequestCode = 1249951875; private long didDetect = 0, didRead = 0, didMeasure = 0, didShare = 0, didReceive = 0; private final static int WARNING_NOTIFICATION_ID = "WARNING".hashCode(); private final Map targetIdentifiers = new ConcurrentHashMap<>(); private final Map payloads = new ConcurrentHashMap<>(); private final List targets = new ArrayList<>(); private TargetListAdapter targetListAdapter = null; private AlertDialog dialog; private RelativeLayout bottom_bar_bluetooth_btn; private RelativeLayout bottom_bar_token_btn; private RelativeLayout bottom_bar_user_btn; private TextView bottom_bar_text_bluetooth; private TextView bottom_bar_text_token; private TextView bottom_bar_text_user; private ImageView bottom_bar_image_bluetooth; private ImageView bottom_bar_image_token; private ImageView bottom_bar_image_user; private LinearLayout main_bottom_bar; private LinearLayout main_body; private int TAG = 0; private FragmentActivity1 fragmentActivity1; private FragmentActivity2 fragmentActivity2; private FragmentActivity3 fragmentActivity3; public final static Sensor sensor = AppDelegate.getAppDelegate().sensor(); private static MainActivity instance; public static MainActivity getInstance(){ // 因为我们程序运行后,Application是首先初始化的,如果在这里不用判断instance是否为空 return instance; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); instance = MainActivity.this; // 开启接收器 final AlarmReceiver alarmReceiver = new AlarmReceiver(getApplicationContext(),this); // 开启定时服务 Intent i = new Intent(this, CustomTimer.class); startService(i); setContentView(R.layout.activity_bottom_bar); initView(); fragmentActivity1 = new FragmentActivity1(); fragmentActivity2 = new FragmentActivity2(); fragmentActivity3 = new FragmentActivity3(); setMain(); // 确保应用具有所有必需的权限 requestPermissions(); ignoreBatteryOpt.ignoreBatteryOptimization(this); } @Override public void matchFound() { if(FragmentActivity1.foreground) { runOnUiThread(new Runnable() { @Override public void run() { // 如果前台则弹出警告框,警告用户可能被感染 AlertDialog.Builder alertdialogbuilder = new AlertDialog.Builder(MainActivity.this); alertdialogbuilder.setMessage("传感器检测到您与感染者有接触过,请及时到医院进行核酸检测"); alertdialogbuilder.setPositiveButton("确定", null); alertdialogbuilder.setCancelable(true); alertdialogbuilder.setIcon(R.drawable.ic_warning); alertdialogbuilder.setTitle("接触警告"); final AlertDialog alertdialog1 = alertdialogbuilder.create(); alertdialog1.show(); try { Field mAlert = AlertDialog.class.getDeclaredField("mAlert"); mAlert.setAccessible(true); Object mAlertController = mAlert.get(alertdialog1); Field mMessage = mAlertController.getClass().getDeclaredField("mMessageView"); mMessage.setAccessible(true); TextView mMessageView = (TextView) mMessage.get(mAlertController); mMessageView.setTextColor(Color.RED); Field mTitleView = mAlertController.getClass().getDeclaredField("mTitleView"); mTitleView.setAccessible(true); TextView title = (TextView) mTitleView.get(mAlertController); title.setTextColor(Color.RED); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } }); } else { // 如果在后台运行,则弹出一个notification告知用户可能被感染 NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.notify(WARNING_NOTIFICATION_ID,getWarningNotification()); } } /// 请求传感器操作的应用程序权限。 private void requestPermissions() { // Check and request permissions final List requiredPermissions = new ArrayList<>(); requiredPermissions.add(Manifest.permission.BLUETOOTH); requiredPermissions.add(Manifest.permission.BLUETOOTH_ADMIN); requiredPermissions.add(Manifest.permission.ACCESS_COARSE_LOCATION); requiredPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { requiredPermissions.add(Manifest.permission.FOREGROUND_SERVICE); } requiredPermissions.add(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); requiredPermissions.add(Manifest.permission.WAKE_LOCK); final String[] requiredPermissionsArray = requiredPermissions.toArray(new String[0]); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(requiredPermissionsArray, permissionRequestCode); } else { ActivityCompat.requestPermissions(this, requiredPermissionsArray, permissionRequestCode); } } /// 处理权限结果 @Override public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == permissionRequestCode) { boolean permissionsGranted = true; for (int i = 0; i < permissions.length; i++) { final String permission = permissions[i]; if (grantResults[i] != PERMISSION_GRANTED) { permissionsGranted = false; } else { } } } } // 电量优化 private void showActivity(@NonNull String packageName) { Intent intent = getPackageManager().getLaunchIntentForPackage(packageName); startActivity(intent); } private void showActivity(@NonNull String packageName, @NonNull String activityDir) { Intent intent = new Intent(); intent.setComponent(new ComponentName(packageName, activityDir)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } private Notification getWarningNotification() { /*final Intent intent = new Intent(this, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);*/ Intent intent = new Intent(this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); final PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0); final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, AppDelegate.getNotificationChannelId()) .setSmallIcon(R.drawable.ic_notification) .setColor(Color.RED) .setContentTitle(this.getString(R.string.warning_notification_content_title)) .setContentText(this.getString(R.string.warning_notification_content_text)) .setWhen(System.currentTimeMillis()) .setContentIntent(pendingIntent) .setAutoCancel(true) .setPriority(NotificationCompat.PRIORITY_DEFAULT); final Notification notification = builder.build(); return notification; } private void setSelectStatus(int index) { switch (index){ case 0: //图片点击选择变换图片,颜色的改变,其他变为原来的颜色,并保持原有的图片 bottom_bar_image_bluetooth.setImageResource(R.drawable.ic_discover_choose); bottom_bar_text_bluetooth.setTextColor(Color.parseColor("#0097F7")); //其他的文本颜色不变 bottom_bar_text_token.setTextColor(Color.parseColor("#666666")); bottom_bar_text_user.setTextColor(Color.parseColor("#666666")); //图片也不变 bottom_bar_image_token.setImageResource(R.drawable.ic_token_icon); bottom_bar_image_user.setImageResource(R.drawable.ic_user); break; case 1: bottom_bar_image_token.setImageResource(R.drawable.ic_token_choose); bottom_bar_text_token.setTextColor(Color.parseColor("#0097F7")); bottom_bar_text_bluetooth.setTextColor(Color.parseColor("#666666")); bottom_bar_text_user.setTextColor(Color.parseColor("#666666")); bottom_bar_image_bluetooth.setImageResource(R.drawable.ic_discover_icon); bottom_bar_image_user.setImageResource(R.drawable.ic_user); break; case 2: bottom_bar_image_user.setImageResource(R.drawable.ic_user_choose); bottom_bar_text_user.setTextColor(Color.parseColor("#0097F7")); bottom_bar_text_token.setTextColor(Color.parseColor("#666666")); bottom_bar_text_bluetooth.setTextColor(Color.parseColor("#666666")); bottom_bar_image_bluetooth.setImageResource(R.drawable.ic_discover_icon); bottom_bar_image_token.setImageResource(R.drawable.ic_token_icon); break; } } private void initView(){ //底部导航栏 bottom_bar_bluetooth_btn = findViewById(R.id.bottom_bar_bluetooth); bottom_bar_token_btn = findViewById(R.id.bottom_bar_token); bottom_bar_user_btn = findViewById(R.id.bottom_bar_user); bottom_bar_text_bluetooth = findViewById(R.id.bottom_bar_text_bluetooth); bottom_bar_text_token = findViewById(R.id.bottom_bar_text_token); bottom_bar_text_user = findViewById(R.id.bottom_bar_text_user); bottom_bar_image_bluetooth = findViewById(R.id.bottom_bar_image_bluetooth); bottom_bar_image_token = findViewById(R.id.bottom_bar_image_token); bottom_bar_image_user = findViewById(R.id.bottom_bar_image_user); main_bottom_bar = findViewById(R.id.main_body_bar); main_body = findViewById(R.id.main_body); //设置点击事件 bottom_bar_bluetooth_btn.setOnClickListener(this); bottom_bar_token_btn.setOnClickListener(this); bottom_bar_user_btn.setOnClickListener(this); } private void setMain() { //打开初始界面 TAG = 1; this.getSupportFragmentManager().beginTransaction().add(R.id.fl_container,fragmentActivity1).commit(); } @SuppressLint("NonConstantResourceId") @Override public void onClick(View v){ if(TAG == 0){ TAG = 1; switch(v.getId()){ case R.id.bottom_bar_bluetooth: getSupportFragmentManager().beginTransaction().add(R.id.fl_container,fragmentActivity1).commitAllowingStateLoss(); setSelectStatus(0); break; case R.id.bottom_bar_token: getSupportFragmentManager().beginTransaction().add(R.id.fl_container,fragmentActivity2).commitAllowingStateLoss(); setSelectStatus(1); break; case R.id.bottom_bar_user: getSupportFragmentManager().beginTransaction().add(R.id.fl_container,fragmentActivity3).commitAllowingStateLoss(); setSelectStatus(2); break; } } else{ switch(v.getId()){ case R.id.bottom_bar_bluetooth: getSupportFragmentManager().beginTransaction().replace(R.id.fl_container,fragmentActivity1).commitAllowingStateLoss(); setSelectStatus(0); break; case R.id.bottom_bar_token: getSupportFragmentManager().beginTransaction().replace(R.id.fl_container,fragmentActivity2).commitAllowingStateLoss(); setSelectStatus(1); break; case R.id.bottom_bar_user: getSupportFragmentManager().beginTransaction().replace(R.id.fl_container,fragmentActivity3).commitAllowingStateLoss(); setSelectStatus(2); break; } } } } ================================================ FILE: Android_app/app/src/main/java/com/ABC/pioneer/app/RegisterActivity.java ================================================ package com.ABC.pioneer.app; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import com.ABC.pioneer.sensor.SensorArray; import com.ABC.pioneer.sensor.payload.Crypto.GenerateKey; import com.ABC.pioneer.sensor.payload.Crypto.SecretKey; import com.ABC.pioneer.sensor.payload.Crypto.SpecificUsePayloadSupplier; import com.ABC.pioneer.sensor.service.Connection; import java.io.IOException; public class RegisterActivity extends AppCompatActivity { private Button registerButton; private EditText phoneEditText; private String serverResponse = ""; private final Context appContext = AppDelegate.getInstance(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_register); initializeViews(); setupRegisterButton(); } private void initializeViews() { registerButton = findViewById(R.id.btn_register); phoneEditText = findViewById(R.id.et_phone_1); } private void setupRegisterButton() { registerButton.setOnClickListener(v -> handleRegistration()); } private void handleRegistration() { String phoneNumber = phoneEditText.getText().toString().trim(); if (!isValidPhoneNumber(phoneNumber)) { showToast("请输入正确的手机号"); return; } performRegistration(phoneNumber); } private boolean isValidPhoneNumber(String phoneNumber) { return phoneNumber.length() == 11; } private void performRegistration(String phoneNumber) { SharedPreferences phonePrefs = getSharedPreferences("PhoneNumber", MODE_PRIVATE); SharedPreferences secretKeyPrefs = getSharedPreferences("SecretKey", MODE_PRIVATE); SecretKey currentSecretKey = AppDelegate.secretKey; new Thread(() -> { try { Connection connection = new Connection(RegisterActivity.this); connection.connectToServer(); serverResponse = connection.register(phoneNumber, currentSecretKey.base64EncodedString()); } catch (IOException e) { // 处理连接异常 } }).start().joinWithUiThread(this::processRegistrationResult); } private void processRegistrationResult() { switch (serverResponse) { case "0": handleSuccessfulRegistration(); break; case "1": showToast("该手机号已被注册"); break; case "2": handleSecretKeyConflict(); break; } } private void handleSuccessfulRegistration() { SharedPreferences.Editor editor = getSharedPreferences("PhoneNumber", MODE_PRIVATE).edit(); editor.putString("PhoneNumber", phoneEditText.getText().toString().trim()); editor.apply(); showToast("注册成功"); } private void handleSecretKeyConflict() { showToast("SecretKey重复,已重新生成,请再次点击注册"); SharedPreferences.Editor editor = getSharedPreferences("SecretKey", MODE_PRIVATE).edit(); SecretKey newSecretKey = GenerateKey.secretKey(); editor.putString("SecretKey", newSecretKey.base64EncodedString()); editor.apply(); SpecificUsePayloadSupplier payloadSupplier = new SpecificUsePayloadSupplier(newSecretKey); AppDelegate.sensor = new SensorArray(getApplicationContext(), payloadSupplier); AppDelegate.sensor.add(AppDelegate.getAppDelegate()); } private void showToast(String message) { runOnUiThread(() -> Toast.makeText(RegisterActivity.this, message, Toast.LENGTH_LONG).show() ); } // 辅助方法:在UI线程执行回调 private interface UiThreadCallback { void execute(); } private static void joinWithUiThread(Thread thread, Activity activity, UiThreadCallback callback) { try { thread.join(); activity.runOnUiThread(callback::execute); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } ================================================ FILE: Android_app/app/src/main/java/com/ABC/pioneer/app/SplashActivity.java ================================================ package com.ABC.pioneer.app; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import androidx.appcompat.app.AppCompatActivity; public class SplashActivity extends AppCompatActivity { private final int SPLASH_DISPLAY_LENGHT = 2000; // 两秒后进入系统 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); Handler x = new Handler();//定义一个handle对象 x.postDelayed(new splashhandler(), 3000);//设置3秒钟延迟执行splashhandler线程。其实你这里可以再新建一个线程去执行初始化工作,如判断SD,网络状态等 } class splashhandler implements Runnable{ public void run() { startActivity(new Intent(getApplicationContext(),LoginActivity.class));// 这个线程的作用3秒后就是进入到你的登录界面 SplashActivity.this.finish();// 把当前的LaunchActivity结束掉 } } } ================================================ FILE: Android_app/app/src/main/java/com/ABC/pioneer/app/Target.java ================================================ package com.ABC.pioneer.app; import com.ABC.pioneer.sensor.analysis.Sample; import com.ABC.pioneer.sensor.datatype.ImmediateSendData; import com.ABC.pioneer.sensor.datatype.PayloadData; import com.ABC.pioneer.sensor.datatype.Proximity; import com.ABC.pioneer.sensor.datatype.TargetIdentifier; import com.ABC.pioneer.sensor.datatype.TimeInterval; import java.util.Date; public class Target { private TargetIdentifier targetIdentifier = null; private PayloadData payloadData = null; private Date lastUpdatedAt = null; private Proximity proximity = null; private ImmediateSendData received = null; private Date didRead = null, didMeasure = null, didShare = null, didReceive = null; private Sample didReadTimeInterval = new Sample(); private Sample didMeasureTimeInterval = new Sample(); private Sample didShareTimeInterval = new Sample(); public Target(TargetIdentifier targetIdentifier, PayloadData payloadData) { this.targetIdentifier = targetIdentifier; this.payloadData = payloadData; lastUpdatedAt = new Date(); didRead = lastUpdatedAt; } public TargetIdentifier targetIdentifier() { return targetIdentifier; } public void targetIdentifier(TargetIdentifier targetIdentifier) { //lastUpdatedAt = new Date(); this.targetIdentifier = targetIdentifier; } public PayloadData payloadData() { return payloadData; } public Date lastUpdatedAt() { return lastUpdatedAt; } public Proximity proximity() { return proximity; } public void proximity(Proximity proximity) { final Date date = new Date(); if (didMeasure != null) { final TimeInterval timeInterval = new TimeInterval(didMeasure, date); didMeasureTimeInterval.add(timeInterval.value); } /*lastUpdatedAt = date; didMeasure = lastUpdatedAt;*/ didMeasure = date; this.proximity = proximity; } public ImmediateSendData received() { return received; } public void received(ImmediateSendData received) { lastUpdatedAt = new Date(); didReceive = lastUpdatedAt; this.received = received; } public Date didRead() { return didRead; } public Sample didReadTimeInterval() { return didReadTimeInterval; } public void didRead(Date date) { if (didRead != null && date != null) { final TimeInterval timeInterval = new TimeInterval(didRead, date); didReadTimeInterval.add(timeInterval.value); } didRead = date; lastUpdatedAt = didRead; } public Date didMeasure() { return didMeasure; } public Sample didMeasureTimeInterval() { return didMeasureTimeInterval; } public Date didShare() { return didShare; } public void didShare(Date date) { if (didShare != null && date != null) { final TimeInterval timeInterval = new TimeInterval(didShare, date); didShareTimeInterval.add(timeInterval.value); } didShare = date; lastUpdatedAt = didShare; } public Sample didShareTimeInterval() { return didShareTimeInterval; } } ================================================ FILE: Android_app/app/src/main/java/com/ABC/pioneer/app/TargetListAdapter.java ================================================ package com.ABC.pioneer.app; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.ABC.pioneer.sensor.payload.Crypto.SpecificUsePayloadSupplier; import java.text.SimpleDateFormat; import java.util.List; import java.util.TimeZone; //用于在UI上显示目标列表的目标列表适配器 public class TargetListAdapter extends ArrayAdapter { private final static SimpleDateFormat dateFormatter = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); public TargetListAdapter(@NonNull Context context, List targets) { super(context, R.layout.listview_targets_row, targets); } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { final Target target = getItem(position); if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate(R.layout.listview_targets_row, parent, false); } final TextView textLabel = (TextView) convertView.findViewById(R.id.targetTextLabel); final TextView detailedTextLabel = (TextView) convertView.findViewById(R.id.targetDetailedTextLabel); SimpleDateFormat Dateformat=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); Dateformat.setTimeZone(TimeZone.getTimeZone("GMT+08")); final StringBuilder labelText = new StringBuilder(target.payloadData().shortName()); final String didReceive = " (接收时间 : " + Dateformat.format(SpecificUsePayloadSupplier.parseStartTimeToLong(target.payloadData())) + ")"; textLabel.setText(labelText.toString() + didReceive); if(SpecificUsePayloadSupplier.checkPayloadtime(target.payloadData())) { detailedTextLabel.setText("更新时间 : " + dateFormatter.format(target.lastUpdatedAt())); } return convertView; } } ================================================ FILE: Android_app/app/src/main/java/com/ABC/pioneer/app/TokenActivity.java ================================================ // Android APP // Token activity package com.ABC.pioneer.app; import android.content.SharedPreferences; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import com.ABC.pioneer.sensor.payload.Crypto.SpecificUsePayloadSupplier; import com.ABC.pioneer.sensor.payload.Crypto.GenerateKey; import com.ABC.pioneer.sensor.payload.Crypto.MatchingKey; import com.ABC.pioneer.sensor.service.Connection; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Date; // token activity public class TokenActivity extends AppCompatActivity { private Button tokenbtn; private EditText tokenet; DataInputStream in=null; DataOutputStream out=null; private String Maching_keys=""; private SharedPreferences sp; String result = ""; String result1 = ""; Connection connection; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_token); sp = getSharedPreferences("PhoneNumber",MODE_PRIVATE); tokenbtn = (Button)findViewById(R.id.btn_token); tokenet = (EditText)findViewById(R.id.et_token); MatchingKey[] MachingKeys = SpecificUsePayloadSupplier.matchingKeys; tokenbtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { /*根据当前时间和app开启时间的时间差计算距开启已经过多少天,用天数i定位到MachingKeys[i], 这个即为当天的Machingkey,然后再向前找14天的Machingkey*/ final int date = GenerateKey.day(new Date()); String token = tokenet.getText().toString(); if (token.trim().length() != 6) { Toast.makeText(TokenActivity.this, "请输入正确的Token号码", Toast.LENGTH_LONG).show(); return; } Thread thread = new Thread(new Runnable(){ @Override public void run(){ try{ connection = new Connection(TokenActivity.this); connection.ConnectToServer(); result = connection.Token(token); if(result.equals("0")) { String phone = sp.getString("PhoneNumber","默认值"); for(int i = 13; i >= 0; i--){ Maching_keys += MachingKeys[date - i].base64EncodedString(); } result1 = connection.Token_TransmitMachingKeys(phone,Maching_keys); } } catch (IOException e) { e.printStackTrace(); } } }); thread.start(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } if(result.equals("0")) { Toast.makeText(TokenActivity.this, "验证通过", Toast.LENGTH_LONG).show(); Toast.makeText(TokenActivity.this, "成功上传ID和14天Maching_keys", Toast.LENGTH_LONG).show(); } else if(result.equals("1")){ Toast.makeText(TokenActivity.this, "Token输入有误,请重新输入!", Toast.LENGTH_LONG).show(); } } }); } } ================================================ FILE: Android_app/app/src/main/java/com/ABC/pioneer/app/fragment/FragmentActivity1.java ================================================ package com.ABC.pioneer.app.fragment; import android.annotation.SuppressLint; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.CompoundButton; import android.widget.ListView; import android.widget.Switch; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.ABC.pioneer.app.MainActivity; import com.ABC.pioneer.app.R; import com.ABC.pioneer.app.Target; import com.ABC.pioneer.app.TargetListAdapter; import com.ABC.pioneer.sensor.SensorDelegate; import com.ABC.pioneer.sensor.datatype.ImmediateSendData; import com.ABC.pioneer.sensor.datatype.PayloadData; import com.ABC.pioneer.sensor.datatype.Proximity; import com.ABC.pioneer.sensor.datatype.SensorType; import com.ABC.pioneer.sensor.datatype.TargetIdentifier; import com.ABC.pioneer.sensor.payload.Crypto.SpecificUsePayloadSupplier; import com.ABC.pioneer.sensor.service.PioneerDb; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; public class FragmentActivity1 extends Fragment implements AdapterView.OnItemClickListener, SensorDelegate { public static boolean foreground = false; private long didDetect = 0, didRead = 0, didMeasure = 0, didShare = 0, didReceive = 0; private final Map targetIdentifiers = new ConcurrentHashMap<>(); private final Map payloads = new ConcurrentHashMap<>(); private final List targets = new ArrayList<>(); private TargetListAdapter targetListAdapter = null; private AlertDialog dialog; private View view; private final Context context = MainActivity.getInstance(); private TextView Read; private TextView Measure; private TextView Detect; private TextView Share; private TextView count; private ListView targetsListView; @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle saveInstanceState){ android.view.View view = inflater.inflate(R.layout.activity_bluetooth,container,false); this.view = view; initView(view); return view; } private void initView(View view){ Read = (TextView)view.findViewById(R.id.didReadCount); Measure = (TextView)view.findViewById(R.id.didMeasureCount); Detect = (TextView)view.findViewById(R.id.didDetectCount); Share = (TextView)view.findViewById(R.id.didShareCount); count = (TextView)view.findViewById(R.id.detection); targetsListView = (ListView)view.findViewById(R.id.targets); } @Override public void onActivityCreated(Bundle savedInstanceState){ super.onActivityCreated(savedInstanceState); //测试特定于UI的过程,以从传感器收集数据进行展示 @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch onOffSwitch = Objects.requireNonNull(getActivity()).findViewById(R.id.sensorOnOffSwitch); MainActivity.sensor.add(this); onOffSwitch.setChecked(true); MainActivity.sensor.start(); onOffSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { MainActivity.sensor.start(); } else { MainActivity.sensor.stop(); } } }); //测试特定于UI的过程,以从传感器收集数据进行展示 targetListAdapter = new TargetListAdapter(context, targets); targetsListView.setAdapter(targetListAdapter); targetsListView.setOnItemClickListener(this); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle saveInstanceState){ super.onViewCreated(view, saveInstanceState); } // 更新目标表 private synchronized void updateTargets() { // 根据短名称删除重复目标,并在时间戳上最后更新 final Map shortNames = new HashMap<>(payloads.size()); for (Map.Entry entry : payloads.entrySet()) { final String shortName = entry.getKey().shortName(); final Target target = entry.getValue(); final Target duplicate = shortNames.get(shortName); if (duplicate == null || duplicate.lastUpdatedAt().getTime() < target.lastUpdatedAt().getTime()) { shortNames.put(shortName, target); } } // 按字母顺序获取目标列表 final List targetList = new ArrayList<>(shortNames.values()); Collections.sort(targetList, new Comparator() { @Override public int compare(Target t0, Target t1) { return t0.payloadData().shortName().compareTo(t1.payloadData().shortName()); } }); // 更新用户界面 count.setText("接收数据包 (" + targetListAdapter.getCount() + ")"); targetListAdapter.clear(); targetListAdapter.addAll(targetList); } // 更新相应检测结果 private void updateCounts() { Detect.setText(Long.toString(this.didDetect)); Read.setText(Long.toString(this.didRead)); Measure.setText(Long.toString(this.didMeasure)); Share.setText(Long.toString(this.didShare)); } @Override public void onResume() { super.onResume(); foreground = true; updateCounts(); updateTargets(); } @Override public void onPause() { foreground = false; super.onPause(); } @Override public void sensor(SensorType sensor, TargetIdentifier didDetect) { this.didDetect++; if (foreground) { final String text = Long.toString(this.didDetect); Objects.requireNonNull(getActivity()).runOnUiThread(new Runnable() { @Override public void run() { Detect.setText(text); } }); } } @Override public void sensor(SensorType sensor, PayloadData didRead, TargetIdentifier fromTarget) { this.didRead++; targetIdentifiers.put(fromTarget, didRead); Target target = payloads.get(didRead); if (target != null) { target.didRead(new Date()); } else { payloads.put(didRead, new Target(fromTarget, didRead)); } if (foreground) { final String text = Long.toString(this.didRead); Objects.requireNonNull(getActivity()).runOnUiThread(new Runnable() { @Override public void run() { Read.setText(text); updateTargets(); } }); } PioneerDb db = new PioneerDb(context,"payloads",null,1); db.insertPayloadData(didRead); } @Override public void sensor(SensorType sensor, List didShare, TargetIdentifier fromTarget) { this.didShare++; final Date now = new Date(); for (PayloadData didRead : didShare) { targetIdentifiers.put(fromTarget, didRead); Target target = payloads.get(didRead); if (target != null) { target.didRead(new Date()); } else { payloads.put(didRead, new Target(fromTarget, didRead)); } } if (foreground) { final String text = Long.toString(this.didShare); Objects.requireNonNull(getActivity()).runOnUiThread(new Runnable() { @Override public void run() { Share.setText(text); updateTargets(); } }); } } @Override public void sensor(SensorType sensor, Proximity didMeasure, TargetIdentifier fromTarget) { this.didMeasure++; final PayloadData didRead = targetIdentifiers.get(fromTarget); if (didRead != null) { final Target target = payloads.get(didRead); if (target != null) { target.targetIdentifier(fromTarget); target.proximity(didMeasure); } } if (foreground) { final String text = Long.toString(this.didMeasure); Objects.requireNonNull(getActivity()).runOnUiThread(new Runnable() { @Override public void run() { Measure.setText(text); } }); } } @Override public void sensor(SensorType sensor, ImmediateSendData didReceive, TargetIdentifier fromTarget) { this.didReceive++; final PayloadData didRead = new PayloadData(didReceive.data.value); if (didRead != null) { final Target target = payloads.get(didRead); if (target != null) { targetIdentifiers.put(fromTarget, didRead); target.targetIdentifier(fromTarget); target.received(didReceive); } } if (foreground) { final String text = Long.toString(this.didReceive); Objects.requireNonNull(getActivity()).runOnUiThread(new Runnable() { @Override public void run() { updateTargets(); } }); } } @Override public void onItemClick(AdapterView adapter, View view, int i, long l) { final Target target = targetListAdapter.getItem(i); final PayloadData payloadData = target.payloadData(); SimpleDateFormat dateformat=new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); dateformat.setTimeZone(TimeZone.getTimeZone("GMT+08")); AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); LayoutInflater inflater = (LayoutInflater) Objects.requireNonNull(getContext()).getSystemService(Context.LAYOUT_INFLATER_SERVICE); View messageview = inflater.inflate(R.layout.activity_payload, null); TextView ContactIdentifier = (TextView)messageview.findViewById(R.id.ContactIdentifier); TextView StartTime = (TextView)messageview.findViewById(R.id.StartTime); TextView EndTime = (TextView)messageview.findViewById(R.id.EndTime); ContactIdentifier.append(SpecificUsePayloadSupplier.parseContactIdentifierToStr(payloadData)); final long startTime = SpecificUsePayloadSupplier.parseStartTimeToLong(payloadData); StartTime.append(dateformat.format(startTime)); EndTime.append(dateformat.format(startTime+360000)); builder.setView(messageview); builder.create(); dialog = builder.show(); } } ================================================ FILE: Android_app/app/src/main/java/com/ABC/pioneer/app/fragment/FragmentActivity2.java ================================================ package com.ABC.pioneer.app.fragment; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.ABC.pioneer.app.MainActivity; import com.ABC.pioneer.app.R; import com.ABC.pioneer.app.TokenActivity; public class FragmentActivity2 extends Fragment { LinearLayout token_pre; private final Context context = MainActivity.getInstance(); private AlertDialog dialog; @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle saveInstanceState){ android.view.View view = inflater.inflate(R.layout.activity_token_pre,container,false); initView(view); return view; } @Override public void onActivityCreated(Bundle savedInstanceState){ super.onActivityCreated(savedInstanceState); token_pre.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { Intent it=new Intent(getContext(), TokenActivity.class);//启动TokenActivity startActivity(it); } }); } private void initView(View view){ token_pre = (LinearLayout) view.findViewById(R.id.token_pre); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle saveInstanceState) { super.onViewCreated(view, saveInstanceState); } } ================================================ FILE: Android_app/app/src/main/java/com/ABC/pioneer/app/fragment/FragmentActivity3.java ================================================ package com.ABC.pioneer.app.fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import com.ABC.pioneer.app.R; import com.ABC.pioneer.sensor.SensorArray; import com.ABC.pioneer.sensor.payload.Crypto.SpecificUsePayloadSupplier; import java.util.Date; public class FragmentActivity3 extends Fragment { @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle saveInstanceState){ android.view.View view = inflater.inflate(R.layout.activity_user,container,false); return view; } @Override public void onActivityCreated(Bundle savedInstanceState){ super.onActivityCreated(savedInstanceState); ((TextView) getActivity().findViewById(R.id.device)).setText("设备名:" + SensorArray.deviceDescription); ((TextView) getActivity().findViewById(R.id.payload)).setText("本机数据包:"+SpecificUsePayloadSupplier.updatePayload(new Date()).shortName()); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle saveInstanceState){ super.onViewCreated(view, saveInstanceState); } } ================================================ FILE: Android_app/app/src/main/java/com/ABC/pioneer/app/ignoreBatteryOpt.java ================================================ package com.ABC.pioneer.app; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.PowerManager; import android.provider.Settings; import androidx.annotation.NonNull; import static android.content.Context.POWER_SERVICE; public class ignoreBatteryOpt { static public void ignoreBatteryOptimization(Activity activity) { PowerManager powerManager = (PowerManager)activity.getSystemService(POWER_SERVICE); boolean hasIgnored = false; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { hasIgnored = powerManager.isIgnoringBatteryOptimizations(activity.getPackageName()); // 判断当前APP是否有加入电池优化的白名单,如果没有,弹出加入电池优化的白名单的设置对话框。 if(!hasIgnored) { Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:"+activity.getPackageName())); activity.startActivity(intent); } } } } ================================================ FILE: Android_app/app/src/main/res/drawable/border_input_box.xml ================================================ ================================================ FILE: Android_app/app/src/main/res/drawable/button_background.xml ================================================ ================================================ FILE: Android_app/app/src/main/res/drawable/ic_launcher_background.xml ================================================ ================================================ FILE: Android_app/app/src/main/res/drawable/token_background.xml ================================================ ================================================ FILE: Android_app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml ================================================ ================================================ FILE: Android_app/app/src/main/res/layout/activity_bluetooth.xml ================================================ ================================================ FILE: Android_app/app/src/main/res/layout/activity_bottom_bar.xml ================================================ ================================================ FILE: Android_app/app/src/main/res/layout/activity_login.xml ================================================