介紹
本示例實現了一個簡單桌面應用,實現了以下幾點功能:
1.展示了系統安裝的應用,實現點擊啟動、應用上滑彈出卡片、卡片添加到桌面、卡片移除功能。
2.實現桌面數據持久化存儲,應用支持卸載、監聽應用卸載和安裝并顯示。
3.實現最近任務管理功能,包括任務卡片加鎖、解鎖、清理和清理所有任務功能。
4.通過點擊應用圖標或點擊由長按圖標彈出的菜單欄中的打開按鈕的方式打開應用,是以打開最近任務方式拉起應用Ability。
效果預覽
使用說明
1.安裝編譯的hap包,使用hdc shell aa start -b ohos.samples.launcher -a MainAbility命令啟動應用,應用啟動后顯示系統安裝的應用。
2.點擊應用主界面上的應用圖標可以啟動應用,長按彈出菜單,點擊打開可以正常啟動應用。
3.圖庫等支持卡片的應用,長按菜單中有服務卡片,點擊進入卡片預覽界面,在卡片預覽界面點擊 添加到桌面 ,返回到桌面并且卡片成功添加到桌面。
4.上滑圖庫等支持卡片的應用,可以彈出默認上滑卡片,點擊上滑卡片右上角的**+**圖標,可以添加卡片到桌面。
5.應用在桌面界面,使用hdc install安裝一個應用,桌面可以監聽到應用安裝,并顯示新安裝的應用到桌面上。
6.應用在桌面界面,使用hdc uninstall 卸載第5步安裝的應用,桌面可以監聽到卸載,并移除桌面上的應用。
7.在桌面空白處上滑,可以進入最近任務管理界面,下滑任務卡片可以加鎖/解鎖,上滑卡片可以清理該后臺任務,點擊垃圾桶可以清除所有后臺任務(加鎖的應用不會被清理掉)。
代碼解讀
entry/src/main/ets/
|---Application
| |---MyAbilityStage.ts
|---components
| |---FormManagerComponent.ets // 彈窗組件
|---MainAbility
| |---MainAbility.ts
|---manager
| |---WindowManager.ts // 數據類型
|---pages
| |---FormPage.ets // 首頁
| |---Home.ets // 詳情頁面
| |---RecentsPage.ets // 詳情頁面
鴻蒙HarmonyOS與OpenHarmony知識更新+mau123789是v籽料領取
###具體實現
![搜狗高速瀏覽器截圖20240326151344.png](//file1.elecfans.com/web2/M00/C6/C5/wKgaomYCyYKAZp6HAAB4LWPdpdQ014.jpg)
* 獲取應用功能模塊
* 使用launcherBundleManager模塊接口(系統能力:SystemCapability.BundleManager.BundleFramework),獲取所有應用信息和給定包名獲取應用信息,實現桌面展示所有安裝的應用。使用on接口監聽應用的安裝和卸載從而實現應用安裝和卸載刷新桌面。
* 源碼鏈接:[LauncherAbilityManager.ts]
/*
Copyright (c) 2022-2023 Huawei Device Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import installer from '@ohos.bundle.installer';
import launcherBundleManager from '@ohos.bundle.launcherBundleManager';
import bundleMonitor from '@ohos.bundle.bundleMonitor';
import osAccount from '@ohos.account.osAccount'
import { AppItemInfo } from '../bean/AppItemInfo'
import { CheckEmptyUtils } from '../utils/CheckEmptyUtils'
import { CommonConstants } from '../constants/CommonConstants'
import { EventConstants } from '../constants/EventConstants'
import { ResourceManager } from './ResourceManager'
import { Logger } from '../utils/Logger'
import type { BusinessError } from '@ohos.base';
const TAG: string = 'LauncherAbilityManager'
/**
- Wrapper class for innerBundleManager and formManager interfaces.
*/
export class LauncherAbilityManager {
private static readonly BUNDLE_STATUS_CHANGE_KEY_REMOVE = 'remove'
private static readonly BUNDLE_STATUS_CHANGE_KEY_ADD = 'add'
private static launcherAbilityManager: LauncherAbilityManager = undefined
private readonly mAppMap = new Map< string, AppItemInfo >()
private mResourceManager: ResourceManager = undefined
private readonly mLauncherAbilityChangeListeners: any[] = []
private mUserId: number = 100
private context: any = undefined
constructor(context) {
this.context = context
this.mResourceManager = ResourceManager.getInstance(context)
const osAccountManager = osAccount.getAccountManager()
osAccountManager.getOsAccountLocalIdFromProcess((err, localId) = > {
Logger.debug(TAG, `getOsAccountLocalIdFromProcess localId ${localId}`)
this.mUserId = localId
})
}
/**
Get the application data model object.
@return {object} application data model singleton
*/
static getInstance(context): LauncherAbilityManager {
if (this.launcherAbilityManager === null || this.launcherAbilityManager === undefined) {
this.launcherAbilityManager = new LauncherAbilityManager(context)
}
return this.launcherAbilityManager
}
/**
get all app List info from BMS
@return 應用的入口Ability信息列表
*/
async getLauncherAbilityList(): Promise< AppItemInfo[] > {
Logger.info(TAG, 'getLauncherAbilityList begin')
let abilityList = await launcherBundleManager.getAllLauncherAbilityInfo(this.mUserId)
const appItemInfoList = new Array< AppItemInfo >()
if (CheckEmptyUtils.isEmpty(abilityList)) {
Logger.info(TAG, 'getLauncherAbilityList Empty')
return appItemInfoList
}
for (let i = 0; i < abilityList.length; i++) {
let appItem = await this.transToAppItemInfo(abilityList[i])
appItemInfoList.push(appItem)
}
return appItemInfoList
}
/**
get AppItemInfo from BMS with bundleName
@params bundleName
@return AppItemInfo
*/
async getAppInfoByBundleName(bundleName: string): Promise< AppItemInfo | undefined > {
let appItemInfo: AppItemInfo | undefined = undefined
// get from cache
if (this.mAppMap != null && this.mAppMap.has(bundleName)) {
appItemInfo = this.mAppMap.get(bundleName)
}
if (appItemInfo != undefined) {
Logger.info(TAG, `getAppInfoByBundleName from cache: ${JSON.stringify(appItemInfo)}`)
return appItemInfo
}
// get from system
let abilityInfos = await launcherBundleManager.getLauncherAbilityInfo(bundleName, this.mUserId)
if (abilityInfos == undefined || abilityInfos.length == 0) {
Logger.info(TAG, `${bundleName} has no launcher ability`)
return undefined
}
let appInfo = abilityInfos[0]
const data = await this.transToAppItemInfo(appInfo)
Logger.info(TAG, `getAppInfoByBundleName from BMS: ${JSON.stringify(data)}`)
return data
}
private async transToAppItemInfo(info): Promise< AppItemInfo > {
const appItemInfo = new AppItemInfo()
appItemInfo.appName = await this.mResourceManager.getAppNameSync(
info.labelId, info.elementName.bundleName, info.applicationInfo.label
)
appItemInfo.isSystemApp = info.applicationInfo.systemApp
appItemInfo.isUninstallAble = info.applicationInfo.removable
appItemInfo.appIconId = info.iconId
appItemInfo.appLabelId = info.labelId
appItemInfo.bundleName = info.elementName.bundleName
appItemInfo.abilityName = info.elementName.abilityName
await this.mResourceManager.updateIconCache(appItemInfo.appIconId, appItemInfo.bundleName)
this.mAppMap.set(appItemInfo.bundleName, appItemInfo)
return appItemInfo
}
/**
啟動應用
@params paramAbilityName Ability名
@params paramBundleName 應用包名
*/
startLauncherAbility(paramAbilityName, paramBundleName) {
Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`)
this.context.startAbility({
bundleName: paramBundleName,
abilityName: paramAbilityName
}).then(() = > {
Logger.info(TAG, 'startApplication promise success')
}, (err) = > {
Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`)
})
}
/**
通過桌面圖標啟動應用
@params paramAbilityName Ability名
@params paramBundleName 應用包名
*/
startLauncherAbilityFromRecent(paramAbilityName, paramBundleName): void {
Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`);
this.context.startRecentAbility({
bundleName: paramBundleName,
abilityName: paramAbilityName
}).then(() = > {
Logger.info(TAG, 'startApplication promise success');
}, (err) = > {
Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`);
});
}
/**
卸載應用
@params bundleName 應用包名
@params callback 卸載回調
*/
async uninstallLauncherAbility(bundleName: string, callback): Promise< void > {
Logger.info(TAG, `uninstallLauncherAbility bundleName: ${bundleName}`);
const bundlerInstaller = await installer.getBundleInstaller();
bundlerInstaller.uninstall(bundleName, {
userId: this.mUserId,
installFlag: 0,
isKeepData: false
}, (err: BusinessError) = > {
Logger.info(TAG, `uninstallLauncherAbility result = > ${JSON.stringify(err)}`);
callback(err);
})
}
/**
開始監聽系統應用狀態.
@params listener 監聽對象
*/
registerLauncherAbilityChangeListener(listener: any): void {
if (!CheckEmptyUtils.isEmpty(listener)) {
if (this.mLauncherAbilityChangeListeners.length == 0) {
bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD, (bundleChangeInfo) = > {
Logger.debug(TAG, `mBundleStatusCallback add bundleName: ${bundleChangeInfo.bundleName},
userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`)
if (this.mUserId === bundleChangeInfo.userId) {
this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_ADDED,
bundleChangeInfo.bundleName, bundleChangeInfo.userId)
}
})
bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE, (bundleChangeInfo) = > {
Logger.debug(TAG, `mBundleStatusCallback remove bundleName: ${bundleChangeInfo.bundleName},
userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`)
if (this.mUserId === bundleChangeInfo.userId) {
this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_REMOVED,
bundleChangeInfo.bundleName, bundleChangeInfo.userId)
}
AppStorage.Set('isRefresh', true)
})
}
const index = this.mLauncherAbilityChangeListeners.indexOf(listener)
if (index == CommonConstants.INVALID_VALUE) {
this.mLauncherAbilityChangeListeners.push(listener)
}
}
}
/**
取消監聽系統應用狀態.
@params listener 監聽對象
*/
unregisterLauncherAbilityChangeListener(listener: any): void {
if (!CheckEmptyUtils.isEmpty(listener)) {
const index = this.mLauncherAbilityChangeListeners.indexOf(listener)
if (index != CommonConstants.INVALID_VALUE) {
this.mLauncherAbilityChangeListeners.splice(index, 1)
}
if (this.mLauncherAbilityChangeListeners.length == 0) {
bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD)
bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE)
}
}
}
private notifyLauncherAbilityChange(event: string, bundleName: string, userId: number): void {
for (let index = 0; index < this.mLauncherAbilityChangeListeners.length; index++) {
this.mLauncherAbilityChangeListeners[index](event, bundleName, userId)
}
}
}
* 接口參考:[@ohos.bundle.launcherBundleManager]
* 應用卸載功能模塊
* 使用bundle模塊的getBundleInstaller接口獲取到BundleInstaller(系統能力:SystemCapability.BundleManager.BundleFramework),調用uninstall接口實現應用卸載功能。
* 源碼鏈接:[LauncherAbilityManager.ts]
/*
Copyright (c) 2022-2023 Huawei Device Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import installer from '@ohos.bundle.installer';
import launcherBundleManager from '@ohos.bundle.launcherBundleManager';
import bundleMonitor from '@ohos.bundle.bundleMonitor';
import osAccount from '@ohos.account.osAccount'
import { AppItemInfo } from '../bean/AppItemInfo'
import { CheckEmptyUtils } from '../utils/CheckEmptyUtils'
import { CommonConstants } from '../constants/CommonConstants'
import { EventConstants } from '../constants/EventConstants'
import { ResourceManager } from './ResourceManager'
import { Logger } from '../utils/Logger'
import type { BusinessError } from '@ohos.base';
const TAG: string = 'LauncherAbilityManager'
/**
- Wrapper class for innerBundleManager and formManager interfaces.
*/
export class LauncherAbilityManager {
private static readonly BUNDLE_STATUS_CHANGE_KEY_REMOVE = 'remove'
private static readonly BUNDLE_STATUS_CHANGE_KEY_ADD = 'add'
private static launcherAbilityManager: LauncherAbilityManager = undefined
private readonly mAppMap = new Map< string, AppItemInfo >()
private mResourceManager: ResourceManager = undefined
private readonly mLauncherAbilityChangeListeners: any[] = []
private mUserId: number = 100
private context: any = undefined
constructor(context) {
this.context = context
this.mResourceManager = ResourceManager.getInstance(context)
const osAccountManager = osAccount.getAccountManager()
osAccountManager.getOsAccountLocalIdFromProcess((err, localId) = > {
Logger.debug(TAG, `getOsAccountLocalIdFromProcess localId ${localId}`)
this.mUserId = localId
})
}
/**
Get the application data model object.
@return {object} application data model singleton
*/
static getInstance(context): LauncherAbilityManager {
if (this.launcherAbilityManager === null || this.launcherAbilityManager === undefined) {
this.launcherAbilityManager = new LauncherAbilityManager(context)
}
return this.launcherAbilityManager
}
/**
get all app List info from BMS
@return 應用的入口Ability信息列表
*/
async getLauncherAbilityList(): Promise< AppItemInfo[] > {
Logger.info(TAG, 'getLauncherAbilityList begin')
let abilityList = await launcherBundleManager.getAllLauncherAbilityInfo(this.mUserId)
const appItemInfoList = new Array< AppItemInfo >()
if (CheckEmptyUtils.isEmpty(abilityList)) {
Logger.info(TAG, 'getLauncherAbilityList Empty')
return appItemInfoList
}
for (let i = 0; i < abilityList.length; i++) {
let appItem = await this.transToAppItemInfo(abilityList[i])
appItemInfoList.push(appItem)
}
return appItemInfoList
}
/**
get AppItemInfo from BMS with bundleName
@params bundleName
@return AppItemInfo
*/
async getAppInfoByBundleName(bundleName: string): Promise< AppItemInfo | undefined > {
let appItemInfo: AppItemInfo | undefined = undefined
// get from cache
if (this.mAppMap != null && this.mAppMap.has(bundleName)) {
appItemInfo = this.mAppMap.get(bundleName)
}
if (appItemInfo != undefined) {
Logger.info(TAG, `getAppInfoByBundleName from cache: ${JSON.stringify(appItemInfo)}`)
return appItemInfo
}
// get from system
let abilityInfos = await launcherBundleManager.getLauncherAbilityInfo(bundleName, this.mUserId)
if (abilityInfos == undefined || abilityInfos.length == 0) {
Logger.info(TAG, `${bundleName} has no launcher ability`)
return undefined
}
let appInfo = abilityInfos[0]
const data = await this.transToAppItemInfo(appInfo)
Logger.info(TAG, `getAppInfoByBundleName from BMS: ${JSON.stringify(data)}`)
return data
}
private async transToAppItemInfo(info): Promise< AppItemInfo > {
const appItemInfo = new AppItemInfo()
appItemInfo.appName = await this.mResourceManager.getAppNameSync(
info.labelId, info.elementName.bundleName, info.applicationInfo.label
)
appItemInfo.isSystemApp = info.applicationInfo.systemApp
appItemInfo.isUninstallAble = info.applicationInfo.removable
appItemInfo.appIconId = info.iconId
appItemInfo.appLabelId = info.labelId
appItemInfo.bundleName = info.elementName.bundleName
appItemInfo.abilityName = info.elementName.abilityName
await this.mResourceManager.updateIconCache(appItemInfo.appIconId, appItemInfo.bundleName)
this.mAppMap.set(appItemInfo.bundleName, appItemInfo)
return appItemInfo
}
/**
啟動應用
@params paramAbilityName Ability名
@params paramBundleName 應用包名
*/
startLauncherAbility(paramAbilityName, paramBundleName) {
Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`)
this.context.startAbility({
bundleName: paramBundleName,
abilityName: paramAbilityName
}).then(() = > {
Logger.info(TAG, 'startApplication promise success')
}, (err) = > {
Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`)
})
}
/**
通過桌面圖標啟動應用
@params paramAbilityName Ability名
@params paramBundleName 應用包名
*/
startLauncherAbilityFromRecent(paramAbilityName, paramBundleName): void {
Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`);
this.context.startRecentAbility({
bundleName: paramBundleName,
abilityName: paramAbilityName
}).then(() = > {
Logger.info(TAG, 'startApplication promise success');
}, (err) = > {
Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`);
});
}
/**
卸載應用
@params bundleName 應用包名
@params callback 卸載回調
*/
async uninstallLauncherAbility(bundleName: string, callback): Promise< void > {
Logger.info(TAG, `uninstallLauncherAbility bundleName: ${bundleName}`);
const bundlerInstaller = await installer.getBundleInstaller();
bundlerInstaller.uninstall(bundleName, {
userId: this.mUserId,
installFlag: 0,
isKeepData: false
}, (err: BusinessError) = > {
Logger.info(TAG, `uninstallLauncherAbility result = > ${JSON.stringify(err)}`);
callback(err);
})
}
/**
開始監聽系統應用狀態.
@params listener 監聽對象
*/
registerLauncherAbilityChangeListener(listener: any): void {
if (!CheckEmptyUtils.isEmpty(listener)) {
if (this.mLauncherAbilityChangeListeners.length == 0) {
bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD, (bundleChangeInfo) = > {
Logger.debug(TAG, `mBundleStatusCallback add bundleName: ${bundleChangeInfo.bundleName},
userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`)
if (this.mUserId === bundleChangeInfo.userId) {
this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_ADDED,
bundleChangeInfo.bundleName, bundleChangeInfo.userId)
}
})
bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE, (bundleChangeInfo) = > {
Logger.debug(TAG, `mBundleStatusCallback remove bundleName: ${bundleChangeInfo.bundleName},
userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`)
if (this.mUserId === bundleChangeInfo.userId) {
this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_REMOVED,
bundleChangeInfo.bundleName, bundleChangeInfo.userId)
}
AppStorage.Set('isRefresh', true)
})
}
const index = this.mLauncherAbilityChangeListeners.indexOf(listener)
if (index == CommonConstants.INVALID_VALUE) {
this.mLauncherAbilityChangeListeners.push(listener)
}
}
}
/**
取消監聽系統應用狀態.
@params listener 監聽對象
*/
unregisterLauncherAbilityChangeListener(listener: any): void {
if (!CheckEmptyUtils.isEmpty(listener)) {
const index = this.mLauncherAbilityChangeListeners.indexOf(listener)
if (index != CommonConstants.INVALID_VALUE) {
this.mLauncherAbilityChangeListeners.splice(index, 1)
}
if (this.mLauncherAbilityChangeListeners.length == 0) {
bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD)
bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE)
}
}
}
private notifyLauncherAbilityChange(event: string, bundleName: string, userId: number): void {
for (let index = 0; index < this.mLauncherAbilityChangeListeners.length; index++) {
this.mLauncherAbilityChangeListeners[index](event, bundleName, userId)
}
}
}
* 接口參考:[@ohos.bundle]
* 添加卡片功能模塊
* 使用formHost接口(系統能力:SystemCapability.Ability.Form),獲取應用卡片信息,使用FormComponent組件展示卡片內容,從而實現添加卡片到桌面的功能。
* 源碼鏈接:[FormManager.ts]
/*
Copyright (c) 2022 Huawei Device Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import formManagerAbility from '@ohos.app.form.formHost'
import { CardItemInfo } from '../bean/CardItemInfo'
import { CommonConstants } from '../constants/CommonConstants'
import { Logger } from '../utils/Logger'
const TAG: string = 'FormManager'
/**
- Wrapper class for formManager interfaces.
*/
class FormManagerModel {
private readonly CARD_SIZE_1x2: number[] = [1, 2]
private readonly CARD_SIZE_2x2: number[] = [2, 2]
private readonly CARD_SIZE_2x4: number[] = [2, 4]
private readonly CARD_SIZE_4x4: number[] = [4, 4]
/**
get all form info
@return Array< CardItemInfo > cardItemInfoList
*/
public async getAllFormsInfo(): Promise< CardItemInfo[] > {
const formList = await formManagerAbility.getAllFormsInfo()
const cardItemInfoList = new Array< CardItemInfo >()
for (const formItem of formList) {
const cardItemInfo = new CardItemInfo()
cardItemInfo.bundleName = formItem.bundleName
cardItemInfo.abilityName = formItem.abilityName
cardItemInfo.moduleName = formItem.moduleName
cardItemInfo.cardName = formItem.name
cardItemInfo.cardDimension = formItem.defaultDimension
cardItemInfo.description = formItem.description
cardItemInfo.formConfigAbility = formItem.formConfigAbility
cardItemInfo.supportDimensions = formItem.supportDimensions
cardItemInfo.area = this.getCardSize(cardItemInfo.cardDimension)
cardItemInfoList.push(cardItemInfo)
}
return cardItemInfoList
}
/**
get card area by dimension
@param dimension
@return number[]
*/
public getCardSize(dimension: number): number[] {
if (dimension == CommonConstants.CARD_DIMENSION_1x2) {
return this.CARD_SIZE_1x2
} else if (dimension == CommonConstants.CARD_DIMENSION_2x2) {
return this.CARD_SIZE_2x2
} else if (dimension == CommonConstants.CARD_DIMENSION_2x4) {
return this.CARD_SIZE_2x4
} else {
return this.CARD_SIZE_4x4
}
}
/**
get card dimension bty area
@param dimension
@return number[]
*/
public getCardDimension(area: number[]) {
if (area.toString() === this.CARD_SIZE_1x2.toString()) {
return CommonConstants.CARD_DIMENSION_1x2
} else if (area.toString() === this.CARD_SIZE_2x2.toString()) {
return CommonConstants.CARD_DIMENSION_2x2
} else if (area.toString() == this.CARD_SIZE_2x4.toString()) {
return CommonConstants.CARD_DIMENSION_2x4
} else {
return CommonConstants.CARD_DIMENSION_4x4
}
}
/**
get form info by bundleName
@param bundle
@return Array< CardItemInfo > cardItemInfoList
*/
public async getFormsInfoByApp(bundle: string): Promise< CardItemInfo[] > {
Logger.info(TAG, `getFormsInfoByApp bundle: ${bundle}`)
const formList = await formManagerAbility.getFormsInfo(bundle)
const cardItemInfoList = new Array< CardItemInfo >()
for (const formItem of formList) {
const cardItemInfo = new CardItemInfo()
cardItemInfo.bundleName = formItem.bundleName
cardItemInfo.abilityName = formItem.abilityName
cardItemInfo.moduleName = formItem.moduleName
cardItemInfo.cardName = formItem.name
cardItemInfo.cardDimension = formItem.defaultDimension
cardItemInfo.area = this.getCardSize(cardItemInfo.cardDimension)
cardItemInfo.description = formItem.description
cardItemInfo.formConfigAbility = formItem.formConfigAbility
cardItemInfo.supportDimensions = formItem.supportDimensions
cardItemInfoList.push(cardItemInfo)
}
return cardItemInfoList
}
}
export let FormManager = new FormManagerModel()
* 接口參考:[@ohos.app.form.formHost]
* 桌面數據持久化存儲功能模塊
* 使用關系型數據庫rdb接口(系統能力:SystemCapability.DistributedDataManager.RelationalStore.Core),實現桌面數據持久化存儲,存儲應用的位置信息,卡片信息。
* 源碼鏈接:[RdbManager.ts]
/*
Copyright (c) 2022-2023 Huawei Device Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import dataRdb from '@ohos.data.relationalStore'
import { CheckEmptyUtils } from '../utils/CheckEmptyUtils'
import { CommonConstants } from '../constants/CommonConstants'
import { GridLayoutItemInfo } from '../bean/GridLayoutItemInfo'
import { GridLayoutInfoColumns } from '../bean/GridLayoutInfoColumns'
import { Logger } from '../utils/Logger'
export const TABLE_NAME: string = 'launcher'
export const SQL_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS launcher ' +
'(id INTEGER PRIMARY KEY AUTOINCREMENT, ' +
'app_name TEXT, ' +
'appIcon_id INTEGER, ' +
'container INTEGER, ' +
'type_id INTEGER, ' +
'card_id INTEGER, ' +
'card_name TEXT, ' +
'badge_number INTEGER, ' +
'module_name TEXT, ' +
'bundle_name TEXT, ' +
'ability_name TEXT, ' +
'area TEXT, ' +
'page INTEGER, ' +
'column INTEGER, ' +
'row INTEGER)'
export const STORE_CONFIG = { name: 'launcher.db', securityLevel: dataRdb.SecurityLevel.S1 }
const TAG: string = 'RdbModel'
class RdbManagerModel {
private mRdbStore: dataRdb.RdbStore = undefined
constructor() {
}
/**
initRdbConfig
@param context
*/
async initRdbConfig(context): Promise< void > {
Logger.info(TAG, 'initRdbConfig start')
if (this.mRdbStore === undefined) {
this.mRdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG);
await this.mRdbStore.executeSql(SQL_CREATE_TABLE);
Logger.info(TAG, 'create table end');
}
}
/**
deleteTable
@param tableName
*/
async deleteTable(tableName: string): Promise< void > {
Logger.info(TAG, 'deleteTable start')
try {
let detelSql = `DELETE FROM ${tableName};`
let detelSequenceSql = `UPDATE sqlite_sequence SET seq=0 WHERE name = '${tableName}';`
await this.mRdbStore.executeSql(detelSql)
await this.mRdbStore.executeSql(detelSequenceSql)
Logger.debug(TAG, 'deleteTable end')
} catch (e) {
Logger.error(TAG, `deleteTable err: ${e}`)
}
}
/**
insertData
@param layoutInfo
*/
async insertData(layoutInfo: any) {
Logger.info(TAG, 'insertGridLayoutInfo start');
let result: boolean = true
if (CheckEmptyUtils.isEmpty(layoutInfo)) {
Logger.error(TAG, 'insertGridLayoutInfo gridlayoutinfo is empty')
result = false
return result
}
try {
// delete gridlayoutinfo table
await this.deleteTable(TABLE_NAME)
// insert into gridlayoutinfo
for (let i in layoutInfo) {
let layout = layoutInfo[i]
for (let j in layout) {
let element = layout[j]
Logger.info(TAG, `insertGridLayoutInfo i= ${i}`)
let item = {}
if (element.typeId === CommonConstants.TYPE_APP) {
item = {
'app_name': element.appName,
'bundle_name': element.bundleName,
'module_name': element.modelName,
'ability_name': element.abilityName,
'appIcon_id': element.appIconId,
'type_id': element.typeId,
'area': element.area[0] + ',' + element.area[1],
'page': element.page,
'column': element.column,
'row': element.row,
'container': -100
}
let ret = await this.mRdbStore.insert(TABLE_NAME, item)
Logger.debug(TAG, `insertGridLayoutInfo type is app ${i} ret: ${ret}`)
} else if (element.typeId === CommonConstants.TYPE_CARD) {
item = {
'app_name': element.appName,
'bundle_name': element.bundleName,
'module_name': element.modelName,
'ability_name': element.abilityName,
'card_id': element.cardId,
'card_name': element.cardName,
'type_id': element.typeId,
'area': element.area[0] + ',' + element.area[1],
'page': element.page,
'column': element.column,
'row': element.row,
'container': -100
}
let ret = await this.mRdbStore.insert(TABLE_NAME, item)
Logger.debug(TAG, `insertGridLayoutInfo type is card ${i} ret: ${ret}`)
}
}
}
} catch (e) {
Logger.error(TAG, `insertGridLayoutInfo error: ${e}`)
}
return result
}
async queryLayoutInfo() {
Logger.info(TAG, 'queryLayoutInfo start')
const resultList: GridLayoutItemInfo[] = []
const predicates = new dataRdb.RdbPredicates(TABLE_NAME)
predicates.equalTo(GridLayoutInfoColumns.CONTAINER, -100)
.and().orderByAsc('page').and().orderByAsc('row').and().orderByAsc('column')
let resultSet = await this.mRdbStore.query(predicates)
Logger.info(TAG, `queryLayoutInfo query,count=${resultSet.rowCount}`)
let isLast = resultSet.goToFirstRow()
while (isLast) {
const layoutInfo: GridLayoutItemInfo = GridLayoutItemInfo.fromResultSet(resultSet)
resultList.push(layoutInfo)
isLast = resultSet.goToNextRow()
}
resultSet.close()
resultSet = null
return resultList
}
async insertItem(item: GridLayoutItemInfo) {
if (CheckEmptyUtils.isEmpty(item)) {
return
}
let element = {
'app_name': item.appName,
'module_name': item.moduleName,
'bundle_name': item.bundleName,
'ability_name': item.abilityName,
'appIcon_id': item.appIconId,
'card_id': item.cardId,
'card_name': item.cardName,
'type_id': item.typeId,
'area': item.area[0] + ',' + item.area[1],
'page': item.page,
'column': item.column,
'row': item.row,
'container': -100
}
let ret = await this.mRdbStore.insert(TABLE_NAME, element)
Logger.debug(TAG, `insertGridLayoutInfo ret: ${ret}`)
}
async deleteItemByPosition(page: number, row: number, column: number) {
const predicates = new dataRdb.RdbPredicates(TABLE_NAME);
predicates.equalTo('page', page)
.and().equalTo('row', row)
.and().equalTo('column', column);
let query = await this.mRdbStore.query(predicates);
if (query.rowCount > 0) {
let ret = await this.mRdbStore.delete(predicates);
Logger.debug(TAG, `deleteItem ret: ${ret}`);
}
}
}
export let RdbManager = new RdbManagerModel()
* 接口參考:[@ohos.data.relationalStore]
* 加鎖、解鎖、清理后臺任務功能模塊
* 使用missionManager模塊接口(系統能力:SystemCapability.Ability.AbilityRuntime.Mission),獲取最近任務信息,并實現加鎖、解鎖、清理后臺任務的功能。
* 源碼鏈接:[MissionModel.ts]
* 接口參考:[@ohos.application.missionManager]
* 點擊桌面應用拉起最近任務至前臺功能模塊
* 使用ServiceExtensionContext模塊的startRecentAbility接口(系統能力:SystemCapability.Ability.AbilityRuntime.Core),拉起最近任務至前臺顯示,若應用Ability未啟動時,則拉起新創建的應用Ability顯示到前臺。
源碼鏈接:[LauncherAbilityManager.ts]
/*
Copyright (c) 2022-2023 Huawei Device Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import installer from '@ohos.bundle.installer';
import launcherBundleManager from '@ohos.bundle.launcherBundleManager';
import bundleMonitor from '@ohos.bundle.bundleMonitor';
import osAccount from '@ohos.account.osAccount'
import { AppItemInfo } from '../bean/AppItemInfo'
import { CheckEmptyUtils } from '../utils/CheckEmptyUtils'
import { CommonConstants } from '../constants/CommonConstants'
import { EventConstants } from '../constants/EventConstants'
import { ResourceManager } from './ResourceManager'
import { Logger } from '../utils/Logger'
import type { BusinessError } from '@ohos.base';
const TAG: string = 'LauncherAbilityManager'
/**
- Wrapper class for innerBundleManager and formManager interfaces.
*/
export class LauncherAbilityManager {
private static readonly BUNDLE_STATUS_CHANGE_KEY_REMOVE = 'remove'
private static readonly BUNDLE_STATUS_CHANGE_KEY_ADD = 'add'
private static launcherAbilityManager: LauncherAbilityManager = undefined
private readonly mAppMap = new Map< string, AppItemInfo >()
private mResourceManager: ResourceManager = undefined
private readonly mLauncherAbilityChangeListeners: any[] = []
private mUserId: number = 100
private context: any = undefined
constructor(context) {
this.context = context
this.mResourceManager = ResourceManager.getInstance(context)
const osAccountManager = osAccount.getAccountManager()
osAccountManager.getOsAccountLocalIdFromProcess((err, localId) = > {
Logger.debug(TAG, `getOsAccountLocalIdFromProcess localId ${localId}`)
this.mUserId = localId
})
}
/**
Get the application data model object.
@return {object} application data model singleton
*/
static getInstance(context): LauncherAbilityManager {
if (this.launcherAbilityManager === null || this.launcherAbilityManager === undefined) {
this.launcherAbilityManager = new LauncherAbilityManager(context)
}
return this.launcherAbilityManager
}
/**
get all app List info from BMS
@return 應用的入口Ability信息列表
*/
async getLauncherAbilityList(): Promise< AppItemInfo[] > {
Logger.info(TAG, 'getLauncherAbilityList begin')
let abilityList = await launcherBundleManager.getAllLauncherAbilityInfo(this.mUserId)
const appItemInfoList = new Array< AppItemInfo >()
if (CheckEmptyUtils.isEmpty(abilityList)) {
Logger.info(TAG, 'getLauncherAbilityList Empty')
return appItemInfoList
}
for (let i = 0; i < abilityList.length; i++) {
let appItem = await this.transToAppItemInfo(abilityList[i])
appItemInfoList.push(appItem)
}
return appItemInfoList
}
/**
get AppItemInfo from BMS with bundleName
@params bundleName
@return AppItemInfo
*/
async getAppInfoByBundleName(bundleName: string): Promise< AppItemInfo | undefined > {
let appItemInfo: AppItemInfo | undefined = undefined
// get from cache
if (this.mAppMap != null && this.mAppMap.has(bundleName)) {
appItemInfo = this.mAppMap.get(bundleName)
}
if (appItemInfo != undefined) {
Logger.info(TAG, `getAppInfoByBundleName from cache: ${JSON.stringify(appItemInfo)}`)
return appItemInfo
}
// get from system
let abilityInfos = await launcherBundleManager.getLauncherAbilityInfo(bundleName, this.mUserId)
if (abilityInfos == undefined || abilityInfos.length == 0) {
Logger.info(TAG, `${bundleName} has no launcher ability`)
return undefined
}
let appInfo = abilityInfos[0]
const data = await this.transToAppItemInfo(appInfo)
Logger.info(TAG, `getAppInfoByBundleName from BMS: ${JSON.stringify(data)}`)
return data
}
private async transToAppItemInfo(info): Promise< AppItemInfo > {
const appItemInfo = new AppItemInfo()
appItemInfo.appName = await this.mResourceManager.getAppNameSync(
info.labelId, info.elementName.bundleName, info.applicationInfo.label
)
appItemInfo.isSystemApp = info.applicationInfo.systemApp
appItemInfo.isUninstallAble = info.applicationInfo.removable
appItemInfo.appIconId = info.iconId
appItemInfo.appLabelId = info.labelId
appItemInfo.bundleName = info.elementName.bundleName
appItemInfo.abilityName = info.elementName.abilityName
await this.mResourceManager.updateIconCache(appItemInfo.appIconId, appItemInfo.bundleName)
this.mAppMap.set(appItemInfo.bundleName, appItemInfo)
return appItemInfo
}
/**
啟動應用
@params paramAbilityName Ability名
@params paramBundleName 應用包名
*/
startLauncherAbility(paramAbilityName, paramBundleName) {
Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`)
this.context.startAbility({
bundleName: paramBundleName,
abilityName: paramAbilityName
}).then(() = > {
Logger.info(TAG, 'startApplication promise success')
}, (err) = > {
Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`)
})
}
/**
通過桌面圖標啟動應用
@params paramAbilityName Ability名
@params paramBundleName 應用包名
*/
startLauncherAbilityFromRecent(paramAbilityName, paramBundleName): void {
Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`);
this.context.startRecentAbility({
bundleName: paramBundleName,
abilityName: paramAbilityName
}).then(() = > {
Logger.info(TAG, 'startApplication promise success');
}, (err) = > {
Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`);
});
}
/**
卸載應用
@params bundleName 應用包名
@params callback 卸載回調
*/
async uninstallLauncherAbility(bundleName: string, callback): Promise< void > {
Logger.info(TAG, `uninstallLauncherAbility bundleName: ${bundleName}`);
const bundlerInstaller = await installer.getBundleInstaller();
bundlerInstaller.uninstall(bundleName, {
userId: this.mUserId,
installFlag: 0,
isKeepData: false
}, (err: BusinessError) = > {
Logger.info(TAG, `uninstallLauncherAbility result = > ${JSON.stringify(err)}`);
callback(err);
})
}
/**
開始監聽系統應用狀態.
@params listener 監聽對象
*/
registerLauncherAbilityChangeListener(listener: any): void {
if (!CheckEmptyUtils.isEmpty(listener)) {
if (this.mLauncherAbilityChangeListeners.length == 0) {
bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD, (bundleChangeInfo) = > {
Logger.debug(TAG, `mBundleStatusCallback add bundleName: ${bundleChangeInfo.bundleName},
userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`)
if (this.mUserId === bundleChangeInfo.userId) {
this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_ADDED,
bundleChangeInfo.bundleName, bundleChangeInfo.userId)
}
})
bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE, (bundleChangeInfo) = > {
Logger.debug(TAG, `mBundleStatusCallback remove bundleName: ${bundleChangeInfo.bundleName},
userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`)
if (this.mUserId === bundleChangeInfo.userId) {
this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_REMOVED,
bundleChangeInfo.bundleName, bundleChangeInfo.userId)
}
AppStorage.Set('isRefresh', true)
})
}
const index = this.mLauncherAbilityChangeListeners.indexOf(listener)
if (index == CommonConstants.INVALID_VALUE) {
this.mLauncherAbilityChangeListeners.push(listener)
}
}
}
/**
取消監聽系統應用狀態.
@params listener 監聽對象
*/
unregisterLauncherAbilityChangeListener(listener: any): void {
if (!CheckEmptyUtils.isEmpty(listener)) {
const index = this.mLauncherAbilityChangeListeners.indexOf(listener)
if (index != CommonConstants.INVALID_VALUE) {
this.mLauncherAbilityChangeListeners.splice(index, 1)
}
if (this.mLauncherAbilityChangeListeners.length == 0) {
bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD)
bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE)
}
}
}
private notifyLauncherAbilityChange(event: string, bundleName: string, userId: number): void {
for (let index = 0; index < this.mLauncherAbilityChangeListeners.length; index++) {
this.mLauncherAbilityChangeListeners[index](event, bundleName, userId)
}
}
}
接口參考:[@ohos.app.ability.ServiceExtensionAbility]
審核編輯 黃宇
-
鴻蒙
+關注
關注
57文章
2377瀏覽量
42922 -
OpenHarmony
+關注
關注
25文章
3730瀏覽量
16424
發布評論請先 登錄
相關推薦
評論