diff --git a/positions/build.gradle b/positions/build.gradle
index e4f159b..8893ea5 100644
--- a/positions/build.gradle
+++ b/positions/build.gradle
@@ -38,9 +38,22 @@ android {
}
}
+ // 米盟 SDK
+ packagingOptions {
+ doNotStrip "*/*/libmimo_1011.so"
+ }
}
dependencies {
+ // 米盟
+ api 'com.miui.zeus:mimo-ad-sdk:5.3.+'//请使用最新版sdk
+ //注意:以下5个库必须要引入
+ //api 'androidx.appcompat:appcompat:1.4.1'
+ api 'androidx.recyclerview:recyclerview:1.0.0'
+ api 'com.google.code.gson:gson:2.8.5'
+ api 'com.github.bumptech.glide:glide:4.9.0'
+ //annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
+
// https://mvnrepository.com/artifact/com.jzxiang.pickerview/TimePickerDialog
api 'com.jzxiang.pickerview:TimePickerDialog:1.0.1'
diff --git a/positions/build.properties b/positions/build.properties
index bf8a130..d80758c 100644
--- a/positions/build.properties
+++ b/positions/build.properties
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
-#Sun Dec 07 21:00:59 HKT 2025
+#Sun Dec 07 15:55:26 GMT 2025
stageCount=1
libraryProject=
baseVersion=15.12
publishVersion=15.12.0
-buildCount=0
+buildCount=5
baseBetaVersion=15.12.1
diff --git a/positions/src/main/AndroidManifest.xml b/positions/src/main/AndroidManifest.xml
index 336e451..764c31b 100644
--- a/positions/src/main/AndroidManifest.xml
+++ b/positions/src/main/AndroidManifest.xml
@@ -112,7 +112,7 @@
-
+
@@ -134,16 +134,15 @@
-
+
-
+
-
+
+
-
+
\ No newline at end of file
diff --git a/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java b/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java
index d105d63..22e8f5e 100644
--- a/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java
+++ b/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java
@@ -6,6 +6,8 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
@@ -15,11 +17,14 @@ import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
+import cc.winboll.studio.libaes.utils.AESThemeUtil;
+import cc.winboll.studio.libaes.utils.DevelopUtils;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
+import cc.winboll.studio.libaes.views.ADsBannerView;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.positions.activities.LocationActivity;
+import cc.winboll.studio.positions.activities.SettingsActivity;
import cc.winboll.studio.positions.activities.WinBoLLActivity;
-import cc.winboll.studio.positions.services.MainService;
import cc.winboll.studio.positions.utils.AppConfigsUtil;
import cc.winboll.studio.positions.utils.ServiceUtil;
@@ -34,7 +39,7 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
// 权限请求码(建议定义为类常量,避免魔法值)
private static final int REQUEST_LOCATION_PERMISSIONS = 1001;
private static final int REQUEST_BACKGROUND_LOCATION_PERMISSION = 1002;
-
+
// UI 控件:服务控制开关、顶部工具栏
private Switch mServiceSwitch;
private Button mManagePositionsButton;
@@ -42,6 +47,7 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
// 服务相关:服务实例、绑定状态标记
//private DistanceRefreshService mDistanceService;
private boolean isServiceBound = false;
+ ADsBannerView mADsBannerView;
@Override
@@ -93,11 +99,18 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
}
// 4. 绑定服务(仅用于获取服务实时状态,不影响服务独立运行)
//bindDistanceService();
+
+ mADsBannerView = findViewById(R.id.adsbanner);
+
}
@Override
protected void onDestroy() {
super.onDestroy();
+ if (mADsBannerView != null) {
+ mADsBannerView.releaseAdResources();
+ }
+
// 页面销毁时解绑服务,避免Activity与服务相互引用导致内存泄漏
// if (isServiceBound) {
// unbindService(mServiceConn);
@@ -106,6 +119,16 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
// }
}
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (mADsBannerView != null) {
+ mADsBannerView.resumeADs(MainActivity.this);
+ }
+ }
+
+
+
// ---------------------- 核心功能1:初始化UI组件(Toolbar + 服务开关) ----------------------
/**
* 初始化顶部 Toolbar,设置页面标题
@@ -155,6 +178,39 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
}
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // 主题菜单
+ AESThemeUtil.inflateMenu(this, menu);
+ // 调试工具菜单
+ if (App.isDebugging()) {
+ DevelopUtils.inflateMenu(this, menu);
+ }
+ // 应用其他菜单
+ getMenuInflater().inflate(R.menu.toolbar_main, menu);
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int menuItemId = item.getItemId();
+ if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
+ recreate();
+ } if (DevelopUtils.onDevelopItemSelected(this, item)) {
+ LogUtils.d(TAG, String.format("onOptionsItemSelected item.getItemId() %d ", item.getItemId()));
+ } else if (item.getItemId() == R.id.item_settings) {
+ Intent intent = new Intent();
+ intent.setClass(this, SettingsActivity.class);
+ startActivity(intent);
+ } else {
+ // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。
+ return super.onOptionsItemSelected(item);
+ }
+ return true;
+ }
+
+
/**
* 绑定服务(仅用于获取服务状态,不启动服务)
*/
diff --git a/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java b/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java
index c254e8a..8f49ffd 100644
--- a/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java
+++ b/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java
@@ -16,8 +16,10 @@ import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.appcompat.widget.Toolbar;
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.libappbase.ToastUtils;
import cc.winboll.studio.positions.R;
@@ -33,12 +35,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
* 2. Adapter 初始化传入 MainService 实例,确保数据来源唯一
* 3. 所有位置/任务操作通过 MainService 接口执行
*/
-public class LocationActivity extends Activity {
+public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivity {
public static final String TAG = "LocationActivity";
+ private Toolbar mToolbar;
+
private RecyclerView mRvPosition;
private PositionAdapter mPositionAdapter;
-
+
// MainService 引用+绑定状态(AtomicBoolean 确保多线程状态可见性)
private MainService mMainService;
private final AtomicBoolean isServiceBound = new AtomicBoolean(false);
@@ -96,11 +100,34 @@ public class LocationActivity extends Activity {
}
};
+ @Override
+ public Activity getActivity() {
+ return this;
+ }
+
+ @Override
+ public String getTag() {
+ return TAG;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location);
+ mToolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(mToolbar);
+ mToolbar.setSubtitle(getTag());
+ mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ LogUtils.d(TAG, "【导航栏】点击返回");
+ finish();
+ }
+ });
+
// 1. 初始化视图(优先执行,避免Adapter初始化时视图为空)
initView();
// 2. 初始化GPS监听(提前创建,避免绑定服务后空指针)
@@ -167,7 +194,7 @@ public class LocationActivity extends Activity {
}
}
LogUtils.d(TAG, "数据同步完成:服务位置数=" + (servicePosList == null ? 0 : servicePosList.size())
- + ",本地缓存数=" + mLocalPosCache.size());
+ + ",本地缓存数=" + mLocalPosCache.size());
} catch (Exception e) {
LogUtils.d(TAG, "同步服务数据失败:" + e.getMessage());
@@ -183,9 +210,9 @@ public class LocationActivity extends Activity {
// 1. 多重安全校验(避免销毁后初始化/重复初始化/依赖未就绪)
if (isAdapterInited.get() || !isServiceBound.get() || mMainService == null || mRvPosition == null) {
LogUtils.w(TAG, "Adapter初始化跳过:"
- + "已初始化=" + isAdapterInited.get()
- + ",服务绑定=" + isServiceBound.get()
- + ",视图就绪=" + (mRvPosition != null));
+ + "已初始化=" + isAdapterInited.get()
+ + ",服务绑定=" + isServiceBound.get()
+ + ",视图就绪=" + (mRvPosition != null));
return;
}
@@ -195,54 +222,54 @@ public class LocationActivity extends Activity {
// 3. 设置删除回调(删除时同步服务+本地缓存+Adapter)
mPositionAdapter.setOnDeleteClickListener(new PositionAdapter.OnDeleteClickListener() {
- @Override
- public void onDeleteClick(int position) {
- // 安全校验(索引有效+服务绑定+缓存非空)
- if (position < 0 || position >= mLocalPosCache.size() || !isServiceBound.get() || mMainService == null) {
- LogUtils.w(TAG, "删除位置失败:索引无效/服务未就绪(索引=" + position + ",缓存量=" + mLocalPosCache.size() + ")");
- return;
- }
+ @Override
+ public void onDeleteClick(int position) {
+ // 安全校验(索引有效+服务绑定+缓存非空)
+ if (position < 0 || position >= mLocalPosCache.size() || !isServiceBound.get() || mMainService == null) {
+ LogUtils.w(TAG, "删除位置失败:索引无效/服务未就绪(索引=" + position + ",缓存量=" + mLocalPosCache.size() + ")");
+ return;
+ }
- PositionModel deletePos = mLocalPosCache.get(position);
- if (deletePos != null && !deletePos.getPositionId().isEmpty()) {
- // 步骤1:调用服务删除(确保服务数据一致性)
- mMainService.removePosition(deletePos.getPositionId());
- // 步骤2:删除本地缓存(确保缓存与服务同步)
- synchronized (mLocalPosCache) {
- mLocalPosCache.remove(position);
- }
- // 步骤3:通知Adapter刷新(基于缓存操作,避免空数据)
- mPositionAdapter.notifyItemRemoved(position);
- showToast("删除位置成功:" + deletePos.getMemo());
- LogUtils.d(TAG, "删除位置完成:ID=" + deletePos.getPositionId() + "(服务+缓存已同步)");
- }
- }
- });
+ PositionModel deletePos = mLocalPosCache.get(position);
+ if (deletePos != null && !deletePos.getPositionId().isEmpty()) {
+ // 步骤1:调用服务删除(确保服务数据一致性)
+ mMainService.removePosition(deletePos.getPositionId());
+ // 步骤2:删除本地缓存(确保缓存与服务同步)
+ synchronized (mLocalPosCache) {
+ mLocalPosCache.remove(position);
+ }
+ // 步骤3:通知Adapter刷新(基于缓存操作,避免空数据)
+ mPositionAdapter.notifyItemRemoved(position);
+ showToast("删除位置成功:" + deletePos.getMemo());
+ LogUtils.d(TAG, "删除位置完成:ID=" + deletePos.getPositionId() + "(服务+缓存已同步)");
+ }
+ }
+ });
// 4. 设置保存回调(保存时同步服务+本地缓存+Adapter)
mPositionAdapter.setOnSavePositionClickListener(new PositionAdapter.OnSavePositionClickListener() {
- @Override
- public void onSavePositionClick(int position, PositionModel updatedPos) {
- // 安全校验(索引有效+服务绑定+数据非空)
- if (!isServiceBound.get() || mMainService == null
- || position < 0 || position >= mLocalPosCache.size() || updatedPos == null) {
- LogUtils.w(TAG, "保存位置失败:服务未就绪/索引无效/数据空");
- showToast("服务未就绪,保存失败");
- return;
- }
+ @Override
+ public void onSavePositionClick(int position, PositionModel updatedPos) {
+ // 安全校验(索引有效+服务绑定+数据非空)
+ if (!isServiceBound.get() || mMainService == null
+ || position < 0 || position >= mLocalPosCache.size() || updatedPos == null) {
+ LogUtils.w(TAG, "保存位置失败:服务未就绪/索引无效/数据空");
+ showToast("服务未就绪,保存失败");
+ return;
+ }
- // 步骤1:调用服务更新(确保服务数据一致性)
- mMainService.updatePosition(updatedPos);
- // 步骤2:更新本地缓存(确保缓存与服务同步)
- synchronized (mLocalPosCache) {
- mLocalPosCache.set(position, updatedPos);
- }
- // 步骤3:通知Adapter刷新(基于缓存操作,避免空数据)
- mPositionAdapter.notifyItemChanged(position);
- showToast("保存位置成功:" + updatedPos.getMemo());
- LogUtils.d(TAG, "保存位置完成:ID=" + updatedPos.getPositionId() + "(服务+缓存已同步)");
- }
- });
+ // 步骤1:调用服务更新(确保服务数据一致性)
+ mMainService.updatePosition(updatedPos);
+ // 步骤2:更新本地缓存(确保缓存与服务同步)
+ synchronized (mLocalPosCache) {
+ mLocalPosCache.set(position, updatedPos);
+ }
+ // 步骤3:通知Adapter刷新(基于缓存操作,避免空数据)
+ mPositionAdapter.notifyItemChanged(position);
+ showToast("保存位置成功:" + updatedPos.getMemo());
+ LogUtils.d(TAG, "保存位置完成:ID=" + updatedPos.getPositionId() + "(服务+缓存已同步)");
+ }
+ });
// 5. 设置Adapter到RecyclerView(最后一步,确保Adapter已配置完成)
mRvPosition.setAdapter(mPositionAdapter);
@@ -268,7 +295,7 @@ public class LocationActivity extends Activity {
}
Toast.makeText(this, content, Toast.LENGTH_SHORT).show();
}
-
+
// ---------------------- 页面交互(新增位置逻辑保留,适配GPS数据) ----------------------
/**
* 新增位置(调用服务addPosition(),可选:用当前GPS位置初始化新位置)
@@ -395,9 +422,7 @@ public class LocationActivity extends Activity {
LogUtils.d(TAG, "onResume:服务已绑定但Adapter未初始化,重新同步数据");
syncDataFromMainService();
initPositionAdapter();
- }
- // 2. 服务已绑定且Adapter已初始化:刷新数据(确保与服务同步)
- else if (isServiceBound.get() && mMainService != null && isAdapterInited.get() && mPositionAdapter != null) {
+ } else if (isServiceBound.get() && mMainService != null && isAdapterInited.get() && mPositionAdapter != null) {
syncDataFromMainService();
mPositionAdapter.notifyDataSetChanged();
LogUtils.d(TAG, "onResume:刷新位置数据(与服务同步)");
diff --git a/positions/src/main/java/cc/winboll/studio/positions/activities/SettingsActivity.java b/positions/src/main/java/cc/winboll/studio/positions/activities/SettingsActivity.java
new file mode 100644
index 0000000..9b432f1
--- /dev/null
+++ b/positions/src/main/java/cc/winboll/studio/positions/activities/SettingsActivity.java
@@ -0,0 +1,51 @@
+package cc.winboll.studio.positions.activities;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import androidx.appcompat.widget.Toolbar;
+import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
+import cc.winboll.studio.libappbase.LogUtils;
+import cc.winboll.studio.libappbase.ToastUtils;
+import cc.winboll.studio.positions.R;
+
+/**
+ * @Author ZhanGSKen&豆包大模型
+ * @Date 2025/12/07 23:29
+ * @Describe 应用设置活动窗口
+ */
+public class SettingsActivity extends WinBoLLActivity implements IWinBoLLActivity {
+
+ public static final String TAG = "SettingsActivity";
+
+ private Toolbar mToolbar;
+
+ @Override
+ public Activity getActivity() {
+ return this;
+ }
+
+ @Override
+ public String getTag() {
+ return TAG;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_settings);
+
+ mToolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(mToolbar);
+ mToolbar.setSubtitle(getTag());
+ mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ LogUtils.d(TAG, "【导航栏】点击返回");
+ finish();
+ }
+ });
+ }
+}
diff --git a/positions/src/main/java/cc/winboll/studio/positions/activities/WinBoLLActivity.java b/positions/src/main/java/cc/winboll/studio/positions/activities/WinBoLLActivity.java
index 3cf13b7..fba149f 100644
--- a/positions/src/main/java/cc/winboll/studio/positions/activities/WinBoLLActivity.java
+++ b/positions/src/main/java/cc/winboll/studio/positions/activities/WinBoLLActivity.java
@@ -10,6 +10,8 @@ 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.models.AESThemeBean;
+import cc.winboll.studio.libaes.utils.AESThemeUtil;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.LogUtils;
@@ -17,6 +19,8 @@ public class WinBoLLActivity extends AppCompatActivity implements IWinBoLLActivi
public static final String TAG = "WinBoLLActivity";
+ protected volatile AESThemeBean.ThemeType mThemeType;
+
@Override
public Activity getActivity() {
return this;
@@ -27,6 +31,22 @@ public class WinBoLLActivity extends AppCompatActivity implements IWinBoLLActivi
return TAG;
}
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ mThemeType = getThemeType();
+ setThemeStyle();
+ super.onCreate(savedInstanceState);
+ }
+
+ AESThemeBean.ThemeType getThemeType() {
+ return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext()));
+ }
+
+ void setThemeStyle() {
+ setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext()));
+ }
+
+
@Override
protected void onResume() {
super.onResume();
@@ -36,12 +56,12 @@ public class WinBoLLActivity extends AppCompatActivity implements IWinBoLLActivi
@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;
- }*/
+ 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);
}
diff --git a/positions/src/main/res/layout/activity_location.xml b/positions/src/main/res/layout/activity_location.xml
index e751f33..e7842f6 100644
--- a/positions/src/main/res/layout/activity_location.xml
+++ b/positions/src/main/res/layout/activity_location.xml
@@ -1,67 +1,81 @@
-
+ android:layout_height="match_parent">
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="@dimen/toolbar_height"
+ android:id="@+id/toolbar"
+ android:gravity="center_vertical"/>
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/positions/src/main/res/layout/activity_main.xml b/positions/src/main/res/layout/activity_main.xml
index 67f7f96..da99dac 100644
--- a/positions/src/main/res/layout/activity_main.xml
+++ b/positions/src/main/res/layout/activity_main.xml
@@ -2,38 +2,51 @@
+ android:layout_height="match_parent">
-
+ android:gravity="center_vertical"/>
-
+ android:layout_height="0dp"
+ android:orientation="vertical"
+ android:layout_weight="1.0">
-
+
+
+
+
+
+
+
+
-
-
+ android:id="@+id/adsbanner"
+ android:layout_alignParentBottom="true"/>
diff --git a/positions/src/main/res/layout/activity_settings.xml b/positions/src/main/res/layout/activity_settings.xml
new file mode 100644
index 0000000..e01cf89
--- /dev/null
+++ b/positions/src/main/res/layout/activity_settings.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
diff --git a/positions/src/main/res/menu/toolbar_main.xml b/positions/src/main/res/menu/toolbar_main.xml
new file mode 100644
index 0000000..9aa1e20
--- /dev/null
+++ b/positions/src/main/res/menu/toolbar_main.xml
@@ -0,0 +1,9 @@
+
+
diff --git a/positions/src/main/res/values/dimens.xml b/positions/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..7c56ea2
--- /dev/null
+++ b/positions/src/main/res/values/dimens.xml
@@ -0,0 +1,7 @@
+
+
+ 60dp
+ 18dp
+ 24dp
+ 16dp
+
diff --git a/positions/src/main/res/values/styles.xml b/positions/src/main/res/values/styles.xml
index ae7e6dd..ef130d8 100644
--- a/positions/src/main/res/values/styles.xml
+++ b/positions/src/main/res/values/styles.xml
@@ -14,4 +14,12 @@
+
+
+
+