添加应用图标切换初稿

This commit is contained in:
ZhanGSKen
2025-11-10 11:43:26 +08:00
parent 55d72c3f82
commit 17d2422690
8 changed files with 373 additions and 52 deletions

View File

@@ -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

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 切换启动入口的快捷菜单 -->
<shortcut
android:shortcutId="switch_launcher_main"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:shortcutShortLabel="@string/switch_to_main"
android:shortcutLongLabel="@string/switch_to_main"
android:shortcutDisabledMessage="@string/switch_disabled">
<intent
android:action="cc.winboll.studio.positions.MainActivity"
android:targetPackage="cc.winboll.studio.positions.beta"
android:targetClass="cc.winboll.studio.positions.MainActivity"
android:data="switch_launcher_main" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
<shortcut
android:shortcutId="switch_launcher_laojun"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:shortcutShortLabel="@string/switch_to_laojun"
android:shortcutLongLabel="@string/switch_to_laojun"
android:shortcutDisabledMessage="@string/switch_disabled">
<intent
android:action="cc.winboll.studio.positions.MainActivityLaojun"
android:targetPackage="cc.winboll.studio.positions.beta"
android:targetClass="cc.winboll.studio.positions.MainActivity"
android:data="switch_launcher_laojun" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
</shortcuts>

View File

@@ -3,23 +3,14 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.positions">
<!-- 只能在前台获取精确的位置信息 -->
<!-- 权限配置不变 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- 只有在前台运行时才能获取大致位置信息 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- 在后台使用位置信息 -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<!-- 运行前台服务 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- 运行“location”类型的前台服务 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
<!-- 拥有完全的网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-feature
android:name="android.hardware.location.gps"
@@ -33,41 +24,59 @@
android:resizeableActivity="true"
android:name=".App">
<!-- 主Activity非启动入口无需LAUNCHER意图 -->
<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- 新增应用启动Alias入口桌面会显示两个图标 -->
<!-- Wukong 别名入口(默认禁用,通过代码启用 -->
<activity-alias
android:name=".MainActivityWukong"
android:targetActivity=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:enabled="true"> <!-- 默认禁用,避免桌面显示 -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- 长按图标快捷菜单 -->
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity-alias>
<!-- Laojun 别名入口(默认禁用,通过代码启用) -->
<activity-alias
android:name=".MainActivityLaojun"
android:targetActivity=".MainActivity"
android:exported="true"
android:label="@string/app_laojun_name"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/ic_launcher"
android:enabled="false"> <!-- 默认禁用,避免桌面显示 -->
<!-- 配置为启动入口 -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- 长按图标快捷菜单 -->
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity-alias>
<!-- 其他配置不变 -->
<meta-data
android:name="android.max_aspect"
android:value="4.0"/>
<activity android:name=".GlobalApplication$CrashActivity"/>
<activity android:name="cc.winboll.studio.positions.activities.LocationActivity"/>
<meta-data
@@ -77,25 +86,20 @@
<service
android:name=".services.MainService"
android:exported="false"/>
<service
android:name=".services.AssistantService"
android:exported="false"/>
<service
android:name=".services.DistanceRefreshService"
android:exported="false"/>
<receiver android:name="cc.winboll.studio.positions.receivers.MotionStatusReceiver">
<intent-filter>
<action android:name="cc.winboll.studio.positions.receivers.MotionStatusReceiver"/>
</intent-filter>
</receiver>
</application>
</manifest>

View File

@@ -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;
/**
* 主页面:仅负责
@@ -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保留原逻辑设置页面标题
@@ -96,6 +101,19 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
//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() {

View File

@@ -0,0 +1,222 @@
package cc.winboll.studio.positions.utils;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @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
);
}
}
}

View File

@@ -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 {
// 视图模式常量
@@ -484,10 +486,14 @@ 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);
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); // 开启开关
}

View File

@@ -1,4 +1,7 @@
<resources>
<string name="app_name">Positions</string>
<string name="app_laojun_name">Positions</string>
<string name="switch_to_main">切换到悟空笔记</string>
<string name="switch_to_laojun">切换到老君道說</string>
<string name="switch_disabled">切换功能不可用</string>
</resources>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 切换启动入口的快捷菜单 -->
<shortcut
android:shortcutId="switch_launcher_main"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:shortcutShortLabel="@string/switch_to_main"
android:shortcutLongLabel="@string/switch_to_main"
android:shortcutDisabledMessage="@string/switch_disabled">
<intent
android:action="cc.winboll.studio.positions.MainActivity"
android:targetPackage="cc.winboll.studio.positions"
android:targetClass="cc.winboll.studio.positions.MainActivity"
android:data="switch_launcher" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
<shortcut
android:shortcutId="switch_launcher_laojun"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:shortcutShortLabel="@string/switch_to_laojun"
android:shortcutLongLabel="@string/switch_to_laojun"
android:shortcutDisabledMessage="@string/switch_disabled">
<intent
android:action="cc.winboll.studio.positions.MainActivityLaojun"
android:targetPackage="cc.winboll.studio.positions"
android:targetClass="cc.winboll.studio.positions.MainActivity"
android:data="switch_launcher" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
</shortcuts>