2025-07-17 10:53:35 +08:00
|
|
|
package com.example.myapplication.Service;
|
|
|
|
import android.app.Notification;
|
|
|
|
import android.app.NotificationChannel;
|
|
|
|
import android.app.NotificationManager;
|
|
|
|
import android.app.PendingIntent;
|
|
|
|
import android.app.Service;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
2025-07-25 14:29:27 +08:00
|
|
|
import android.content.SharedPreferences;
|
2025-07-17 10:53:35 +08:00
|
|
|
import android.database.ContentObserver;
|
|
|
|
import android.database.Cursor;
|
|
|
|
import android.location.Location;
|
|
|
|
import android.location.LocationManager;
|
|
|
|
import android.media.ExifInterface;
|
|
|
|
import android.net.ConnectivityManager;
|
|
|
|
import android.net.NetworkCapabilities;
|
|
|
|
import android.net.Uri;
|
|
|
|
import android.os.Build;
|
|
|
|
import android.os.Handler;
|
|
|
|
import android.os.IBinder;
|
|
|
|
import android.os.Looper;
|
|
|
|
import android.provider.MediaStore;
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
import androidx.annotation.Nullable;
|
2025-07-25 14:29:27 +08:00
|
|
|
import androidx.appcompat.app.AlertDialog;
|
2025-07-17 10:53:35 +08:00
|
|
|
import androidx.core.app.NotificationCompat;
|
|
|
|
import androidx.room.Room;
|
|
|
|
|
|
|
|
import com.example.myapplication.DataBase.AppDatabase;
|
|
|
|
import com.example.myapplication.R;
|
|
|
|
import com.example.myapplication.Tool.BackgroundToast;
|
|
|
|
import com.example.myapplication.Tool.NotificationReceiver;
|
|
|
|
import com.example.myapplication.model.ImageEntity;
|
|
|
|
import com.example.myapplication.model.SharedDataManager;
|
|
|
|
|
2025-07-25 14:29:27 +08:00
|
|
|
import org.json.JSONObject;
|
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
import java.io.File;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.concurrent.ExecutorService;
|
|
|
|
import java.util.concurrent.Executors;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
2025-07-25 14:29:27 +08:00
|
|
|
import okhttp3.HttpUrl;
|
2025-07-17 10:53:35 +08:00
|
|
|
import okhttp3.MediaType;
|
|
|
|
import okhttp3.MultipartBody;
|
|
|
|
import okhttp3.OkHttpClient;
|
|
|
|
import okhttp3.Request;
|
|
|
|
import okhttp3.RequestBody;
|
|
|
|
import okhttp3.Response;
|
|
|
|
|
|
|
|
public class PhotoMonitoringService extends Service implements SharedDataManager.DataChangeListener {
|
|
|
|
private static final String CHANNEL_ID = "PhotoMonitoringChannel";
|
|
|
|
private static final int NOTIFICATION_ID = 101;
|
|
|
|
private static final int THUMBNAIL_SIZE = 100;
|
|
|
|
|
|
|
|
// 锁对象
|
|
|
|
private final Object monitoringLock = new Object();
|
|
|
|
private final Object uploadLock = new Object();
|
2025-07-25 14:29:27 +08:00
|
|
|
private long lastSuccessToastTime = 0;
|
|
|
|
private static final long TOAST_THROTTLE_INTERVAL = 1500;
|
2025-07-17 10:53:35 +08:00
|
|
|
|
|
|
|
// 状态标志
|
|
|
|
private boolean isMonitoring = false;
|
|
|
|
private boolean isUploading = false;
|
|
|
|
private boolean isRecording = false;
|
|
|
|
private int successCount = 0;
|
2025-07-25 14:29:27 +08:00
|
|
|
private int totalUploadedCount = 0; // 新增:总上传成功计数
|
2025-07-17 10:53:35 +08:00
|
|
|
|
|
|
|
// 组件
|
|
|
|
private ContentObserver contentObserver;
|
2025-07-25 14:29:27 +08:00
|
|
|
private final ExecutorService executor = Executors.newFixedThreadPool(5);
|
2025-07-17 10:53:35 +08:00
|
|
|
private final OkHttpClient httpClient = new OkHttpClient.Builder()
|
|
|
|
.connectTimeout(30, TimeUnit.SECONDS) // 连接超时
|
|
|
|
.readTimeout(60, TimeUnit.SECONDS) // 读取超时
|
|
|
|
.writeTimeout(60, TimeUnit.SECONDS) // 写入超时
|
|
|
|
.build();
|
|
|
|
|
|
|
|
// 数据库
|
|
|
|
private AppDatabase db;
|
|
|
|
private AppDatabase db2;
|
|
|
|
|
|
|
|
// 位置相关
|
|
|
|
private Location lastKnownLocation;
|
|
|
|
private LocationManager locationManager;
|
|
|
|
|
|
|
|
// 配置参数
|
|
|
|
private String token;
|
|
|
|
private String user;
|
|
|
|
private String projectId;
|
|
|
|
private String unit;
|
|
|
|
private int blade;
|
|
|
|
private String unitName;
|
|
|
|
private String Temperator;
|
|
|
|
private String Humidity;
|
|
|
|
private String Weather;
|
|
|
|
private String ChooseImageSource;
|
|
|
|
|
|
|
|
// 其他状态
|
|
|
|
private long lastPhotoId = 0;
|
2025-07-25 14:29:27 +08:00
|
|
|
private String currentAudioPath="-1";
|
2025-07-17 10:53:35 +08:00
|
|
|
private String imgpath="-1";
|
|
|
|
private String partid="-1";
|
2025-07-25 14:29:27 +08:00
|
|
|
private String UserId;
|
2025-07-17 10:53:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
@Override
|
2025-07-25 14:29:27 +08:00
|
|
|
public void onImageIdChanged(String newId) {
|
2025-07-17 10:53:35 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onTokenChanged(String newToken) {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onUserChanged(String newUser) {
|
2025-07-25 14:29:27 +08:00
|
|
|
user=newUser;
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onAudioPathChanged(String newAudioPath) {
|
2025-07-25 14:29:27 +08:00
|
|
|
currentAudioPath=newAudioPath;
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onProjectIdChanged(String newProjectId) {
|
2025-07-25 14:29:27 +08:00
|
|
|
projectId=newProjectId;
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onUnitChanged(String newUnit) {
|
2025-07-25 14:29:27 +08:00
|
|
|
unit=newUnit;
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onBladeChanged(int newBlade) {
|
2025-07-25 14:29:27 +08:00
|
|
|
blade=newBlade;
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPartidChanged(String newPartid) {
|
2025-07-25 14:29:27 +08:00
|
|
|
partid=newPartid;
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onChooseImageSourceChanged(String newChooseImageSource) {
|
2025-07-25 14:29:27 +08:00
|
|
|
ChooseImageSource=newChooseImageSource;
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onUnitNameChanged(String newUnitName) {
|
2025-07-25 14:29:27 +08:00
|
|
|
unitName=newUnitName;
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onIsRecordingChanged(boolean newisRecording) {
|
2025-07-25 14:29:27 +08:00
|
|
|
isRecording=newisRecording;
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onUploadingStatusChanged(boolean isUploading) {
|
2025-07-25 14:29:27 +08:00
|
|
|
this.isUploading=isUploading;
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
|
2025-07-25 14:29:27 +08:00
|
|
|
@Override
|
|
|
|
public void onLocationChanged(Location newLocation) {
|
|
|
|
lastKnownLocation=newLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onOtherMsgChanged(String msg) {
|
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
2025-07-25 14:29:27 +08:00
|
|
|
|
|
|
|
SharedDataManager dataManager;
|
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
@Override
|
|
|
|
public void onCreate() {
|
|
|
|
super.onCreate();
|
|
|
|
createNotificationChannel();
|
2025-07-25 14:29:27 +08:00
|
|
|
SharedPreferences prefs = getSharedPreferences("WeatherPrefs", MODE_PRIVATE);
|
|
|
|
Weather = prefs.getString("weather", "0");
|
|
|
|
Temperator = prefs.getString("temperature", "0");
|
|
|
|
Humidity = prefs.getString("humidity", "0");
|
|
|
|
SharedPreferences sharedPreferences = getSharedPreferences("LoginPrefs", Context.MODE_PRIVATE);
|
2025-07-17 10:53:35 +08:00
|
|
|
// 初始化数据库
|
2025-07-25 14:29:27 +08:00
|
|
|
UserId=sharedPreferences.getString("userid","-1");
|
2025-07-17 10:53:35 +08:00
|
|
|
db = Room.databaseBuilder(getApplicationContext(),
|
|
|
|
AppDatabase.class, "image-database").build();
|
|
|
|
db2 = Room.databaseBuilder(getApplicationContext(),
|
|
|
|
AppDatabase.class, "image-database2").build();
|
|
|
|
|
|
|
|
// 初始化位置管理器
|
|
|
|
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
2025-07-25 14:29:27 +08:00
|
|
|
dataManager=SharedDataManager.getInstance();
|
2025-07-17 10:53:35 +08:00
|
|
|
|
|
|
|
dataManager.addListener(this);
|
|
|
|
updateFromSharedData();
|
2025-07-25 14:29:27 +08:00
|
|
|
|
|
|
|
// 初始化时从数据库获取已上传成功的数量
|
|
|
|
|
|
|
|
totalUploadedCount = 0;
|
|
|
|
updateNotification("partid"+partid);
|
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
2025-07-25 14:29:27 +08:00
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
private void updateFromSharedData() {
|
2025-07-25 14:29:27 +08:00
|
|
|
dataManager = SharedDataManager.getInstance();
|
2025-07-17 10:53:35 +08:00
|
|
|
this.token = dataManager.getToken();
|
|
|
|
this.user = dataManager.getUser();
|
|
|
|
this.currentAudioPath = dataManager.getAudioPath();
|
|
|
|
this.projectId = dataManager.getProjectId();
|
|
|
|
this.unit = dataManager.getUnit();
|
|
|
|
this.blade = dataManager.getBlade();
|
|
|
|
this.ChooseImageSource = dataManager.getChooseImageSource();
|
|
|
|
this.unitName = dataManager.getUnitName();
|
|
|
|
this.partid=dataManager.getPartid();
|
|
|
|
this.isUploading=dataManager.getisUploading();
|
2025-07-25 14:29:27 +08:00
|
|
|
this.lastKnownLocation=dataManager.getLocation();
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
2025-07-25 14:29:27 +08:00
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
@Override
|
|
|
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
|
|
|
if (intent != null && "start_monitoring".equals(intent.getStringExtra("command"))) {
|
|
|
|
startMonitoring();
|
|
|
|
}
|
|
|
|
|
|
|
|
startForeground(NOTIFICATION_ID, buildNotification("服务正在运行", "监听照片变化中"));
|
|
|
|
|
|
|
|
return START_STICKY;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
@Override
|
|
|
|
public IBinder onBind(Intent intent) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
stopMonitoring();
|
|
|
|
super.onDestroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void startMonitoring() {
|
|
|
|
synchronized (monitoringLock) {
|
|
|
|
if (isMonitoring) return;
|
|
|
|
|
|
|
|
lastPhotoId = getLastPhotoId();
|
|
|
|
|
|
|
|
contentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
|
|
|
|
@Override
|
|
|
|
public void onChange(boolean selfChange, Uri uri) {
|
|
|
|
super.onChange(selfChange, uri);
|
|
|
|
if (!isRecording && uri != null && uri.toString().contains("images/media")) {
|
|
|
|
checkNewPhotos();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
getContentResolver().registerContentObserver(
|
|
|
|
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
|
|
|
true,
|
|
|
|
contentObserver
|
|
|
|
);
|
|
|
|
|
|
|
|
isMonitoring = true;
|
|
|
|
|
|
|
|
executor.execute(() -> {
|
|
|
|
List<ImageEntity> history = db2.imageDao().getAll();
|
|
|
|
if (history != null && !history.isEmpty()) {
|
|
|
|
synchronized (uploadLock) {
|
|
|
|
for (ImageEntity image : history) {
|
|
|
|
String partname = getPartName(image.blade);
|
|
|
|
if (partid == null) partid = partname;
|
|
|
|
uploadPhoto(image.path, image.time, lastKnownLocation, image.user,
|
|
|
|
image.audioPath, image.project, image.unit, image.blade,
|
|
|
|
partid, image.imageSource, image.unitName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
db2.imageDao().deleteAll();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void stopMonitoring() {
|
|
|
|
synchronized (monitoringLock) {
|
|
|
|
if (!isMonitoring) return;
|
|
|
|
|
|
|
|
if (contentObserver != null) {
|
|
|
|
getContentResolver().unregisterContentObserver(contentObserver);
|
|
|
|
contentObserver = null;
|
|
|
|
}
|
2025-07-25 14:29:27 +08:00
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
isMonitoring=false;
|
|
|
|
}
|
|
|
|
}
|
2025-07-25 14:29:27 +08:00
|
|
|
|
|
|
|
private String getPartName(int b) {
|
2025-07-17 10:53:35 +08:00
|
|
|
return "叶片" +b;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-07-25 14:29:27 +08:00
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
private void checkNewPhotos() {
|
|
|
|
String[] projection = {
|
|
|
|
MediaStore.Images.Media._ID,
|
|
|
|
MediaStore.Images.Media.DATA,
|
|
|
|
MediaStore.Images.Media.DATE_ADDED,
|
|
|
|
MediaStore.Images.Media.DATE_TAKEN,
|
|
|
|
MediaStore.Images.Media.LATITUDE,
|
|
|
|
MediaStore.Images.Media.LONGITUDE
|
|
|
|
};
|
|
|
|
|
|
|
|
String selection = MediaStore.Images.Media._ID + " > ? AND " +
|
|
|
|
MediaStore.Images.Media.DATE_TAKEN + " > 0 AND " +
|
|
|
|
"(" + MediaStore.Images.Media.DATA + " LIKE '%/DCIM/%' OR " +
|
|
|
|
MediaStore.Images.Media.DATA + " LIKE '%/Camera/%')";
|
|
|
|
String[] selectionArgs = new String[]{String.valueOf(lastPhotoId)};
|
|
|
|
|
|
|
|
try (Cursor cursor = getContentResolver().query(
|
|
|
|
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
|
|
|
projection,
|
|
|
|
selection,
|
|
|
|
selectionArgs,
|
|
|
|
MediaStore.Images.Media._ID + " DESC"
|
|
|
|
)) {
|
|
|
|
if (cursor != null) {
|
|
|
|
while (cursor.moveToNext()) {
|
|
|
|
processNewPhoto(cursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
Log.e("PhotoMonitoringService", "Error checking new photos", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void processNewPhoto(Cursor cursor) {
|
|
|
|
long id = cursor.getLong(0);
|
|
|
|
String path = cursor.getString(1);
|
|
|
|
imgpath = path;
|
2025-07-25 14:29:27 +08:00
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
long time = cursor.getLong(2) * 1000;
|
|
|
|
double latitude = cursor.getDouble(3);
|
|
|
|
double longitude = cursor.getDouble(4);
|
|
|
|
double altitude = 0.0;
|
|
|
|
|
|
|
|
if (lastKnownLocation != null) {
|
|
|
|
latitude = lastKnownLocation.getLatitude();
|
|
|
|
longitude = lastKnownLocation.getLongitude();
|
|
|
|
altitude = lastKnownLocation.getAltitude();
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
ExifInterface exif = new ExifInterface(path);
|
|
|
|
String altitudeStr = exif.getAttribute(ExifInterface.TAG_GPS_ALTITUDE);
|
|
|
|
if (altitudeStr != null) {
|
|
|
|
altitude = Double.parseDouble(altitudeStr);
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
Log.e("PhotoMonitoringService", "Error reading EXIF data", e);
|
|
|
|
}
|
|
|
|
|
2025-07-25 14:29:27 +08:00
|
|
|
String audioPath = currentAudioPath;
|
2025-07-17 10:53:35 +08:00
|
|
|
lastPhotoId = Math.max(lastPhotoId, id);
|
|
|
|
|
|
|
|
if (isNetworkAvailable() && !isRecording) {
|
2025-07-25 14:29:27 +08:00
|
|
|
uploadNewPhoto(path, time, audioPath);
|
2025-07-17 10:53:35 +08:00
|
|
|
} else {
|
|
|
|
queuePhotoForLater(path, time, audioPath, latitude, longitude, altitude);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-07-25 14:29:27 +08:00
|
|
|
private void uploadNewPhoto(String path, long time, String audioPath) {
|
2025-07-17 10:53:35 +08:00
|
|
|
executor.execute(() -> {
|
|
|
|
List<ImageEntity> history = db2.imageDao().getAll();
|
|
|
|
if (history != null && !history.isEmpty()) {
|
|
|
|
synchronized (uploadLock) {
|
|
|
|
for (ImageEntity image : history) {
|
|
|
|
String partname = getPartName(image.blade);
|
|
|
|
String ipartid = image.partid;
|
|
|
|
if (ipartid == null) ipartid = partname;
|
|
|
|
uploadPhoto(image.path, image.time, lastKnownLocation,
|
|
|
|
image.user, image.audioPath, image.project,
|
|
|
|
image.unit, image.blade, ipartid, image.imageSource, image.unitName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
db2.imageDao().deleteAll();
|
|
|
|
|
|
|
|
String partname = getPartName(blade);
|
|
|
|
if (partid == null) partid = partname;
|
|
|
|
|
|
|
|
uploadPhoto(path, time, lastKnownLocation, user,
|
|
|
|
audioPath, projectId, unit, blade, partid, ChooseImageSource, unitName);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private void queuePhotoForLater(String path, long time, String audioPath,
|
|
|
|
double latitude, double longitude, double altitude) {
|
|
|
|
executor.execute(() -> {
|
|
|
|
String partname = getPartName(blade);
|
|
|
|
if (partid == null) partid = partname;
|
|
|
|
db2.imageDao().insert(new ImageEntity(path, time, latitude, longitude, altitude,
|
|
|
|
user, audioPath, projectId, unit, blade, false, unitName,
|
|
|
|
Temperator, Humidity, Weather, ChooseImageSource,partid));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private void uploadPhoto(String filePath, long time, Location location, String user,
|
|
|
|
String audioPath, String project, String unit, int blade,
|
2025-07-25 14:29:27 +08:00
|
|
|
String partId, String imageSource, String unitName) {
|
2025-07-17 10:53:35 +08:00
|
|
|
synchronized (uploadLock) {
|
|
|
|
if (isUploading) {
|
|
|
|
queuePhotoForLater(filePath, time, audioPath,
|
|
|
|
location != null ? location.getLatitude() : 0,
|
|
|
|
location != null ? location.getLongitude() : 0,
|
|
|
|
location != null ? location.getAltitude() : 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
executor.execute(() -> {
|
|
|
|
try {
|
|
|
|
File imageFile = new File(filePath);
|
|
|
|
if (!imageFile.exists()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
double latitude = location != null ? location.getLatitude() : 0;
|
|
|
|
double longitude = location != null ? location.getLongitude() : 0;
|
|
|
|
double altitude = location != null ? location.getAltitude() : 0;
|
|
|
|
|
2025-07-25 14:29:27 +08:00
|
|
|
// 构建请求URL
|
|
|
|
HttpUrl.Builder urlBuilder = HttpUrl.parse("http://pms.dtyx.net:9158/image/" + imageSource + "/upload/" + partId)
|
|
|
|
.newBuilder()
|
|
|
|
.addQueryParameter("collectorId",UserId)
|
|
|
|
.addQueryParameter("collectorName", user)
|
|
|
|
.addQueryParameter("humidness", String.valueOf(Humidity))
|
|
|
|
.addQueryParameter("shootingDistance", String.valueOf(0)) // 根据需要设置实际值
|
|
|
|
.addQueryParameter("temperatureMax", String.valueOf(Temperator))
|
|
|
|
.addQueryParameter("temperatureMin", String.valueOf(Temperator))
|
|
|
|
.addQueryParameter("weather", Weather)
|
|
|
|
.addQueryParameter("windLevel", String.valueOf(0)); // 根据需要设置实际值
|
|
|
|
|
|
|
|
// 创建请求体
|
|
|
|
RequestBody requestBody = new MultipartBody.Builder()
|
2025-07-17 10:53:35 +08:00
|
|
|
.setType(MultipartBody.FORM)
|
2025-07-25 14:29:27 +08:00
|
|
|
.addFormDataPart("file", imageFile.getName(),
|
2025-07-17 10:53:35 +08:00
|
|
|
RequestBody.create(imageFile, MediaType.parse("image/*")))
|
2025-07-25 14:29:27 +08:00
|
|
|
.build();
|
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
Request request = new Request.Builder()
|
2025-07-25 14:29:27 +08:00
|
|
|
.url(urlBuilder.build())
|
2025-07-17 10:53:35 +08:00
|
|
|
.post(requestBody)
|
|
|
|
.addHeader("Authorization", token)
|
2025-07-25 14:29:27 +08:00
|
|
|
.addHeader("Content-Type", "application/x-www-form-urlencoded")
|
2025-07-17 10:53:35 +08:00
|
|
|
.build();
|
|
|
|
|
|
|
|
try (Response response = httpClient.newCall(request).execute()) {
|
|
|
|
if (response.isSuccessful()) {
|
2025-07-25 14:29:27 +08:00
|
|
|
// 解析响应数据
|
|
|
|
String responseData = response.body().string();
|
|
|
|
JSONObject jsonResponse = new JSONObject(responseData);
|
|
|
|
JSONObject data = jsonResponse.optJSONObject("data");
|
|
|
|
System.out.println(responseData);
|
|
|
|
String imageId = data != null ? data.optString("imageId") : "";
|
|
|
|
dataManager.setImageId(imageId);
|
|
|
|
dataManager.setOthermsg("partid:"+partid+"\n"+"imageid:"+imageId+"\n"+"response:"+responseData);
|
2025-07-17 10:53:35 +08:00
|
|
|
db.imageDao().insert(new ImageEntity(filePath, time, latitude, longitude, altitude,
|
|
|
|
user, audioPath, project, unit, blade, true, unitName,
|
2025-07-25 14:29:27 +08:00
|
|
|
Temperator, Humidity, Weather, ChooseImageSource, partId));
|
|
|
|
|
|
|
|
totalUploadedCount++;
|
|
|
|
updateNotification(imageId);
|
|
|
|
Intent intent = new Intent("RESPONSE_ACTION");
|
|
|
|
intent.putExtra("response", response.toString());
|
|
|
|
sendBroadcast(intent);
|
|
|
|
long currentTime = System.currentTimeMillis();
|
|
|
|
if (currentTime - lastSuccessToastTime > TOAST_THROTTLE_INTERVAL) {
|
|
|
|
BackgroundToast.show(this, "图片上传成功,已上传" + totalUploadedCount + "张");
|
|
|
|
lastSuccessToastTime = currentTime;
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
db2.imageDao().insert(new ImageEntity(filePath, time, latitude, longitude, altitude,
|
|
|
|
user, audioPath, project, unit, blade, false, unitName,
|
2025-07-25 14:29:27 +08:00
|
|
|
Temperator, Humidity, Weather, ChooseImageSource, partId));
|
|
|
|
dataManager.setImageId("-1");
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
}
|
2025-07-25 14:29:27 +08:00
|
|
|
} catch (Exception e) {
|
2025-07-17 10:53:35 +08:00
|
|
|
db2.imageDao().insert(new ImageEntity(filePath, time, 0, 0, 0,
|
|
|
|
user, audioPath, project, unit, blade, false, unitName,
|
2025-07-25 14:29:27 +08:00
|
|
|
Temperator, Humidity, Weather, ChooseImageSource, partId));
|
|
|
|
dataManager.setImageId("-1");
|
2025-07-17 10:53:35 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2025-07-25 14:29:27 +08:00
|
|
|
private void updateNotification(String msg) {
|
|
|
|
String content = "已成功上传 " + totalUploadedCount + " 张照片"+msg;
|
|
|
|
Notification notification = buildNotification("照片上传服务运行中", content);
|
|
|
|
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
|
|
|
if (manager != null) {
|
|
|
|
manager.notify(NOTIFICATION_ID, notification);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
private boolean isNetworkAvailable() {
|
|
|
|
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
|
|
if (cm == null) return false;
|
|
|
|
|
|
|
|
NetworkCapabilities capabilities = cm.getNetworkCapabilities(cm.getActiveNetwork());
|
|
|
|
return capabilities != null &&
|
|
|
|
(capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
|
|
|
|
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
|
|
|
|
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET));
|
|
|
|
}
|
|
|
|
|
|
|
|
private void createNotificationChannel() {
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
|
NotificationChannel channel = new NotificationChannel(
|
|
|
|
CHANNEL_ID,
|
|
|
|
"照片上传服务",
|
2025-07-25 14:29:27 +08:00
|
|
|
NotificationManager.IMPORTANCE_HIGH
|
2025-07-17 10:53:35 +08:00
|
|
|
);
|
|
|
|
channel.setDescription("显示照片上传状态和进度");
|
|
|
|
NotificationManager manager = getSystemService(NotificationManager.class);
|
|
|
|
manager.createNotificationChannel(channel);
|
|
|
|
}
|
|
|
|
}
|
2025-07-25 14:29:27 +08:00
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
private Notification buildNotification(String title, String content) {
|
|
|
|
return new NotificationCompat.Builder(this, CHANNEL_ID)
|
|
|
|
.setContentTitle(title)
|
|
|
|
.setContentText(content)
|
2025-07-25 14:29:27 +08:00
|
|
|
.setSmallIcon(R.drawable.ic_upload)
|
2025-07-17 10:53:35 +08:00
|
|
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
2025-07-25 14:29:27 +08:00
|
|
|
.setOngoing(true)
|
|
|
|
.setOnlyAlertOnce(true)
|
2025-07-17 10:53:35 +08:00
|
|
|
.addAction(createStopAction())
|
|
|
|
.build();
|
|
|
|
}
|
2025-07-25 14:29:27 +08:00
|
|
|
|
2025-07-17 10:53:35 +08:00
|
|
|
private NotificationCompat.Action createStopAction() {
|
|
|
|
Intent stopIntent = new Intent(this, NotificationReceiver.class);
|
|
|
|
stopIntent.setAction("ACTION_STOP_SERVICE");
|
|
|
|
PendingIntent stopPendingIntent = PendingIntent.getBroadcast(
|
|
|
|
this,
|
|
|
|
0,
|
|
|
|
stopIntent,
|
2025-07-25 14:29:27 +08:00
|
|
|
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
|
2025-07-17 10:53:35 +08:00
|
|
|
|
|
|
|
return new NotificationCompat.Action(
|
|
|
|
R.drawable.ic_stop, "停止", stopPendingIntent);
|
|
|
|
}
|
|
|
|
|
|
|
|
private long getLastPhotoId() {
|
|
|
|
long id = -1;
|
|
|
|
Cursor cursor = getContentResolver().query(
|
|
|
|
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
|
|
|
new String[]{"MAX(" + MediaStore.Images.Media._ID + ")"},
|
|
|
|
null,
|
|
|
|
null,
|
|
|
|
null
|
|
|
|
);
|
|
|
|
|
|
|
|
if (cursor != null && cursor.moveToFirst()) {
|
2025-07-25 14:29:27 +08:00
|
|
|
id = cursor.getLong(0);
|
2025-07-17 10:53:35 +08:00
|
|
|
cursor.close();
|
|
|
|
}
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
}
|