1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.intelligence.search.indexing; 18 19 import android.content.Context; 20 import android.content.res.TypedArray; 21 import androidx.annotation.Nullable; 22 import android.text.TextUtils; 23 import android.util.AttributeSet; 24 import android.util.Log; 25 import android.util.TypedValue; 26 27 import androidx.preference.R; 28 29 /** 30 * Utility class to parse elements of XML preferences 31 */ 32 public class XmlParserUtils { 33 34 private static final String TAG = "XmlParserUtils"; 35 private static final String NS_APP_RES_AUTO = "http://schemas.android.com/apk/res-auto"; 36 private static final String ENTRIES_SEPARATOR = "|"; 37 getDataKey(Context context, AttributeSet attrs)38 public static String getDataKey(Context context, AttributeSet attrs) { 39 return getData(context, attrs, 40 R.styleable.Preference, 41 R.styleable.Preference_android_key); 42 } 43 getDataTitle(Context context, AttributeSet attrs)44 public static String getDataTitle(Context context, AttributeSet attrs) { 45 return getData(context, attrs, 46 R.styleable.Preference, 47 R.styleable.Preference_android_title); 48 } 49 getDataSummary(Context context, AttributeSet attrs)50 public static String getDataSummary(Context context, AttributeSet attrs) { 51 return getData(context, attrs, 52 R.styleable.Preference, 53 R.styleable.Preference_android_summary); 54 } 55 getDataSummaryOn(Context context, AttributeSet attrs)56 public static String getDataSummaryOn(Context context, AttributeSet attrs) { 57 return getData(context, attrs, 58 R.styleable.CheckBoxPreference, 59 R.styleable.CheckBoxPreference_android_summaryOn); 60 } 61 getDataSummaryOff(Context context, AttributeSet attrs)62 public static String getDataSummaryOff(Context context, AttributeSet attrs) { 63 return getData(context, attrs, 64 R.styleable.CheckBoxPreference, 65 R.styleable.CheckBoxPreference_android_summaryOff); 66 } 67 getDataEntries(Context context, AttributeSet attrs)68 public static String getDataEntries(Context context, AttributeSet attrs) { 69 return getDataEntries(context, attrs, 70 R.styleable.ListPreference, 71 R.styleable.ListPreference_android_entries); 72 } 73 getDataKeywords(Context context, AttributeSet attrs)74 public static String getDataKeywords(Context context, AttributeSet attrs) { 75 final String keywordRes = attrs.getAttributeValue(NS_APP_RES_AUTO, "keywords"); 76 if (TextUtils.isEmpty(keywordRes)) { 77 return null; 78 } 79 return getString(context, keywordRes); 80 } 81 getDataIcon(Context context, AttributeSet attrs)82 public static int getDataIcon(Context context, AttributeSet attrs) { 83 final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.Preference); 84 final int dataIcon = ta.getResourceId(R.styleable.Preference_android_icon, 0); 85 ta.recycle(); 86 return dataIcon; 87 } 88 89 /** 90 * Returns the fragment name if this preference launches a child fragment. 91 */ getDataChildFragment(Context context, AttributeSet attrs)92 public static String getDataChildFragment(Context context, AttributeSet attrs) { 93 return getData(context, attrs, R.styleable.Preference, 94 R.styleable.Preference_android_fragment); 95 } 96 97 /** 98 * Returns if the attrs contains highlightableMenuKey="" element. 99 */ getHighlightableMenuKey(Context context, AttributeSet attrs)100 public static String getHighlightableMenuKey(Context context, AttributeSet attrs) { 101 String menuKey = attrs.getAttributeValue(NS_APP_RES_AUTO, "highlightableMenuKey"); 102 if (!TextUtils.isEmpty(menuKey)) { 103 menuKey = getString(context, menuKey); 104 } 105 return menuKey; 106 } 107 108 @Nullable getData(Context context, AttributeSet set, int[] attrs, int resId)109 private static String getData(Context context, AttributeSet set, int[] attrs, int resId) { 110 final TypedArray ta = context.obtainStyledAttributes(set, attrs); 111 String data; 112 if (DevicePolicyResourcesUtils.isDevicePolicyResource(context, ta, resId)) { 113 data = DevicePolicyResourcesUtils.getDevicePolicyResource(context, ta, resId); 114 } else { 115 data = ta.getString(resId); 116 } 117 ta.recycle(); 118 return data; 119 } 120 getDataEntries(Context context, AttributeSet set, int[] attrs, int resId)121 private static String getDataEntries(Context context, AttributeSet set, int[] attrs, 122 int resId) { 123 final TypedArray sa = context.obtainStyledAttributes(set, attrs); 124 final TypedValue tv = sa.peekValue(resId); 125 sa.recycle(); 126 String[] data = null; 127 if (tv != null && tv.type == TypedValue.TYPE_REFERENCE) { 128 if (tv.resourceId != 0) { 129 data = context.getResources().getStringArray(tv.resourceId); 130 } 131 } 132 final int count = (data == null) ? 0 : data.length; 133 if (count == 0) { 134 return null; 135 } 136 final StringBuilder result = new StringBuilder(); 137 for (int n = 0; n < count; n++) { 138 result.append(data[n]); 139 result.append(ENTRIES_SEPARATOR); 140 } 141 return result.toString(); 142 } 143 getString(Context context, String res)144 private static String getString(Context context, String res) { 145 // The format of the resource is either a string, or @ followed by int (@123456). 146 // When it's int, we need to look up the actual string from context. 147 if (!res.startsWith("@")) { 148 // It's a string. 149 return res; 150 } else { 151 // It's a resource 152 try { 153 final int resValue = Integer.parseInt(res.substring(1)); 154 if (DevicePolicyResourcesUtils.isDevicePolicyResource(context, resValue)) { 155 return DevicePolicyResourcesUtils.getDevicePolicyResource(context, resValue); 156 } else { 157 return context.getString(resValue); 158 } 159 } catch (NumberFormatException e) { 160 Log.w(TAG, "Failed to parse keyword attribute, skipping " + res); 161 return null; 162 } 163 } 164 } 165 } 166