Compare commits

...

5 Commits

Author SHA1 Message Date
caef679d9a <positions>APK 15.0.6 release Publish. 2025-10-01 21:30:08 +08:00
ZhanGSKen
5194d7a188 修复应用初始设置问题,添加应用权限申请。 2025-10-01 21:28:52 +08:00
a0f88a423a <positions>APK 15.0.5 release Publish. 2025-10-01 21:03:35 +08:00
ZhanGSKen
81b5141608 编译参数修复 2025-10-01 21:03:00 +08:00
ZhanGSKen
ddda54bd75 命名应用的中文化名称。调整一些按钮的响应逻辑。 2025-10-01 20:59:39 +08:00
10 changed files with 181 additions and 67 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Wed Oct 01 21:01:10 HKT 2025
stageCount=5
#Wed Oct 01 21:30:08 HKT 2025
stageCount=7
libraryProject=
baseVersion=15.0
publishVersion=15.0.4
publishVersion=15.0.6
buildCount=0
baseBetaVersion=15.0.5
baseBetaVersion=15.0.7

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">@笨笨龙@</string>
</resources>

View File

@@ -41,6 +41,7 @@ import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
public class App extends GlobalApplication {
@@ -51,6 +52,8 @@ public class App extends GlobalApplication {
super.onCreate();
setIsDebuging(BuildConfig.DEBUG);
WinBoLLActivityManager.init(this);
// 初始化 Toast 框架
ToastUtils.init(this);
// 设置 Toast 布局样式

View File

@@ -1,24 +1,26 @@
package cc.winboll.studio.positions;
import android.content.ComponentName;
import android.content.Context;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.Switch;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.LogActivity;
import androidx.core.content.ContextCompat;
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.positions.activities.LocationActivity;
import cc.winboll.studio.positions.activities.WinBoLLActivity;
import cc.winboll.studio.positions.services.MainService;
import cc.winboll.studio.positions.utils.AppConfigsUtil;
import com.hjq.toast.ToastUtils;
/**
* 主页面:仅负责
@@ -26,18 +28,31 @@ import com.hjq.toast.ToastUtils;
* 2. 跳转至“位置管理页LocationActivity”和“日志页LogActivity
* 3. Java 7 语法适配:无 Lambda、显式接口实现、兼容低版本
*/
public class MainActivity extends AppCompatActivity {
public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
public static final String TAG = "MainActivity";
// 位置权限请求码(自定义唯一标识
private static final int REQUEST_LOCATION_PERMISSIONS = 1001;
// 权限请求码(建议定义为类常量,避免魔法值
private static final int REQUEST_LOCATION_PERMISSIONS = 1001;
private static final int REQUEST_BACKGROUND_LOCATION_PERMISSION = 1002;
// UI 控件:服务控制开关、顶部工具栏
private Switch mServiceSwitch;
private Button mManagePositionsButton;
private Toolbar mToolbar;
// 服务相关:服务实例、绑定状态标记
//private DistanceRefreshService mDistanceService;
private boolean isServiceBound = false;
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
// ---------------------- 服务连接回调(仅用于获取服务状态,不依赖服务执行核心逻辑) ----------------------
// private final ServiceConnection mServiceConn = new ServiceConnection() {
// /**
@@ -69,8 +84,8 @@ public class MainActivity extends AppCompatActivity {
// 1. 初始化顶部 Toolbar保留原逻辑设置页面标题
initToolbar();
// 2. 初始化服务控制开关(核心功能:绑定开关点击事件)
initServiceSwitch();
// 2. 初始化其他控件
initViews();
// 3. 检查并申请位置权限含后台GPS权限确保服务启动前权限就绪
if (!checkLocationPermissions()) {
requestLocationPermissions();
@@ -106,10 +121,13 @@ public class MainActivity extends AppCompatActivity {
/**
* 初始化服务控制开关读取SP状态、绑定点击事件含权限检查
*/
private void initServiceSwitch() {
private void initViews() {
mServiceSwitch = (Switch) findViewById(R.id.switch_service_control); // 显式强转
mServiceSwitch.setChecked(AppConfigsUtil.getInstance(this).isEnableMainService(true));
mManagePositionsButton = (Button) findViewById(R.id.btn_manage_positions);
mManagePositionsButton.setEnabled(mServiceSwitch.isChecked());
// Java 7 用匿名内部类实现 CompoundButton.OnCheckedChangeListener
mServiceSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
@@ -136,6 +154,8 @@ public class MainActivity extends AppCompatActivity {
// }
stopService(new Intent(MainActivity.this, MainService.class));
}
mManagePositionsButton.setEnabled(isChecked);
}
});
}
@@ -166,7 +186,7 @@ public class MainActivity extends AppCompatActivity {
* 无服务状态限制,直接跳转
*/
public void onLog(View view) {
LogActivity.startLogActivity(this); // 调用LogActivity静态方法跳转保留原逻辑
WinBoLLActivityManager.getInstance().startLogActivity(this); // 调用LogActivity静态方法跳转保留原逻辑
}
// ---------------------- 新增位置权限处理适配Java7 + 后台GPS权限 ----------------------
@@ -190,49 +210,57 @@ public class MainActivity extends AppCompatActivity {
return hasForegroundPerm && hasBackgroundPerm;
}
/**
* 申请「前台+后台」位置权限(弹出系统权限弹窗,适配版本差异)
*/
private void requestLocationPermissions() {
String[] permissions;
// Java7 显式版本判断Android 10+ 需同时申请前台+后台权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
permissions = new String[]{
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
};
} else {
// 低版本仅需申请前台权限
permissions = new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION};
}
// 触发系统权限申请Java7 显式调用requestPermissions无方法引用
requestPermissions(permissions, REQUEST_LOCATION_PERMISSIONS);
}
private void requestLocationPermissions() {
// 1. 先判断前台定位权限ACCESS_FINE_LOCATION是否已授予
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// 1.1 未授予前台权限先申请前台权限API 30+ 后台权限依赖前台权限)
String[] foregroundPermissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
// 对API 23+Android 6.0)动态申请,低版本会直接授予(清单已声明前提下)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(foregroundPermissions, REQUEST_LOCATION_PERMISSIONS);
}
} else {
// 2. 已授予前台权限判断是否需要申请后台权限仅API 29+需要)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// 2.1 检查后台权限是否未授予
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// 2.2 API 30+ 必须单独申请后台权限(不能和前台权限一起弹框)
requestPermissions(
new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION},
REQUEST_BACKGROUND_LOCATION_PERMISSION
);
}
}
// 3. 前台权限已授予(+ 后台权限按需授予):此处可执行定位相关逻辑
// doLocationRelatedLogic();
}
}
/**
* 处理权限申请结果系统弹窗用户选择后回调Java7 显式重写方法)
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// 仅处理位置权限的申请结果
if (requestCode == REQUEST_LOCATION_PERMISSIONS) {
boolean allGranted = true;
// Java7 显式for循环遍历结果无增强for简化写法
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
break; // 有一个权限未通过,直接终止判断
}
}
// 【必须补充】权限申请结果回调(处理用户同意/拒绝逻辑)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// 处理前台权限申请结果
if (requestCode == REQUEST_LOCATION_PERMISSIONS) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 前台权限同意自动尝试申请后台权限如果是API 29+
requestLocationPermissions();
} else {
// 前台权限拒绝:提示用户(可选:引导跳转到应用设置页)
Toast.makeText(this, "需要前台定位权限才能使用该功能", Toast.LENGTH_SHORT).show();
}
} else if (requestCode == REQUEST_BACKGROUND_LOCATION_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 后台权限同意:可执行后台定位逻辑
Toast.makeText(this, "已获得后台定位权限", Toast.LENGTH_SHORT).show();
} else {
// 后台权限拒绝:提示用户(可选:说明后台定位的用途,引导手动开启)
Toast.makeText(this, "拒绝后台权限将无法在后台持续定位", Toast.LENGTH_SHORT).show();
}
}
}
// 提示用户权限结果,并处理开关状态
if (allGranted) {
ToastUtils.show("已获取位置权限(含后台),可正常使用定位功能");
} else {
ToastUtils.show("位置权限未完全授予无法后台获取GPS数据请在设置中开启");
}
}
}
}

View File

@@ -5,15 +5,16 @@ package cc.winboll.studio.positions.activities;
* @Date 2025/09/29 18:22
* @Describe 位置列表页面(直连服务数据+移除绑定,兼容服务私有字段)
*/
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.positions.R;
import cc.winboll.studio.positions.adapters.PositionAdapter;
@@ -29,7 +30,7 @@ import java.util.ArrayList;
* 3. 保留“直连服务实例”的核心需求,避免绑定,但尊重服务数据私有性
* 4. 兼容Java 7语法无Lambda、显式类型转换
*/
public class LocationActivity extends AppCompatActivity {
public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivity {
public static final String TAG = "LocationActivity";
// SP配置常量判断服务是否运行
@@ -43,6 +44,17 @@ public class LocationActivity extends AppCompatActivity {
// 缓存服务数据从服务PUBLIC方法获取避免重复调用
private ArrayList<PositionModel> mCachedPositionList;
private ArrayList<PositionTaskModel> mCachedTaskList;
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
// ---------------------- 页面生命周期(简化资源管理,无服务绑定) ----------------------
@Override

View File

@@ -0,0 +1,60 @@
package cc.winboll.studio.positions.activities;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/09/29 00:11
* @Describe WinBoLL 窗口基础类
*/
import android.app.Activity;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.appcompat.app.AppCompatActivity;
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.LogUtils;
public class WinBoLLActivity extends AppCompatActivity implements IWinBoLLActivity {
public static final String TAG = "WinBoLLActivity";
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
@Override
protected void onResume() {
super.onResume();
LogUtils.d(TAG, String.format("onResume %s", getTag()));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
/*if (item.getItemId() == R.id.item_log) {
WinBoLLActivityManager.getInstance().startLogActivity(this);
return true;
} else if (item.getItemId() == R.id.item_home) {
startActivity(new Intent(this, MainActivity.class));
return true;
}*/
// 在switch语句中处理每个ID并在处理完后返回true未处理的情况返回false。
return super.onOptionsItemSelected(item);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
WinBoLLActivityManager.getInstance().add(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
WinBoLLActivityManager.getInstance().registeRemove(this);
}
}

View File

@@ -53,11 +53,14 @@ public class AppConfigsUtil {
if (isReloadConfigs) {
loadConfigs();
}
return mAppConfigsModel.isEnableMainService();
return (mAppConfigsModel == null) ?false: mAppConfigsModel.isEnableMainService();
}
public void setIsEnableMainService(boolean isEnableMainService) {
if(mAppConfigsModel == null) {
mAppConfigsModel = new AppConfigsModel();
}
mAppConfigsModel.setIsEnableMainService(isEnableMainService);
saveConfigs();
}

View File

@@ -25,7 +25,8 @@
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:onClick="onPositions"
android:text="进入位置管理"/>
android:text="进入位置管理"
android:id="@+id/btn_manage_positions"/>
<Button
android:layout_width="match_parent"

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">~笨笨龙~</string>
</resources>

View File

@@ -1,4 +1,3 @@
<resources>
<string name="app_name">Positions</string>
</resources>