1 /* 2 * Copyright (C) 2011 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.content.res; 18 19 import com.android.annotations.Nullable; 20 import com.android.ide.common.rendering.api.ResourceReference; 21 import com.android.ide.common.rendering.api.StyleResourceValue; 22 import com.android.layoutlib.bridge.android.BridgeContext; 23 import com.android.layoutlib.bridge.impl.DelegateManager; 24 import com.android.layoutlib.bridge.impl.RenderSessionImpl; 25 import com.android.resources.ResourceType; 26 import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 27 28 import android.content.res.Resources.NotFoundException; 29 import android.content.res.Resources.Theme; 30 import android.util.AttributeSet; 31 import android.util.TypedValue; 32 33 /** 34 * Delegate used to provide new implementation of a select few methods of {@link Resources.Theme} 35 * 36 * Through the layoutlib_create tool, the original methods of Theme have been replaced 37 * by calls to methods of the same name in this delegate class. 38 * 39 */ 40 public class Resources_Theme_Delegate { 41 42 // ---- delegate manager ---- 43 44 private static final DelegateManager<Resources_Theme_Delegate> sManager = 45 new DelegateManager<Resources_Theme_Delegate>(Resources_Theme_Delegate.class); 46 47 public static DelegateManager<Resources_Theme_Delegate> getDelegateManager() { 48 return sManager; 49 } 50 51 // ---- delegate methods. ---- 52 53 @LayoutlibDelegate 54 /*package*/ static TypedArray obtainStyledAttributes( 55 Resources thisResources, Theme thisTheme, 56 int[] attrs) { 57 boolean changed = setupResources(thisTheme); 58 BridgeTypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(attrs); 59 ta.setTheme(thisTheme); 60 restoreResources(changed); 61 return ta; 62 } 63 64 @LayoutlibDelegate 65 /*package*/ static TypedArray obtainStyledAttributes( 66 Resources thisResources, Theme thisTheme, 67 int resid, int[] attrs) 68 throws NotFoundException { 69 boolean changed = setupResources(thisTheme); 70 BridgeTypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(resid, 71 attrs); 72 ta.setTheme(thisTheme); 73 restoreResources(changed); 74 return ta; 75 } 76 77 @LayoutlibDelegate 78 /*package*/ static TypedArray obtainStyledAttributes( 79 Resources thisResources, Theme thisTheme, 80 AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) { 81 boolean changed = setupResources(thisTheme); 82 BridgeTypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(set, 83 attrs, defStyleAttr, defStyleRes); 84 ta.setTheme(thisTheme); 85 restoreResources(changed); 86 return ta; 87 } 88 89 @LayoutlibDelegate 90 /*package*/ static boolean resolveAttribute( 91 Resources thisResources, Theme thisTheme, 92 int resid, TypedValue outValue, 93 boolean resolveRefs) { 94 boolean changed = setupResources(thisTheme); 95 boolean found = RenderSessionImpl.getCurrentContext().resolveThemeAttribute(resid, 96 outValue, resolveRefs); 97 restoreResources(changed); 98 return found; 99 } 100 101 @LayoutlibDelegate 102 /*package*/ static TypedArray resolveAttributes(Resources thisResources, Theme thisTheme, 103 int[] values, int[] attrs) { 104 // FIXME 105 return null; 106 } 107 108 // ---- private helper methods ---- 109 110 private static boolean setupResources(Theme thisTheme) { 111 // Key is a space-separated list of theme ids applied that have been merged into the 112 // BridgeContext's theme to make thisTheme. 113 String[] appliedStyles = thisTheme.getKey().split(" "); 114 boolean changed = false; 115 for (String s : appliedStyles) { 116 if (s.isEmpty()) { 117 continue; 118 } 119 // See the definition of force parameter in Theme.applyStyle(). 120 boolean force = false; 121 if (s.charAt(s.length() - 1) == '!') { 122 force = true; 123 s = s.substring(0, s.length() - 1); 124 } 125 int styleId = Integer.parseInt(s, 16); 126 StyleResourceValue style = resolveStyle(styleId); 127 if (style != null) { 128 RenderSessionImpl.getCurrentContext().getRenderResources().applyStyle(style, force); 129 changed = true; 130 } 131 132 } 133 return changed; 134 } 135 136 private static void restoreResources(boolean changed) { 137 if (changed) { 138 RenderSessionImpl.getCurrentContext().getRenderResources().clearStyles(); 139 } 140 } 141 142 @Nullable 143 private static StyleResourceValue resolveStyle(int nativeResid) { 144 if (nativeResid == 0) { 145 return null; 146 } 147 BridgeContext context = RenderSessionImpl.getCurrentContext(); 148 ResourceReference theme = context.resolveId(nativeResid); 149 if (theme.isFramework()) { 150 return (StyleResourceValue) context.getRenderResources() 151 .getFrameworkResource(ResourceType.STYLE, theme.getName()); 152 } else { 153 return (StyleResourceValue) context.getRenderResources() 154 .getProjectResource(ResourceType.STYLE, theme.getName()); 155 } 156 } 157 } 158