settingsdata支持多用户独立配置

Signed-off-by: 侯志雄 <houzhixiong1@h-partners.com>
This commit is contained in:
侯志雄 2024-06-21 17:59:52 +08:00
parent 83b50757e7
commit 04165725e4
7 changed files with 522 additions and 296 deletions

View File

@ -31,224 +31,234 @@ import { GlobalContext} from '../Utils/GlobalContext';
interface IRequest {
operation:string ;
columns:string[];
predicates:dataSharePredicates.DataSharePredicates|relationalStore.RdbPredicates|null;
value:relationalStore.ValuesBucket|null
operation:string ;
columns:string[];
predicates:dataSharePredicates.DataSharePredicates|relationalStore.RdbPredicates|null;
value:relationalStore.ValuesBucket|null
}
let rdbStore:relationalStore.RdbStore|undefined = undefined;
let requests:IRequest[] = [];
let SETTINGS_AUDIO_RINGTONE = "settings.audio.ringtone"
let SETTINGS_AUDIO_MEDIA = "settings.audio.media"
let SETTINGS_AUDIO_VOICE_CALL = "settings.audio.voicecall"
let trustList: Array<String> = [
let SETTINGS_AUDIO_RINGTONE = 'settings.audio.ringtone'
let SETTINGS_AUDIO_MEDIA = 'settings.audio.media'
let SETTINGS_AUDIO_VOICE_CALL = 'settings.audio.voicecall'
let trustList: String[] = [
settings.display.SCREEN_BRIGHTNESS_STATUS,
settings.display.AUTO_SCREEN_BRIGHTNESS,
settings.display.SCREEN_OFF_TIMEOUT
];
let ret:number = 0;
let err:BusinessError = {"code":-1} as BusinessError;
let err:BusinessError = {'code':-1} as BusinessError;
export default class DataExtAbility extends DataShareExtensionAbility {
onCreate(want: Want) {
GlobalContext.thisContext = this.context;
this.onInitialized();
Log.info('onCreate context'+ JSON.stringify(this.context));
onCreate(want: Want) {
GlobalContext.thisContext = this.context;
this.onInitialized();
Log.info('onCreate context' + JSON.stringify(this.context));
}
onInitialized() {
Log.info('onInitialize start');
let context = GlobalContext.thisContext as common.Context;
Log.info('onInitialize start context: ' + JSON.stringify(this.context));
if (context !== undefined) {
SettingsDBHelper.getInstance().getRdbStore().then((rdb: relationalStore.RdbStore|undefined) => {
rdbStore = rdb;
for (let i = 0; i < requests.length; i++) {
let opt: string = requests[i].operation;
let columns: string[] = requests[i].columns;
let predicates = (requests[i].predicates) as dataSharePredicates.DataSharePredicates;
let value: relationalStore.ValuesBucket|null = requests[i].value;
if (opt == 'insert') {
if(value){
rdbStore?.insert(SettingsDataConfig.TABLE_NAME, value, (err, ret) => {
Log.info('onInitialized insert ret: ' + ret);
});
}
} else if (opt == 'query') {
if(predicates){
rdbStore?.query(SettingsDataConfig.TABLE_NAME, predicates, columns, (
err: BusinessError, resultSet: relationalStore.ResultSet) => {
Log.info('onInitialized query ret: ' + JSON.stringify(resultSet));
});
}
} else if (opt == 'update') {
if(value){
rdbStore?.update(SettingsDataConfig.TABLE_NAME, value, predicates, (err, ret) => {
Log.info('onInitialized update ret: ' + ret);
});
}
}
}
}).catch((err: Error) => {
Log.error('onInitialize failed:' + JSON.stringify(err));
})
} else {
Log.info('onInitialize context error!');
}
Log.info('onInitialize end');
}
insert(uri: string, value: relationalStore.ValuesBucket, callback : AsyncCallback<number>) {
Log.info('insert keyword = ' + value[SettingsDataConfig.FIELD_KEYWORD] + ' start:' + uri);
let rdbInsert = (GrantStatus: boolean) => {
if (!GrantStatus) {
callback(err, ret);
return;
}
this.DoSystemSetting(
value[SettingsDataConfig.FIELD_KEYWORD]?.toString(), value[SettingsDataConfig.FIELD_VALUE]?.toString());
if (rdbStore == null) {
let request: IRequest = {
operation: 'insert', columns: [], predicates: null, value: value
};
Log.info('insert request = ' + JSON.stringify(request));
requests.push(request);
callback(err, ret);
} else {
rdbStore.insert(SettingsDataConfig.TABLE_NAME, value, (err, ret) => {
Log.info('insert result: ' + ret);
callback(err, ret);
});
}
}
onInitialized() {
Log.info('onInitialize start');
let context = GlobalContext.thisContext as common.Context;
Log.info('onInitialize start context: '+ JSON.stringify(this.context));
if (context !== undefined) {
SettingsDBHelper.getInstance().getRdbStore().then((rdb: relationalStore.RdbStore|undefined) => {
rdbStore = rdb;
for (let i = 0; i < requests.length; i++) {
let opt: string = requests[i].operation;
let columns: string[] = requests[i].columns;
let predicates = (requests[i].predicates) as dataSharePredicates.DataSharePredicates;
try {
Log.info('Start to verify permissions.');
this.verifyPermission(value, rdbInsert);
} catch (err) {
Log.error('Insert Data error:' + JSON.stringify(err));
callback(err, ret);
}
}
let value: relationalStore.ValuesBucket|null = requests[i].value;
if (opt == "insert") {
if(value){
rdbStore?.insert(SettingsDataConfig.TABLE_NAME, value, (err, ret) => {
Log.info('onInitialized insert ret: ' + ret);
});
}
} else if (opt == "query") {
if(predicates){
rdbStore?.query(SettingsDataConfig.TABLE_NAME, predicates, columns, (err: BusinessError, resultSet: relationalStore.ResultSet) => {
Log.info('onInitialized query ret: ' + JSON.stringify(resultSet));
});
}
} else if (opt == "update") {
if(value){
rdbStore?.update(SettingsDataConfig.TABLE_NAME, value, predicates, (err, ret) => {
Log.info('onInitialized update ret: ' + ret);
});
}
}
}
}).catch((err: Error) => {
Log.error('onInitialize failed:' + JSON.stringify(err));
})
update(
uri: string, predicates: dataSharePredicates.DataSharePredicates,
value:relationalStore.ValuesBucket, callback: AsyncCallback<number>) {
Log.info('update keyword = ' + value[SettingsDataConfig.FIELD_KEYWORD] + ' start:' + uri);
let rdbUpData = (GrantStatus:boolean) => {
if (!GrantStatus) {
callback(err, ret);
return;
}
this.DoSystemSetting(
value[SettingsDataConfig.FIELD_KEYWORD]?.toString(), value[SettingsDataConfig.FIELD_VALUE]?.toString());
if (rdbStore == null) {
let request : IRequest = {
operation: 'update', columns: [], predicates: predicates, value: value
};
Log.info('update request = ' + JSON.stringify(request));
requests.push(request);
callback(err, ret);
} else {
rdbStore.update(SettingsDataConfig.TABLE_NAME, value, predicates , (err, ret)=> {
Log.info('update result: ' + ret);
callback(err, ret);
});
}
}
try {
Log.info('Start to verify permissions.');
this.verifyPermission(value, rdbUpData);
} catch (err) {
Log.error('upData error:' + JSON.stringify(err));
callback(err, ret);
}
}
delete(uri: string, predicates: dataSharePredicates.DataSharePredicates, callback: AsyncCallback<number>) {
Log.info('nothing to do');
}
query(uri: string,
predicates: dataSharePredicates.DataSharePredicates, columns: string[], callback: AsyncCallback<Object>) {
Log.info( 'query start uri:' + uri);
if (rdbStore == null) {
let request: IRequest = {operation:'query', columns : columns, predicates : predicates, value:null};
Log.info('query request = ' + JSON.stringify(request));
requests.push(request);
callback(err, {'_napiwrapper':{}});
} else {
rdbStore.query(SettingsDataConfig.TABLE_NAME, predicates, columns,
(err:BusinessError, resultSet:relationalStore.ResultSet)=> {
Log.info(
'query result:' + JSON.stringify(resultSet.rowCount) + 'columnNames' + JSON.stringify(resultSet.columnNames));
callback(err, resultSet);
})
}
}
private DoSystemSetting(settingsKey: string|undefined, settingsValue: string|undefined) {
switch (settingsKey) {
case SETTINGS_AUDIO_RINGTONE:
try {
let volumeType = Audio.AudioVolumeType.RINGTONE;
Audio.getAudioManager().setVolume(volumeType, Number(settingsValue)).then(() => {
Log.info('settings Promise returned to indicate a successful RINGTONE setting.')
});
} catch (err) {
Log.info('settings RINGTONE failed error = ' + JSON.stringify(err));
}
break
case SETTINGS_AUDIO_MEDIA:
try {
let volumeType = Audio.AudioVolumeType.MEDIA;
Audio.getAudioManager().setVolume(volumeType, Number(settingsValue)).then(() => {
Log.info('settings Promise returned to indicate a successful MEDIA setting.')
});
} catch (err) {
Log.info('settings MEDIA failed error = ' + JSON.stringify(err));
}
break
case SETTINGS_AUDIO_VOICE_CALL:
try {
let volumeType = Audio.AudioVolumeType.VOICE_CALL;
Audio.getAudioManager().setVolume(volumeType, Number(settingsValue)).then(() => {
Log.info('settings Promise returned to indicate a successful VOICE_CALL setting.')
});
} catch (err) {
Log.info('settings VOICE_CALL failed error = ' + JSON.stringify(err));
}
break
default:
Log.info(settingsKey + ' key is not audio');
break
}
}
private verifyPermission(value: relationalStore.ValuesBucket, callBack: (GrantStatus: boolean) => void ) {
if (this.isTrustList(
value[SettingsDataConfig.FIELD_KEYWORD] as string) || process.uid == rpc.IPCSkeleton.getCallingUid()) {
callBack(true);
return;
}
try {
let tokenID = rpc.IPCSkeleton.getCallingTokenId();
Log.info('tokenID = ' + tokenID);
let grantStatus = abilityAccessCtrl.createAtManager().verifyAccessToken(
tokenID, 'ohos.permission.MANAGE_SECURE_SETTINGS');
grantStatus.then(data => {
if (data == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
Log.info('MANAGE_SECURE_SETTINGS active');
callBack(true);
} else {
Log.info('onInitialize context error!');
Log.warn('MANAGE_SECURE_SETTINGS grantStatus= ' + JSON.stringify(data));
callBack(false);
}
Log.info('onInitialize end');
}).catch((err: BusinessError) => {
Log.error('tokenID = ' + tokenID + ' verifyAccessToken is failed: ' + JSON.stringify(err));
callBack(false);
})
} catch (err) {
Log.error('err = ' + JSON.stringify(err));
callBack(false);
}
}
insert(uri: string, value: relationalStore.ValuesBucket, callback : AsyncCallback<number>) {
Log.info('insert keyword = ' + value[SettingsDataConfig.FIELD_KEYWORD] + ' start:' + uri);
let rdbInsert = (GrantStatus: boolean) => {
if (!GrantStatus) {
callback(err, ret);
return;
}
this.DoSystemSetting(value[SettingsDataConfig.FIELD_KEYWORD]?.toString(), value[SettingsDataConfig.FIELD_VALUE]?.toString());
if (rdbStore == null) {
let request: IRequest= {
operation: "insert", columns: [], predicates: null, value: value
};
Log.info('insert request = ' + JSON.stringify(request));
requests.push(request);
callback(err, ret);
} else {
rdbStore.insert(SettingsDataConfig.TABLE_NAME, value, (err, ret) => {
Log.info('insert result: ' + ret);
callback(err, ret);
});
}
}
try {
Log.info('Start to verify permissions.');
this.verifyPermission(value, rdbInsert);
} catch (err) {
Log.error('Insert Data error:' + JSON.stringify(err));
callback(err, ret);
}
}
update(uri: string, predicates: dataSharePredicates.DataSharePredicates, value:relationalStore.ValuesBucket, callback: AsyncCallback<number>) {
Log.info('update keyword = ' + value[SettingsDataConfig.FIELD_KEYWORD] + ' start:' + uri);
let rdbUpData = (GrantStatus:boolean) => {
if (!GrantStatus) {
callback(err, ret);
return;
}
this.DoSystemSetting(value[SettingsDataConfig.FIELD_KEYWORD]?.toString(), value[SettingsDataConfig.FIELD_VALUE]?.toString());
if (rdbStore == null) {
let request : IRequest= {
operation: "update", columns: [], predicates: predicates, value: value
};
Log.info('update request = ' + JSON.stringify(request));
requests.push(request);
callback(err, ret);
} else {
rdbStore.update(SettingsDataConfig.TABLE_NAME, value, predicates , (err, ret)=> {
Log.info('update result: ' + ret);
callback(err, ret);
});
}
}
try {
Log.info('Start to verify permissions.');
this.verifyPermission(value, rdbUpData);
} catch (err) {
Log.error('upData error:' + JSON.stringify(err));
callback(err, ret);
}
}
delete(uri: string, predicates: dataSharePredicates.DataSharePredicates, callback: AsyncCallback<number>) {
Log.info('nothing to do');
}
query(uri: string, predicates: dataSharePredicates.DataSharePredicates, columns: string[], callback: AsyncCallback<Object>) {
Log.info( 'query start uri:' + uri);
if (rdbStore == null) {
let request: IRequest= {operation:"query", columns : columns, predicates : predicates, value:null};
Log.info('query request = '+ JSON.stringify(request));
requests.push(request);
callback(err, {"_napiwrapper":{}});
} else {
rdbStore.query(SettingsDataConfig.TABLE_NAME, predicates, columns, (err:BusinessError, resultSet:relationalStore.ResultSet)=> {
Log.info('query result: '+ JSON.stringify(resultSet.rowCount) +'columnNames'+ JSON.stringify(resultSet.columnNames));
callback(err, resultSet);
})
}
}
private DoSystemSetting(settingsKey: string|undefined, settingsValue: string|undefined) {
switch (settingsKey) {
case SETTINGS_AUDIO_RINGTONE:
try {
let volumeType = Audio.AudioVolumeType.RINGTONE;
Audio.getAudioManager().setVolume(volumeType, Number(settingsValue)).then(() => {
Log.info('settings Promise returned to indicate a successful RINGTONE setting.')
});
} catch (err) {
Log.info('settings RINGTONE failed error = ' + JSON.stringify(err));
}
break
case SETTINGS_AUDIO_MEDIA:
try {
let volumeType = Audio.AudioVolumeType.MEDIA;
Audio.getAudioManager().setVolume(volumeType, Number(settingsValue)).then(() => {
Log.info('settings Promise returned to indicate a successful MEDIA setting.')
});
} catch (err) {
Log.info('settings MEDIA failed error = ' + JSON.stringify(err));
}
break
case SETTINGS_AUDIO_VOICE_CALL:
try {
let volumeType = Audio.AudioVolumeType.VOICE_CALL;
Audio.getAudioManager().setVolume(volumeType, Number(settingsValue)).then(() => {
Log.info('settings Promise returned to indicate a successful VOICE_CALL setting.')
});
} catch (err) {
Log.info('settings VOICE_CALL failed error = ' + JSON.stringify(err));
}
break
default:
Log.info(settingsKey + ' key is not audio');
break
}
}
private verifyPermission(value: relationalStore.ValuesBucket, callBack: (GrantStatus: boolean) => void ) {
if (this.isTrustList(value[SettingsDataConfig.FIELD_KEYWORD] as string) || process.uid == rpc.IPCSkeleton.getCallingUid()) {
callBack(true);
return;
}
try {
let tokenID = rpc.IPCSkeleton.getCallingTokenId();
Log.info('tokenID = ' + tokenID);
let grantStatus = abilityAccessCtrl.createAtManager().verifyAccessToken(tokenID, "ohos.permission.MANAGE_SECURE_SETTINGS");
grantStatus.then(data => {
if (data == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
Log.info('MANAGE_SECURE_SETTINGS active');
callBack(true);
} else {
Log.warn('MANAGE_SECURE_SETTINGS grantStatus= ' + JSON.stringify(data));
callBack(false);
}
}).catch((err: BusinessError) => {
Log.error('tokenID = ' + tokenID + ' verifyAccessToken is failed: ' + JSON.stringify(err));
callBack(false);
})
} catch (err) {
Log.error('err = ' + JSON.stringify(err));
callBack(false);
}
}
private isTrustList(keyWord: string): boolean {
return trustList.includes(keyWord)
}
private isTrustList(keyWord: string): boolean {
return trustList.includes(keyWord)
}
}

View File

@ -1,5 +1,5 @@
/**
* Copyright (c) 2021-2023 Huawei Device Co., Ltd.
* Copyright (c) 2021-2024 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
@ -12,50 +12,64 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import StaticSubscriberExtensionAbility from '@ohos.application.StaticSubscriberExtensionAbility';
import commonEventManager from '@ohos.commonEventManager';
import { Log, CommonEventData} from '../Utils/Log';
import SettingsDataConfig from '../Utils/SettingsDataConfig';
import SettingsDBHelper from '../Utils/SettingsDBHelper';
import StaticSubscriberExtensionAbility from '@ohos.application.StaticSubscriberExtensionAbility';
import { Log } from '../Utils/Log';
import commonEventManager from '@ohos.commonEventManager';
import { IContent, TableType } from '../common/Common';
import { GlobalContext } from '../Utils/GlobalContext';
const CURRENT_USER_TABLE_DROP: string = `DROP TABLE IF EXISTS ${SettingsDataConfig.USER_TABLE_NAME}_`
const CURRENT_USER_TABLE_DROP: string = `DROP TABLE IF EXISTS ${SettingsDataConfig.USER_TABLE_NAME}_`;
const CURRENT_SECURE_USER_TABLE_DROP: string = `DROP TABLE IF EXISTS ${SettingsDataConfig.SECURE_TABLE_NAME}_`;
const TAG: string = 'UserChangeStaticSubscriber : '
interface IContent {
settings: Array<Map<string,string>> ;
}
export default class UserChangeStaticSubscriber extends StaticSubscriberExtensionAbility {
async onReceiveEvent(event: commonEventManager.CommonEventData) {
if (!event) {
return
private init() {
GlobalContext.getContext().setObject('abilityContext', this.context);
this.context.area = SettingsDBHelper.getInstance().getArea();
}
async onReceiveEvent(event: CommonEventData) {
if (!event || event.code) {
Log.error('invalid parameters')
return;
}
Log.info(TAG + 'onReceiveEvent, event' + JSON.stringify(event))
Log.info(`onReceiveEvent, event: ${event.event}, userId: ${event.code}`);
this.init();
let rdb = await SettingsDBHelper.getInstance().getRdbStore();
switch (event.event) {
case commonEventManager.Support.COMMON_EVENT_USER_ADDED:
// 创建对应用户的数据表
await rdb?.executeSql(SettingsDBHelper.CURRENT_USER_TABLE_CREATE_PREFIX + event.code + SettingsDBHelper.TABLE_CREATE_SUFFIX, []);
await rdb?.executeSql(SettingsDBHelper.CURRENT_USER_TABLE_CREATE_PREFIX + event.code +
SettingsDBHelper.TABLE_CREATE_SUFFIX, []);
await rdb?.executeSql(SettingsDBHelper.CURRENT_SECURE_TABLE_CREATE_PREFIX + event.code +
SettingsDBHelper.TABLE_CREATE_SUFFIX, []);
// 加载用户数据表的默认值
try {
let content = await SettingsDBHelper.getInstance().readDefaultFile() as IContent;
if (!content) {
Log.error("readDefaultFile is failed!");
Log.error('readDefaultFile is failed!');
return
}
for (let index = 0; index < content.settings.length; index++) {
if (content.settings[index]["userConfig"] && event.code) {
await SettingsDBHelper.getInstance().loadUserSettings(content.settings[index]["name"], content.settings[index]["value"], event.code)
Log.info("content.settings[index]"+content.settings[index]["value"]);
}
}
// 初始化用户表数据
await SettingsDBHelper.getInstance().initialInsert(SettingsDataConfig.USER_TABLE_NAME + '_' + event.code);
await SettingsDBHelper.getInstance().initialInsert(SettingsDataConfig.SECURE_TABLE_NAME + '_' + event.code);
// 用户数据表包含USER、USER_SECURE
await SettingsDBHelper.getInstance().loadTableData({ settings: content.settings,
user: content.user,
userSecure: content.userSecure }, TableType.USER, event.code as number);
await SettingsDBHelper.getInstance().loadTableData({ settings: content.settings,
user: content.user,
userSecure: content.userSecure }, TableType.USER_SECURE, event.code as number);
} catch (err) {
Log.error("loadDefaultSettingsData failed! err = " + err);
Log.error('loadDefaultSettingsData failed! err = ' + err);
}
break
case commonEventManager.Support.COMMON_EVENT_USER_REMOVED:
// 删除对应用户的数据表
rdb?.executeSql(CURRENT_USER_TABLE_DROP + event.code, []);
rdb?.executeSql(CURRENT_SECURE_USER_TABLE_DROP + event.code, []);
break
default:
break

View File

@ -27,4 +27,24 @@ const TAG = 'SettingsData';
export class GlobalContext {
public static dbHelper:Object | undefined = undefined;
public static thisContext: Object | undefined = undefined;
private static instance: GlobalContext | null = null;
private context = new Map<string, Object>();
private constructor() {
}
public static getContext(): GlobalContext {
if (GlobalContext.instance === null){
GlobalContext.instance = new GlobalContext();
}
return GlobalContext.instance;
}
getObject(value: string): object | undefined {
return this.context.get(value);
}
setObject(key: string, objectClass: object): void {
this.context.set(key, objectClass);
}
}

View File

@ -14,10 +14,22 @@
*/
import hiLog from '@ohos.hilog';
import ExtensionAbility from '@ohos.app.ability.ExtensionAbility';
const DOMAIN: number = 0x0500;
const TAG = 'SettingsData';
/**
* 4.0.10
*/
export interface CommonEventData{
event: string;
bundleName?: string;
code?: number;
data?: string;
parameters?: { [key: string]: string | number | boolean | null | undefined };
}
/**
* Basic log class
*/

View File

@ -17,74 +17,158 @@ import common from '@ohos.app.ability.common';
import dataStorage from '@ohos.data.preferences';
import deviceInfo from '@ohos.deviceInfo';
import relationalStore from '@ohos.data.relationalStore';
import fs from '@ohos.file.fs';
import i18n from '@ohos.i18n';
import settings from '@ohos.settings';
import systemParameter from '@ohos.systemparameter';
import SettingsDataConfig from './SettingsDataConfig';
import { Log } from '../Utils/Log';
import { GlobalContext } from './GlobalContext';
const DEFAULT_JSON_FILE_NAME : string = "default_settings.json";
const SETTINGSDATA_PREFERENCE : string = "SettingsDataPreference";
import contextConstant from '@ohos.app.ability.contextConstant';
import { TableType } from '../common/Common';
const DEFAULT_JSON_FILE_NAME : string = 'default_settings.json';
const SETTINGSDATA_PREFERENCE : string = 'SettingsDataPreference';
const SETTINGSDATA_PREFERENCE_USER : string = 'SettingsDataPreferenceUser';
const EL2_DB_PATH: string = '/data/storage/el2/database/entry/rdb/settingsdata.db'
const EMULATOR_TYPE: string = 'emulator'
interface TIME_FORMAT_DATA {
TIME_FORMAT_24: string ;
TIME_FORMAT_12: string ;
}
const TIME_FORMAT: TIME_FORMAT_DATA = {
TIME_FORMAT_24: "24",
TIME_FORMAT_12: "12",
TIME_FORMAT_24: '24',
TIME_FORMAT_12: '12',
}
interface IContent {
settings: Array<Map<string,string>> ;
user: Array<Map<string,string>> ;
userSecure: Array<Map<string,string>> ;
}
class SettingsDBHelper {
static readonly SHARED_TABLE_CREATE_PREFIX = `CREATE TABLE IF NOT EXISTS ${SettingsDataConfig.TABLE_NAME}`;
// 需要在在表名后拼接当前的userid
static readonly CURRENT_USER_TABLE_CREATE_PREFIX = `CREATE TABLE IF NOT EXISTS ${SettingsDataConfig.USER_TABLE_NAME}_`
static readonly TABLE_CREATE_SUFFIX = ` (${SettingsDataConfig.FIELD_ID} INTEGER PRIMARY KEY AUTOINCREMENT, `
+ `${SettingsDataConfig.FIELD_KEYWORD} TEXT, `
+ `${SettingsDataConfig.FIELD_VALUE} TEXT CHECK (LENGTH(VALUE)<=1000))`;
private rdbStore_?: relationalStore.RdbStore;
private context_: Context;
const INITIAL_KEY: string = '_CreatedTime';
const VALID_DB_LENGTH: number = 48;
const SETTINGS_CLONED_STATUS: string = 'settingsClonedStatus';
class SettingsDBHelper {
public static readonly SHARED_TABLE_CREATE_PREFIX = `CREATE TABLE IF NOT EXISTS ${SettingsDataConfig.TABLE_NAME}`;
// 需要在在表名后拼接当前的userid
public static readonly CURRENT_USER_TABLE_CREATE_PREFIX: string =
`CREATE TABLE IF NOT EXISTS ${SettingsDataConfig.USER_TABLE_NAME}_`;
public static readonly CURRENT_SECURE_TABLE_CREATE_PREFIX: string =
`CREATE TABLE IF NOT EXISTS ${SettingsDataConfig.SECURE_TABLE_NAME}_`;
public static readonly TABLE_CREATE_SUFFIX = ` (${SettingsDataConfig.FIELD_ID} INTEGER PRIMARY KEY AUTOINCREMENT, ` +
`${SettingsDataConfig.FIELD_KEYWORD} TEXT, ` +
`${SettingsDataConfig.FIELD_VALUE} TEXT CHECK (LENGTH(VALUE)<=1000))`;
private rdbStore?: relationalStore.RdbStore;
private context: Context;
private readonly DEFAULT_USER_ID: number = 100;
private area: contextConstant.AreaMode | undefined = undefined;
public isFirstStartup: dataStorage.ValueType = true;
public maxUserNO: dataStorage.ValueType = 100;
private faultOccured: boolean = false;
private constructor() {
this.rdbStore_ = undefined;
this.context_ = GlobalContext.thisContext as Context;
Log.info("context_ start"+ JSON.stringify(this.context_));
this.rdbStore = undefined;
this.context = GlobalContext.thisContext as Context;
Log.info('context start'+ JSON.stringify(this.context));
}
private async emulatorParamInit(): Promise<void> {
if (this.getProductModel() !== EMULATOR_TYPE) {
Log.info('currently not a emulator');
return;
}
let tableName: string = this.getTableName(TableType.SETTINGS, this.DEFAULT_USER_ID);
await this.loadTableSettings('device_provisioned', '1', tableName);
tableName = this.getTableName(TableType.USER_SECURE, this.DEFAULT_USER_ID);
await this.loadTableSettings('basic_statement_agreed', '1', tableName);
await this.loadTableSettings('user_setup_complete', '1', tableName);
await this.loadTableSettings('is_ota_finished', '1', tableName);
}
public getProductModel(): string {
return deviceInfo.productModel;
}
public getArea() {
const dbFile = EL2_DB_PATH;
if (this.area === undefined) {
try {
let stat = fs.statSync(dbFile);
if (stat.size > VALID_DB_LENGTH) {
this.area = contextConstant.AreaMode.EL2;
} else {
this.area = contextConstant.AreaMode.EL1;
}
} catch {
this.area = contextConstant.AreaMode.EL1;
}
}
Log.info(`Area ${this.area}`);
return this.area;
}
public async initialInsert(tableName: string): Promise<void> {
try {
Log.info(`insert ${tableName} with key: ${tableName + INITIAL_KEY} `);
if (this.rdbStore) {
let ret = await this.rdbStore.insert(tableName,
{ 'KEYWORD': tableName + INITIAL_KEY, 'VALUE': new Date().toString() });
if (ret <= 0) {
Log.error(`insert initial key-value failed for ${tableName}`);
}
} else {
Log.error(`insert initial key-value failed for ${tableName}, no rdbStore`);
this.faultOccured = true;
}
} catch (e) {
Log.error(`insert initial key-value failed for ${tableName}`);
}
}
private async firstStartupConfig() : Promise<void> {
Log.info("firstStartupConfig start");
let storage = await dataStorage.getPreferences(this.context_ as Context, SETTINGSDATA_PREFERENCE);
Log.info("context_ storage = " + this.context_);
let isFirst: dataStorage.ValueType = await storage.get('isFirstStartUp', true);
Log.info("firstStartupConfig isFirstStartUp = " + isFirst);
if (isFirst) {
// 创建公共数据表
await this.rdbStore_?.executeSql(SettingsDBHelper.SHARED_TABLE_CREATE_PREFIX + SettingsDBHelper.TABLE_CREATE_SUFFIX, []);
// 创建默认用户数据表
await this.rdbStore_?.executeSql(SettingsDBHelper.CURRENT_USER_TABLE_CREATE_PREFIX + this.DEFAULT_USER_ID + SettingsDBHelper.TABLE_CREATE_SUFFIX, []);
await storage.put('isFirstStartUp', false);
await storage.flush();
await this.loadDefaultSettingsData();
Log.info('firstStartupConfig start');
let storage = await dataStorage.getPreferences(this.context as Context, SETTINGSDATA_PREFERENCE);
this.isFirstStartup = await storage.get('isFirstStartup', true);
storage = await dataStorage.getPreferences(this.context as Context, SETTINGSDATA_PREFERENCE_USER);
this.maxUserNO = await storage.get('MAXUSERNO', 100);
Log.info(`firstStartupConfig isFirstStartUp = ${this.isFirstStartup} max user no: ${this.maxUserNO}`);
// 总是创建以下三张表 if not exists
// 创建公共数据表
await this.rdbStore?.executeSql(SettingsDBHelper.SHARED_TABLE_CREATE_PREFIX +
SettingsDBHelper.TABLE_CREATE_SUFFIX, []);
// 创建默认用户数据表
await this.rdbStore?.executeSql(SettingsDBHelper.CURRENT_USER_TABLE_CREATE_PREFIX +
this.DEFAULT_USER_ID + SettingsDBHelper.TABLE_CREATE_SUFFIX, []);
// 创建默认用户 secure 数据表
await this.rdbStore?.executeSql(SettingsDBHelper.CURRENT_SECURE_TABLE_CREATE_PREFIX +
this.DEFAULT_USER_ID + SettingsDBHelper.TABLE_CREATE_SUFFIX, []);
if (this.isFirstStartup) {
// 推迟 this.loadDefaultSettingsData() =>after data migrate in DataExtAbility;
await this.initialInsert(SettingsDataConfig.TABLE_NAME);
await this.initialInsert(SettingsDataConfig.USER_TABLE_NAME + '_' + this.DEFAULT_USER_ID);
await this.initialInsert(SettingsDataConfig.SECURE_TABLE_NAME + '_' + this.DEFAULT_USER_ID);
}
Log.info("firstStartupConfig end");
Log.info('firstStartupConfig end');
return;
}
public async initRdbStore() {
Log.info('call initRdbStore start');
let rdbStore = await relationalStore.getRdbStore(this.context_ as Context, { name: SettingsDataConfig.DB_NAME,securityLevel:1 });
let rdbStore = await relationalStore.getRdbStore(
this.context as Context, { name: SettingsDataConfig.DB_NAME,securityLevel:1 });
if(rdbStore){
this.rdbStore_ = rdbStore;
this.rdbStore = rdbStore;
}
await this.firstStartupConfig();
Log.info('call initRdbStore end');
return this.rdbStore_;
return this.rdbStore;
}
public static getInstance(): SettingsDBHelper {
@ -95,96 +179,154 @@ class SettingsDBHelper {
}
public async getRdbStore() {
if (!this.rdbStore_) {
if (!this.rdbStore) {
return await (GlobalContext.dbHelper as SettingsDBHelper).initRdbStore();
// return await globalThis.settingsDBHelper.initRdbStore();
}
return this.rdbStore_
return this.rdbStore
}
private async loadGlobalSettings(key: string, value: string): Promise<void> {
if (!this.rdbStore_) {
public async loadTableData(content: IContent, tableType: TableType, userId: number): Promise<void> {
if (!content) {
Log.error('content is empty');
return;
}
switch (tableType) {
case TableType.SETTINGS:
this.loadDefaultTaleData(content.settings, TableType.SETTINGS, userId);
return;
case TableType.USER:
this.loadDefaultTaleData(content.user, TableType.USER, userId);
return;
case TableType.SETTINGS:
this.loadDefaultTaleData(content.userSecure, TableType.USER_SECURE, userId);
return;
default:
Log.error('invalid type');
}
}
private getTableName(tableType: TableType, userId: number): string {
if (tableType === TableType.SETTINGS) {
return SettingsDataConfig.TABLE_NAME;
}
if (tableType === TableType.USER) {
return `${SettingsDataConfig.USER_TABLE_NAME}_${userId}`;
}
return `${SettingsDataConfig.SECURE_TABLE_NAME}_${userId}`;
}
private async loadTableSettings(key: string, value: string, tableName: string): Promise<void> {
if (!this.rdbStore) {
Log.error('rdbStore is null!');
return
}
Log.info("key=" + key + " value " + value);
await this.rdbStore_.insert(SettingsDataConfig.TABLE_NAME, { "KEYWORD": key, "VALUE": value }, (err, ret) => {
if (err) {
Log.error("loadGlobalSettings insert error:" + JSON.stringify(err));
}
Log.info("loadGlobalSettings insert ret = " + ret);
Log.info(`tableName: ${tableName}, key: ${key}, value: ${value}`);
try {
let ret = await this.rdbStore.insert(tableName, { 'KEYWORD': key, 'VALUE': value });
if (ret >= 0) {
Log.info(`insert into DB success; ${ret}`);
} else {
this.faultOccured = true;
Log.error(`insert into DB faild; ${ret}`);
}
);
} catch (err) {
Log.warn(`insert key ${key} failed`);
}
}
public async loadUserSettings(key: string, value: string, userId: number|undefined): Promise<void> {
if (!this.rdbStore_) {
if (!this.rdbStore) {
Log.error('rdbStore is null!');
return
}
Log.info("key=" + key + " value " + value + " userid " + userId);
await this.rdbStore_.insert(SettingsDataConfig.USER_TABLE_NAME + '_' + userId,
{ "KEYWORD": key, "VALUE": value }, (err, ret) => {
Log.info('key=' + key + ' value ' + value + ' userid ' + userId);
await this.rdbStore.insert(SettingsDataConfig.USER_TABLE_NAME + '_' + userId,
{ 'KEYWORD': key, 'VALUE': value }, (err, ret) => {
if (err) {
Log.error("loadGlobalSettings insert error:" + JSON.stringify(err));
Log.error('loadGlobalSettings insert error:' + JSON.stringify(err));
}
Log.info("loadGlobalSettings insert ret = " + ret);
Log.info('loadGlobalSettings insert ret = ' + ret);
});
}
public async readDefaultFile(): Promise<Object> {
let rawStr: string = "";
let rawStr: string = '';
try {
let content: number[] = Array.from(await this.context_?.resourceManager.getRawFile(DEFAULT_JSON_FILE_NAME));
let content: number[] = Array.from(await this.context?.resourceManager.getRawFile(DEFAULT_JSON_FILE_NAME));
rawStr = String.fromCharCode(...Array.from(content));
} catch (err) {
Log.error("readDefaultFile readRawFile err" + err);
Log.error('readDefaultFile readRawFile err' + err);
}
if (rawStr) {
Log.info("readDefaultFile success");
Log.info('readDefaultFile success');
return JSON.parse(rawStr);
}
return rawStr;
}
private async loadDefaultSettingsData(): Promise<void> {
Log.info("loadDefaultSettingsData start");
if (!this.isFirstStartup) {
Log.info('loadDefaultSettingsData exists');
return;
}
Log.info('loadDefaultSettingsData start');
try {
let content = await this.readDefaultFile() as IContent;
if (!content) {
Log.error("readDefaultFile is failed!");
Log.error('readDefaultFile is failed!');
return;
}
for (let index = 0; index < content.settings.length; index++) {
if (content.settings[index]["userConfig"]) {
// 加载用户数据表的默认值
await this.loadUserSettings(content.settings[index]["name"], content.settings[index]["value"], this.DEFAULT_USER_ID)
} else {
// 加载公共数据表的默认值
await this.loadGlobalSettings(content.settings[index]["name"], content.settings[index]["value"]);
}
}
// 同时加载三张表,主要用于首次加载场景
await this.loadTableData(content, TableType.SETTINGS, this.DEFAULT_USER_ID);
await this.loadTableData(content, TableType.USER, this.DEFAULT_USER_ID);
await this.loadTableData(content, TableType.USER_SECURE, this.DEFAULT_USER_ID);
} catch (err) {
Log.error("loadDefaultSettingsData catch error! err = " + err);
Log.error('loadDefaultSettingsData catch error! err = ' + err);
}
let tableName: string = this.getTableName(TableType.SETTINGS, this.DEFAULT_USER_ID);
// 初始化设备名称
let deviceName: string = deviceInfo.marketName;
if (deviceName.startsWith('"') && deviceName.endsWith('"')) {
deviceName = JSON.parse(deviceName);
}
await this.loadGlobalSettings(settings.general.DEVICE_NAME, deviceName);
// 初始化24小时制
await this.loadGlobalSettings(settings.date.TIME_FORMAT, i18n.is24HourClock() ? TIME_FORMAT.TIME_FORMAT_24 : TIME_FORMAT.TIME_FORMAT_12);
await this.loadTableSettings(settings.general.DEVICE_NAME, deviceName, tableName);
// 初始化亮度值
let defaultBrightness = systemParameter.getSync('const.display.brightness.default');
if (defaultBrightness) {
await this.loadGlobalSettings(settings.display.SCREEN_BRIGHTNESS_STATUS, defaultBrightness);
await this.loadTableSettings(settings.display.SCREEN_BRIGHTNESS_STATUS, defaultBrightness, tableName);
}
// 初始化克隆标识
await this.loadTableSettings(SETTINGS_CLONED_STATUS, '0', tableName);
// 适配模拟器开机不走OOBE
await this.emulatorParamInit();
//make sure no faultoccured, then write isFirstStartup false;
if (this.faultOccured === false) {
let storage = await dataStorage.getPreferences(this.context as Context, SETTINGSDATA_PREFERENCE);
await storage.put('isFirstStartUp', false);
await storage.flush();
Log.info('settingsdata initial DB success. ')
} else {
Log.warn('settingsdata initial DB failed! Will retry possible during next startup!!!');
}
Log.info('loadDefaultSettingsData end');
}
private async loadDefaultTaleData(tableData: Array<Map<string, string>>, tableType: TableType,
userID: number): Promise<void> {
if (tableData?.length <= 0) {
Log.error(`${tableType} table data is empty`);
return;
}
let tableName: string = this.getTableName(tableType, userID);
for (let index = 0; index < tableData.length; index++) {
await this.loadTableSettings(tableData[index]['name'], tableData[index]['value'], tableName);
}
Log.info("loadDefaultSettingsData end");
}
}

View File

@ -17,6 +17,7 @@ interface SettingsDataBaseConfig {
DB_NAME: string;
TABLE_NAME: string;
USER_TABLE_NAME: string;
SECURE_TABLE_NAME: string;
FIELD_ID: string;
FIELD_KEYWORD: string;
FIELD_VALUE: string;
@ -25,6 +26,7 @@ const SettingsDataConfig: SettingsDataBaseConfig = {
DB_NAME: 'settingsdata.db',
TABLE_NAME: 'SETTINGSDATA',
USER_TABLE_NAME: 'USER_SETTINGSDATA',
SECURE_TABLE_NAME: 'USER_SETTINGSDATA_SECURE',
FIELD_ID: 'ID',
FIELD_KEYWORD: 'KEYWORD',
FIELD_VALUE: 'VALUE'

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2024-2024 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.
*/
export interface IContent {
settings: Array<Map<string, string>>;
user: Array<Map<string, string>>;
userSecure: Array<Map<string, string>>;
}
export enum TableType {
SETTINGS,
USER,
USER_SECURE
}