1 /* 2 * Copyright (C) 2023 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.testutils.shadow; 18 19 import static org.robolectric.RuntimeEnvironment.application; 20 import static org.robolectric.shadow.api.Shadow.directlyOn; 21 22 import android.content.res.Resources; 23 import android.content.res.Resources.NotFoundException; 24 import android.util.SparseArray; 25 26 import androidx.annotation.ArrayRes; 27 28 import org.robolectric.annotation.Implementation; 29 import org.robolectric.annotation.Implements; 30 import org.robolectric.annotation.RealObject; 31 import org.robolectric.annotation.Resetter; 32 import org.robolectric.shadows.ShadowResources; 33 import org.robolectric.util.ReflectionHelpers.ClassParameter; 34 35 /** 36 * Shadow Resources and Theme classes to handle resource references that Robolectric shadows cannot 37 * handle because they are too new or private. 38 */ 39 @Implements(value = Resources.class) 40 public class SettingsShadowResources extends ShadowResources { 41 42 @RealObject 43 public Resources realResources; 44 45 private static SparseArray<Object> sResourceOverrides = new SparseArray<>(); 46 overrideResource(int id, Object value)47 public static void overrideResource(int id, Object value) { 48 sResourceOverrides.put(id, value); 49 } 50 overrideResource(String name, Object value)51 public static void overrideResource(String name, Object value) { 52 final Resources res = application.getResources(); 53 final int resId = res.getIdentifier(name, null, null); 54 if (resId == 0) { 55 throw new Resources.NotFoundException("Cannot override \"" + name + "\""); 56 } 57 overrideResource(resId, value); 58 } 59 60 @Resetter reset()61 public static void reset() { 62 sResourceOverrides.clear(); 63 } 64 65 @Implementation getIntArray(@rrayRes int id)66 protected int[] getIntArray(@ArrayRes int id) throws NotFoundException { 67 final Object override = sResourceOverrides.get(id); 68 if (override instanceof int[]) { 69 return (int[]) override; 70 } 71 return directlyOn(realResources, Resources.class).getIntArray(id); 72 } 73 74 @Implementation getString(int id)75 protected String getString(int id) { 76 final Object override = sResourceOverrides.get(id); 77 if (override instanceof String) { 78 return (String) override; 79 } 80 return directlyOn( 81 realResources, Resources.class, "getString", ClassParameter.from(int.class, id)); 82 } 83 84 @Implementation getInteger(int id)85 protected int getInteger(int id) { 86 final Object override = sResourceOverrides.get(id); 87 if (override instanceof Integer) { 88 return (Integer) override; 89 } 90 return directlyOn( 91 realResources, Resources.class, "getInteger", ClassParameter.from(int.class, id)); 92 } 93 94 @Implementation getBoolean(int id)95 protected boolean getBoolean(int id) { 96 final Object override = sResourceOverrides.get(id); 97 if (override instanceof Boolean) { 98 return (boolean) override; 99 } 100 return directlyOn(realResources, Resources.class, "getBoolean", 101 ClassParameter.from(int.class, id)); 102 } 103 } 104