1. 程式人生 > >【學以致用】android功能實現7---android8.0 Launcher獲取快捷方式原始碼分析(3)

【學以致用】android功能實現7---android8.0 Launcher獲取快捷方式原始碼分析(3)

獲取完快捷方式的資訊之後,便是如何具體的將快捷方式的名字,圖示和開啟方式放置到桌面上。

最後一步addAndBindAddedWorkspaceItems(
                new LazyShortcutsProvider(context.getApplicationContext(), items));

先將獲取的LazyShortcutsProvider,是將PendingInstallShortcutInfo放在LazyShortcutsProvider,然後傳入addAndBindAddedWorkspaceItems

這裡實際是做了一個任務,工作包括獲取 workspaceApps = mAppsProvider.get()

分配該快捷方式的位置Pair<Long, int[]> coords = findSpaceForItem(app, dataModel, workspaceScreens, addedWorkspaceScreensFinal, item.spanX, item.spanY); 

以及程式碼裡面註釋提到的這兩句。

// Add the shortcut to the db
 // Save the ShortcutInfo for binding in the workspace

public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
    List<ItemInfo> workspaceApps = mAppsProvider.get();
    if (workspaceApps.isEmpty()) {
        return;
    }
    Context context = app.getContext();

    final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
    final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<>();

    // Get the list of workspace screens.  We need to append to this list and
    // can not use sBgWorkspaceScreens because loadWorkspace() may not have been
    // called.
    ArrayList<Long> workspaceScreens = LauncherModel.loadWorkspaceScreensDb(context);
    synchronized(dataModel) {
        for (ItemInfo item : workspaceApps) {
            if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
                    item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
                // Short-circuit this logic if the icon exists somewhere on the workspace
                if (shortcutExists(dataModel, item.getIntent(), item.user)) {
                    continue;
                }
            }

            // Find appropriate space for the item.
            Pair<Long, int[]> coords = findSpaceForItem(app, dataModel, workspaceScreens,
                    addedWorkspaceScreensFinal, item.spanX, item.spanY);
            long screenId = coords.first;
            int[] cordinates = coords.second;

            ItemInfo itemInfo;
            if (item instanceof ShortcutInfo || item instanceof FolderInfo ||
                    item instanceof LauncherAppWidgetInfo) {
                itemInfo = item;
            } else if (item instanceof AppInfo) {
                itemInfo = ((AppInfo) item).makeShortcut();
            } else {
                throw new RuntimeException("Unexpected info type");
            }

            // Add the shortcut to the db
            getModelWriter().addItemToDatabase(itemInfo,
                    LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId,
                    cordinates[0], cordinates[1]);

            // Save the ShortcutInfo for binding in the workspace
            addedItemsFinal.add(itemInfo);
        }
    }
}

獲取到的workspaceApps = mAppsProvider.get()的內容是pendingInfo.getItemInfo()

最終返回的藏在PendingInstallShortcutInfo中的itemInfo引數,getItemInfo()通過從外界獲取的資訊轉化成的相容性ShortcutInfoCompat生成Launcher可用的ShortcutInfo 並且傳入icon引數

} else if (shortcutInfo != null) {
    ShortcutInfo si = new ShortcutInfo(shortcutInfo, mContext);
    si.iconBitmap = LauncherIcons.createShortcutIcon(shortcutInfo, mContext);
    return si;

}

這裡獲取外來資訊的圖片資訊。

LauncherAppState app = LauncherAppState.getInstance(context);
Drawable unbadgedDrawable = DeepShortcutManager.getInstance(context)
        .getShortcutIconDrawable(shortcutInfo, app.getInvariantDeviceProfile().fillResIconDpi);

其方法是:通過getShortcutInfo和螢幕的density資訊,通過LauncherApps在手機中獲取對應的圖片,也就是快捷方式的圖片是存在手機裡的,獲取的時候,通過傳入的shortcut資訊獲取。

public Drawable getShortcutIconDrawable(ShortcutInfoCompat shortcutInfo, int density) {
    if (Utilities.ATLEAST_NOUGAT_MR1) {
        try {
            Drawable icon = mLauncherApps.getShortcutIconDrawable(
                    shortcutInfo.getShortcutInfo(), density);
            mWasLastCallSuccess = true;
            return icon;
        } catch (SecurityException|IllegalStateException e) {
            Log.e(TAG, "Failed to get shortcut icon", e);
            mWasLastCallSuccess = false;
        }
    }
    return null;
}

根據以上操作,按照Launcher的標準流程,建立快捷方式,從建立快捷方式這一步來說,獲取labelicon。就可以完成

但是為了後面還能夠開啟這個應用,需要獲取了外來資訊的package nameshortcut ID。在之前提到的makeIntent中,將IDpackage name,這兩個重要引數通過intent存到資料庫中。

8.0不再將快捷方式的具體地址儲存到資料庫中,改用shortcut ID。接來下是啟動流程

桌面的activity會有onClick方法,點選在桌面的操作均會被該方法截獲。

如果是點選在快捷方式上,則會呼叫startAppShortcutOrInfoActivity方法,而深入下去,會發現我們之前建立的快捷方式叫做deepShortcut,而啟用deepShortcut是和查詢是通用的引數,通過IDpackageName

if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
    String id = ((ShortcutInfo) info).getDeepShortcutId();
    String packageName = intent.getPackage();
    DeepShortcutManager.getInstance(this).startShortcut(
            packageName, id, intent.getSourceBounds(), optsBundle, info.user);
}

最終呼叫DeepShortcutManagerstartShortcut方法,這是一個api高於25才能使用的方法。

@TargetApi(25)
public void startShortcut(String packageName, String id, Rect sourceBounds,
                          Bundle startActivityOptions, UserHandle user) {
    if (Utilities.ATLEAST_NOUGAT_MR1) {
        try {
            mLauncherApps.startShortcut(packageName, id, sourceBounds,
                    startActivityOptions, user);
            mWasLastCallSuccess = true;
        } catch (SecurityException | IllegalStateException e) {
            Log.e(TAG, "Failed to start shortcut", e);
            mWasLastCallSuccess = false;
        }
    }
}

以上,就是桌面建立一個快捷方式的原始碼分析。