From 17d2422690be9c9bc475c5b791b56354ac157ac5 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Mon, 10 Nov 2025 11:43:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BA=94=E7=94=A8=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E5=88=87=E6=8D=A2=E5=88=9D=E7=A8=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- positions/build.properties | 4 +- positions/src/beta/res/xml/shortcuts.xml | 34 +++ positions/src/main/AndroidManifest.xml | 82 ++++--- .../studio/positions/MainActivity.java | 26 +- .../positions/utils/AppIconSwitcher.java | 222 ++++++++++++++++++ .../positions/views/PositionTaskListView.java | 20 +- positions/src/main/res/values/strings.xml | 3 + positions/src/main/res/xml/shortcuts.xml | 34 +++ 8 files changed, 373 insertions(+), 52 deletions(-) create mode 100644 positions/src/beta/res/xml/shortcuts.xml create mode 100644 positions/src/main/java/cc/winboll/studio/positions/utils/AppIconSwitcher.java create mode 100644 positions/src/main/res/xml/shortcuts.xml diff --git a/positions/build.properties b/positions/build.properties index d46882a5..86aca6e3 100644 --- a/positions/build.properties +++ b/positions/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Mon Nov 10 00:53:37 GMT 2025 +#Mon Nov 10 03:35:32 GMT 2025 stageCount=18 libraryProject= baseVersion=15.0 publishVersion=15.0.17 -buildCount=39 +buildCount=71 baseBetaVersion=15.0.18 diff --git a/positions/src/beta/res/xml/shortcuts.xml b/positions/src/beta/res/xml/shortcuts.xml new file mode 100644 index 00000000..3b6d5865 --- /dev/null +++ b/positions/src/beta/res/xml/shortcuts.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/positions/src/main/AndroidManifest.xml b/positions/src/main/AndroidManifest.xml index f0a8ba7e..e50e3a00 100644 --- a/positions/src/main/AndroidManifest.xml +++ b/positions/src/main/AndroidManifest.xml @@ -3,23 +3,14 @@ xmlns:android="http://schemas.android.com/apk/res/android" package="cc.winboll.studio.positions"> - + - - - - - - - - - - + + - - - - - - - - - - + + - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + 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 8e7e5cbf..ebf92599 100644 --- a/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java +++ b/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java @@ -22,6 +22,7 @@ import cc.winboll.studio.positions.activities.LocationActivity; import cc.winboll.studio.positions.activities.WinBoLLActivity; import cc.winboll.studio.positions.utils.AppConfigsUtil; import cc.winboll.studio.positions.utils.ServiceUtil; +import cc.winboll.studio.positions.utils.AppIconSwitcher; /** * 主页面:仅负责 @@ -34,7 +35,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; @@ -82,6 +83,10 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 关联主页面布局 + // 处理应用级别的切换请求 + handleSwitchRequest(); + + // 设置当前应用级别 App.setAppLevel(this); // 1. 初始化顶部 Toolbar(保留原逻辑,设置页面标题) @@ -95,7 +100,20 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity { // 4. 绑定服务(仅用于获取服务实时状态,不影响服务独立运行) //bindDistanceService(); } - + + /** + * 处理快捷菜单的「切换入口」请求 + */ + private void handleSwitchRequest() { + Intent intent = getIntent(); + if (intent != null && "switch_launcher_main".equals(intent.getDataString())) { + ToastUtils.show("应用级别切换到悟空笔记"); + AppIconSwitcher.switchToWukongIcon(this); + } else if (intent != null && "switch_launcher_laojun".equals(intent.getDataString())) { + ToastUtils.show("應用級別切換到老君道說"); + AppIconSwitcher.switchToLaojunIcon(this); + } + } @Override protected void onDestroy() { @@ -117,8 +135,8 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity { setSupportActionBar(mToolbar); // 给ActionBar设置标题(先判断非空,避免空指针异常) /*if (getSupportActionBar() != null) { - getSupportActionBar().setTitle(getString(R.string.app_name)); - }*/ + getSupportActionBar().setTitle(getString(R.string.app_name)); + }*/ } /** diff --git a/positions/src/main/java/cc/winboll/studio/positions/utils/AppIconSwitcher.java b/positions/src/main/java/cc/winboll/studio/positions/utils/AppIconSwitcher.java new file mode 100644 index 00000000..535242b7 --- /dev/null +++ b/positions/src/main/java/cc/winboll/studio/positions/utils/AppIconSwitcher.java @@ -0,0 +1,222 @@ +package cc.winboll.studio.positions.utils; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/11/10 09:51 + * @Describe 应用图标切换工具类(启用组件时创建对应快捷方式) + */ +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Build; +import android.util.Log; +import android.widget.Toast; +import cc.winboll.studio.positions.R; + +public class AppIconSwitcher { + public static final String TAG = "AppIconSwitcher"; + + // 组件名常量(需与 AndroidManifest 一致) + private static final String WUKONG_ACTIVITY = "cc.winboll.studio.positions.MainActivityWukong"; + private static final String LAOJUN_ACTIVITY = "cc.winboll.studio.positions.MainActivityLaojun"; + + // 快捷方式配置(名称+图标,需与实际资源匹配) + private static final String WUKONG_SHORTCUT_NAME = "位置服务-Wukong"; + private static final int WUKONG_SHORTCUT_ICON = R.drawable.ic_launcher; // Wukong 图标资源 + private static final String LAOJUN_SHORTCUT_NAME = "位置服务-Laojun"; + private static final int LAOJUN_SHORTCUT_ICON = R.mipmap.ic_launcher; // Laojun 图标资源 + + /** + * 切换到 Laojun 图标:禁用 Wukong,启用 Laojun + 创建 Laojun 快捷方式 + */ + public static boolean switchToLaojunIcon(Context context) { + if (context == null) { + Log.e(TAG, "切换失败:上下文为空"); + Toast.makeText(context, "图标切换失败", Toast.LENGTH_SHORT).show(); + return false; + } + + PackageManager pm = context.getPackageManager(); + ComponentName wukongComponent = new ComponentName(context, WUKONG_ACTIVITY); + ComponentName laojunComponent = new ComponentName(context, LAOJUN_ACTIVITY); + + try { + // 1. 禁用 Wukong 组件,启用 Laojun 组件 + disableComponent(pm, wukongComponent); + enableComponent(pm, laojunComponent); + + // 2. 创建 Laojun 组件对应的快捷方式(自动去重) + boolean shortcutCreated = createComponentShortcut(context, laojunComponent, LAOJUN_SHORTCUT_NAME, LAOJUN_SHORTCUT_ICON); + + // 3. 通知桌面刷新图标 + context.sendBroadcast(new Intent(Intent.ACTION_PACKAGE_CHANGED) + .setData(android.net.Uri.parse("package:" + context.getPackageName()))); + + // 4. 反馈结果 + String logMsg = shortcutCreated ? "启用 Laojun + 快捷方式创建成功" : "启用 Laojun 成功,快捷方式创建失败"; + String toastMsg = shortcutCreated ? "图标切换为 Laojun,已创建快捷方式" : "图标切换为 Laojun,快捷方式创建失败"; + Log.d(TAG, logMsg); + Toast.makeText(context, toastMsg, Toast.LENGTH_SHORT).show(); + + return true; + + } catch (Exception e) { + Log.e(TAG, "Laojun 图标切换失败:" + e.getMessage()); + // 失败兜底:启用 Wukong 组件 + enableComponent(pm, wukongComponent); + Toast.makeText(context, "图标切换失败", Toast.LENGTH_SHORT).show(); + return false; + } + } + + /** + * 切换到 Wukong 图标:启用 Wukong,禁用 Laojun + 创建 Wukong 快捷方式 + */ + public static boolean switchToWukongIcon(Context context) { + if (context == null) { + Log.e(TAG, "切换失败:上下文为空"); + Toast.makeText(context, "图标切换失败", Toast.LENGTH_SHORT).show(); + return false; + } + + PackageManager pm = context.getPackageManager(); + ComponentName wukongComponent = new ComponentName(context, WUKONG_ACTIVITY); + ComponentName laojunComponent = new ComponentName(context, LAOJUN_ACTIVITY); + + try { + // 1. 启用 Wukong 组件,禁用 Laojun 组件 + enableComponent(pm, wukongComponent); + disableComponent(pm, laojunComponent); + + // 2. 创建 Wukong 组件对应的快捷方式(自动去重) + boolean shortcutCreated = createComponentShortcut(context, wukongComponent, WUKONG_SHORTCUT_NAME, WUKONG_SHORTCUT_ICON); + + // 3. 通知桌面刷新图标 + context.sendBroadcast(new Intent(Intent.ACTION_PACKAGE_CHANGED) + .setData(android.net.Uri.parse("package:" + context.getPackageName()))); + + // 4. 反馈结果 + String logMsg = shortcutCreated ? "启用 Wukong + 快捷方式创建成功" : "启用 Wukong 成功,快捷方式创建失败"; + String toastMsg = shortcutCreated ? "图标切换为 Wukong,已创建快捷方式" : "图标切换为 Wukong,快捷方式创建失败"; + Log.d(TAG, logMsg); + Toast.makeText(context, toastMsg, Toast.LENGTH_SHORT).show(); + + return true; + + } catch (Exception e) { + Log.e(TAG, "Wukong 图标切换失败:" + e.getMessage()); + // 失败兜底:启用 Wukong 组件 + enableComponent(pm, wukongComponent); + Toast.makeText(context, "图标切换失败", Toast.LENGTH_SHORT).show(); + return false; + } + } + + /** + * 创建指定组件的桌面快捷方式(自动去重,兼容 Android 8.0+) + * @param component 目标组件(如 LAOJUN_ACTIVITY) + * @param name 快捷方式名称 + * @param iconRes 快捷方式图标资源ID + * @return 是否创建成功 + */ + private static boolean createComponentShortcut(Context context, ComponentName component, String name, int iconRes) { + if (context == null || component == null || name == null || iconRes == 0) { + Log.e(TAG, "快捷方式创建失败:参数为空"); + return false; + } + + // Android 8.0+(API 26+):使用 ShortcutManager(系统推荐) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + try { + PackageManager pm = context.getPackageManager(); + android.content.pm.ShortcutManager shortcutManager = context.getSystemService(android.content.pm.ShortcutManager.class); + if (shortcutManager == null || !shortcutManager.isRequestPinShortcutSupported()) { + Log.e(TAG, "系统不支持创建快捷方式"); + return false; + } + + // 检查是否已存在该组件的快捷方式(去重) + for (android.content.pm.ShortcutInfo info : shortcutManager.getPinnedShortcuts()) { + if (component.getClassName().equals(info.getIntent().getComponent().getClassName())) { + Log.d(TAG, "快捷方式已存在:" + component.getClassName()); + return true; + } + } + + // 构建启动目标组件的意图 + Intent launchIntent = new Intent(Intent.ACTION_MAIN) + .setComponent(component) + .addCategory(Intent.CATEGORY_LAUNCHER) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + + // 构建快捷方式信息 + android.content.pm.ShortcutInfo shortcutInfo = new android.content.pm.ShortcutInfo.Builder(context, component.getClassName()) + .setShortLabel(name) + .setLongLabel(name) + .setIcon(android.graphics.drawable.Icon.createWithResource(context, iconRes)) + .setIntent(launchIntent) + .build(); + + // 请求创建快捷方式(需用户确认) + shortcutManager.requestPinShortcut(shortcutInfo, null); + return true; + + } catch (Exception e) { + Log.e(TAG, "Android O+ 快捷方式创建失败:" + e.getMessage()); + return false; + } + } else { + // Android 8.0 以下:使用广播(兼容旧机型) + try { + // 构建启动目标组件的意图 + Intent launchIntent = new Intent(Intent.ACTION_MAIN) + .setComponent(component) + .addCategory(Intent.CATEGORY_LAUNCHER) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + + // 构建创建快捷方式的广播意图 + Intent installIntent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT"); + installIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, launchIntent); + installIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name); + installIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, + Intent.ShortcutIconResource.fromContext(context, iconRes)); + installIntent.putExtra("duplicate", false); // 禁止重复创建 + + context.sendBroadcast(installIntent); + return true; + + } catch (Exception e) { + Log.e(TAG, "Android O- 快捷方式创建失败:" + e.getMessage()); + return false; + } + } + } + + /** + * 启用组件(带状态检查,避免重复操作) + */ + private static void enableComponent(PackageManager pm, ComponentName component) { + if (pm.getComponentEnabledSetting(component) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + pm.setComponentEnabledSetting( + component, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP | PackageManager.SYNCHRONOUS + ); + } + } + + /** + * 禁用组件(带状态检查,避免重复操作) + */ + private static void disableComponent(PackageManager pm, ComponentName component) { + if (pm.getComponentEnabledSetting(component) != PackageManager.COMPONENT_ENABLED_STATE_DISABLED) { + pm.setComponentEnabledSetting( + component, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP | PackageManager.SYNCHRONOUS + ); + } + } +} + diff --git a/positions/src/main/java/cc/winboll/studio/positions/views/PositionTaskListView.java b/positions/src/main/java/cc/winboll/studio/positions/views/PositionTaskListView.java index 5608dbf6..8478fc45 100644 --- a/positions/src/main/java/cc/winboll/studio/positions/views/PositionTaskListView.java +++ b/positions/src/main/java/cc/winboll/studio/positions/views/PositionTaskListView.java @@ -33,6 +33,8 @@ import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Locale; +import cc.winboll.studio.positions.App; +import cc.winboll.studio.positions.AppLevel; public class PositionTaskListView extends LinearLayout { // 视图模式常量 @@ -380,7 +382,7 @@ public class PositionTaskListView extends LinearLayout { // 步骤3:刷新Adapter(局部刷新+范围通知,避免列表错乱) notifyItemRemoved(position); notifyItemRangeChanged(position, mAdapterData.size()); - + LogUtils.d(TAG, "Adapter已移除任务,刷新列表(位置索引=" + position + ")"); // 步骤4:通知外部(如Activity)任务已更新 @@ -457,7 +459,7 @@ public class PositionTaskListView extends LinearLayout { } }); } - + private String genSelectedTimeText(long timeMillis) { // 2. 格式化时间字符串(Java 7 用 SimpleDateFormat,需处理 ParseException) SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()); @@ -484,11 +486,15 @@ public class PositionTaskListView extends LinearLayout { Button btnCancel = dialogView.findViewById(R.id.btn_dialog_cancel); Button btnSave = dialogView.findViewById(R.id.btn_dialog_save); HourglassView hourglassView = dialogView.findViewById(R.id.hourglassView); - hourglassView.setHourglassId("hourglass_001"); - hourglassView.setHour(1); - hourglassView.setMinute(30); - hourglassView.setEnabled(false); // 开启开关 - + if (App._mAppLevel == AppLevel.WUKONG) { + hourglassView.setVisibility(View.GONE); + } else if (App._mAppLevel == AppLevel.WUKONG) { + hourglassView.setHourglassId("hourglass_001"); + hourglassView.setHour(1); + hourglassView.setMinute(30); + hourglassView.setEnabled(false); // 开启开关 + } + // 绑定外层对话框内的控件 diff --git a/positions/src/main/res/values/strings.xml b/positions/src/main/res/values/strings.xml index 68fdf541..4dfd1953 100644 --- a/positions/src/main/res/values/strings.xml +++ b/positions/src/main/res/values/strings.xml @@ -1,4 +1,7 @@ Positions Positions + 切换到悟空笔记 + 切换到老君道說 + 切换功能不可用 diff --git a/positions/src/main/res/xml/shortcuts.xml b/positions/src/main/res/xml/shortcuts.xml new file mode 100644 index 00000000..c14f0a72 --- /dev/null +++ b/positions/src/main/res/xml/shortcuts.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + +