FT8CN/ft8CN/app/src/main/java/com/bg7yoz/ft8cn/MainActivity.java

660 wiersze
26 KiB
Java
Executable File
Czysty Wina Historia

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.bg7yoz.ft8cn;
/**
* FT8CN程序的主Activity。本APP采用Fragment框架实现每个Fragment实现不同的功能。
* ----2022.5.6-----
* 主要完成以下功能:
* 1.生成MainViewModel实例。MainViewModel是用于整个生存周期用于录音、解析等功能。
* 2.录音、存储的权限申请。
* 3.实现Fragment的导航管理。
* 4.USB串口连接后的提示
* @author BG7YOZ
* @date 2022.5.6
*/
import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AnimationUtils;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.Observer;
import androidx.navigation.NavController;
import androidx.navigation.fragment.NavHostFragment;
import androidx.navigation.ui.NavigationUI;
import com.bg7yoz.ft8cn.bluetooth.BluetoothStateBroadcastReceive;
import com.bg7yoz.ft8cn.callsign.CallsignDatabase;
import com.bg7yoz.ft8cn.connector.CableSerialPort;
import com.bg7yoz.ft8cn.database.DatabaseOpr;
import com.bg7yoz.ft8cn.database.OnAfterQueryConfig;
import com.bg7yoz.ft8cn.database.OperationBand;
import com.bg7yoz.ft8cn.databinding.MainActivityBinding;
import com.bg7yoz.ft8cn.floatview.FloatView;
import com.bg7yoz.ft8cn.floatview.FloatViewButton;
import com.bg7yoz.ft8cn.grid_tracker.GridTrackerMainActivity;
import com.bg7yoz.ft8cn.maidenhead.MaidenheadGrid;
import com.bg7yoz.ft8cn.timer.UtcTimer;
import com.bg7yoz.ft8cn.ui.FreqDialog;
import com.bg7yoz.ft8cn.ui.SetVolumeDialog;
import com.bg7yoz.ft8cn.ui.ToastMessage;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private BluetoothStateBroadcastReceive mReceive;
private static final String TAG = "MainActivity";
private MainViewModel mainViewModel;
private NavController navController;
private static boolean animatorRunned = false;
//private boolean animationEnd = false;
private MainActivityBinding binding;
private FloatView floatView;
String[] permissions = new String[]{Manifest.permission.RECORD_AUDIO
, Manifest.permission.ACCESS_COARSE_LOCATION
, Manifest.permission.ACCESS_WIFI_STATE
, Manifest.permission.BLUETOOTH
, Manifest.permission.BLUETOOTH_ADMIN
, Manifest.permission.MODIFY_AUDIO_SETTINGS
, Manifest.permission.WAKE_LOCK
, Manifest.permission.ACCESS_FINE_LOCATION};
List<String> mPermissionList = new ArrayList<>();
private static final int PERMISSION_REQUEST = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
permissions = new String[]{Manifest.permission.RECORD_AUDIO
, Manifest.permission.ACCESS_COARSE_LOCATION
, Manifest.permission.ACCESS_WIFI_STATE
, Manifest.permission.BLUETOOTH
, Manifest.permission.BLUETOOTH_ADMIN
, Manifest.permission.BLUETOOTH_CONNECT
, Manifest.permission.MODIFY_AUDIO_SETTINGS
, Manifest.permission.WAKE_LOCK
, Manifest.permission.ACCESS_FINE_LOCATION};
}
checkPermission();
//全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
, WindowManager.LayoutParams.FLAG_FULLSCREEN);
//禁止休眠
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
super.onCreate(savedInstanceState);
GeneralVariables.getInstance().setMainContext(getApplicationContext());
//判断是不是简体中文
GeneralVariables.isTraditionalChinese =
getResources().getConfiguration().locale.getDisplayCountry().equals("中國");
//确定是不是中国、香港、澳门、台湾
GeneralVariables.isChina = (getResources().getConfiguration().locale
.getLanguage().toUpperCase().startsWith("ZH"));
mainViewModel = MainViewModel.getInstance(this);
binding = MainActivityBinding.inflate(getLayoutInflater());
binding.initDataLayout.setVisibility(View.VISIBLE);//显示LOG页面
setContentView(binding.getRoot());
ToastMessage.getInstance();
registerBluetoothReceiver();//注册蓝牙动作改变的广播
if (mainViewModel.isBTConnected()) {
mainViewModel.setBlueToothOn();
}
//观察DEBUG信息
GeneralVariables.mutableDebugMessage.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
if (s.length() > 1) {
binding.debugLayout.setVisibility(View.VISIBLE);
} else {
binding.debugLayout.setVisibility(View.GONE);
}
binding.debugMessageTextView.setText(s);
}
});
binding.debugLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
binding.debugLayout.setVisibility(View.GONE);
}
});
mainViewModel.mutableIsRecording.observe(this, new Observer<Boolean>() {
@Override
public void onChanged(Boolean aBoolean) {
if (aBoolean) {
binding.utcProgressBar.setVisibility(View.VISIBLE);
} else {
binding.utcProgressBar.setVisibility(View.GONE);
}
}
});
//观察时钟的变化,显示进度条
mainViewModel.timerSec.observe(this, new Observer<Long>() {
@Override
public void onChanged(Long aLong) {
if (mainViewModel.ft8TransmitSignal.sequential == UtcTimer.getNowSequential()
&& mainViewModel.ft8TransmitSignal.isActivated()) {
binding.utcProgressBar.setBackgroundColor(getColor(R.color.calling_list_isMyCall_color));
} else {
binding.utcProgressBar.setBackgroundColor(getColor(R.color.progresss_bar_back_color));
}
binding.utcProgressBar.setProgress((int) ((aLong / 1000) % 15));
}
});
//添加点击发射消息提示窗口点击关闭动作
binding.transmittingLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
binding.transmittingLayout.setVisibility(View.GONE);
}
});
//清空缓存中的文件
//deleteFolderFile(this.getCacheDir().getPath());
//Log.e(TAG, this.getCacheDir().getPath());
//用于Fragment的导航。
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentContainerView);
assert navHostFragment != null;//断言不为空
navController = navHostFragment.getNavController();
NavigationUI.setupWithNavController(binding.navView, navController);
//此处增加回调是因为当APP主动navigation后无法回到解码的界面
binding.navView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
//Log.e(TAG, "onNavigationItemSelected: "+item.toString() );
navController.navigate(item.getItemId());
//binding.navView.setLabelFor(item.getItemId());
return true;
}
});
//FT8CN Ver %s\nBG7YOZ\n%s
binding.welcomTextView.setText(String.format(getString(R.string.version_info)
, GeneralVariables.VERSION, GeneralVariables.BUILD_DATE));
floatView = new FloatView(this, 32);
if (!animatorRunned) {
animationImage();
animatorRunned = true;
} else {
binding.initDataLayout.setVisibility(View.GONE);
InitFloatView();
}
//初始化数据
InitData();
//观察是不是flex radio
mainViewModel.mutableIsFlexRadio.observe(this, new Observer<Boolean>() {
@Override
public void onChanged(Boolean aBoolean) {
//if (floatView==null) return;
if (aBoolean) {
//添加flex配置按钮
floatView.addButton(R.id.flex_radio, "flex_radio", R.drawable.flex_icon
, new View.OnClickListener() {
@Override
public void onClick(View view) {
navController.navigate(R.id.flexRadioInfoFragment);
// if (mainViewModel.baseRig != null) {
// if (mainViewModel.baseRig.isConnected()) {
// ToastMessage.show("flex connected");
// }else {
// ToastMessage.show("flex disconnected");
// }
// }else {
// ToastMessage.show("rig is null");
// }
}
});
} else {//删除flex配置按钮
floatView.deleteButtonByName("flex_radio");
}
}
});
//关闭串口设备列表按钮
binding.closeSelectSerialPortImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
binding.selectSerialPortLayout.setVisibility(View.GONE);
}
});
//观察串口设备列表的变化
mainViewModel.mutableSerialPorts.observe(this, new Observer<ArrayList<CableSerialPort.SerialPort>>() {
@Override
public void onChanged(ArrayList<CableSerialPort.SerialPort> serialPorts) {
setSelectUsbDevice();
}
});
//列USB设备列表
mainViewModel.getUsbDevice();
//设置发射消息框的动画
binding.transmittingMessageTextView.setAnimation(AnimationUtils.loadAnimation(this
, R.anim.view_blink));
//观察发射的状态
mainViewModel.ft8TransmitSignal.mutableIsTransmitting.observe(this,
new Observer<Boolean>() {
@Override
public void onChanged(Boolean aBoolean) {
if (aBoolean) {
binding.transmittingLayout.setVisibility(View.VISIBLE);
} else {
binding.transmittingLayout.setVisibility(View.GONE);
}
}
});
//观察发射内容的变化
mainViewModel.ft8TransmitSignal.mutableTransmittingMessage.observe(this,
new Observer<String>() {
@Override
public void onChanged(String s) {
binding.transmittingMessageTextView.setText(s);
}
});
}
/**
* 添加浮动按钮
*/
private void InitFloatView() {
//floatView = new FloatView(this, 32);
binding.container.addView(floatView);
floatView.setButtonMargin(0);
floatView.setFloatBoard(FloatView.FLOAT_BOARD.RIGHT);
floatView.setButtonBackgroundResourceId(R.drawable.float_button_style);
//动态添加按钮建议使用静态的ID静态ID在VALUES/FLOAT_BUTTON_IDS.XML中设置
floatView.addButton(R.id.float_nav, "float_nav", R.drawable.ic_baseline_fullscreen_24
, new View.OnClickListener() {
@Override
public void onClick(View view) {
FloatViewButton button = floatView.getButtonByName("float_nav");
if (binding.navView.getVisibility() == View.VISIBLE) {
binding.navView.setVisibility(View.GONE);
if (button != null) {
button.setImageResource(R.drawable.ic_baseline_fullscreen_exit_24);
}
} else {
binding.navView.setVisibility(View.VISIBLE);
if (button != null) {
button.setImageResource(R.drawable.ic_baseline_fullscreen_24);
}
}
}
});
floatView.addButton(R.id.float_freq, "float_freq", R.drawable.ic_baseline_freq_24
, new View.OnClickListener() {
@Override
public void onClick(View view) {
new FreqDialog(binding.container.getContext(), mainViewModel).show();
}
});
floatView.addButton(R.id.set_volume, "set_volume", R.drawable.ic_baseline_volume_up_24
, new View.OnClickListener() {
@Override
public void onClick(View view) {
new SetVolumeDialog(binding.container.getContext(), mainViewModel).show();
}
});
//打开网格追踪
floatView.addButton(R.id.grid_tracker, "grid_tracker", R.drawable.ic_baseline_grid_tracker_24
, new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), GridTrackerMainActivity.class);
startActivity(intent);
}
});
// floatView.addButton(R.id.flex_radio, "flex_radio", R.drawable.flex_icon
// , new View.OnClickListener() {
// @Override
// public void onClick(View view) {
// navController.navigate(R.id.flexRadioInfoFragment);
// }
// });
floatView.initLocation();
}
/**
* 初始化一些数据
*/
private void InitData() {
if (mainViewModel.configIsLoaded) return;//如果数据已经读取一遍了,就不用再读取了。
//读取波段数据
if (mainViewModel.operationBand == null) {
mainViewModel.operationBand = OperationBand.getInstance(getBaseContext());
}
mainViewModel.databaseOpr.getQslDxccToMap();
//获取所有的配置参数
mainViewModel.databaseOpr.getAllConfigParameter(new OnAfterQueryConfig() {
@Override
public void doOnBeforeQueryConfig(String KeyName) {
}
@Override
public void doOnAfterQueryConfig(String KeyName, String Value) {
mainViewModel.configIsLoaded = true;
//此处梅登海德已经通过数据库得到了但是如果GPS能获取到还是用GPS的
String grid = MaidenheadGrid.getMyMaidenheadGrid(getApplicationContext());
if (!grid.equals("")) {//说明获取到了GPS数据
GeneralVariables.setMyMaidenheadGrid(grid);
//写到数据库中
mainViewModel.databaseOpr.writeConfig("grid", grid, null);
}
mainViewModel.ft8TransmitSignal.setTimer_sec(GeneralVariables.transmitDelay);
//如果呼号、网格为空,就进入设置界面
if (GeneralVariables.getMyMaidenheadGrid().equals("")
|| GeneralVariables.myCallsign.equals("")) {
runOnUiThread(new Runnable() {
@Override
public void run() {//导航到设置页面
navController.navigate(R.id.menu_nav_config);
}
});
}
}
});
//把历史中通联成功的呼号与网格的对应关系
new DatabaseOpr.GetCallsignMapGrid(mainViewModel.databaseOpr.getDb()).execute();
mainViewModel.getFollowCallsignsFromDataBase();
//打开呼号位置信息的数据库,目前是以内存数据库方式。
if (GeneralVariables.callsignDatabase == null) {
GeneralVariables.callsignDatabase = CallsignDatabase.getInstance(getBaseContext(), null, 1);
}
}
/**
* 检查权限
*/
private void checkPermission() {
mPermissionList.clear();
//判断哪些权限未授予
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
mPermissionList.add(permission);
}
}
//判断是否为空
if (!mPermissionList.isEmpty()) {//请求权限方法
String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]);//将List转为数组
ActivityCompat.requestPermissions(MainActivity.this, permissions, PERMISSION_REQUEST);
}
}
/**
* 响应授权
* 这里不管用户是否拒绝,都进入首页,不再重复申请权限
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode != PERMISSION_REQUEST) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
/**
* 显示串口设备列表
*/
public void setSelectUsbDevice() {
ArrayList<CableSerialPort.SerialPort> ports = mainViewModel.mutableSerialPorts.getValue();
binding.selectSerialPortLinearLayout.removeAllViews();
for (int i = 0; i < ports.size(); i++) {//动态添加串口设备列表
View layout = LayoutInflater.from(getApplicationContext())
.inflate(R.layout.select_serial_port_list_view_item, null);
layout.setId(i);
TextView textView = layout.findViewById(R.id.selectSerialPortListViewItemTextView);
textView.setText(ports.get(i).information());
binding.selectSerialPortLinearLayout.addView(layout);
layout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//连接电台并做电台的频率设置等操作
mainViewModel.connectCableRig(getApplicationContext(), ports.get(view.getId()));
binding.selectSerialPortLayout.setVisibility(View.GONE);
}
});
}
//选择串口设备弹框
if ((ports.size() >= 1) && (!mainViewModel.isRigConnected())) {
binding.selectSerialPortLayout.setVisibility(View.VISIBLE);
} else {//说明没有可以识别的驱动,不显示设备弹框
binding.selectSerialPortLayout.setVisibility(View.GONE);
}
}
/**
* 删除指定文件夹中的所有文件
*
* @param filePath 指定的文件夹
*/
public static void deleteFolderFile(String filePath) {
try {
File file = new File(filePath);//获取SD卡指定路径
File[] files = file.listFiles();//获取SD卡指定路径下的文件或者文件夹
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {//如果是文件直接删除
File tempFile = new File(files[i].getPath());
tempFile.delete();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void animationImage() {
ObjectAnimator navigationAnimator = ObjectAnimator.ofFloat(binding.navView, "translationY", 200);
navigationAnimator.setDuration(3000);
navigationAnimator.setFloatValues(200, 200, 200, 0);
ObjectAnimator hideLogoAnimator = ObjectAnimator.ofFloat(binding.initDataLayout, "alpha", 1f, 1f, 1f, 0);
hideLogoAnimator.setDuration(3000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(navigationAnimator, hideLogoAnimator);
//animatorSet.playTogether(initPositionStrAnimator, logoAnimator, navigationAnimator, hideLogoAnimator);
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
//animationEnd = true;
binding.initDataLayout.setVisibility(View.GONE);
binding.utcProgressBar.setVisibility(View.VISIBLE);
InitFloatView();//显示浮窗
//binding.floatView.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
animatorSet.start();
}
//此方法只有在android:launchMode="singleTask"模式下起作用
@Override
protected void onNewIntent(Intent intent) {
if ("android.hardware.usb.action.USB_DEVICE_ATTACHED".equals(intent.getAction())) {
mainViewModel.getUsbDevice();
}
super.onNewIntent(intent);
}
@Override
public void onBackPressed() {
if (navController.getGraph().getStartDestination() == navController.getCurrentDestination().getId()) {//说明是到最后一个页面了
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setMessage(getString(R.string.exit_confirmation))
.setPositiveButton(getString(R.string.exit)
, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
if (mainViewModel.ft8TransmitSignal.isActivated()) {
mainViewModel.ft8TransmitSignal.setActivated(false);
}
closeThisApp();//退出APP
}
}).setNegativeButton(getString(R.string.cancel)
, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
builder.create().show();
} else {//退出activity堆栈
navController.navigateUp();
//setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
}
}
private void closeThisApp() {
mainViewModel.ft8TransmitSignal.setActivated(false);
if (mainViewModel.baseRig != null) {
if (mainViewModel.baseRig.getConnector() != null) {
mainViewModel.baseRig.getConnector().disconnect();
}
}
mainViewModel.ft8SignalListener.stopListen();
mainViewModel = null;
System.exit(0);
}
/**
* 注册蓝牙动作广播
*/
private void registerBluetoothReceiver() {
if (mReceive == null) {
mReceive = new BluetoothStateBroadcastReceive(getApplicationContext(), mainViewModel);
}
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
intentFilter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
intentFilter.addAction(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE);
intentFilter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
intentFilter.addAction(AudioManager.EXTRA_SCO_AUDIO_STATE);
intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
intentFilter.addAction(BluetoothAdapter.EXTRA_CONNECTION_STATE);
intentFilter.addAction(BluetoothAdapter.EXTRA_STATE);
intentFilter.addAction("android.bluetooth.BluetoothAdapter.STATE_OFF");
intentFilter.addAction("android.bluetooth.BluetoothAdapter.STATE_ON");
registerReceiver(mReceive, intentFilter);
}
/**
* 注销蓝牙动作广播
*/
private void unregisterBluetoothReceiver() {
if (mReceive != null) {
unregisterReceiver(mReceive);
mReceive = null;
}
}
@Override
protected void onDestroy() {
unregisterBluetoothReceiver();
super.onDestroy();
}
}