Android launcher3 -- launcher3源码3

Android launcher3 – launcher3源码3

前面讲了简单的默认布局xml:Android launcher3 – launcher3源码1
本章主要讲解默认桌面布局存储到数据库中。

默认布局读取

手机:华为Honor 5C
默认布局:default_workspace_4x4.xml

ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles() {
    ArrayList<InvariantDeviceProfile> predefinedDeviceProfiles = new ArrayList<>();
    // width, height, #rows, #columns, #folder rows, #folder columns,
    // iconSize, iconTextSize, #hotseat, #hotseatIconSize, defaultLayoutId.
...
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 4",
            335, 567, 4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
    predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 5",
            359, 567, 4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
...
    LogHelper.i("getPredefinedDeviceProfiles()", " predefinedDeviceProfiles length is " + predefinedDeviceProfiles.size());
    return predefinedDeviceProfiles;
}

该方法返回了InvariantDeviceProfile的ArrayList数组;看下面Log返回了11个InvariantDeviceProfile;在Log中minWidthDps=336.0,minHeightDps=580.0,通过手机DisplayMetrics属性计算获取的显示的workspace最小宽高。

08-03 23:54:36.074 I/XhLauncher( 2606): [ (InvariantDeviceProfile.java:135)#<init> ]
08-03 23:54:36.074 I/XhLauncher( 2606): minWidthDps=336.0,minHeightDps=580.0
08-03 23:54:36.075 I/XhLauncher( 2606): getPredefinedDeviceProfiles(): [ (InvariantDeviceProfile.java:207)#GetPredefinedDeviceProfiles ]
08-03 23:54:36.075 I/XhLauncher( 2606):  predefinedDeviceProfiles length is 11

InvariantDeviceProfile.java中默认布局Id: defaultLayoutId = closestProfile.defaultLayoutId

ArrayList<InvariantDeviceProfile> closestProfiles =
                findClosestDeviceProfiles(minWidthDps, minHeightDps, getPredefinedDeviceProfiles());

findClosestDeviceProfiles返回按照“与指定宽度和高度接近”排序的设备配置文件ArrayList数组。最终取最接近的数组的第一个数据:InvariantDeviceProfile closestProfile = closestProfiles.get(0);

ArrayList<InvariantDeviceProfile> findClosestDeviceProfiles(
        final float width, final float height, ArrayList<InvariantDeviceProfile> points) {

    // Sort the profiles by their closeness to the dimensions
    ArrayList<InvariantDeviceProfile> pointsByNearness = points;
    Collections.sort(pointsByNearness, new Comparator<InvariantDeviceProfile>() {
        public int compare(InvariantDeviceProfile a, InvariantDeviceProfile b) {
            return (int) (dist(width, height, a.minWidthDps, a.minHeightDps)
                    - dist(width, height, b.minWidthDps, b.minHeightDps));
        }
    });

    return pointsByNearness;
}

最后获取default_workspace_4x4.xml布局

private DefaultLayoutParser getDefaultLayoutParser() {
    int defaultLayout = LauncherAppState.getInstance()
            .getInvariantDeviceProfile().defaultLayoutId;
    return new DefaultLayoutParser(getContext(), mOpenHelper.mAppWidgetHost,
            mOpenHelper, getContext().getResources(), defaultLayout);
}

默认布局解析

截图说明流程

这里写图片描述

这里写图片描述

调用AutoInstallsLayout.java类loadLayout方法,进入解析xml
这里写图片描述

这里写图片描述

这里写图片描述

/**
 * Parses the current node and returns the number of elements added.
 */
protected int parseAndAddNode(
        XmlResourceParser parser,
        HashMap<String, TagParser> tagParserMap,
        ArrayList<Long> screenIds)
        throws XmlPullParserException, IOException {

    if (TAG_INCLUDE.equals(parser.getName())) {
        final int resId = getAttributeResourceValue(parser, ATTR_WORKSPACE, 0);
        if (resId != 0) {
            // recursively load some more favorites, why not?
            return parseLayout(resId, screenIds);
        } else {
            return 0;
        }
    }
......
    TagParser tagParser = tagParserMap.get(parser.getName());
    if (tagParser == null) {
        LogHelper.d(TAG, "Ignoring unknown element tag: " + parser.getName());
        return 0;
    }
    long newElementId = tagParser.parseAndAdd(parser);
......
}

各种标签解析

在parseLayout方法中获取各种解析方式getLayoutElementsMap();
这里写图片描述

都是继承(interface)接口TagParser,方法parseAndAdd正如描述功能是:解析标记并添加到数据库
这里写图片描述


例如:FolderParser文件夹标签解析
布局xml:

<folder
    launcher:container="-100"
    launcher:screen="0"
    launcher:title="@string/folder_name"
    launcher:x="0"
    launcher:y="2">
    <favorite
        launcher:className="com.android.mediacenter.MainActivity"
        launcher:packageName="com.android.mediacenter" />
    <favorite
        launcher:className="com.android.settings.HWSettings"
        launcher:packageName="com.android.settings" />
</folder>

代码:

protected class FolderParser implements TagParser {
    private final HashMap<String, TagParser> mFolderElements;

    public FolderParser() {
        this(getFolderElementsMap());
    }

    public FolderParser(HashMap<String, TagParser> elements) {
        mFolderElements = elements;
    }

    @Override
    public long parseAndAdd(XmlResourceParser parser)
            throws XmlPullParserException, IOException {
        final String title;
        final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0);
        if (titleResId != 0) {
            title = mSourceRes.getString(titleResId);
        } else {
            title = mContext.getResources().getString(R.string.folder_name);
        }

        mValues.put(Favorites.TITLE, title);
        mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_FOLDER);
        mValues.put(Favorites.SPANX, 1);
        mValues.put(Favorites.SPANY, 1);
        mValues.put(Favorites._ID, mCallback.generateNewItemId());
        long folderId = mCallback.insertAndCheck(mDb, mValues);
        if (folderId < 0) {
            if (LOGD) Log.e(TAG, "Unable to add folder");
            return -1;
        }

        final ContentValues myValues = new ContentValues(mValues);
        ArrayList<Long> folderItems = new ArrayList<Long>();

        int type;
        int folderDepth = parser.getDepth();
        int rank = 0;
        while ((type = parser.next()) != XmlPullParser.END_TAG ||
                parser.getDepth() > folderDepth) {
            if (type != XmlPullParser.START_TAG) {
                continue;
            }
            mValues.clear();
            mValues.put(Favorites.CONTAINER, folderId);
            mValues.put(Favorites.RANK, rank);

            TagParser tagParser = mFolderElements.get(parser.getName());
            if (tagParser != null) {
                final long id = tagParser.parseAndAdd(parser);
                if (id >= 0) {
                    folderItems.add(id);
                    rank++;
                }
            } else {
                throw new RuntimeException("Invalid folder item " + parser.getName());
            }
        }

        long addedId = folderId;

        // We can only have folders with >= 2 items, so we need to remove the
        // folder and clean up if less than 2 items were included, or some
        // failed to add, and less than 2 were actually added
        if (folderItems.size() < 2) {
            // Delete the folder
            Uri uri = Favorites.getContentUri(folderId);
            SqlArguments args = new SqlArguments(uri, null, null);
            mDb.delete(args.table, args.where, args.args);
            addedId = -1;

            // If we have a single item, promote it to where the folder
            // would have been.
            if (folderItems.size() == 1) {
                final ContentValues childValues = new ContentValues();
                copyInteger(myValues, childValues, Favorites.CONTAINER);
                copyInteger(myValues, childValues, Favorites.SCREEN);
                copyInteger(myValues, childValues, Favorites.CELLX);
                copyInteger(myValues, childValues, Favorites.CELLY);

                addedId = folderItems.get(0);
                mDb.update(LauncherProvider.TABLE_FAVORITES, childValues,
                        Favorites._ID + "=" + addedId, null);
            }
        }
        return addedId;
    }
}
  1. 文件名:布局标签launcher:title;代码默认文件夹名R.string.folder_name
  2. 文件夹中图标:folderItems.size(),如果图标少于2个则要删除文件夹图表形式,若刚好为1图标时,添加图标快捷方式
  3. 添加到数据库:long folderId = mCallback.insertAndCheck(mDb, mValues);如2中文件夹只有一个图标时,更新数据mDb.update(LauncherProvider.TABLE_FAVORITES, childValues, Favorites._ID + “=” + addedId, null)。

添加到数据库 的 相关代码:

@Override
public long insertAndCheck(SQLiteDatabase db, ContentValues values) {
    return dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
}
static long dbInsertAndCheck(DatabaseHelper helper,
                             SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) {
    if (values == null) {
        throw new RuntimeException("Error: attempting to insert null values");
    }
    if (!values.containsKey(LauncherSettings.ChangeLogColumns._ID)) {
        throw new RuntimeException("Error: attempting to add item without specifying an id");
    }
    helper.checkId(table, values);
    return db.insert(table, nullColumnHack, values);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xhBruce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值