1/** 2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import common from '@ohos.app.ability.common'; 17import Audio from '@ohos.multimedia.audio'; 18import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; 19import DataShareExtensionAbility from '@ohos.application.DataShareExtensionAbility'; 20import rpc from '@ohos.rpc'; 21import process from '@ohos.process'; 22import settings from '@ohos.settings'; 23import relationalStore from '@ohos.data.relationalStore'; 24import Want from '@ohos.app.ability.Want'; 25import dataSharePredicates from '@ohos.data.dataSharePredicates'; 26import { AsyncCallback, BusinessError } from '@ohos.base'; 27import SettingsDataConfig from '../Utils/SettingsDataConfig'; 28import SettingsDBHelper from '../Utils/SettingsDBHelper'; 29import { Log } from '../Utils/Log'; 30import { GlobalContext} from '../Utils/GlobalContext'; 31import contextConstant from '@ohos.app.ability.contextConstant'; 32 33 34interface IRequest { 35 operation:string ; 36 columns:string[]; 37 predicates:dataSharePredicates.DataSharePredicates|relationalStore.RdbPredicates|null; 38 value:relationalStore.ValuesBucket|null 39} 40let rdbStore:relationalStore.RdbStore|undefined = undefined; 41let requests:IRequest[] = []; 42let SETTINGS_AUDIO_RINGTONE = 'settings.audio.ringtone' 43let SETTINGS_AUDIO_MEDIA = 'settings.audio.media' 44let SETTINGS_AUDIO_VOICE_CALL = 'settings.audio.voicecall' 45let trustList: String[] = [ 46settings.display.SCREEN_BRIGHTNESS_STATUS, 47settings.display.AUTO_SCREEN_BRIGHTNESS, 48settings.display.SCREEN_OFF_TIMEOUT 49]; 50let ret:number = 0; 51let err:BusinessError = {'code':-1} as BusinessError; 52 53export default class DataExtAbility extends DataShareExtensionAbility { 54 onCreate(want: Want) { 55 GlobalContext.getContext().setObject('abilityContext', this.context); 56 // database move to DE area; 57 this.context.area = contextConstant.AreaMode.EL2; 58 this.context.area = SettingsDBHelper.getInstance().getArea(); 59 this.onInitialized(); 60 Log.info('onCreate context' + JSON.stringify(this.context)); 61 } 62 63 onInitialized() { 64 Log.info('onInitialize start'); 65 let context = GlobalContext.getContext().getObject('abilityContext') as Context; 66 Log.info('onInitialize start context: ' + JSON.stringify(this.context)); 67 if (context !== null) { 68 SettingsDBHelper.getInstance().getRdbStore().then((rdb: relationalStore.RdbStore|undefined) => { 69 rdbStore = rdb; 70 if (!rdbStore) { 71 Log.error('onInitialized: get rdb store failed!'); 72 return; 73 } 74 Log.info('onInitialized: get rdb store succeed!'); 75 for (let i = 0; i < requests.length; i++) { 76 let opt: string = requests[i].operation; 77 let columns: string[] = requests[i].columns; 78 let predicates = (requests[i].predicates) as dataSharePredicates.DataSharePredicates; 79 80 let value: relationalStore.ValuesBucket|null = requests[i].value; 81 if (opt == 'insert') { 82 if(value){ 83 rdbStore?.insert(SettingsDataConfig.TABLE_NAME, value, (err, ret) => { 84 Log.info('onInitialized insert ret: ' + ret); 85 }); 86 } 87 } else if (opt == 'query') { 88 if(predicates){ 89 rdbStore?.query(SettingsDataConfig.TABLE_NAME, predicates, columns, ( 90 err: BusinessError, resultSet: relationalStore.ResultSet) => { 91 Log.info('onInitialized query ret: ' + JSON.stringify(resultSet)); 92 }); 93 } 94 95 } else if (opt == 'update') { 96 if(value){ 97 rdbStore?.update(SettingsDataConfig.TABLE_NAME, value, predicates, (err, ret) => { 98 Log.info('onInitialized update ret: ' + ret); 99 }); 100 } 101 } 102 } 103 }).catch((err: Error) => { 104 Log.error('onInitialize failed:' + JSON.stringify(err)); 105 }) 106 } else { 107 Log.info('onInitialize context error!'); 108 } 109 Log.info('onInitialize end'); 110 } 111 112 insert(uri: string, value: relationalStore.ValuesBucket, callback : AsyncCallback<number>) { 113 Log.info('insert keyword = ' + value[SettingsDataConfig.FIELD_KEYWORD] + ' start:' + uri); 114 let rdbInsert = (GrantStatus: boolean) => { 115 if (!GrantStatus) { 116 callback(err, ret); 117 return; 118 } 119 this.DoSystemSetting( 120 value[SettingsDataConfig.FIELD_KEYWORD]?.toString(), value[SettingsDataConfig.FIELD_VALUE]?.toString()); 121 122 if (rdbStore == null) { 123 let request: IRequest = { 124 operation: 'insert', columns: [], predicates: null, value: value 125 }; 126 Log.info('insert request = ' + JSON.stringify(request)); 127 requests.push(request); 128 } else { 129 rdbStore.insert(SettingsDataConfig.TABLE_NAME, value, (err, ret) => { 130 Log.info('insert result: ' + ret); 131 callback(err, ret); 132 }); 133 } 134 } 135 136 try { 137 Log.info('Start to verify permissions.'); 138 this.verifyPermission(value, rdbInsert); 139 } catch (err) { 140 Log.error('Insert Data error:' + JSON.stringify(err)); 141 callback(err, ret); 142 } 143 } 144 145 146 update( 147 uri: string, predicates: dataSharePredicates.DataSharePredicates, 148 value:relationalStore.ValuesBucket, callback: AsyncCallback<number>) { 149 Log.info('update keyword = ' + value[SettingsDataConfig.FIELD_KEYWORD] + ' start:' + uri); 150 let rdbUpData = (GrantStatus:boolean) => { 151 if (!GrantStatus) { 152 callback(err, ret); 153 return; 154 } 155 this.DoSystemSetting( 156 value[SettingsDataConfig.FIELD_KEYWORD]?.toString(), value[SettingsDataConfig.FIELD_VALUE]?.toString()); 157 if (rdbStore == null) { 158 let request : IRequest = { 159 operation: 'update', columns: [], predicates: predicates, value: value 160 }; 161 Log.info('update request = ' + JSON.stringify(request)); 162 requests.push(request); 163 } else { 164 rdbStore.update(SettingsDataConfig.TABLE_NAME, value, predicates , (err, ret)=> { 165 Log.info('update result: ' + ret); 166 callback(err, ret); 167 }); 168 } 169 } 170 try { 171 Log.info('Start to verify permissions.'); 172 this.verifyPermission(value, rdbUpData); 173 } catch (err) { 174 Log.error('upData error:' + JSON.stringify(err)); 175 callback(err, ret); 176 } 177 } 178 179 delete(uri: string, predicates: dataSharePredicates.DataSharePredicates, callback: AsyncCallback<number>) { 180 Log.info('nothing to do'); 181 } 182 183 query(uri: string, 184 predicates: dataSharePredicates.DataSharePredicates, columns: string[], callback: AsyncCallback<Object>) { 185 Log.info( 'query start uri:' + uri); 186 if (rdbStore == null) { 187 let request: IRequest = {operation:'query', columns : columns, predicates : predicates, value:null}; 188 Log.info('query request = ' + JSON.stringify(request)); 189 requests.push(request); 190 } else { 191 rdbStore.query(SettingsDataConfig.TABLE_NAME, predicates, columns, 192 (err:BusinessError, resultSet:relationalStore.ResultSet)=> { 193 Log.info( 194 'query result:' + JSON.stringify(resultSet.rowCount) + 'columnNames' + JSON.stringify(resultSet.columnNames)); 195 callback(err, resultSet); 196 }) 197 } 198 } 199 200 private DoSystemSetting(settingsKey: string|undefined, settingsValue: string|undefined) { 201 switch (settingsKey) { 202 case SETTINGS_AUDIO_RINGTONE: 203 try { 204 let volumeType = Audio.AudioVolumeType.RINGTONE; 205 Audio.getAudioManager().setVolume(volumeType, Number(settingsValue)).then(() => { 206 Log.info('settings Promise returned to indicate a successful RINGTONE setting.') 207 }); 208 } catch (err) { 209 Log.info('settings RINGTONE failed error = ' + JSON.stringify(err)); 210 } 211 break 212 case SETTINGS_AUDIO_MEDIA: 213 try { 214 let volumeType = Audio.AudioVolumeType.MEDIA; 215 Audio.getAudioManager().setVolume(volumeType, Number(settingsValue)).then(() => { 216 Log.info('settings Promise returned to indicate a successful MEDIA setting.') 217 }); 218 } catch (err) { 219 Log.info('settings MEDIA failed error = ' + JSON.stringify(err)); 220 } 221 break 222 case SETTINGS_AUDIO_VOICE_CALL: 223 try { 224 let volumeType = Audio.AudioVolumeType.VOICE_CALL; 225 Audio.getAudioManager().setVolume(volumeType, Number(settingsValue)).then(() => { 226 Log.info('settings Promise returned to indicate a successful VOICE_CALL setting.') 227 }); 228 } catch (err) { 229 Log.info('settings VOICE_CALL failed error = ' + JSON.stringify(err)); 230 } 231 break 232 default: 233 Log.info(settingsKey + ' key is not audio'); 234 break 235 } 236 } 237 238 private verifyPermission(value: relationalStore.ValuesBucket, callBack: (GrantStatus: boolean) => void ) { 239 if (this.isTrustList( 240 value[SettingsDataConfig.FIELD_KEYWORD] as string) || process.uid == rpc.IPCSkeleton.getCallingUid()) { 241 callBack(true); 242 return; 243 } 244 try { 245 let tokenID = rpc.IPCSkeleton.getCallingTokenId(); 246 Log.info('tokenID = ' + tokenID); 247 let grantStatus = abilityAccessCtrl.createAtManager().verifyAccessToken( 248 tokenID, 'ohos.permission.MANAGE_SECURE_SETTINGS'); 249 grantStatus.then(data => { 250 if (data == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { 251 Log.info('MANAGE_SECURE_SETTINGS active'); 252 callBack(true); 253 } else { 254 Log.warn('MANAGE_SECURE_SETTINGS grantStatus= ' + JSON.stringify(data)); 255 callBack(false); 256 } 257 }).catch((err: BusinessError) => { 258 Log.error('tokenID = ' + tokenID + ' verifyAccessToken is failed: ' + JSON.stringify(err)); 259 callBack(false); 260 }) 261 } catch (err) { 262 Log.error('err = ' + JSON.stringify(err)); 263 callBack(false); 264 } 265 } 266 267 private isTrustList(keyWord: string): boolean { 268 return trustList.includes(keyWord) 269 } 270}