项目结构优化和AI识别的支持

serial
BlueMatthew 2 years ago
parent 4530a4ed8c
commit db99318e28

@ -223,7 +223,7 @@ Java_com_xypower_mpapp_MicroPhotoService_init(
extern "C" JNIEXPORT jboolean JNICALL
Java_com_xypower_mpapp_MicroPhotoService_notifyToTakePhoto(
JNIEnv* env,
jobject pThis, jlong handler, jint channel, jint preset, jlong scheduleTime, jstring path, jstring fileName, jboolean sendToCma) {
jobject pThis, jlong handler, jint channel, jint preset, jlong scheduleTime, jboolean sendToCma) {
if (channel < 1 || channel > 0xFF)
{

@ -21,6 +21,7 @@
#include "PhoneDevice.h"
#include <Client/Terminal.h>
#include <Utils.h>
#include <LogThread.h>
#include "ncnn/yolov5ncnn.h"
#include <opencv2/opencv.hpp>
@ -242,7 +243,15 @@ void CPhoneDevice::SetRecognizationCfg(const IDevice::CFG_RECOGNIZATION* pRecogn
ncnn_init();
std::string paramFile = m_appPath + (APP_PATH_RECOG_PARAM);
std::string binFile = m_appPath + (APP_PATH_RECOG_BIN);
YoloV5Ncnn_Init(paramFile, binFile);
bool res = YoloV5Ncnn_Init(paramFile, binFile);
if (res)
{
XYLOG(XYLOG_SEVERITY_INFO, "Succeeded to Init NCNN");
}
else
{
XYLOG(XYLOG_SEVERITY_ERROR, "Failed to Init NCNN");
}
}
m_pRecognizationCfg = pRecognizationCfg;
@ -738,11 +747,11 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
// cv::Rect rc(0, 0, mat.cols, mat.rows);
// cv::rectangle (mat, rc, cv::Scalar(255, 255, 255), cv::FILLED);
std::vector<IDevice::RECOG_OBJECT> objs;
if ((m_pRecognizationCfg != NULL) && (m_pRecognizationCfg->enabled != 0) && (mPhotoInfo.recognization != 0))
{
// visualize(ncnnPath.c_str(), in);
std::vector<Object> objs;
#ifdef _DEBUG
double startTime = ncnn::get_current_time();
#endif // _DEBUG
@ -771,7 +780,7 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
};
#endif
cv::Scalar borderColor(m_pRecognizationCfg->borderColor & 0xFF, (m_pRecognizationCfg->borderColor & 0xFF00) >> 8, (m_pRecognizationCfg->borderColor & 0xFF0000) >> 16);
for (std::vector<Object>::const_iterator it = objs.cbegin(); it != objs.cend(); ++it)
for (std::vector<IDevice::RECOG_OBJECT>::const_iterator it = objs.cbegin(); it != objs.cend(); ++it)
{
if (it->label >= m_pRecognizationCfg->items.size())
{
@ -860,7 +869,7 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
{
ALOGI("Succeeded to write photo: %s", fullPath.c_str());
}
TakePhotoCb(res, mPhotoInfo, fullPath, time(NULL));
TakePhotoCb(res, mPhotoInfo, fullPath, time(NULL), objs);
}
else
{

@ -193,11 +193,22 @@ protected:
bool SendBroadcastMessage(std::string action, int value);
// bool MatchCaptureSizeRequest(ACameraManager *cameraManager, const char *selectedCameraId, unsigned int width, unsigned int height, uint32_t cameraOrientation_,
inline bool TakePhotoCb(bool res, const IDevice::PHOTO_INFO& photoInfo, const string& path, time_t photoTime, const std::vector<IDevice::RECOG_OBJECT>& objects) const
{
if (m_listener != NULL)
{
return m_listener->OnPhotoTaken(res, photoInfo, path, photoTime, objects);
}
return false;
}
inline bool TakePhotoCb(bool res, const IDevice::PHOTO_INFO& photoInfo, const string& path, time_t photoTime) const
{
if (m_listener != NULL)
{
return m_listener->OnPhotoTaken(res, photoInfo, path, photoTime);
std::vector<IDevice::RECOG_OBJECT> objects;
return m_listener->OnPhotoTaken(res, photoInfo, path, photoTime, objects);
}
return false;

@ -67,7 +67,8 @@ protected:
{
if (m_listener != NULL)
{
return m_listener->OnPhotoTaken(res, photoInfo, path, photoTime);
std::vector<IDevice::RECOG_OBJECT> objects;
return m_listener->OnPhotoTaken(res, photoInfo, path, photoTime, objects);
}
return false;

@ -9,7 +9,7 @@ ncnn::Net yolov5;
DEFINE_LAYER_CREATOR(YoloV5Focus)
void qsort_descent_inplace(std::vector<Object>& faceobjects, int left, int right)
void qsort_descent_inplace(std::vector<IDevice::RECOG_OBJECT>& faceobjects, int left, int right)
{
int i = left;
int j = right;
@ -46,7 +46,7 @@ void qsort_descent_inplace(std::vector<Object>& faceobjects, int left, int right
}
}
void qsort_descent_inplace(std::vector<Object>& faceobjects)
void qsort_descent_inplace(std::vector<IDevice::RECOG_OBJECT>& faceobjects)
{
if (faceobjects.empty())
return;
@ -54,7 +54,7 @@ void qsort_descent_inplace(std::vector<Object>& faceobjects)
qsort_descent_inplace(faceobjects, 0, faceobjects.size() - 1);
}
void nms_sorted_bboxes(const std::vector<Object>& faceobjects, std::vector<int>& picked, float nms_threshold)
void nms_sorted_bboxes(const std::vector<IDevice::RECOG_OBJECT>& faceobjects, std::vector<int>& picked, float nms_threshold)
{
picked.clear();
@ -68,12 +68,12 @@ void nms_sorted_bboxes(const std::vector<Object>& faceobjects, std::vector<int>&
for (int i = 0; i < n; i++)
{
const Object& a = faceobjects[i];
const IDevice::RECOG_OBJECT& a = faceobjects[i];
int keep = 1;
for (int j = 0; j < (int)picked.size(); j++)
{
const Object& b = faceobjects[picked[j]];
const IDevice::RECOG_OBJECT& b = faceobjects[picked[j]];
// intersection over union
float inter_area = intersection_area(a, b);
@ -88,7 +88,7 @@ void nms_sorted_bboxes(const std::vector<Object>& faceobjects, std::vector<int>&
}
}
void generate_proposals(const ncnn::Mat& anchors, int stride, const ncnn::Mat& in_pad, const ncnn::Mat& feat_blob, float prob_threshold, std::vector<Object>& objects)
void generate_proposals(const ncnn::Mat& anchors, int stride, const ncnn::Mat& in_pad, const ncnn::Mat& feat_blob, float prob_threshold, std::vector<IDevice::RECOG_OBJECT>& objects)
{
const int num_grid = feat_blob.h;
@ -162,7 +162,7 @@ void generate_proposals(const ncnn::Mat& anchors, int stride, const ncnn::Mat& i
float x1 = pb_cx + pb_w * 0.5f;
float y1 = pb_cy + pb_h * 0.5f;
Object obj;
IDevice::RECOG_OBJECT obj;
obj.x = x0;
obj.y = y0;
obj.w = x1 - x0;
@ -177,6 +177,7 @@ void generate_proposals(const ncnn::Mat& anchors, int stride, const ncnn::Mat& i
}
}
// public native boolean Init(AssetManager mgr);
bool YoloV5Ncnn_Init(const std::string& paramFile, const std::string& binFile)
{
@ -221,7 +222,7 @@ bool YoloV5Ncnn_Init(const std::string& paramFile, const std::string& binFile)
}
// public native Obj[] Detect(Bitmap bitmap, boolean use_gpu);
bool YoloV5NcnnDetect( ncnn::Mat& mat, bool use_gpu, std::vector<Object>& objects)
bool YoloV5NcnnDetect( ncnn::Mat& mat, bool use_gpu, std::vector<IDevice::RECOG_OBJECT>& objects)
{
if (use_gpu && ncnn::get_gpu_count() == 0)
{
@ -282,7 +283,7 @@ bool YoloV5NcnnDetect( ncnn::Mat& mat, bool use_gpu, std::vector<Object>& object
ex.input("images", in_pad);
std::vector<Object> proposals;
std::vector<IDevice::RECOG_OBJECT> proposals;
// anchor setting from yolov5/models/yolov5s.yaml
@ -299,7 +300,7 @@ bool YoloV5NcnnDetect( ncnn::Mat& mat, bool use_gpu, std::vector<Object>& object
anchors[4] = 33.f;
anchors[5] = 23.f;
std::vector<Object> objects8;
std::vector<IDevice::RECOG_OBJECT> objects8;
generate_proposals(anchors, 8, in_pad, out, prob_threshold, objects8);
proposals.insert(proposals.end(), objects8.begin(), objects8.end());
@ -318,7 +319,7 @@ bool YoloV5NcnnDetect( ncnn::Mat& mat, bool use_gpu, std::vector<Object>& object
anchors[4] = 59.f;
anchors[5] = 119.f;
std::vector<Object> objects16;
std::vector<IDevice::RECOG_OBJECT> objects16;
generate_proposals(anchors, 16, in_pad, out, prob_threshold, objects16);
proposals.insert(proposals.end(), objects16.begin(), objects16.end());
@ -337,7 +338,7 @@ bool YoloV5NcnnDetect( ncnn::Mat& mat, bool use_gpu, std::vector<Object>& object
anchors[4] = 373.f;
anchors[5] = 326.f;
std::vector<Object> objects32;
std::vector<IDevice::RECOG_OBJECT> objects32;
generate_proposals(anchors, 32, in_pad, out, prob_threshold, objects32);
proposals.insert(proposals.end(), objects32.begin(), objects32.end());
@ -413,7 +414,7 @@ bool YoloV5NcnnDetect( ncnn::Mat& mat, bool use_gpu, std::vector<Object>& object
return true;
}
bool YoloV5NcnnDetect( cv::Mat& mat, bool use_gpu, std::vector<Object>& objects)
bool YoloV5NcnnDetect( cv::Mat& mat, bool use_gpu, std::vector<IDevice::RECOG_OBJECT>& objects)
{
if (use_gpu && ncnn::get_gpu_count() == 0)
{
@ -472,7 +473,7 @@ bool YoloV5NcnnDetect( cv::Mat& mat, bool use_gpu, std::vector<Object>& objects)
ex.input("images", in_pad);
std::vector<Object> proposals;
std::vector<IDevice::RECOG_OBJECT> proposals;
// anchor setting from yolov5/models/yolov5s.yaml
@ -489,7 +490,7 @@ bool YoloV5NcnnDetect( cv::Mat& mat, bool use_gpu, std::vector<Object>& objects)
anchors[4] = 33.f;
anchors[5] = 23.f;
std::vector<Object> objects8;
std::vector<IDevice::RECOG_OBJECT> objects8;
generate_proposals(anchors, 8, in_pad, out, prob_threshold, objects8);
proposals.insert(proposals.end(), objects8.begin(), objects8.end());
@ -508,7 +509,7 @@ bool YoloV5NcnnDetect( cv::Mat& mat, bool use_gpu, std::vector<Object>& objects)
anchors[4] = 59.f;
anchors[5] = 119.f;
std::vector<Object> objects16;
std::vector<IDevice::RECOG_OBJECT> objects16;
generate_proposals(anchors, 16, in_pad, out, prob_threshold, objects16);
proposals.insert(proposals.end(), objects16.begin(), objects16.end());
@ -527,7 +528,7 @@ bool YoloV5NcnnDetect( cv::Mat& mat, bool use_gpu, std::vector<Object>& objects)
anchors[4] = 373.f;
anchors[5] = 326.f;
std::vector<Object> objects32;
std::vector<IDevice::RECOG_OBJECT> objects32;
generate_proposals(anchors, 32, in_pad, out, prob_threshold, objects32);
proposals.insert(proposals.end(), objects32.begin(), objects32.end());

@ -14,6 +14,8 @@
#include <opencv2/opencv.hpp>
#include <Client/Device.h>
extern ncnn::UnlockedPoolAllocator g_blob_pool_allocator;
extern ncnn::PoolAllocator g_workspace_pool_allocator;
@ -65,17 +67,7 @@ public:
}
};
struct Object
{
float x;
float y;
float w;
float h;
int label;
float prob;
};
static inline float intersection_area(const Object& a, const Object& b)
static inline float intersection_area(const IDevice::RECOG_OBJECT& a, const IDevice::RECOG_OBJECT& b)
{
if (a.x > b.x + b.w || a.x + a.w < b.x || a.y > b.y + b.h || a.y + a.h < b.y)
{
@ -89,18 +81,18 @@ static inline float intersection_area(const Object& a, const Object& b)
return inter_width * inter_height;
}
void qsort_descent_inplace(std::vector<Object>& faceobjects, int left, int right);
void qsort_descent_inplace(std::vector<IDevice::RECOG_OBJECT>& faceobjects, int left, int right);
void qsort_descent_inplace(std::vector<Object>& faceobjects);
void qsort_descent_inplace(std::vector<IDevice::RECOG_OBJECT>& faceobjects);
void nms_sorted_bboxes(const std::vector<Object>& faceobjects, std::vector<int>& picked, float nms_threshold);
void nms_sorted_bboxes(const std::vector<IDevice::RECOG_OBJECT>& faceobjects, std::vector<int>& picked, float nms_threshold);
static inline float sigmoid(float x)
{
return static_cast<float>(1.f / (1.f + exp(-x)));
}
void generate_proposals(const ncnn::Mat& anchors, int stride, const ncnn::Mat& in_pad, const ncnn::Mat& feat_blob, float prob_threshold, std::vector<Object>& objects);
void generate_proposals(const ncnn::Mat& anchors, int stride, const ncnn::Mat& in_pad, const ncnn::Mat& feat_blob, float prob_threshold, std::vector<IDevice::RECOG_OBJECT>& objects);
inline void ncnn_init()
{
@ -116,5 +108,5 @@ inline void ncnn_uninit()
bool YoloV5Ncnn_Init(const std::string& paramFile, const std::string& binFile);
// public native Obj[] Detect(Bitmap bitmap, boolean use_gpu);
bool YoloV5NcnnDetect( ncnn::Mat& mat, bool use_gpu, std::vector<Object>& objects);
bool YoloV5NcnnDetect( cv::Mat& mat, bool use_gpu, std::vector<Object>& objects);
bool YoloV5NcnnDetect( ncnn::Mat& mat, bool use_gpu, std::vector<IDevice::RECOG_OBJECT>& objects);
bool YoloV5NcnnDetect( cv::Mat& mat, bool use_gpu, std::vector<IDevice::RECOG_OBJECT>& objects);

@ -20,6 +20,7 @@ import android.util.Pair;
import com.dev.devapi.api.SysApi;
import com.xypower.common.FileDownloader;
import com.xypower.common.MicroPhotoContext;
import org.json.JSONObject;
@ -119,7 +120,7 @@ public class AppMaster {
private void upgradeApp(String url) {
FileDownloader dl = new FileDownloader();
File path = new File(MicroPhotoService.buildAppDir(mService.getApplicationContext()), "packages");
File path = new File(MicroPhotoContext.buildAppDir(mService.getApplicationContext()), "packages");
if (!path.exists()) {
path.mkdirs();
}

@ -8,8 +8,8 @@ import android.text.TextUtils;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import androidx.appcompat.app.ActionBar;
import com.xypower.common.MicroPhotoContext;
import com.xypower.mpapp.databinding.ActivityChannelBinding;
import org.json.JSONException;
@ -99,7 +99,7 @@ public class ChannelActivity extends AppCompatActivity {
binding.exposuretime.setText("0");
binding.sensitivity.setText("0");
String appPath = MicroPhotoService.buildAppDir(getApplicationContext());
String appPath = MicroPhotoContext.buildAppDir(getApplicationContext());
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
@ -169,7 +169,7 @@ public class ChannelActivity extends AppCompatActivity {
private void saveChannelParams(int channel) {
JSONObject jsonObject = null;
String appPath = MicroPhotoService.buildAppDir(this.getApplicationContext());
String appPath = MicroPhotoContext.buildAppDir(this.getApplicationContext());
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
File dataPath = new File(appPath + "data/channels/");

@ -4,13 +4,11 @@ import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.FileObserver;
@ -18,13 +16,13 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.StrictMode;
import android.os.SystemClock;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.core.app.ActivityCompat;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import android.os.Bundle;
import android.telephony.SubscriptionManager;
@ -38,6 +36,7 @@ import android.view.WindowManager;
import android.widget.Toast;
import com.dowse.camera.client.DSCameraManager;
import com.xypower.common.MicroPhotoContext;
import com.xypower.mpapp.databinding.ActivityMainBinding;
import com.xypower.mpapp.utils.RandomReader;
//import com.xinyingpower.microphoto.request.INettyMessageListener;
@ -54,8 +53,6 @@ import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.json.JSONException;
import org.json.JSONObject;
@ -209,6 +206,9 @@ public class MainActivity extends AppCompatActivity {
int width = defaultDisplay.getWidth();
int height = defaultDisplay.getHeight();
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Intent intent = getIntent();
final int noDelay = intent.getIntExtra("noDelay", 0);
int rebootFlag = intent.getIntExtra("reboot", 0);
@ -491,7 +491,7 @@ public class MainActivity extends AppCompatActivity {
// call the superclass method first
super.onStart();
String logFilePath = MicroPhotoService.buildAppDir(this.getApplicationContext());
String logFilePath = MicroPhotoContext.buildAppDir(this.getApplicationContext());
logFilePath += "logs/log.txt";
mLogFileObserver = new LogFileObserver(logFilePath);
@ -557,7 +557,7 @@ public class MainActivity extends AppCompatActivity {
AppConfig appConfig = new AppConfig();
String appPath = MicroPhotoService.buildAppDir(context);
String appPath = MicroPhotoContext.buildAppDir(context);
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
@ -606,7 +606,7 @@ public class MainActivity extends AppCompatActivity {
private void saveAppConfig(String cmdid, String server, int port, int protocol, int networkProtocol) {
String appPath = MicroPhotoService.buildAppDir(this.getApplicationContext());
String appPath = MicroPhotoContext.buildAppDir(this.getApplicationContext());
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
OutputStreamWriter outputStreamWriter = null;

@ -22,7 +22,6 @@ import android.net.wifi.WifiManager;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@ -45,9 +44,12 @@ import android.widget.Toast;
import com.dev.devapi.api.SysApi;
import com.xypower.common.FileDownloader;
import com.xypower.common.InetAddressUtils;
import com.xypower.common.MicroPhotoContext;
import java.io.File;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
@ -255,7 +257,7 @@ public class MicroPhotoService extends Service {
int preset = (int) ((val & 0xFF00L) >> 8);
Log.i(TAG, "PhotoTimer Fired: CH=" + channel + " PR=" + preset);
mService.notifyToTakePhoto(mService.mNativeHandle, channel, preset, ts, mService.buildPhotoDir(mService.getApplicationContext(), channel), mService.buildPhotoFileName(channel, preset, ts), true);
mService.notifyToTakePhoto(mService.mNativeHandle, channel, preset, ts, true);
}
}
@ -277,7 +279,7 @@ public class MicroPhotoService extends Service {
long ts = System.currentTimeMillis() / 1000;
Log.i(TAG, "Take Photo CH=" + channel + " PR=" + preset + " Mannually");
mService.notifyToTakePhoto(mService.mNativeHandle, channel, preset, ts, mService.buildPhotoDir(mService.getApplicationContext(), channel), mService.buildPhotoFileName(channel, preset, ts), photoOrVideo);
mService.notifyToTakePhoto(mService.mNativeHandle, channel, preset, ts, photoOrVideo);
} else if (TextUtils.equals(ACTION_TIMEOUT, action)) {
long uid = intent.getLongExtra(EXTRA_PARAM_TIMER_UID, 0);
long expectedTimes = intent.getLongExtra(EXTRA_PARAM_TIMES, 0);
@ -524,18 +526,31 @@ public class MicroPhotoService extends Service {
mMessenger = intent.getParcelableExtra("messenger");
}
String appPath = buildAppDir(this.getApplicationContext());
String appPath = MicroPhotoContext.buildAppDir(this.getApplicationContext());
String ip = intent.getStringExtra("server");
String server = intent.getStringExtra("server");
int port = intent.getIntExtra("port", 0);
String cmdid = intent.getStringExtra("cmdid");
int protocol = intent.getIntExtra("protocol", 0);
int networkProtocol = intent.getIntExtra("networkProtocol", 0);
Log.i(TAG, "AppPath=" + appPath + " Server=" + ip + ":" + port + " cmdid=" + cmdid + " Protocol=" + protocol + " Network=" + networkProtocol);
if (!InetAddressUtils.isIPv4Address(server) && !InetAddressUtils.isIPv6Address(server)) {
// It is a domain
InetAddress addr = null;
try {
addr = InetAddress.getByName(server);
} catch (Exception e) {
e.printStackTrace();
}
if (addr != null) {
server = addr.getHostAddress();
}
}
Log.i(TAG, "AppPath=" + appPath + " Server=" + server + ":" + port + " cmdid=" + cmdid + " Protocol=" + protocol + " Network=" + networkProtocol);
MicroPhotoService service = MicroPhotoService.this;
service.mNativeHandle = init(appPath, ip, port, cmdid, protocol, networkProtocol);
service.mNativeHandle = init(appPath, server, port, cmdid, protocol, networkProtocol);
if (service.mNativeHandle !=0) {
service.mCmdid = cmdid;
@ -676,58 +691,6 @@ public class MicroPhotoService extends Service {
return notificationBuilder.build();
}
public static String buildAppDir(Context contxt) {
/*
File[] paths = contxt.getExternalFilesDirs(null);
if (paths == null || paths.length == 0) {
return null;
}
File path = paths[0];
*/
File path = new File(Environment.getExternalStorageDirectory(), contxt.getPackageName() + "/");
if (!path.exists() && !path.mkdirs()) {
return null;
}
String p = path.getAbsolutePath();
if (!p.endsWith(File.separator)) {
p += File.separator;
}
return p;
}
public static String buildPhotoDir(Context contxt, int channel) {
// File path = new File(Environment.getExternalStorageDirectory(), "com.xinyingpower.mp/photos/");
String appDir = buildAppDir(contxt);
if (appDir == null) {
return null;
}
File path = new File(appDir, "photos/");
if (!path.exists() && !path.mkdirs()) {
return null;
}
String p = path.getAbsolutePath();
if (!p.endsWith(File.separator)) {
p += File.separator;
}
return p;
}
private String buildPhotoFileName(int channel, int preset, long ts) {
LocalDateTime nowDT = LocalDateTime.now();
String date = nowDT.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss.S"));
String photoFile = "img_" + Integer.toString(channel) + "_" + Integer.toHexString(preset).toUpperCase() + "_" + date + ".jpg";
return photoFile;
}
public boolean updateTime(long timeInMillis) {
try {
SysApi.setSystemTime(getApplicationContext(), timeInMillis);
@ -773,7 +736,7 @@ public class MicroPhotoService extends Service {
public void downloadAndInstall(final String url) {
final Context context = getApplicationContext();
final String tempPath = buildAppDir(context) + File.separator + "tmp";
final String tempPath = MicroPhotoContext.buildAppDir(context) + File.separator + "tmp";
File file = new File(tempPath);
file.mkdirs();
final String filePath = tempPath + File.separator + "mp.apk";
@ -919,7 +882,7 @@ cellSignalStrengthGsm.getDbm();
protected native long getHeartbeatDuration(long handler);
protected native long[] getPhotoTimeData(long handler);
// protected native long[] getNextScheduleItem(long handler);
protected native boolean notifyToTakePhoto(long handler, int channel, int preset, long scheduleTime, String path, String fileName, boolean sendToCma);
protected native boolean notifyToTakePhoto(long handler, int channel, int preset, long scheduleTime, boolean sendToCma);
protected native boolean sendHeartbeat(long handler);
protected native boolean fireTimeout(long handler, long uid, long times);
protected native void updatePosition(long handler, double lon, double lat, long ts);

@ -25,7 +25,8 @@
android:layout_marginLeft="4dp"
android:layout_marginTop="8dp"
android:ems="10"
android:inputType="none"
android:maxLines="1"
android:inputType="text"
android:imeOptions="actionDone"
android:singleLine="true"
android:text="XY-ANDROIDSIM-001"
@ -58,7 +59,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:ems="10"
android:inputType="none"
android:maxLines="1"
android:inputType="text"
android:imeOptions="actionDone"
android:text="47.96.238.157"
app:layout_constraintStart_toStartOf="@+id/cmdid"
@ -71,6 +73,7 @@
android:ems="10"
android:inputType="none|number"
android:imeOptions="actionDone"
android:maxLines="1"
android:text="6891"
app:layout_constraintBottom_toBottomOf="@+id/server"
app:layout_constraintLeft_toRightOf="@+id/server"

@ -5,6 +5,7 @@
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryDark">@color/purple_700</item>
<item name="colorAccent">@color/teal_200</item>
<item name="android:textSize">12sp</item>
<!-- Customize your theme here. -->
</style>
</resources>

@ -5,7 +5,7 @@
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryDark">@color/purple_700</item>
<item name="colorAccent">@color/teal_200</item>
<item name="android:textSize">14sp</item>
<item name="android:textSize">12sp</item>
</style>
</resources>

@ -32,5 +32,5 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation files('libs/devapi.aar')
compileOnly files('libs/devapi.aar')
}

@ -0,0 +1,28 @@
package com.xypower.common;
import java.util.regex.Pattern;
public class InetAddressUtils {
// String regex = "^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$";
private static final Pattern IPV4_PATTERN = Pattern.compile("^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
private static final Pattern IPV6_STD_PATTERN = Pattern.compile("^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");
private static final Pattern IPV6_HEX_COMPRESSED_PATTERN = Pattern.compile("^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");
public static boolean isIPv4Address(final String input) {
return IPV4_PATTERN.matcher(input).matches();
}
public static boolean isIPv6StdAddress(final String input) {
return IPV6_STD_PATTERN.matcher(input).matches();
}
public static boolean isIPv6HexCompressedAddress(final String input) {
return IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
}
public static boolean isIPv6Address(final String input) {
return isIPv6StdAddress(input) || isIPv6HexCompressedAddress(input);
}
}

@ -1,4 +1,27 @@
package com.xypower.common;
import android.content.Context;
import android.os.Environment;
import java.io.File;
public class MicroPhotoContext {
public static final String PACKAGE_NAME_MPAPP = "com.xypower.mpapp";
public static final String PACKAGE_NAME_MPMASTER = "com.xypower.mpmaster";
public final static String MASTER_URL = "http://180.166.218.222:40101/?cmdid=";
public static String buildAppDir(Context contxt) {
File path = new File(Environment.getExternalStorageDirectory(), contxt.getPackageName() + "/");
if (!path.exists() && !path.mkdirs()) {
return null;
}
String p = path.getAbsolutePath();
if (!p.endsWith(File.separator)) {
p += File.separator;
}
return p;
}
}

@ -36,4 +36,5 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation files('libs/devapi.aar')
}

Binary file not shown.

@ -7,15 +7,20 @@
<application
android:allowBackup="true"
android:requestLegacyExternalStorage="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MpMaster"
tools:targetApi="31">
<service
android:name=".MicroPhotoService"
android:enabled="true"
android:exported="true"></service>
<activity
android:name=".MainActivity"
android:exported="true">
@ -29,7 +34,7 @@
<receiver
android:name=".UpdateReceiver"
android:enabled="true"
android:exported="true" >
android:exported="true">
<intent-filter android:priority="90000">
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REPLACED" />

@ -0,0 +1,211 @@
package com.xypower.mpmaster;
import android.content.Context;
import android.os.PowerManager;
import android.text.TextUtils;
import android.util.Pair;
import com.dev.devapi.api.SysApi;
import com.xypower.common.FileDownloader;
import com.xypower.common.MicroPhotoContext;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
public class AppMaster {
private MicroPhotoService mService;
private String mCmdid;
private PowerManager.WakeLock mWakelock;
public AppMaster(MicroPhotoService service, String cmdid) {
PowerManager powerManager = (PowerManager) service.getSystemService(Context.POWER_SERVICE);
mWakelock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "com.xinyingpower.microphoto:Upgrader");
mService = service;
mCmdid = cmdid;
}
@Override
protected void finalize() {
try {
if (mWakelock != null) {
mWakelock.release();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
mWakelock = null;
}
mService = null;
}
public void start() {
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection httpURLConnection = null;
InputStream inputStream = null;
try {
String url = MicroPhotoContext.MASTER_URL + URLEncoder.encode(mCmdid, "UTF-8");
URL mUrl = new URL(url);
httpURLConnection = (HttpURLConnection) mUrl.openConnection();
httpURLConnection.setConnectTimeout(15000);
httpURLConnection.setReadTimeout(15000);
httpURLConnection.setRequestMethod("POST");
// httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true);
List<Pair<String, String>> postParams = new ArrayList<>();
postParams.add(new Pair<String, String>("id", mCmdid));
// postParams(httpURLConnection.getOutputStream(), postParams);
buildParams(httpURLConnection.getOutputStream());
httpURLConnection.connect();
inputStream = httpURLConnection.getInputStream();
int responseCode = httpURLConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
//在子线程中不能操作UI线程通过handler在UI线程中进行操作
// handler.sendEmptyMessage(0x00);
String response = convertStreamToString(inputStream);
process(response);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
private void process(String content) {
if (TextUtils.isEmpty(content)) {
return;
}
try {
JSONObject jsonObject = new JSONObject(content);
int isUpgrade = jsonObject.optInt("isUpgrade", 0);
String url = jsonObject.optString("url", null);
if (isUpgrade == 1 && !TextUtils.isEmpty(url)) {
upgradeApp(url);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void upgradeApp(String url) {
FileDownloader dl = new FileDownloader();
File path = new File(MicroPhotoContext.buildAppDir(mService.getApplicationContext()), "packages");
if (!path.exists()) {
path.mkdirs();
}
File file = new File(path, "app.apk");
if (file.exists()) {
file.delete();
}
String apkPath = file.getAbsolutePath();
if (dl.download(url, apkPath)) {
Context context = mService.getApplicationContext();
SysApi.installApk(context, apkPath, context.getPackageName(), true);
}
}
private void buildParams(OutputStream output) {
BufferedWriter bufferedWriter = null;
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", mCmdid);
bufferedWriter = new BufferedWriter(new OutputStreamWriter(output, "UTF-8"));
bufferedWriter.write(jsonObject.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bufferedWriter != null) {
bufferedWriter.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void postParams(OutputStream output, List<Pair<String, String>> paramsList) {
BufferedWriter bufferedWriter = null;
try {
StringBuilder stringBuilder = new StringBuilder();
for (Pair<String, String> pair : paramsList) {
if (!TextUtils.isEmpty(stringBuilder)) {
stringBuilder.append("&");
}
stringBuilder.append(URLEncoder.encode(pair.first, "UTF-8"));
stringBuilder.append("=");
stringBuilder.append(URLEncoder.encode(pair.second, "UTF-8"));
bufferedWriter = new BufferedWriter(new OutputStreamWriter(output, "UTF-8"));
bufferedWriter.write(stringBuilder.toString());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bufferedWriter != null) {
bufferedWriter.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private String convertStreamToString(InputStream inputStream) {
BufferedReader bufferedReader = null;
StringBuffer stringBuffer = new StringBuffer();
String line;
try {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
while ((line = bufferedReader.readLine()) != null) {
stringBuffer.append(line).append("\n");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bufferedReader != null) {
bufferedReader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return stringBuffer.toString();
}
}

@ -0,0 +1,16 @@
package com.xypower.mpmaster;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MicroPhotoService extends Service {
public MicroPhotoService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
Loading…
Cancel
Save