一键生成default_workspace.xml文件

本文介绍了一种通过编程方式一键生成Android系统默认桌面布局文件default_workspace.xml的方法。该方法使用了StringBuilder来构建XML文件,并详细展示了如何从数据库中读取桌面图标信息并将其转换为XML格式的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

昨天写了一个app demo,功能:一键生成桌面布局文件default_workspace.xml。已经在8.1上验证ok。把代码片段贴上来。

TreeSet<IconWorkspace> mHotseatBean;//hotseat下的app
TreeSet<IconWorkspace> mAppWidgetBean;//appwidget
TreeSet<IconWorkspace> mIconBean;//app
TreeSet<IconWorkspace> mFolderBean;//folder
TreeSet<IconWorkspace> mFolderIconBean;//folder内的app
public class IconWorkspace{ //桌面的icon info
        public String packageName;//launcher:packageName
        public String className;//launcher:className
        public String title; //launcher:title
        public  int  screen;//launcher:screen
        public  int  container;//launcher:container
        public  int  cellX;//launcher:x
        public  int  cellY;//launcher:y
        public  int  rank = -1;
        public int spanX;//launcher:spanx
        public int spanY;//launcher:spany

        @Override
        public String toString() {
            return "["+"packageName:"+packageName+", className:"+className+",screen:"+screen+",cellX:"+cellX+",cellY:"+cellY+"]";
        }
    }
//属性
    String appwidgetBegin = "    <appwidget\n";
    String favoriteBegin = "    <favorite\n";
    String favoritesEnd = "</favorites>";
    String tagEnd = "        />\n\n";
    String attributeEnd = "\"\n";
    String folderBegin = "<folder\n";
    String folderEnd = "</folder>\n";

    String packageName = "        launcher:packageName=\"";
    String className = "        launcher:className=\"";
    String screen = "        launcher:screen=\"";
    String x = "        launcher:x=\"";
    String y = "        launcher:y=\"";
    String spanX = "        launcher:spanX=\"";
    String spanY = "        launcher:spanY=\"";
    String container_tag = "        launcher:container=\"";
    String title_tag = "        launcher:title=\"";
//数据库读取,保存对应数据到TreeSet
   public void getDefaultWorkspace(){
        Log.d(TAG,"zrx getDefaultWorkspace");
        final String AUTHORITY = "com.android.launcher3.settings";
        final Uri CONTENT_URI = Uri.parse("content://" +  AUTHORITY + "/favorites?notify=true");

        final String SCREEN = "screen";
        final String CELLX = "cellX";
        final String CELLY = "cellY";
        final String INTENT = "intent";
        final String CONTAINER = "container";
        final String ITEMTYPE = "itemType";
        final String SPANX = "spanX";
        final String SPANY = "spanY";
        final String APPWIDGETID = "appWidgetId";
        final String RANK = "rank";
        final String TITLE = "title";

        int itemtype;
        String intent;
        String title;
        int screen_db;
        int cellX_db;
        int cellY_db;
        int spanX_db;
        int spanY_db;
        int container;
        int appwidgetid;
        String[] in;
        Cursor cursor = null;



        try
        {
            cursor = getContentResolver().query(CONTENT_URI, null, null, null, null);

            if (cursor != null && cursor.getCount() > 0)
            {

                mAppWidgetBean.clear();
                mFolderIconBean.clear();
                mHotseatBean.clear();
                mFolderBean.clear();
                mIconBean.clear();
                while (cursor.moveToNext())
                {

                    int rank = -1 ;
                    IconWorkspace iconBean = new IconWorkspace();

                    itemtype = cursor.getInt(cursor.getColumnIndex(ITEMTYPE));
                    title = cursor.getString(cursor.getColumnIndex(TITLE));
                    intent = cursor.getString(cursor.getColumnIndex(INTENT));
                    screen_db = cursor.getInt(cursor.getColumnIndex(SCREEN));
                    cellX_db = cursor.getInt(cursor.getColumnIndex(CELLX));
                    cellY_db = cursor.getInt(cursor.getColumnIndex(CELLY));
                    spanX_db = cursor.getInt(cursor.getColumnIndex(SPANX));
                    spanY_db = cursor.getInt(cursor.getColumnIndex(SPANY));
                    container = cursor.getInt(cursor.getColumnIndex(CONTAINER));
                    appwidgetid = cursor.getInt(cursor.getColumnIndex(APPWIDGETID));
                   // Log.d("MainActivity", "zrx--title:"+title+",itemtype:" + itemtype+",appwidgetid:"+appwidgetid+",rank:"+rank);

                    if(intent!=null){
                        Intent intent1 = Intent.parseUri(intent, 0);
                        ComponentName component = intent1.getComponent();
                        if(component!=null)
                        {
                            iconBean.className = component.getClassName();
                            iconBean.packageName = component.getPackageName();
                        }
                       /* in = intent.substring(intent.indexOf("component=")+10, intent.indexOf(";end")).split("/");
                        iconBean.className = in[1];
                        iconBean.packageName = in[0];
                        Log.d(TAG,"zrx className:"+in[1]+",packageName:"+in[0]);*/
                    }


                    iconBean.title = title;
                    iconBean.cellX = cellX_db;
                    iconBean.cellY = cellY_db;
                    iconBean.screen = screen_db;
                    iconBean.container = container;
                    iconBean.spanX = spanX_db;
                    iconBean.spanY = spanY_db;


                    Log.i(TAG,"zrx--appwidgetid:"+appwidgetid);
                  //  Log.d(TAG,"zrx title:"+title+", container:"+container+",")
                    if (container == -101)
                    {//hotseat
                        mHotseatBean.add(iconBean);
                        continue;

                    }

                    if(appwidgetid > 0){//app widget
                        mAppWidgetBean.add(iconBean);
                        continue;

                    }

                    if(container > 0){
                        rank = cursor.getInt(cursor.getColumnIndex(RANK));
                        Log.d("MainActivty","zrx--rank:"+rank);
                    }
                    iconBean.rank = rank;

                    if(rank < 0){
                        if(itemtype == 2){
                            iconBean.title = title;
                            mFolderBean.add(iconBean);
                            Log.d(TAG, "zrx mFolderBean=" +iconBean.toString());
                        }else {
                            mIconBean.add(iconBean);
                        }
                    }else {
                        mFolderIconBean.add(iconBean) ;
                        Log.d(TAG, "zrx mFolderIconBean=" +iconBean.toString());
                    }
                }

               // builder.append(favoritesEnd);
            }
        } catch (Exception e)
        {
            e.printStackTrace();
        } finally
        {
            cursor.close();
            writeFile();
        }

    }
//生成default_workspace.xml文件保存到/storage/emulated/0/
   private void writeFile() {

        Log.i(TAG, Environment.getExternalStorageDirectory().getPath()
                + "/default_workspace.xml");

        File targetFile = new File(Environment.getExternalStorageDirectory().getPath()
                + "/default_workspace.xml");
        if (targetFile.exists()) {
            targetFile.delete();
        }

        builder = new StringBuilder();
        builder.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
        builder.append("<favorites xmlns:launcher=\"http://schemas.android.com/apk/res-auto/com.android.launcher3\">\n");

        for(IconWorkspace iconBean:mHotseatBean){
            builder.append("    <!-- ");
            builder.append(iconBean.title);
            builder.append(" -->\n");

            builder.append(favoriteBegin);

            if (iconBean.packageName != null)
            {
                builder.append(packageName);
                builder.append(iconBean.packageName);
                builder.append(attributeEnd);

                builder.append(className);
                builder.append(iconBean.className);
                builder.append(attributeEnd);

            }
            builder.append(container_tag);
            builder.append(iconBean.container);
            builder.append(attributeEnd);

            builder.append(screen);
            builder.append(iconBean.screen);
            builder.append(attributeEnd);

            builder.append(x);
            builder.append(iconBean.cellX);
            builder.append(attributeEnd);

            builder.append(y);
            builder.append(iconBean.cellY);
            builder.append(attributeEnd);

            builder.append(tagEnd);
        }


        for(IconWorkspace iconBean:mAppWidgetBean){
            builder.append("    <!-- ");
            builder.append(iconBean.title);
            builder.append(" -->\n");

            builder.append(appwidgetBegin);

            if(iconBean.packageName != null){
                builder.append(packageName);
                builder.append(iconBean.packageName);
                builder.append(attributeEnd);

                builder.append(className);
                builder.append(iconBean.className);
                builder.append(attributeEnd);
            }

            builder.append(screen);
            builder.append(iconBean.screen);
            builder.append(attributeEnd);

            builder.append(x);
            builder.append(iconBean.cellX);
            builder.append(attributeEnd);

            builder.append(y);
            builder.append(iconBean.cellY);
            builder.append(attributeEnd);

            builder.append(spanX);
            builder.append(iconBean.spanX);
            builder.append(attributeEnd);

            builder.append(spanY);
            builder.append(iconBean.spanY);
            builder.append(attributeEnd);

            builder.append(tagEnd);
        }

        for(IconWorkspace iconBean: mIconBean ){
            builder.append("    <!-- ");
            builder.append(iconBean.title);
            builder.append(" -->\n");

            builder.append(favoriteBegin);

            if (iconBean.packageName != null)
            {
                builder.append(packageName);
                builder.append(iconBean.packageName);
                builder.append(attributeEnd);

                builder.append(className);
                builder.append(iconBean.className);
                builder.append(attributeEnd);

            }
            /*builder.append(container_tag);
            builder.append(iconBean.container);
            builder.append(attributeEnd);*/

            builder.append(screen);
            builder.append(iconBean.screen);
            builder.append(attributeEnd);

            builder.append(x);
            builder.append(iconBean.cellX);
            builder.append(attributeEnd);

            builder.append(y);
            builder.append(iconBean.cellY);
            builder.append(attributeEnd);

            builder.append(tagEnd);
        }

        for(IconWorkspace iconBean:mFolderBean){
            builder.append("    <!-- ");
            builder.append(iconBean.title);
            builder.append(" -->\n");

            builder.append(folderBegin);

            builder.append(title_tag);
            builder.append(iconBean.title);
            builder.append(attributeEnd);

            builder.append(screen);
            builder.append(iconBean.screen);
            builder.append(attributeEnd);

            builder.append(x);
            builder.append(iconBean.cellX);
            builder.append(attributeEnd);

            builder.append(y);
            builder.append(iconBean.cellY);
            builder.append(attributeEnd);

            builder.append(tagEnd);

            for(IconWorkspace bean:mFolderIconBean){
                builder.append("    <!-- ");
                builder.append(bean.title);
                builder.append(" -->\n");

                builder.append(favoriteBegin);

                if (bean.packageName != null)
                {
                    builder.append(packageName);
                    builder.append(bean.packageName);
                    builder.append(attributeEnd);

                    builder.append(className);
                    builder.append(bean.className);
                    builder.append(attributeEnd);

                }

                builder.append(screen);
                builder.append(bean.screen);
                builder.append(attributeEnd);

                builder.append(x);
                builder.append(bean.cellX);
                builder.append(attributeEnd);

                builder.append(y);
                builder.append(bean.cellY);
                builder.append(attributeEnd);

                builder.append(tagEnd);
            }

            builder.append(folderEnd);

        }

        builder.append(favoritesEnd);


        OutputStreamWriter osw;
        try{
            osw = new OutputStreamWriter(
                    new FileOutputStream(targetFile),"utf-8");

            osw.write(builder.toString());
            osw.flush();
            osw.close();

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        builder=null;
    }
添加权限,在android 6.0及以上动态设置权限
<uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS"/>
    <uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

public static final int REQUEST_PERMISSION_ALL = 0;
    public static String[] sAllPermissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};
    private void checkPermission(){
        List<String> noOkPermissions = new ArrayList<>();

        for (String permission : sAllPermissions) {
            if (ActivityCompat.checkSelfPermission(this,permission) == PackageManager.PERMISSION_DENIED) {
                noOkPermissions.add(permission);
            }
        }
        if (noOkPermissions.size() <= 0)
            return ;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(noOkPermissions.toArray(new String[noOkPermissions.size()]), REQUEST_PERMISSION_ALL);
        }
    }

上面的代码是用StringBuilder拼接字符串生成一份xml文件,代码质量很low,质量高一点的代码可以用XmlSerializer格式化生成文档

android 版本8.0以下的平台可以戳我

我最近在学习激光雷达SLAM。我安装了ubuntu22.04并且根据博主鱼香ros的一键安装了ros2 humble版本。为了运行lego loam,我在github上找到了博主鱼香ros改写的lego loam humble版,并且我已经成功编译。但是rviz中并没有轨迹,于是我下载了原作者的bag文件并将其转换成了.bd3文件,但仍然没有轨迹。第一个终端窗口:lei@leiguoguo:~/ros2_ws$ ros2 launch lego_loam_sr run.launch.py [INFO] [launch]: All log files can be found below /home/lei/.ros/log/2025-06-17-10-36-39-658661-leiguoguo-7646 [INFO] [launch]: Default logging verbosity is set to INFO [INFO] [lego_loam_sr-1]: process started with pid [7647] [INFO] [static_transform_publisher-2]: process started with pid [7649] [INFO] [static_transform_publisher-3]: process started with pid [7651] [INFO] [static_transform_publisher-4]: process started with pid [7653] [INFO] [rviz2-5]: process started with pid [7655] [static_transform_publisher-4] RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED is now ignored. Please set RCUTILS_LOGGING_USE_STDOUT and RCUTILS_LOGGING_BUFFERED_STREAM to control the stream and the buffering of log messages. [static_transform_publisher-3] RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED is now ignored. Please set RCUTILS_LOGGING_USE_STDOUT and RCUTILS_LOGGING_BUFFERED_STREAM to control the stream and the buffering of log messages. [static_transform_publisher-2] RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED is now ignored. Please set RCUTILS_LOGGING_USE_STDOUT and RCUTILS_LOGGING_BUFFERED_STREAM to control the stream and the buffering of log messages. [static_transform_publisher-3] [WARN] [1750127799.715366258] []: Old-style arguments are deprecated; see --help for new-style arguments [static_transform_publisher-4] [WARN] [1750127799.715367461] []: Old-style arguments are deprecated; see --help for new-style arguments [static_transform_publisher-2] [WARN] [1750127799.715368389] []: Old-style arguments are deprecated; see --help for new-style arguments [rviz2-5] RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED is now ignored. Please set RCUTILS_LOGGING_USE_STDOUT and RCUTILS_LOGGING_BUFFERED_STREAM to control the stream and the buffering of log messages. [rviz2-5] Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome. Use QT_QPA_PLATFORM=wayland to run on Wayland anyway. [lego_loam_sr-1] RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED is now ignored. Please set RCUTILS_LOGGING_USE_STDOUT and RCUTILS_LOGGING_BUFFERED_STREAM to control the stream and the buffering of log messages. [static_transform_publisher-3] [INFO] [1750127799.736069007] [base_link_to_camera]: Spinning until stopped - publishing transform [static_transform_publisher-3] translation: ('0.000000', '0.000000', '0.000000') [static_transform_publisher-3] rotation: ('-0.499999', '-0.500000', '-0.500000', '0.500001') [static_transform_publisher-3] from 'camera' to 'base_link' [static_transform_publisher-4] [INFO] [1750127799.736074443] [velodyne_to_base_link]: Spinning until stopped - publishing transform [static_transform_publisher-4] translation: ('0.000000', '0.000000', '0.000000') [static_transform_publisher-4] rotation: ('0.000000', '0.000000', '0.000000', '1.000000') [static_transform_publisher-4] from 'base_link' to 'velodyne' [static_transform_publisher-2] [INFO] [1750127799.736076789] [camera_init_to_map]: Spinning until stopped - publishing transform [static_transform_publisher-2] translation: ('0.000000', '0.000000', '0.000000') [static_transform_publisher-2] rotation: ('0.500000', '0.499999', '0.500000', '0.500001') [static_transform_publisher-2] from 'map' to 'camera_init' [lego_loam_sr-1] [INFO] [1750127799.756201716] [image_projection]: ----> Started. [lego_loam_sr-1] [INFO] [1750127799.756278719] [feature_association]: ----> Started. [lego_loam_sr-1] [INFO] [1750127799.756287725] [map_optimization]: ----> Started. [lego_loam_sr-1] [INFO] [1750127799.756294112] [transform_fusion]: ----> Started. [rviz2-5] [INFO] [1750127801.783291447] [rviz2]: Stereo is NOT SUPPORTED [rviz2-5] [INFO] [1750127801.783409655] [rviz2]: OpenGl version: 4.6 (GLSL 4.6) [rviz2-5] [INFO] [1750127801.796149614] [rviz2]: Stereo is NOT SUPPORTED ros2 launch lego_loam /home/lei/ros2_ws/src/LeGO-LOAM-ROS2/LeGO-LOAM/launch/run.launch.py [INFO] [rviz2-5]: process has finished cleanly [pid 7655] 第二个终端创窗口:lei@leiguoguo:~/ros2_ws$ source /opt/ros/humble/setup.bash lei@leiguoguo:~/ros2_ws$ source ~/ros2_ws/install/setup.bash lei@leiguoguo:~/ros2_ws$ ros2 bag play /home/lei/ros2_bag [INFO] [1750127971.316237348] [rosbag2_storage]: Opened database '/home/lei/ros2_bag/ros2_bag.db3' for READ_ONLY. [INFO] [1750127971.316356460] [rosbag2_player]: Set rate to 1 [WARN] [1750127971.319173825] [rosbag2_player]: Ignoring a topic '/rosout', reason: Something went wrong loading the typesupport library for message type rosgraph_msgs/Log. Library could not be found.. [WARN] [1750127971.319306206] [rosbag2_player]: Ignoring a topic '/rosout_agg', reason: Something went wrong loading the typesupport library for message type rosgraph_msgs/Log. Library could not be found.. [INFO] [1750127971.328125593] [rosbag2_player]: Adding keyboard callbacks. [INFO] [1750127971.328146451] [rosbag2_player]: Press SPACE for Pause/Resume [INFO] [1750127971.328154723] [rosbag2_player]: Press CURSOR_RIGHT for Play Next Message [INFO] [1750127971.328161427] [rosbag2_player]: Press CURSOR_UP for Increase Rate 10% [INFO] [1750127971.328167456] [rosbag2_player]: Press CURSOR_DOWN for Decrease Rate 10% [INFO] [1750127971.328443036] [rosbag2_storage]: Opened database '/home/lei/ros2_bag/ros2_bag.db3' for READ_ONLY. 第三个终端窗口:lei@leiguoguo:~/ros2_ws$ sudo apt update [sudo] lei 的密码: 命中:1 http://mirrors.huaweicloud.com/repository/ubuntu jammy InRelease 获取:2 http://mirrors.tuna.tsinghua.edu.cn/ros2/ubuntu jammy InRelease [4,682 B] 命中:4 https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu jammy InRelease 命中:3 https://packages.microsoft.com/repos/code stable InRelease 命中:5 http://mirrors.huaweicloud.com/repository/ubuntu jammy-updates InRelease 命中:6 http://mirrors.huaweicloud.com/repository/ubuntu jammy-backports InRelease 命中:7 http://mirrors.huaweicloud.com/repository/ubuntu jammy-security InRelease 已下载 4,682 B,耗时 7秒 (653 B/s) 正在读取软件包列表... 完成 正在分析软件包的依赖关系树... 完成 正在读取状态信息... 完成 有 268 个软件包可以升级。请执行 ‘apt list --upgradable’ 来查看它们。 lei@leiguoguo:~/ros2_ws$ cd .. lei@leiguoguo:~$ sudo apt install --reinstall ros-humble-rosgraph-msgs 正在读取软件包列表... 完成 正在分析软件包的依赖关系树... 完成 正在读取状态信息... 完成 升级了 0 个软件包,新安装了 0 个软件包,重新安装了 1 个软件包,要卸载 0 个软件包,有 268 个软件包未被升级。 需要下载 36.2 kB 的归档。 解压缩后会消耗 0 B 的额外空间。 获取:1 http://mirrors.tuna.tsinghua.edu.cn/ros2/ubuntu jammy/main amd64 ros-humble-rosgraph-msgs amd64 1.2.1-1jammy.20250607.025930 [36.2 kB] 已下载 36.2 kB,耗时 1秒 (39.1 kB/s) (正在读取数据库 ... 系统当前共安装有 262567 个文件和目录。) 准备解压 .../ros-humble-rosgraph-msgs_1.2.1-1jammy.20250607.025930_amd64.deb ... 正在解压 ros-humble-rosgraph-msgs (1.2.1-1jammy.20250607.025930) 并覆盖 (1.2.1-1jammy.20250607.025930) ... 正在设置 ros-humble-rosgraph-msgs (1.2.1-1jammy.20250607.025930) ... 正在处理用于 libc-bin (2.35-0ubuntu3.8) 的触发器 ...
最新发布
06-18
一 Launcher默认界面配置(default workspace) 2 1 界面默认配置文件 2 2 LauncherProvider java的loadFavorites分析 3 二 Icon修改 界面布局调整 壁纸设置 5 1 图标大小和标题大小 5 2 Launcher 图标加入默认背景 6 3 更换Launcher默认壁纸 7 4 壁纸设置过程: 8 三 Launcher启动和初始化 9 1 Launcher进程启动过程 9 2 Launcher初始化――LauncherApplication 10 3 Launcher java初始化 12 1 Callbacks接口 15 2 数据加载流程 16 4 LoaderTask的run 方法 17 5 workspace加载数据 18 6 workspace绑定数据 20 7 ALL APP数据加载绑定 22 五 HotSeat分析 24 1 Hotseat配置文件 24 2 Hotseat构造函数 26 3 Hotseat加载数据 27 4 Hotseat绑定数据 27 5 Hotseat类 28 6 总结 30 六 页面滑动 PagedView 30 七 AllApp全部应用列表 AppsCustomizeTabHost 38 1 AllApp列表配置文件 38 2 AppsCustomizeTabHost分析 40 3 Tab变化时执行onTabChanged 41 八 AllApp界面拖拽元素 42 1 触摸拦截 43 2 handleTouchEvent方法 43 4 拖曳按钮 44 九 Launcher启动APP流程 45 1 WorkSpace触摸 45 2 CellLayout的onInterceptTouchEvent 方法 46 3 WorkSpace的onTouch 事件 47 4 BubbleTextView 48 5 onClick 方法 49 6 总结 50 1 常用类介绍 50 2 Launcher的数据库 51">一 Launcher默认界面配置(default workspace) 2 1 界面默认配置文件 2 2 LauncherProvider java的loadFavorites分析 3 二 Icon修改 界面布局调整 壁纸设置 5 1 图标大小和标题大小 5 2 Launcher 图标加入默认背景 6 3 更换Launcher默认壁纸 7 [更多]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值