package com.xypower.mpapp; import android.Manifest; import android.app.Activity; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.location.Location; import android.location.LocationListener; import android.net.Uri; import android.os.Build; import android.os.Handler; import android.os.Messenger; import android.os.PowerManager; import android.os.StrictMode; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.core.app.ActivityCompat; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.os.SystemClock; import android.provider.Settings; import android.telephony.SubscriptionManager; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.WindowManager; import android.widget.Toast; import com.dev.devapi.api.SysApi; import com.xypower.common.CameraUtils; import com.xypower.common.FilesUtils; import com.xypower.common.MicroPhotoContext; import com.xypower.mpapp.databinding.ActivityMainBinding; import com.xypower.mpapp.utils.LocationUtil; import java.io.File; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Date; public class MainActivity extends AppCompatActivity { public static final String TAG = "MPLOG"; private static int MY_PERMISSIONS_REQUEST_FOREGROUND_SERVICE = 100; // Used to load the 'microphoto' library on application startup. private ActivityMainBinding binding; private Messenger mMessenger = null; private long mConfigModificationTime = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "Start inflate"); binding = ActivityMainBinding.inflate(getLayoutInflater()); Log.d(TAG, "Finish inflate"); setContentView(binding.getRoot()); // getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); try { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) { int activeSubId = SubscriptionManager.getActiveDataSubscriptionId(); if (activeSubId == -1) { MicroPhotoContext.selectSimCard(getApplicationContext(), 1); } } ActionBar actionBar = getSupportActionBar(); Date date = new Date(BuildConfig.BUILD_TIMESTAMP); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); String caption = "MP"; switch (MicroPhotoService.getCustomAppId()) { case 1: caption = "RP"; break; case 2: caption = "N938"; break; default: break; } caption += " v" + MicroPhotoContext.getVersionName(getApplicationContext()) + " " + sdf.format(date); sdf = new SimpleDateFormat("MM-dd HH:mm:ss"); caption += " / " + sdf.format(new Date()); actionBar.setTitle(caption); StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); initListener(); Context appContext = getApplicationContext(); String appPath = MicroPhotoContext.buildMpAppDir(appContext); File appPathFile = new File(appPath); if (!appPathFile.exists()) { try { appPathFile.mkdirs(); } catch (Exception ex) { ex.printStackTrace(); } } if (!MicroPhotoContext.hasMpAppConfig(appContext)) { String mstPath = MicroPhotoContext.buildMpResAppDir(appContext); File mstPathFile = new File(mstPath); File mpdataFile = new File(mstPathFile, "mpdata"); if (mpdataFile.exists()) { File dataFile = new File(appPathFile, "data"); if (dataFile.exists()) { try { FilesUtils.delete(dataFile); } catch (Exception ex) { ex.printStackTrace(); } } try { mpdataFile.renameTo(dataFile); } catch (Exception ex) { ex.printStackTrace(); } } else { Intent resIntent = getPackageManager().getLaunchIntentForPackage(MicroPhotoContext.PACKAGE_NAME_MPRES); if (resIntent != null) { resIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); resIntent.putExtra("initres", 1); String sn = MicroPhotoService.getSerialNumber(); if (!TextUtils.isEmpty(sn)) { resIntent.putExtra("sn", sn); } startActivity(resIntent); } } } Intent intent = getIntent(); final int noDelay = intent.getIntExtra("noDelay", 0); int rebootFlag = intent.getIntExtra("reboot", 0); String reason = intent.getStringExtra("reason"); if (!TextUtils.isEmpty(reason)) { Log.w(TAG, "App Started with reason: " + reason); } if (rebootFlag == 1) { Log.i(TAG, "After Reboot"); } Log.d(TAG, "MainActivity: reboot=" + rebootFlag + " noDelay=" + noDelay); MicroPhotoContext.AppConfig appConfig = loadConfigInfo(); binding.btnStartServ.setEnabled(!MicroPhotoService.isRunning); binding.btnStopServ.setEnabled(MicroPhotoService.isRunning); if (MicroPhotoService.isRunning) { Intent intent2 = new Intent(MainActivity.this, MicroPhotoService.class); try { // stopService(intent2); } catch (Exception ex) { ex.printStackTrace(); } } if (MicroPhotoContext.hasMpAppConfig(appContext)) { final Runnable runnable = new Runnable() { @Override public void run() { if (!MicroPhotoService.isRunning && !TextUtils.isEmpty(appConfig.cmdid) && !TextUtils.isEmpty(appConfig.server) && appConfig.port != 0) { if (binding.btnStartServ.isEnabled()) { Log.i(TAG, "Perform AutoStart"); binding.btnStartServ.performClick(); } } } }; long timeout = 500; if (SystemClock.elapsedRealtime() < 180000) { // In 3 minutes timeout = 10000; // in 10 seconds } Handler handler = new Handler(); handler.postDelayed(runnable, timeout); Log.i(TAG, "Set AutoStart after " + Long.toString(timeout) + "ms"); } } catch (Exception ex) { ex.printStackTrace(); } } @Override protected void onDestroy() { super.onDestroy(); } @Override protected void onResume() { super.onResume(); try { File file = MicroPhotoContext.getMpAppConfigFile(getApplicationContext()); if (file.lastModified() > mConfigModificationTime) { loadConfigInfo(); } } catch (Exception ex) { ex.printStackTrace(); } } protected MicroPhotoContext.AppConfig loadConfigInfo() { final MicroPhotoContext.AppConfig appConfig = MicroPhotoContext.getMpAppConfig(getApplicationContext()); mConfigModificationTime = appConfig.modificationTime; if (TextUtils.isEmpty(appConfig.cmdid)) { appConfig.cmdid = MicroPhotoService.getSerialNumber(); binding.cmdid.setText(appConfig.cmdid); } else { binding.cmdid.setText(appConfig.cmdid); } binding.server.setText(appConfig.server); binding.port.setText(appConfig.port != 0 ? Integer.toString(appConfig.port) : ""); String protocolStr = appConfig.protocol + "-"; for (int idx = 0; idx < binding.protocol.getCount(); idx++) { String item = binding.protocol.getItemAtPosition(idx).toString(); if (item.startsWith(protocolStr)) { binding.protocol.setSelection(idx); break; } } protocolStr = appConfig.networkProtocol + "-"; for (int idx = 0; idx < binding.networkProtocol.getCount(); idx++) { String item = binding.networkProtocol.getItemAtPosition(idx).toString(); if (item.startsWith(protocolStr)) { binding.networkProtocol.setSelection(idx); break; } } if (appConfig.encryption < binding.encryptions.getCount()) { binding.encryptions.setSelection(appConfig.encryption); } binding.heartbeat.setText((appConfig.heartbeat > 0) ? Integer.toString(appConfig.heartbeat) : ""); binding.packetSize.setText((appConfig.packetSize > 0) ? Integer.toString(appConfig.packetSize) : ""); if (appConfig.network < binding.network.getCount()) { binding.network.setSelection(appConfig.network); } return appConfig; } protected void initListener() { this.binding.btnStartServ.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String[] accessPermissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.FOREGROUND_SERVICE, Manifest.permission.READ_PHONE_STATE, /*Manifest.permission.PACKAGE_USAGE_STATS,*/ /*Manifest.permission.SET_TIME,*/}; boolean needRequire = false; for (String access : accessPermissions) { int curPermission = ActivityCompat.checkSelfPermission(MainActivity.this, access); if (curPermission != PackageManager.PERMISSION_GRANTED) { needRequire = true; break; } } if (needRequire) { ActivityCompat.requestPermissions(MainActivity.this, accessPermissions, MY_PERMISSIONS_REQUEST_FOREGROUND_SERVICE); // return; } Context appContext = getApplicationContext(); MicroPhotoContext.AppConfig curAppConfig = MicroPhotoContext.getMpAppConfig(appContext); if (TextUtils.isEmpty(curAppConfig.cmdid)) { curAppConfig.cmdid = MicroPhotoService.getSerialNumber(); } startMicroPhotoService(appContext, curAppConfig, mMessenger); Log.i(TAG, "Service auto-started"); binding.btnStartServ.setEnabled(false); binding.btnStopServ.setEnabled(true); } }); this.binding.btnSaveCfg.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View view) { MicroPhotoContext.AppConfig appCfg = MicroPhotoContext.getMpAppConfig(getApplicationContext()); String protocolStr = MainActivity.this.binding.protocol.getSelectedItem().toString(); int protocol = MicroPhotoContext.DEFAULT_PROTOCOL; String[] parts = protocolStr.split("-"); if (parts != null) { protocol = Integer.parseInt(parts[0]); } if (appCfg.protocol != protocol) { AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); builder.setTitle(R.string.confirm_change_protocol); builder.setMessage(R.string.confirm_change_protocol_text); builder.setCancelable(true); builder.setPositiveButton(R.string.btn_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { dialogInterface.dismiss(); retrieveAndSaveAppConfig(); MicroPhotoContext.removeMpConfigFiles(getApplicationContext()); MicroPhotoService.updateConfigs(MainActivity.this.getApplicationContext()); } }); builder.setNegativeButton(R.string.btn_cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { dialogInterface.dismiss(); } }); builder.show(); } else { retrieveAndSaveAppConfig(); MicroPhotoService.updateConfigs(MainActivity.this.getApplicationContext()); } } }); this.binding.btnTakePhoto.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { takePhoto(1, 255, true); } }); this.binding.btnTakePhoto2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { takePhoto(2, 255, true); } }); this.binding.btnTakePhoto3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { takePhoto(3, 255, true); } }); this.binding.btnTakePhoto4.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { takePhoto(4, 255, true); } }); this.binding.takeVideoBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { takePhoto(1, 255, false); } }); this.binding.takeVideoBtn2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { takePhoto(2, 255, false); } }); this.binding.takeVideoBtn3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { takePhoto(3, 255, false); } }); this.binding.takeVideoBtn4.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { takePhoto(4, 255, false); } }); this.binding.btnStopServ.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { MicroPhotoService.infoLog("Call stopTerminalService Manually"); MicroPhotoService.stopTerminalService(getApplicationContext()); binding.btnStartServ.setEnabled(true); binding.btnStopServ.setEnabled(false); } }); binding.btnChannels.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, ChannelActivity.class); startActivity(intent); } }); binding.btnLogs.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, LogActivity.class); startActivity(intent); } }); binding.btnSendHb.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MicroPhotoService.sendHeartbeat(getApplicationContext()); } }); binding.btnRestartApp.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { restartSelfWithStartActivity(); // restartSelfWithAlarmManager(); } private void restartSelfWithStartActivity() { final Context context = getApplicationContext(); Intent intent = new Intent(context, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); int noDelay = 1; intent.putExtra("noDelay", noDelay); intent.putExtra("reason", "Manual Restart From MainActivity"); context.startActivity(intent); final Handler handler = new Handler(); finish(); handler.postDelayed(new Runnable() { @Override public void run() { System.exit(0); } }, 0); } private void restartSelfWithAlarmManager() { Intent intent = new Intent(MainActivity.this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); int noDelay = 1; intent.putExtra("noDelay", noDelay); intent.putExtra("reason", "Manual Restart From MainActivity"); // Create PendingIntent PendingIntent pendingIntent = PendingIntent.getActivity( MainActivity.this, 12312, intent, PendingIntent.FLAG_UPDATE_CURRENT/* | PendingIntent.FLAG_IMMUTABLE*/); AlarmManager alarmManager = (AlarmManager) MainActivity.this.getSystemService(Context.ALARM_SERVICE); if (alarmManager != null) { alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 200, pendingIntent); } MainActivity.this.finish(); System.exit(0); } }); binding.btnReboot.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext()); builder.setTitle(R.string.confirm_reboot); builder.setMessage(R.string.text_confirm_reboot); builder.setCancelable(true); builder.setPositiveButton(R.string.btn_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { dialogInterface.dismiss(); SysApi.reboot(v.getContext().getApplicationContext()); } }); builder.setNegativeButton(R.string.btn_cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { dialogInterface.dismiss(); } }); builder.show(); } }); binding.btnCameraInfo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { MicroPhotoService.setCam3V3Enable(true); Runnable runnable = new Runnable() { @Override public void run() { String cameraInfo = CameraUtils.getAllCameraInfo(view.getContext()); Log.d(TAG, cameraInfo); MicroPhotoService.setCam3V3Enable(false); MicroPhotoService.infoLog(cameraInfo); Toast.makeText(view.getContext(), cameraInfo, Toast.LENGTH_LONG).show(); } }; Handler handler = new Handler(); handler.postDelayed(runnable, 1500); } }); } public static void startMicroPhotoService(Context context, MicroPhotoContext.AppConfig curAppConfig, Messenger messenger) { if (TextUtils.isEmpty(curAppConfig.cmdid) || TextUtils.isEmpty(curAppConfig.server) || curAppConfig.port == 0) { return; } Intent intent = new Intent(context, MicroPhotoService.class); intent.setAction(MicroPhotoService.ACTION_START); intent.putExtra("cmdid", curAppConfig.cmdid); intent.putExtra("server", curAppConfig.server); intent.putExtra("port", curAppConfig.port); intent.putExtra("protocol", curAppConfig.protocol); intent.putExtra("networkProtocol", curAppConfig.networkProtocol); intent.putExtra("encryption", curAppConfig.encryption); intent.putExtra("network", curAppConfig.network); if (messenger != null) { intent.putExtra("messenger", messenger); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(intent); } else { context.startService(intent); } } private void takePhoto(int channel, int preset, boolean photoOrVideo) { if (binding.btnStartServ.isEnabled()) { String appPath = MicroPhotoContext.buildMpAppDir(getApplicationContext()); File file = new File(appPath); File tempFile = new File(file, "tmp"); if (!tempFile.exists()) { tempFile.mkdirs(); } SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmss"); Date dt = new Date(); File photoFile = new File(tempFile, "IMG-" + Integer.toString(channel) + "-" + simpleDateFormat.format(dt) + (photoOrVideo ? ".jpg" : ".mp4")); if (photoFile.exists()) { photoFile.delete(); } File configFile = new File(appPath); configFile = new File(configFile, "data/channels/" + Integer.toString(channel) + ".json"); MicroPhotoService.takePhoto(channel, preset, photoOrVideo, configFile.getAbsolutePath(), photoFile.getAbsolutePath()); } else { MicroPhotoService.takePhoto(this.getApplicationContext(), channel, preset, photoOrVideo); } } protected void TakeAndThrowPhoto(int channel, int preset) { String appPath = MicroPhotoContext.buildMpAppDir(getApplicationContext()); File configFile = new File(appPath); configFile = new File(configFile, "data/channels/" + Integer.toString(channel) + ".json"); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); Date dt = new Date(); File tmpPath = new File(appPath, "tmp"); if (!tmpPath.exists()) { tmpPath.mkdirs(); } File photoFile = new File(tmpPath, "IMG-" + Integer.toString(channel) + "-" + sdf.format(dt) + ".jpg"); if (photoFile.exists()) { photoFile.delete(); } MicroPhotoService.takePhoto(channel, preset, true, configFile.getAbsolutePath(), photoFile.getAbsolutePath()); } private MicroPhotoContext.AppConfig retrieveAndSaveAppConfig() { MicroPhotoContext.AppConfig appConfig = new MicroPhotoContext.AppConfig(); appConfig.cmdid = MainActivity.this.binding.cmdid.getText().toString(); appConfig.server = MainActivity.this.binding.server.getText().toString(); String portStr = MainActivity.this.binding.port.getText().toString(); appConfig.port = TextUtils.isEmpty(portStr) ? 0 : Integer.parseInt(portStr); String protocolStr = MainActivity.this.binding.protocol.getSelectedItem().toString(); appConfig.protocol = MicroPhotoContext.DEFAULT_PROTOCOL; String[] parts = protocolStr.split("-"); if (parts != null) { appConfig.protocol = Integer.parseInt(parts[0]); } appConfig.networkProtocol = MainActivity.this.binding.networkProtocol.getSelectedItemPosition(); appConfig.encryption = MainActivity.this.binding.encryptions.getSelectedItemPosition(); appConfig.heartbeat = TextUtils.isEmpty(binding.heartbeat.getText().toString()) ? 0 : Integer.parseInt(binding.heartbeat.getText().toString()); appConfig.packetSize = TextUtils.isEmpty(binding.packetSize.getText().toString()) ? 0 : Integer.parseInt(binding.packetSize.getText().toString()); appConfig.network = MainActivity.this.binding.network.getSelectedItemPosition(); saveAppConfig(appConfig); return appConfig; } private MicroPhotoContext.AppConfig getAppConfig() { return MicroPhotoContext.getMpAppConfig(getApplicationContext()); } private void saveAppConfig(MicroPhotoContext.AppConfig appConfig) { MicroPhotoContext.saveMpAppConfig(getApplicationContext(), appConfig); } 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 e) { Log.e(TAG, "wjz debug getDefaultDataSubId: error is " + e.getMessage()); } return 0; } LocationListener locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { // 处理位置更新事件 double latitude = location.getLatitude(); double longitude = location.getLongitude(); // ... Log.e("xyh", "定位方式:" + location.getProvider()); Log.e("xyh", "纬度:" + location.getLatitude()); Log.e("xyh", "经度:" + location.getLongitude()); Log.e("xyh", "海拔:" + location.getAltitude()); Log.e("xyh", "时间:" + location.getTime()); Log.e("xyh", "国家:" + LocationUtil.getCountryName(MainActivity.this, location.getLatitude(), location.getLongitude())); Log.e("xyh", "获取地理位置:" + LocationUtil.getAddress(MainActivity.this, location.getLatitude(), location.getLongitude())); Log.e("xyh", "所在地:" + LocationUtil.getLocality(MainActivity.this, location.getLatitude(), location.getLongitude())); Log.e("xyh", "所在街道:" + LocationUtil.getStreet(MainActivity.this, location.getLatitude(), location.getLongitude())); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { // 处理位置状态变化事件 } @Override public void onProviderEnabled(String provider) { // 处理位置提供者启用事件 } @Override public void onProviderDisabled(String provider) { // 处理位置提供者禁用事件 } }; @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { // Back pressed return true; // disable it } return super.onKeyDown(keyCode, event); } }