1 /* 2 * Copyright (C) 2024 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 android.net.wifi.util; 18 19 import android.content.Context; 20 21 import java.io.PrintWriter; 22 import java.util.Arrays; 23 import java.util.HashMap; 24 import java.util.List; 25 import java.util.Map; 26 27 /** 28 * A class to cache the Wifi resource value and provide override mechanism from shell 29 * @hide 30 */ 31 public class WifiResourceCache { 32 private static final String TAG = "WifiResourceCache"; 33 private final Context mContext; 34 35 private final Map<Integer, Boolean> mBooleanResourceMap; 36 private final Map<Integer, Integer> mIntegerResourceMap; 37 private final Map<Integer, String> mStringResourceMap; 38 private final Map<Integer, String[]> mStringArrayResourceMap; 39 private final Map<Integer, int[]> mIntArrayResourceMap; 40 private final List<Map> mValueMapList; 41 private final Map<String, Integer> mResourceNameMap; 42 43 private int mTempId = -1; 44 private final Object mLock = new Object(); 45 WifiResourceCache(Context context)46 public WifiResourceCache(Context context) { 47 mContext = context; 48 mBooleanResourceMap = new HashMap<>(); 49 mIntegerResourceMap = new HashMap<>(); 50 mStringArrayResourceMap = new HashMap<>(); 51 mIntArrayResourceMap = new HashMap<>(); 52 mStringResourceMap = new HashMap<>(); 53 mValueMapList = List.of(mBooleanResourceMap, mIntegerResourceMap, mIntArrayResourceMap, 54 mStringArrayResourceMap, mStringResourceMap); 55 mResourceNameMap = new HashMap<>(); 56 } 57 58 /** 59 * Get and cache the boolean value as {@link android.content.res.Resources#getBoolean(int)} 60 */ getBoolean(int resourceId)61 public boolean getBoolean(int resourceId) { 62 synchronized (mLock) { 63 if (mBooleanResourceMap.containsKey(resourceId)) { 64 return mBooleanResourceMap.get(resourceId); 65 } 66 67 String resourceName = mContext.getResources().getResourceEntryName(resourceId); 68 if (mResourceNameMap.containsKey(resourceName)) { 69 int tempId = mResourceNameMap.get(resourceName); 70 if (mBooleanResourceMap.containsKey(tempId)) { 71 boolean value = mBooleanResourceMap.get(tempId); 72 mBooleanResourceMap.put(resourceId, value); 73 mBooleanResourceMap.remove(tempId); 74 mResourceNameMap.put(resourceName, resourceId); 75 return value; 76 } 77 } 78 mResourceNameMap.put(resourceName, resourceId); 79 return mBooleanResourceMap.computeIfAbsent(resourceId, 80 v -> mContext.getResources().getBoolean(resourceId)); 81 } 82 } 83 84 /** 85 * Get and cache the integer value as {@link android.content.res.Resources#getInteger(int)} 86 */ getInteger(int resourceId)87 public int getInteger(int resourceId) { 88 synchronized (mLock) { 89 if (mIntegerResourceMap.containsKey(resourceId)) { 90 return mIntegerResourceMap.get(resourceId); 91 } 92 93 String resourceName = mContext.getResources().getResourceEntryName(resourceId); 94 if (mResourceNameMap.containsKey(resourceName)) { 95 int tempId = mResourceNameMap.get(resourceName); 96 if (mIntegerResourceMap.containsKey(tempId)) { 97 int value = mIntegerResourceMap.get(tempId); 98 mIntegerResourceMap.put(resourceId, value); 99 mIntegerResourceMap.remove(tempId); 100 mResourceNameMap.put(resourceName, resourceId); 101 return value; 102 } 103 } 104 mResourceNameMap.put(resourceName, resourceId); 105 return mIntegerResourceMap.computeIfAbsent(resourceId, 106 v -> mContext.getResources().getInteger(resourceId)); 107 } 108 } 109 110 /** 111 * Get and cache the integer value as {@link android.content.res.Resources#getString(int)} 112 */ getString(int resourceId)113 public String getString(int resourceId) { 114 synchronized (mLock) { 115 if (mStringResourceMap.containsKey(resourceId)) { 116 return mStringResourceMap.get(resourceId); 117 } 118 119 String resourceName = mContext.getResources().getResourceEntryName(resourceId); 120 if (mResourceNameMap.containsKey(resourceName)) { 121 int tempId = mResourceNameMap.get(resourceName); 122 if (mStringResourceMap.containsKey(tempId)) { 123 String value = mStringResourceMap.get(tempId); 124 mStringResourceMap.put(resourceId, value); 125 mStringResourceMap.remove(tempId); 126 mResourceNameMap.put(resourceName, resourceId); 127 return value; 128 } 129 } 130 mResourceNameMap.put(resourceName, resourceId); 131 return mStringResourceMap.computeIfAbsent(resourceId, 132 v -> mContext.getResources().getString(resourceId)); 133 } 134 } 135 136 /** 137 * Get and cache the integer value as {@link android.content.res.Resources#getStringArray(int)} 138 */ getStringArray(int resourceId)139 public String[] getStringArray(int resourceId) { 140 synchronized (mLock) { 141 if (mStringArrayResourceMap.containsKey(resourceId)) { 142 return mStringArrayResourceMap.get(resourceId); 143 } 144 145 String resourceName = mContext.getResources().getResourceEntryName(resourceId); 146 if (mResourceNameMap.containsKey(resourceName)) { 147 int tempId = mResourceNameMap.get(resourceName); 148 if (mStringArrayResourceMap.containsKey(tempId)) { 149 String[] value = mStringArrayResourceMap.get(tempId); 150 mStringArrayResourceMap.put(resourceId, value); 151 mStringArrayResourceMap.remove(tempId); 152 mResourceNameMap.put(resourceName, resourceId); 153 return value; 154 } 155 } 156 mResourceNameMap.put(resourceName, resourceId); 157 return mStringArrayResourceMap.computeIfAbsent(resourceId, 158 v -> mContext.getResources().getStringArray(resourceId)); 159 } 160 } 161 162 /** 163 * Get and cache the integer value as {@link android.content.res.Resources#getIntArray(int)} 164 */ getIntArray(int resourceId)165 public int[] getIntArray(int resourceId) { 166 synchronized (mLock) { 167 if (mIntArrayResourceMap.containsKey(resourceId)) { 168 return mIntArrayResourceMap.get(resourceId); 169 } 170 171 String resourceName = mContext.getResources().getResourceEntryName(resourceId); 172 if (mResourceNameMap.containsKey(resourceName)) { 173 int tempId = mResourceNameMap.get(resourceName); 174 if (mIntArrayResourceMap.containsKey(tempId)) { 175 int[] value = mIntArrayResourceMap.get(tempId); 176 mIntArrayResourceMap.put(resourceId, value); 177 mIntArrayResourceMap.remove(tempId); 178 mResourceNameMap.put(resourceName, resourceId); 179 return value; 180 } 181 } 182 mResourceNameMap.put(resourceName, resourceId); 183 return mIntArrayResourceMap.computeIfAbsent(resourceId, 184 v -> mContext.getResources().getIntArray(resourceId)); 185 } 186 } 187 188 /** 189 * Override the target boolean value 190 * 191 * @param resourceName the resource overlay name 192 * @param value override to this value 193 */ overrideBooleanValue(String resourceName, boolean value)194 public void overrideBooleanValue(String resourceName, boolean value) { 195 synchronized (mLock) { 196 int resourceId = mResourceNameMap.computeIfAbsent(resourceName, v -> mTempId--); 197 mBooleanResourceMap.put(resourceId, value); 198 } 199 } 200 201 /** 202 * Override the target boolean value 203 */ restoreBooleanValue(String resourceName)204 public void restoreBooleanValue(String resourceName) { 205 synchronized (mLock) { 206 mBooleanResourceMap.remove(mResourceNameMap.remove(resourceName)); 207 } 208 } 209 210 /** 211 * Override the target integer value 212 * @param resourceName the resource overlay name 213 * @param value override to this value 214 */ overrideIntegerValue(String resourceName, int value)215 public void overrideIntegerValue(String resourceName, int value) { 216 synchronized (mLock) { 217 int resourceId = mResourceNameMap.computeIfAbsent(resourceName, v -> mTempId--); 218 mIntegerResourceMap.put(resourceId, value); 219 } 220 } 221 222 /** 223 * Override the target integer value 224 */ restoreIntegerValue(String resourceName)225 public void restoreIntegerValue(String resourceName) { 226 synchronized (mLock) { 227 mIntegerResourceMap.remove(mResourceNameMap.remove(resourceName)); 228 } 229 } 230 231 /** 232 * Override the target String value 233 * @param resourceName the resource overlay name 234 * @param value override to this value 235 */ overrideStringValue(String resourceName, String value)236 public void overrideStringValue(String resourceName, String value) { 237 synchronized (mLock) { 238 int resourceId = mResourceNameMap.computeIfAbsent(resourceName, v -> mTempId--); 239 mStringResourceMap.put(resourceId, value); 240 } 241 } 242 243 /** 244 * Override the target integer value 245 */ restoreStringValue(String resourceName)246 public void restoreStringValue(String resourceName) { 247 synchronized (mLock) { 248 mStringResourceMap.remove(mResourceNameMap.remove(resourceName)); 249 } 250 } 251 252 /** 253 * Override the target string array value 254 * @param resourceName the resource overlay name 255 * @param value override to this value 256 */ overrideStringArrayValue(String resourceName, String[] value)257 public void overrideStringArrayValue(String resourceName, String[] value) { 258 synchronized (mLock) { 259 int resourceId = mResourceNameMap.computeIfAbsent(resourceName, v -> mTempId--); 260 mStringArrayResourceMap.put(resourceId, value); 261 } 262 } 263 264 /** 265 * Override the target string array value 266 */ restoreStringArrayValue(String resourceName)267 public void restoreStringArrayValue(String resourceName) { 268 synchronized (mLock) { 269 mStringArrayResourceMap.remove(mResourceNameMap.remove(resourceName)); 270 } 271 } 272 273 /** 274 * Override the target int array value 275 * @param resourceName the resource overlay name 276 * @param value override to this value 277 */ overrideIntArrayValue(String resourceName, int[] value)278 public void overrideIntArrayValue(String resourceName, int[] value) { 279 synchronized (mLock) { 280 int resourceId = mResourceNameMap.computeIfAbsent(resourceName, v -> mTempId--); 281 mIntArrayResourceMap.put(resourceId, value); 282 } 283 } 284 285 /** 286 * Override the target int array value 287 */ restoreIntArrayValue(String resourceName)288 public void restoreIntArrayValue(String resourceName) { 289 synchronized (mLock) { 290 mIntArrayResourceMap.remove(mResourceNameMap.remove(resourceName)); 291 } 292 } 293 294 /** 295 * Dump of current resource value 296 */ dump(PrintWriter pw)297 public void dump(PrintWriter pw) { 298 pw.println("Dump of WifiResourceCache"); 299 pw.println("WifiResourceCache - resource value Begin ----"); 300 synchronized (mLock) { 301 for (Map.Entry<String, Integer> resourceEntry : mResourceNameMap.entrySet()) { 302 for (Map m : mValueMapList) { 303 if (m.containsKey(resourceEntry.getValue())) { 304 pw.println("Resource Name: " + resourceEntry.getKey() 305 + ", value: " + valueToString(m.get(resourceEntry.getValue()))); 306 break; 307 } 308 } 309 } 310 } 311 pw.println("WifiResourceCache - resource value End ----"); 312 } 313 valueToString(Object input)314 private String valueToString(Object input) { 315 if (input instanceof Object[]) { 316 return Arrays.deepToString((Object[]) input); 317 } 318 return input.toString(); 319 } 320 321 /** 322 * Remove all override value and set to default 323 */ reset()324 public void reset() { 325 synchronized (mLock) { 326 for (Map m : mValueMapList) { 327 m.clear(); 328 } 329 mResourceNameMap.clear(); 330 } 331 } 332 333 /** 334 * Handle the locale change to apply the translation 335 */ handleLocaleChange()336 public void handleLocaleChange() { 337 mStringResourceMap.clear(); 338 mStringArrayResourceMap.clear(); 339 } 340 } 341