1#!/usr/bin/env python 2# 3# Copyright (C) 2022 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import xml.etree.ElementTree as ET 18import datetime 19import os 20from os import listdir 21from os.path import isfile, join 22 23 24# This script generates and updates the public.xml file for sample ota app automatically. 25# Must be run after adding new strings to sample ota app. 26 27class AdServicesOTAUtil: 28 ADSERVICES_PUBLIC_RES_FILE = '../apk/publicres/values/public.xml' 29 OTA_PUBLIC_RES_FILE = '../samples/ota/res/values/public.xml' 30 OTA_RES_VALUES_DIR = '../samples/ota/res/values/' 31 OTA_LAYOUT_DIR = "../samples/ota/res/layout" 32 OTA_DRAWABLE_DIR = "../samples/ota/res/drawable" 33 OTA_COLOR_DIR = "../samples/ota/res/color" 34 35 COPYRIGHT_TEXT = f'''<?xml version="1.0" encoding="utf-8"?> 36 <!-- Copyright (C) {datetime.date.today().year} The Android Open Source Project 37 38 Licensed under the Apache License, Version 2.0 (the "License"); 39 you may not use this file except in compliance with the License. 40 You may obtain a copy of the License at 41 42 http://www.apache.org/licenses/LICENSE-2.0 43 44 Unless required by applicable law or agreed to in writing, software 45 distributed under the License is distributed on an "AS IS" BASIS, 46 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 47 See the License for the specific language governing permissions and 48 limitations under the License. 49 --> 50 ''' 51 52 def _add_value_res(self, adservices_dict, public_xml, ota_res_values_dir): 53 if (not os.path.isdir(ota_res_values_dir)): 54 return 55 for file in os.scandir(ota_res_values_dir): 56 if (file.name == 'public.xml'): 57 continue 58 root_element = ET.parse(file.path).getroot() 59 elem_type = file.name.split(".")[0][:-1] 60 for x in root_element: 61 cur_element = ET.SubElement(public_xml, 'public') 62 cur_element.set('type', elem_type) 63 cur_element.set('name', x.attrib['name']) 64 if (elem_type, x.attrib['name']) not in adservices_dict: 65 print(f"ERROR: ({elem_type},{x.attrib['name']}) is not in adservices ") 66 exit(0) 67 cur_element.set('id', adservices_dict[(elem_type, x.attrib['name'])]) 68 69 def _add_file_res(self, adservices_dict, public_xml, res_dir, res_type): 70 if (not os.path.isdir(res_dir)): 71 return 72 res_files = [f for f in listdir(res_dir) if isfile(join(res_dir, f))] 73 for file in res_files: 74 cur_element = ET.SubElement(public_xml, 'public') 75 cur_element.set('type', res_type) 76 res_name = file.split('.')[0] 77 cur_element.set('name', res_name) 78 if (res_type, res_name) not in adservices_dict: 79 print(f"ERROR: ({res_type},{res_name}) is not in adservices ") 80 exit(0) 81 cur_element.set('id', adservices_dict[(res_type, res_name)]) 82 83 def _add_id_res(self, adservices_dict, public_xml, res_dir): 84 if (not os.path.isdir(res_dir)): 85 return 86 res_ids = set() 87 for file in os.scandir(res_dir): 88 ns = '{http://schemas.android.com/apk/res/android}' 89 for child in ET.parse(file.path).getroot().iter(): 90 if (ns + 'id' in child.attrib): 91 res_ids.add(child.attrib[ns + 'id'].split('/')[1]) 92 res_ids = list(res_ids) 93 for res_id in res_ids: 94 cur_element = ET.SubElement(public_xml, 'public') 95 cur_element.set('type', 'id') 96 cur_element.set('name', res_id) 97 if ('id', res_id) not in adservices_dict: 98 print(f"ERROR: ('id',{res_id}) is not in adservices ") 99 exit(0) 100 cur_element.set('id', adservices_dict[('id', res_id)]) 101 102 def update_ota_public_xml(self, adservices_public_res=ADSERVICES_PUBLIC_RES_FILE, 103 ota_public_res=OTA_PUBLIC_RES_FILE, 104 ota_res_values_dir=OTA_RES_VALUES_DIR, 105 ota_layout_dir=OTA_LAYOUT_DIR, 106 ota_drawable_dir=OTA_DRAWABLE_DIR, 107 ota_color_dir=OTA_COLOR_DIR): 108 adservices_dict = {} 109 adservices_public_xml = ET.parse(adservices_public_res).getroot() 110 for x in adservices_public_xml: 111 adservices_dict[(x.attrib['type'], x.attrib['name'])] = x.attrib['id'] 112 113 public_xml = ET.Element('resources') 114 115 self._add_value_res(adservices_dict, public_xml, ota_res_values_dir) 116 self._add_file_res(adservices_dict, public_xml, ota_drawable_dir, 'drawable') 117 self._add_file_res(adservices_dict, public_xml, ota_color_dir, 'color') 118 self._add_file_res(adservices_dict, public_xml, ota_layout_dir, 'layout') 119 self._add_id_res(adservices_dict, public_xml, ota_layout_dir) 120 121 ET.indent(public_xml, space=' ') 122 if os.path.exists(ota_public_res): 123 os.remove(ota_public_res) 124 with open(ota_public_res, 'w') as f: 125 f.write(self.COPYRIGHT_TEXT) 126 f.write(ET.tostring(public_xml, encoding="unicode")) 127 128 129if __name__ == "__main__": 130 util = AdServicesOTAUtil() 131 util.update_ota_public_xml() 132