You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
TermApp/mpmaster/src/main/java/com/xypower/mpmaster/MpMasterService.java

1528 lines
57 KiB
Java

package com.xypower.mpmaster;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.SystemClock;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;
import androidx.core.app.NotificationCompat;
import com.dev.devapi.api.SysApi;
import com.xypower.common.FileDownloader;
import com.xypower.common.FilesUtils;
import com.xypower.common.JSONUtils;
import com.xypower.common.LogFormatter;
import com.xypower.common.LogcatHandler;
import com.xypower.common.MicroPhotoContext;
import com.xypower.common.RotatingHandler;
import com.xypower.mpmaster.sms.SimUtil;
import com.xypower.mpmaster.sms.SmsSendReceiver;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.nio.channels.FileLock;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.concurrent.atomic.AtomicInteger;;
public class MpMasterService extends Service {
static {
System.loadLibrary("mpmaster");
}
public static final String TAG = "MPMST";
public Logger logger;
public static final int NOTIFICATION_ID_FOREGROUND_SERVICE = 8466503;
public static final String ACTION_MSG_BROADCAST = "ACT_MSG_BROADCAST";
public static final String ACTION_START = "com.xypower.mpmaster.ACT_START";
public static final String ACTION_STOP = "com.xypower.mpmaster.ACT_STOP";
public static final String ACTION_MAIN = "com.xypower.mpmaster.ACT_MAIN";
public static final String ACTION_REQ_RESTART_APP = "com.xypower.mpmaster.ACT_REQ_RST_APP";
public static final String ACTION_UPD_OTA = SysApi.OTA_RESULT_ACTION;
public static final String ACTION_INSTALL_RESULT = SysApi.INSTALL_RESULT_ACTION;
public static final String ACTION_UNINSTALL_RESULT = SysApi.UNINSTALL_RESULT_ACTION;
private static final String ACTION_UPDATE_CONFIGS = "com.xypower.mpmaster.ACT_UPD_CFG";
private static final String ACTION_HEARTBEAT = "com.xypower.mpmaster.ACT_HB";
private static final String ACTION_TAKE_PHOTO = "com.xypower.mpapp.ACT_TP";
private static final String ACTION_MP_HEARTBEAT_MANUALLY = "com.xypower.mpapp.ACT_HB_M";
public static final String ACTION_MP_RESTART = "com.xypower.mpapp.ACT_RESTART";
public static final String ACTION_IMP_PUBKRY = "com.xypower.mpapp.ACT_IMP_PUBKEY";
private static final String FOREGROUND_CHANNEL_ID = "fg_mpmst";
private SmsSendReceiver mSmsSnedReceiver;
private int mPrevDateForLogs = 0;
private int mMasterTimers = 0;
public static class STATE_SERVICE {
public static final int CONNECTED = 10;
public static final int NOT_CONNECTED = 0;
}
private static int mStateService = STATE_SERVICE.NOT_CONNECTED;
private long mMpHeartbeatDuration = 600000; // = 10minutes Unit: millssecond
private boolean mMntnMode = false;
private boolean mQuickHbMode = false;
private boolean mUsingAbsHbTime = false;
private String mCmdid = "";
private NotificationManager mNotificationManager;
private int mQuickHeartbeatDuration = 60; // Unit: second
private int mHeartbeatDuration = 600; // Unit: second 10m = 10 * 60s
private long mTimeForKeepingLogs = 86400000 * 15; // 15 days
private boolean mSyncTime = false;
private AlarmReceiver mAlarmReceiver = null;
private ScreenActionReceiver mScreenaAtionReceiver = null;
private UpdateReceiver mUpdateReceiver = null;
private Handler mHander = null;
private String mModelName = null;
private static String mMpAppVersion = null;
private static String mMpMasterVersion = null;
private String mSerialNo = null;
private long mTimeToStartMpApp = 0;
private long mTimeOfMpAppAlive = 1800000; // 30minutes
private int mAbsHeartbeatTimes[] = null;
private boolean mSeparateNetwork = false;
private long mDelayedRestartMpTime = 60000;
private PendingIntent mPreviousHB = null;
private long mPreviousHeartbeatTime = 0;
private long mPreviousMpHbTime = 0;
private int mMaxBCV = 0;
private long mMaxBCVTime = 0;
private String mIccid1 = null;
private String mIccid2 = null;
public final static int BROADCAST_REQUEST_CODE_NOTIFICATION = 11;
public final static int BROADCAST_REQUEST_CODE_NOTIFICATION_STOP = 12;
public final static int BROADCAST_REQUEST_CODE_HEARTBEAT = 15;
public final static int BROADCAST_REQUEST_CODE_REAL_HEARTBEAT = 16;
public final static int BROADCAST_REQUEST_CODE_SYS_KEEPALIVE = 17;
public final static int BROADCAST_REQUEST_CODE_RELAUNCH = 18;
//用于创建单例线程保证该线程在项目中唯一
private static final AtomicBoolean created = new AtomicBoolean(false);
public MpMasterService() {
}
@Override
public void onLowMemory() {
final Context context = getApplicationContext();
try {
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, BROADCAST_REQUEST_CODE_RELAUNCH, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 5000, pi);
logger.info("Restart MpApp after 5s as for LowMemory");
} catch (Exception ex) {
ex.printStackTrace();
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "MpMasterService::onCreate");
loadConfig();
loadIccid();
logger = Logger.getLogger("com.xypower.mpmaster.logger");
logger.setLevel(Level.ALL);
// LogFormatter.installFormatter(logger);
LogFormatter logFormatter = new LogFormatter();
if (BuildConfig.DEBUG) {
LogcatHandler logcatHandler = new LogcatHandler(TAG);
logcatHandler.setFormatter(logFormatter);
logger.addHandler(logcatHandler);
}
RotatingHandler rotatingHandler = null;
try {
String appPath = MicroPhotoContext.buildMasterAppDir(getApplicationContext());
String logPath = appPath + "logs";
File fi = new File(logPath);
if (!fi.exists()) {
fi.mkdirs();
}
File logFile = new File(fi, "mlog.txt");
rotatingHandler = new RotatingHandler(logFile.getAbsolutePath(), logFormatter);
logger.addHandler(rotatingHandler);
} catch (Throwable e) {
System.out.println("Failed to create directory:" + e.getMessage());
}
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mSerialNo = Build.getSerial();
} else {
mSerialNo = Build.SERIAL;
}
} catch (Exception ex) {
ex.printStackTrace();
}
mMpMasterVersion = MicroPhotoContext.getVersionName(getApplicationContext());
PackageManager packageManager = getPackageManager();
PackageInfo packageInfo = null;
try {
packageInfo = packageManager.getPackageInfo(MicroPhotoContext.PACKAGE_NAME_MPAPP, 0);
} catch (Exception ex) {
ex.printStackTrace();
}
mMpAppVersion = packageInfo == null ? "" : packageInfo.versionName;
mPreviousMpHbTime = System.currentTimeMillis();
mTimeToStartMpApp = mPreviousMpHbTime;
logger.info("MpMaster started version=" + mMpMasterVersion);
mHander = new Handler();
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mStateService = STATE_SERVICE.NOT_CONNECTED;
mScreenaAtionReceiver = new ScreenActionReceiver();
// 注册广播接受者
{
mAlarmReceiver = new AlarmReceiver(this);
IntentFilter intentFilter = new IntentFilter(ACTION_HEARTBEAT);
intentFilter.addAction(ACTION_MSG_BROADCAST);
intentFilter.addAction(ACTION_UPDATE_CONFIGS);
intentFilter.addAction(ACTION_UPD_OTA);
intentFilter.addAction(ACTION_INSTALL_RESULT);
intentFilter.addAction(ACTION_UNINSTALL_RESULT);
intentFilter.addAction(ACTION_REQ_RESTART_APP);
intentFilter.addAction(MicroPhotoContext.ACTION_HEARTBEAT_MP);
intentFilter.addAction(MicroPhotoContext.ACTION_TAKEPHOTO_MP);
registerReceiver(mAlarmReceiver, intentFilter);
}
{
mUpdateReceiver = new UpdateReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
intentFilter.addDataScheme("package");
registerReceiver(mUpdateReceiver, intentFilter);
}
// SMS broadcast receiver
mSmsSnedReceiver = new SmsSendReceiver();
IntentFilter intentFilter;
intentFilter = new IntentFilter(SimUtil.SMS_SEND_ACTION);
registerReceiver(mSmsSnedReceiver, intentFilter);
}
public String getIccid(int number) {
if (number == 1) {
return mIccid1 == null ? "" : mIccid1;
} else {
return mIccid2 == null ? "" : mIccid2;
}
}
public void cleanLogFiles() {
try {
Date dt = new Date();
if (dt.getDate() == mPrevDateForLogs) {
return;
}
String appPath = MicroPhotoContext.buildMasterAppDir(getApplicationContext());
String logPath = appPath + "logs";
File fi = new File(logPath);
if (!fi.exists()) {
return;
}
mPrevDateForLogs = dt.getDate();
dt.setHours(0);
dt.setMinutes(0);
long millis = dt.getTime() - mTimeForKeepingLogs;
File[] subFiles = fi.listFiles();
for (File f : subFiles) {
if (f.lastModified() < millis) {
f.delete();
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
@Override
public void onDestroy() {
mStateService = STATE_SERVICE.NOT_CONNECTED;
logger.warning("MicroPhotoService::onDestroy called");
unregisterReceiver(mAlarmReceiver);
unregisterReceiver(mScreenaAtionReceiver);
unregisterReceiver(mUpdateReceiver);
unregisterReceiver(mSmsSnedReceiver);
for (java.util.logging.Handler h : logger.getHandlers()) {
try {
h.close();
} catch (Exception ex) {
}
}
Log.i(TAG, "MpMasterService::onDestroy");
super.onDestroy();
}
protected void loadConfig() {
MicroPhotoContext.MasterConfig masterConfig = MicroPhotoContext.getMasterConfig(getApplicationContext());
mMntnMode = masterConfig.mntnMode != 0;
mQuickHbMode = masterConfig.quickHbMode != 0;
mUsingAbsHbTime = masterConfig.usingAbsHbTime != 0;
mHeartbeatDuration = masterConfig.heartbeat * 60; // minute to second
mQuickHeartbeatDuration = masterConfig.quickHeartbeat;
mAbsHeartbeatTimes = masterConfig.absHeartbeats;
if (mAbsHeartbeatTimes != null && mAbsHeartbeatTimes.length > 0) {
Arrays.sort(mAbsHeartbeatTimes);
}
mSeparateNetwork = masterConfig.separateNetwork != 0;
mTimeOfMpAppAlive = masterConfig.mpappMonitorTimeout;
if (masterConfig.timeForKeepingLogs > 0) {
mTimeForKeepingLogs = masterConfig.timeForKeepingLogs * 86400000;
}
mSyncTime = masterConfig.syncTime;
}
private void loadIccid() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
try {
SubscriptionManager sm = SubscriptionManager.from(this);
List<SubscriptionInfo> sis = sm.getActiveSubscriptionInfoList();
if (sis.size() >= 1) {
SubscriptionInfo si1 = sis.get(0);
mIccid1 = si1.getIccId();
// String phoneNum1 = si1.getNumber();
}
if (sis.size() >= 2) {
SubscriptionInfo si2 = sis.get(1);
mIccid2 = si2.getIccId();
// String phoneNum2 = si2.getNumber();
}
// int count = sm.getActiveSubscriptionInfoCount();// real cards
// int max = sm.getActiveSubscriptionInfoCountMax();// Slot number
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
// public boolean useSeparater
public String getCmdid() {
return mCmdid;
}
public boolean isSeparateNetwork() {
return mSeparateNetwork;
}
public boolean isMntnMode() {
return mMntnMode;
}
public boolean shouldSyncTime() {
return mSyncTime;
}
public void detectMpAppAlive() {
final MpMasterService thisObj = this;
Thread th = new Thread(new Runnable() {
@Override
public void run() {
thisObj.detectMpAppAliveImpl();
}
});
th.start();
}
private boolean isMpAppAlive(Context context) {
if (Build.TIME < 1744905600000L) {
// 2025-04-18 old firmware
// Check Log file time
File file = new File(MicroPhotoContext.buildMpAppDir(context) + "logs/log.txt");
if (file.exists()) {
return ((System.currentTimeMillis() - file.lastModified()) < 1800000);
} else {
return false;
}
}
return MicroPhotoContext.isAppAlive(context, MicroPhotoContext.PACKAGE_NAME_MPAPP, MicroPhotoContext.SERVICE_NAME_MPSERVICE);
}
private void detectMpAppAliveImpl() {
try {
final Context context = getApplicationContext();
long ts = System.currentTimeMillis();
try {
int detectionCnt = 4;
if (SystemClock.elapsedRealtime() < 180000) {
// In 3 minutes after device reboot
detectionCnt = 16;
}
boolean isMpAppRunning = false;
for (int idx = 0; idx < detectionCnt; idx++) {
isMpAppRunning = isMpAppAlive(context);
if (isMpAppRunning) {
break;
}
sleep(1000);
}
if (!isMpAppRunning) {
// Restart MpApp
MpMasterService.restartMpApp(context, "MpMST Alive Detection: NO Service Running");
logger.warning("Restart MpAPP as NO Service Running");
mTimeToStartMpApp = ts;
return;
}
} catch (Exception ex) {
ex.printStackTrace();
}
long tempduration = mMpHeartbeatDuration;
if (mMpHeartbeatDuration < 600000) {
tempduration = 600000;
}
if (mPreviousMpHbTime <= ts && (ts - mPreviousMpHbTime) > tempduration * 3) {
// MpApp is not running
if (ts - mTimeToStartMpApp >= 1800000) { // 30 minutes 30 * 60 * 1000
MpMasterService.restartMpApp(context.getApplicationContext(), "MpMST Keep Alive Detection");
String prevMpHBTime = "";
String prevRestartTime = "";
try {
SimpleDateFormat format = new SimpleDateFormat("MM-dd HH:mm:ss");
Date date = new Date(mPreviousMpHbTime);
prevMpHBTime = format.format(date);
Date date2 = new Date(mTimeToStartMpApp);
prevRestartTime = format.format(date2);
} catch (Exception ex) {
ex.printStackTrace();
}
logger.warning("Restart MpAPP as it is NOT Running Prev MPAPP HB=" +
Long.toString((ts - mPreviousMpHbTime) / 1000) + " MPAPP HBDuration=" + Long.toString(tempduration)
+ " Prev MpRestart Time=" + prevRestartTime + " last MPAPPHB =" + prevMpHBTime);
mTimeToStartMpApp = ts;
} else {
logger.warning("MpAPP has restarted during 30min, skip the check.");
}
return;
}
// MpApp is alive
final String appPath = MicroPhotoContext.buildMpAppDir(context);
final File mpappHb = new File(appPath + "data/alive/hb");
final long modifiedTimeOfHb = getFileModificationTime(appPath + "data/alive/hb");
final long modifiedTimeOfPhoto = getFileModificationTime(appPath + "data/alive/taking");
final long modifiedTimeOfUpload = getFileModificationTime(appPath + "data/alive/upload");
if (((ts - modifiedTimeOfHb) > mTimeOfMpAppAlive) ||
((ts - modifiedTimeOfPhoto) > mTimeOfMpAppAlive * 4)// ||
// ((ts - modifiedTimeOfUpload) > mTimeOfMpAppAlive * 4)
) {
if (ts - mTimeToStartMpApp >= 1800000) { // 30 minutes 30 * 60 * 1000
String msg = "Restart MpAPP as it is NOT Running hb=" + Long.toString(ts - modifiedTimeOfHb) +
" taking=" + Long.toString(ts - modifiedTimeOfPhoto) + " sending=" + Long.toString(ts - modifiedTimeOfUpload) +
" Will restart MpApp in " + Long.toString(mDelayedRestartMpTime / 1000) + " seconds";
logger.warning(msg);
MicroPhotoContext.restartMpApp(context, msg, mDelayedRestartMpTime);
mTimeToStartMpApp = ts + mDelayedRestartMpTime / 1000;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
long getFileModificationTime(String path) {
File file = new File(path);
long mt = 0;
if (file.exists()) {
mt = file.lastModified();
}
return mt;
}
public String getMpAppVersion() {
if (!TextUtils.isEmpty(mMpAppVersion)) {
return mMpAppVersion;
}
String version = buildMpAppVersion(getApplicationContext());
mMpAppVersion = version;
return version;
}
public static String buildMpAppVersion(Context context) {
String version = null;
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = null;
try {
packageInfo = packageManager.getPackageInfo(MicroPhotoContext.PACKAGE_NAME_MPAPP, 0);
} catch (Exception ex) {
ex.printStackTrace();
}
version = packageInfo == null ? "" : packageInfo.versionName;
return version;
}
public static void resetVersions(Context context) {
mMpAppVersion = null;
mMpMasterVersion = null;
mMpAppVersion = buildMpAppVersion(context);
}
public String getMasterAppVersion() {
if (TextUtils.isEmpty(mMpMasterVersion)) {
mMpMasterVersion = MicroPhotoContext.getVersionName(getApplicationContext());
}
return mMpMasterVersion;
}
public String getSerialNo() {
return mSerialNo;
}
static String convertSwitch(boolean swtch) {
return swtch ? "ON" : "OFF";
}
public void setMntnMode(boolean mntnMode, boolean quickHbMode) {
boolean oldMntnMode = mMntnMode;
boolean oldQuickHbMode = mQuickHbMode;
mMntnMode = mntnMode;
mQuickHbMode = quickHbMode;
if (oldMntnMode != mntnMode || oldQuickHbMode != quickHbMode) {
MicroPhotoContext.MasterConfig masterConfig = MicroPhotoContext.getMasterConfig(getApplicationContext());
masterConfig.mntnMode = mntnMode ? 1 : 0;
masterConfig.quickHbMode = quickHbMode ? 1 : 0;
MicroPhotoContext.saveMasterConfig(getApplicationContext(), masterConfig);
logger.warning("MNTN Mode Changed from " + convertSwitch(oldMntnMode) + " to " + convertSwitch(mntnMode)
+ " Quick Heartbeat from " + convertSwitch(oldQuickHbMode) + " to " + convertSwitch(quickHbMode));
}
if (oldQuickHbMode != quickHbMode) {
// Cancel cuurent job first
if (quickHbMode) {
registerHeartbeatTimer();
}
}
}
public boolean isCriticalTime() {
if (mSeparateNetwork) {
return true;
}
return (mMasterTimers % 12) == 0;
}
private void startMaster(boolean bundleWithMpApp) {
String masterUrl = MicroPhotoContext.DEFAULT_MASTER_URL;
MicroPhotoContext.MasterConfig masterConfig = MicroPhotoContext.getMasterConfig(getApplicationContext());
String url = masterConfig.getUrl();
if (!TextUtils.isEmpty(url)) {
masterUrl = url;
}
MicroPhotoContext.AppConfig appConfig = MicroPhotoContext.getMpAppConfig(getApplicationContext());
if (appConfig.heartbeat > 0) {
mMpHeartbeatDuration = appConfig.heartbeat * 60000;
}
logger.warning("Start Mntn report: " + masterUrl + " MntnMode=" + (mMntnMode ? "1" : "0") + " QuickHB=" + (mQuickHbMode ? "1" : "0"));
String cmdid = appConfig.cmdid;
if (TextUtils.isEmpty(cmdid)) {
cmdid = getSerialNo();
}
AppMaster appMaster = new AppMaster(this, masterUrl, cmdid, bundleWithMpApp);
appMaster.start(isCriticalTime());
mMasterTimers++;
}
public static class AlarmReceiver extends BroadcastReceiver {
private MpMasterService mService;
public AlarmReceiver() {
mService = null;
}
public AlarmReceiver(MpMasterService service) {
mService = service;
}
public void onReceive(final Context context, final Intent intent) {
mService.mHander.postDelayed(new Runnable() {
@Override
public void run() {
processAction(context, intent);
}
}, 0);
}
public void processAction(final Context context, final Intent intent) {
String action = intent.getAction();
if (TextUtils.equals(ACTION_HEARTBEAT, action)) {
boolean keepAlive = intent.getBooleanExtra("keepAlive", false);
if (keepAlive) {
mService.logger.info("KeepAlive Heartbeat Timer Fired ACTION=" + action);
} else {
mService.logger.info("Heartbeat Timer Fired ACTION=" + action);
}
mService.mPreviousHB = null;
mService.mPreviousHeartbeatTime = 0;
mService.registerHeartbeatTimer();
if (!keepAlive) {
mService.startMaster(false);
}
mService.detectMpAppAlive();
} else if (TextUtils.equals(MicroPhotoContext.ACTION_HEARTBEAT_MP, action)) {
if (intent.hasExtra("HeartbeatDuration")) {
int hbDuration = intent.getIntExtra("HeartbeatDuration", 600000);
mService.mMpHeartbeatDuration = hbDuration > 0 ? hbDuration : 600000;
}
mService.mPreviousMpHbTime = intent.getLongExtra("HeartbeatTime", System.currentTimeMillis());
mService.logger.info("Heartbeat Timer Fired By MpAPP ACTION=" + action + " MpHB=" + Long.toString(mService.mMpHeartbeatDuration) + " HBTime =" + mService.mPreviousMpHbTime);
mService.registerHeartbeatTimer();
if (!mService.mSeparateNetwork && (!mService.mMntnMode)) {
mService.startMaster(true);
}
mService.detectMpAppAlive();
} else if (TextUtils.equals(MicroPhotoContext.ACTION_TAKEPHOTO_MP, action)) {
if (intent.hasExtra("HeartbeatDuration")) {
int hbDuration = intent.getIntExtra("HeartbeatDuration", 600000);
mService.mMpHeartbeatDuration = hbDuration > 0 ? hbDuration : 600000;
mService.mPreviousMpHbTime = intent.getLongExtra("HeartbeatTime", System.currentTimeMillis());
mService.logger.info("Heartbeat Timer Fired By MpAPP ACTION=" + action + " MpHB=" + Long.toString(mService.mMpHeartbeatDuration) + " HBTime =" + mService.mPreviousMpHbTime);
mService.registerHeartbeatTimer();
if (!mService.mSeparateNetwork && (!mService.mMntnMode)) {
mService.startMaster(true);
}
mService.detectMpAppAlive();
}
} else if (TextUtils.equals(ACTION_UPDATE_CONFIGS, action)) {
int restart = intent.getIntExtra("restart", 0);
mService.logger.info("Update Config Fired ACTION=" + action + " restart=" + restart);
if (restart != 0) {
MpMasterService.restartMpMasterApp(context, "Config Updated");
} else {
mService.loadConfig();
mService.registerHeartbeatTimer();
}
} else if (TextUtils.equals(ACTION_UPD_OTA, action)) {
String cmd = intent.getStringExtra("cmd");
String msg = intent.getStringExtra("msg");
// mService.logger.info("cmd=" + cmd + " msg=" + msg);
if ("write".equals(cmd)) {
// int progress = Integer.parseInt(msg);
} else if ("update".equals(cmd)) {
// int progress = Integer.parseInt(msg);
} else if ("info".equals(cmd)) {
} else if ("error".equals(cmd)) {
mService.logger.warning("UPD OTA Failed");
} else if ("success".equals(cmd)) {
//confirm to reboot device ??
mService.logger.warning("UPD OTA Succeeded, will REBOOT device");
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
SysApi.reboot(context);
}
}, 1000);
}
} else if (TextUtils.equals(ACTION_INSTALL_RESULT, action)) {
boolean bSucc = intent.getBooleanExtra("succ", false);
String pkname = intent.getStringExtra("pkname");
String msg = intent.getStringExtra("msg");
// Log.e("_otg_","install result bsuc="+bSucc+",pkname="+pkname+",msg="+msg);
mService.logger.warning("INSTALL APP result =" + bSucc + ",pkname=" + pkname + ",msg=" + msg);
} else if (TextUtils.equals(ACTION_UNINSTALL_RESULT, action)) {
boolean bSucc = intent.getBooleanExtra("succ", false);
String pkname = intent.getStringExtra("pkname");
String msg = intent.getStringExtra("msg");
mService.logger.warning("UNINSTALL APP result =" + bSucc + ",pkname=" + pkname + ",msg=" + msg);
} else if (TextUtils.equals(ACTION_REQ_RESTART_APP, action)) {
try {
String packageName = intent.getStringExtra("packageName");
Intent restartIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
Bundle bundle = intent.getExtras();
bundle.remove("packageName");
restartIntent.putExtras(bundle);
restartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(restartIntent);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
public void installOTA(final String path) {
final Context context = getApplicationContext();
mHander.post(new Runnable() {
@Override
public void run() {
SysApi.installOTA(context, context.getPackageName(), path);
}
});
}
private void registerHeartbeatTimer() {
long timeout = mHeartbeatDuration;
boolean keepAlive = false;
long currentTimeMs = System.currentTimeMillis();
if (mMntnMode) {
if (mQuickHbMode) {
timeout = mQuickHeartbeatDuration;
}
registerHeartbeatTimer(currentTimeMs + timeout * 1000, keepAlive);
} else {
long closestTime = -1;
if (mUsingAbsHbTime) {
Date dt = new Date();
long ts = dt.getTime();
ts -= ts % 1000;
dt.setHours(0);
dt.setMinutes(0);
dt.setSeconds(0);
long zeroPoint = dt.getTime();
zeroPoint -= zeroPoint % 1000;
long offsetTs = (ts - zeroPoint) / 1000;
if (mAbsHeartbeatTimes != null && mAbsHeartbeatTimes.length > 0) {
for (int i = 0; i < mAbsHeartbeatTimes.length; i++) {
if (mAbsHeartbeatTimes[i] > offsetTs) {
closestTime = mAbsHeartbeatTimes[i];
break;
}
}
if (closestTime == -1) {
// next day
closestTime = mAbsHeartbeatTimes[0] + 86400;
}
} else {
closestTime = 9 * 3600 + 13 * 60;
if (offsetTs > closestTime) {
closestTime += 86400;
}
}
if (zeroPoint + closestTime * 1000 > currentTimeMs + mMpHeartbeatDuration) {
keepAlive = true;
registerHeartbeatTimer(currentTimeMs + mMpHeartbeatDuration + 5000, keepAlive);
} else {
registerHeartbeatTimer(zeroPoint + closestTime * 1000, keepAlive);
}
} else {
// mUsingAbsHbTime: false
if ((mPreviousHeartbeatTime != 0) && (mPreviousHeartbeatTime - currentTimeMs < mHeartbeatDuration * 1000)) {
registerHeartbeatTimer(mPreviousHeartbeatTime + mHeartbeatDuration * 1000, keepAlive);
} else {
registerHeartbeatTimer(currentTimeMs + timeout * 1000, keepAlive);
}
}
}
}
private void registerHeartbeatTimer(long triggerTime, boolean keepAlive) {
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
if (mPreviousHB != null) {
try {
logger.info(String.format("Cancel Previos HB: " + format.format(new Date(mPreviousHeartbeatTime))));
alarmManager.cancel(mPreviousHB);
mPreviousHB = null;
} catch (Exception ex) {
}
mPreviousHeartbeatTime = 0;
}
Intent alarmIntent = new Intent();
alarmIntent.setAction(ACTION_HEARTBEAT);
if (keepAlive) {
alarmIntent.putExtra("keepAlive", keepAlive);
}
int reqCode = keepAlive ? BROADCAST_REQUEST_CODE_HEARTBEAT : BROADCAST_REQUEST_CODE_REAL_HEARTBEAT;
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, reqCode, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Date dt = new Date(triggerTime);
if (keepAlive) {
logger.info(String.format("Register KeepAlive HB: " + format.format(dt)) + " MntnMode=" + (mMntnMode ? "1" : "0") + " QuickHb=" + (mQuickHbMode ? "1" : "0"));
} else {
logger.info(String.format("Register HB: " + format.format(dt)) + " MntnMode=" + (mMntnMode ? "1" : "0") + " QuickHb=" + (mQuickHbMode ? "1" : "0"));
}
mPreviousHB = pendingIntent;
mPreviousHeartbeatTime = triggerTime;
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
Intent relaunchIntent = new Intent();
relaunchIntent.putExtra("cmd", "forceLaunch");
relaunchIntent.putExtra("pkname", MicroPhotoContext.PACKAGE_NAME_MPMASTER);
relaunchIntent.setAction("com.xy.xsetting.action");
relaunchIntent.setPackage("com.android.systemui");
// getApplicationContext().sendBroadcast(restartIntent);
long launchTs = System.currentTimeMillis() + (mHeartbeatDuration + 120) * 1000;
PendingIntent sysKAPendingIntent = PendingIntent.getBroadcast(this, BROADCAST_REQUEST_CODE_SYS_KEEPALIVE, relaunchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, launchTs, sysKAPendingIntent);
logger.info(String.format("Register KeepAlive Launch Clock: " + format.format(new Date(launchTs))));
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "MpMasterService::onStartCommand");
if (intent == null) {
stopForeground(true);
stopSelf();
return START_NOT_STICKY;
}
// if user starts the service
switch (intent.getAction()) {
case ACTION_START:
Log.d(TAG, "Received user starts foreground intent");
startForeground(NOTIFICATION_ID_FOREGROUND_SERVICE, prepareNotification());
connect();
registerReceiver(mScreenaAtionReceiver, mScreenaAtionReceiver.getFilter());
String appPath = MicroPhotoContext.buildAppDir(this.getApplicationContext());
String cmdid = intent.getStringExtra("cmdid");
if (TextUtils.isEmpty(cmdid)) {
mCmdid = SysApi.getSerialNo(getApplicationContext());
} else {
mCmdid = cmdid;
}
logger.info("AppPath=" + appPath + " cmdid=" + cmdid);
// startMaster(false);
mHander.postDelayed(new Runnable() {
@Override
public void run() {
detectMpAppAlive();
}
}, 5000);
registerHeartbeatTimer();
startMaster(false);
break;
case ACTION_STOP:
unregisterReceiver(mScreenaAtionReceiver);
stopForeground(true);
stopSelf();
break;
default:
stopForeground(true);
stopSelf();
}
return START_NOT_STICKY;
}
private void connect() {
// after 10 seconds its connected
mHander.postDelayed(
new Runnable() {
public void run() {
// Log.d(TAG, "Bluetooth Low Energy device is connected!!");
Toast.makeText(getApplicationContext(), "MST Connected!", Toast.LENGTH_SHORT).show();
mStateService = STATE_SERVICE.CONNECTED;
startForeground(NOTIFICATION_ID_FOREGROUND_SERVICE, prepareNotification());
}
}, 10000);
}
private Notification prepareNotification() {
// handle build version above android oreo
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O &&
mNotificationManager.getNotificationChannel(FOREGROUND_CHANNEL_ID) == null) {
CharSequence name = getString(R.string.text_name_notification);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(FOREGROUND_CHANNEL_ID, name, importance);
channel.enableVibration(false);
mNotificationManager.createNotificationChannel(channel);
}
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(ACTION_MAIN);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
// if min sdk goes below honeycomb
/*if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
} else {
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}*/
PendingIntent pendingIntent = PendingIntent.getActivity(this, BROADCAST_REQUEST_CODE_NOTIFICATION, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// make a stop intent
Intent stopIntent = new Intent(this, MpMasterService.class);
stopIntent.setAction(ACTION_STOP);
PendingIntent pendingStopIntent = PendingIntent.getService(this, BROADCAST_REQUEST_CODE_NOTIFICATION_STOP, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.notification);
remoteViews.setOnClickPendingIntent(R.id.btn_stop, pendingStopIntent);
// if it is connected
switch (mStateService) {
case STATE_SERVICE.NOT_CONNECTED:
remoteViews.setTextViewText(R.id.tv_state, "DISCONNECTED");
break;
case STATE_SERVICE.CONNECTED:
remoteViews.setTextViewText(R.id.tv_state, "CONNECTED");
break;
}
// notification builder
NotificationCompat.Builder notificationBuilder;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
notificationBuilder = new NotificationCompat.Builder(this, FOREGROUND_CHANNEL_ID);
} else {
notificationBuilder = new NotificationCompat.Builder(this);
}
notificationBuilder
.setContent(remoteViews)
.setSmallIcon(R.drawable.ic_notification_mst)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setOnlyAlertOnce(true)
.setOngoing(true)
.setAutoCancel(true)
.setContentIntent(pendingIntent);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
notificationBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
}
return notificationBuilder.build();
}
public String buildAppDir() {
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
if (!path.endsWith(File.separator)) {
path += File.separator;
}
path += getApplicationContext().getPackageName() + File.separator;
File pathFile = new File(path);
if (!pathFile.exists() && !pathFile.mkdirs()) {
return null;
}
return path;
}
public boolean updateMntn(String url) {
if (TextUtils.isEmpty(url)) {
return false;
}
String path = buildAppDir();
path += "data/Master.json";
JSONObject jsonObject = JSONUtils.loadJson(path);
String oldUrl = null;
try {
oldUrl = jsonObject.getString("url");
} catch (Exception ex) {
ex.printStackTrace();
}
if (TextUtils.equals(url, oldUrl)) {
return true;
}
try {
jsonObject.put("url", url);
} catch (Exception ex) {
ex.printStackTrace();
}
return JSONUtils.saveJson(path, jsonObject);
}
public static int getSignalLevel(int num) {
String result = getSystemProperty("vendor.ril.nw.signalstrength.lte." + Integer.toString(num));
if (TextUtils.isEmpty(result)) {
return 0;
}
String[] items = result.split(",");
int rsrp = -140;
if (items != null && items.length > 0) {
try {
rsrp = Integer.parseInt(items[0]);
} catch (Exception ex) {
}
}
return getSignalLevel(rsrp, num);
}
public static int getSignalLevel(long ss, int num) {
int signalLevel = 0;
if (ss >= -97) {
signalLevel = 4;
} else if (ss >= -107) {
signalLevel = 3;
} else if (ss >= -117) {
signalLevel = 2;
} else if (ss >= -125) {
signalLevel = 1;
} else if (ss >= -140) {
signalLevel = 0;
}
return signalLevel;
}
public String getAndResetMaxBCV() {
String val = Integer.toString(mMaxBCV / 1000) + "." + Integer.toString((mMaxBCV % 1000) / 100)
+ "/" + Long.toString(mMaxBCVTime / 1000);
mMaxBCV = 0;
mMaxBCVTime = 0;
return val;
}
public void downloadAndInstall(final String url) {
final Context context = getApplicationContext();
final String tempPath = MicroPhotoContext.buildAppDir(context) + File.separator + "tmp";
File file = new File(tempPath);
file.mkdirs();
final String filePath = tempPath + File.separator + "mp.apk";
Thread th = new Thread(new Runnable() {
@Override
public void run() {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
PowerManager.WakeLock wl = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "com.xinyingpower.microphoto:Upgrader");
FileDownloader fd = new FileDownloader();
fd.download(url, filePath);
SysApi.installApk(context, filePath, context.getPackageName(), true);
try {
wl.setReferenceCounted(false);
wl.release();
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
th.start();
}
public void reboot(final int rebootType, String reason) {
Runnable runnable = new Runnable() {
@Override
public void run() {
if (rebootType == 0) {
logger.warning("Recv REBOOT MpMst APP cmd");
Context context = MpMasterService.this.getApplicationContext();
MpMasterService.restartMpMasterApp(context, reason);
} else {
logger.warning("Recv RESET cmd");
SysApi.reboot(MpMasterService.this.getApplicationContext());
}
}
};
mHander.postDelayed(runnable, 1000);
}
public int getActiveSlotIndex() {
Context context = getApplicationContext();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
SubscriptionManager subscriptionManager = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
int activeSubId = SubscriptionManager.getActiveDataSubscriptionId();
int activeSlotIdx = SubscriptionManager.getSlotIndex(activeSubId);
return activeSlotIdx + 1;
}
return 0;
}
public void selectSimCard(int num) {
logger.info("Try to Switch To SimCard: " + Integer.toString(num));
Context context = getApplicationContext();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
SubscriptionManager subscriptionManager = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
int activeSubId = SubscriptionManager.getActiveDataSubscriptionId();
int activeSlotIdx = SubscriptionManager.getSlotIndex(activeSubId);
if (activeSlotIdx == (num - 1)) {
logger.info("Active SimCard is already " + Integer.toString(num));
} else {
int subIds[] = subscriptionManager.getSubscriptionIds(num - 1);
if (subIds != null && subIds.length > 0) {
setDefaultDataSubId(subIds[0]);
logger.info("Switched To SimCard: " + Integer.toString(num));
} else {
logger.warning("NO available network for simcard " + Integer.toString(num));
}
}
} else {
SysApi.selectSimCard4Data(context, num);
}
if (num == 1) {
// If it's back to card 1, let MpAPP send heartbeat manully after 10s
mHander.postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent();
intent.setAction(ACTION_MP_HEARTBEAT_MANUALLY);
intent.setPackage(MicroPhotoContext.PACKAGE_NAME_MPAPP);
sendBroadcast(intent);
}
}, 10000);
}
}
private void setDefaultDataSubId(int subId) {
SubscriptionManager subscriptionManager = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
try {
Method method = subscriptionManager.getClass().getDeclaredMethod("setDefaultDataSubId", int.class);
try {
method.invoke(subscriptionManager, subId);
} catch (Exception ex) {
ex.printStackTrace();
}
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
telephonyManager.setDataEnabled(true);
}
Method method1 = telephonyManager.getClass().getDeclaredMethod("setDataEnabled", boolean.class);
method1.invoke(telephonyManager, true);
} catch (Exception e) {
e.printStackTrace();
}
}
private int getDefaultDataSubId() {
SubscriptionManager subscriptionManager = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
try {
Method method = subscriptionManager.getClass().getDeclaredMethod("getDefaultDataSubscriptionId");
return (int) method.invoke(subscriptionManager);
} catch (Exception ex) {
ex.printStackTrace();
}
return 0;
}
//重启运维应用
public static void restartMpMasterApp(Context context, String reason) {
Intent intent = new Intent(context, MainActivity.class);
if (intent != null) {
if (!TextUtils.isEmpty(reason)) {
intent.putExtra("reason", reason);
}
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
context.startActivity(intent);
System.exit(0);
}
//重启MpApp应用
public static void restartMpApp(Context context, String reason) {
forceStopMpApp(context);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//// 然后启动目标应用
try {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(MicroPhotoContext.PACKAGE_NAME_MPAPP);
if (intent != null) {
intent.putExtra("noDelay", 1);
if (!TextUtils.isEmpty(reason)) {
intent.putExtra("reason", reason);
}
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void forceStopMpApp(Context context) {
if (Build.TIME < 1744905600000L) {
SysApi.forceStopApp(context, MicroPhotoContext.PACKAGE_NAME_MPAPP);
} else {
int pid = MicroPhotoContext.getProcessIdOfService(context, MicroPhotoContext.PACKAGE_NAME_MPAPP, MicroPhotoContext.SERVICE_NAME_MPSERVICE);
if (pid != 0) {
android.os.Process.killProcess(pid);
}
}
}
//根据包名重启应用
public static void restartAppByPackage(Context context, String packagename, String reason) {
forceStopMpApp(context);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//// 然后启动目标应用
try {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(packagename);
if (intent != null) {
intent.putExtra("noDelay", 1);
if (!TextUtils.isEmpty(reason)) {
intent.putExtra("reason", reason);
}
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void updateTime(long ms) {
Intent intent = new Intent("com.xy.xsetting.action");
intent.putExtra("cmd", "settime");
intent.putExtra("timemills", ms);
intent.setPackage("com.android.systemui");
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
sendBroadcast(intent);
}
public void reloadMpAppConfigs() {
Intent intent = new Intent();
intent.setAction(MicroPhotoContext.ACTION_UPDATE_CONFIGS_MP);
intent.setPackage(MicroPhotoContext.PACKAGE_NAME_MPAPP);
sendBroadcast(intent);
}
public static boolean initMpAppConfigurations(final Context context) {
boolean existed = true;
String destPath = MicroPhotoContext.buildMpAppDir(context);
File destPathFile = new File(destPath);
if (destPathFile.exists()) {
File dataPath = new File(destPathFile, "data");
if (dataPath.exists()) {
File file = new File(dataPath, "App.json");
if (file.exists()) {
return false;
} else {
existed = false;
}
} else {
existed = false;
try {
dataPath.mkdirs();
} catch (Exception ex) {
ex.printStackTrace();
}
}
} else {
existed = false;
File dataPath = new File(destPathFile, "data");
try {
dataPath.mkdirs();
} catch (Exception ex) {
ex.printStackTrace();
}
}
if (existed) {
return false;
}
Runnable runnable = new Runnable() {
@Override
public void run() {
sleep(5000);
File tmpDestPath = new File(MicroPhotoContext.buildMasterAppDir(context));
tmpDestPath = new File(tmpDestPath, "mpdata");
if (tmpDestPath.exists()) {
try {
tmpDestPath.delete();
} catch (Exception ex) {
ex.printStackTrace();
}
}
copyAssetsDir(context, "mpapp/data", tmpDestPath.getAbsolutePath());
MpMasterService.restartMpApp(context.getApplicationContext(), "FIRST Config Init");
}
};
Thread th = new Thread(runnable);
th.start();
return true;
}
public static boolean initMpMasterConfigurations(final Context context) {
String destPath = MicroPhotoContext.buildMasterAppDir(context);
File destPathFile = new File(destPath);
File dataPath = new File(destPathFile, "data");
File file = new File(dataPath, "Master.json");
if (file.exists()) {
return false;
}
if (!dataPath.exists()) {
try {
dataPath.mkdirs();
} catch (Exception ex) {
ex.printStackTrace();
}
}
copyAssetsDir(context, "mpmst/data", dataPath.getAbsolutePath());
return true;
}
public static void copyAssetsDir(Context context, String directory, String destPath) {
try {
AssetManager assetManager = context.getAssets();
String[] fileList = assetManager.list(directory);
if (fileList != null && fileList.length > 0) {
File file = new File(destPath);
if (!file.exists()) {
file.mkdirs();
}
if (!directory.endsWith(File.separator)) {
directory += File.separator;
}
if (!destPath.endsWith(File.separator)) {
destPath += File.separator;
}
for (String fileName : fileList) {
copyAssetsDir(context, directory + fileName, destPath + fileName);
}
} else {
// Try to file
copyAssetsFile(context, directory, destPath);
}
} catch (Exception e) {
e.printStackTrace();
}
// else {//如果是文件
// InputStream inputStream=context.getAssets().open(filePath);
// File file=new File(context.getFilesDir().getAbsolutePath()+ File.separator+filePath);
// Log.i("copyAssets2Phone","file:"+file);
// if(!file.exists() || file.length()==0) {
// FileOutputStream fos=new FileOutputStream(file);
// int len=-1;
// byte[] buffer=new byte[1024];
// while ((len=inputStream.read(buffer))!=-1){
// fos.write(buffer,0,len);
// }
// fos.flush();
// inputStream.close();
// fos.close();
// showToast(context,"模型文件复制完毕");
// } else {
// showToast(context,"模型文件已存在,无需复制");
// }
// }
}
public static void copyAssetsFile(Context context, String fileName, String destPath) {
InputStream inputStream = null;
FileOutputStream fos = null;
try {
inputStream = context.getAssets().open(fileName);
//getFilesDir() 获得当前APP的安装路径 /data/data/包名/files 目录
File file = new File(destPath);
if (file.exists()) {
file.delete();
}
fos = new FileOutputStream(file);
int len = -1;
byte[] buffer = new byte[1024];
while ((len = inputStream.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
FilesUtils.closeFriendly(inputStream);
FilesUtils.closeFriendly(fos);
}
}
private static void sleep(long ms) {
try {
Thread.sleep(ms);
} catch (Exception ex) {
}
}
public native static int getInt(int cmd);
public native static int setInt(int cmd, int val);
public native static int[] getStats(long ts);
public native static long[] getBatteryInfo();
public native static String getSystemProperty(String key);
public native static void rebootDevice();
//用于将差分包跟老app合并生成新App
public native static boolean applyPatch(String oldFile, String patchFile, String newFile);
//用于将新app跟老app计算生成差分包
public native static boolean applyDiff(String oldFile, String patchFile, String newFile);
////////////////////////GPS////////////////////
}