// Append the given message to the ADT log. Bypass the sandbox if necessary // such that we can write to the log file. private void appendToIdeLog(Throwable exception, String format, Object... args) { boolean token = RenderSecurityManager.enterSafeRegion(mCredential); try { AdtPlugin.log(exception, format, args); } finally { RenderSecurityManager.exitSafeRegion(token); } }
@Override public ILayoutPullParser getParser(ResourceValue layoutResource) { boolean token = RenderSecurityManager.enterSafeRegion(mCredential); try { return getParser(layoutResource.getName(), new File(layoutResource.getValue())); } finally { RenderSecurityManager.exitSafeRegion(token); } }
/** * Returns the namespace for the project. The namespace contains a standard part + the application * package. * * @return The package namespace of the project or null in case of error. */ @Override public String getNamespace() { if (mNamespace == null) { boolean token = RenderSecurityManager.enterSafeRegion(mCredential); try { ManifestData manifestData = AndroidManifestHelper.parseForData(mProject); if (manifestData != null) { String javaPackage = manifestData.getPackage(); mNamespace = String.format(AdtConstants.NS_CUSTOM_RESOURCES, javaPackage); } } finally { RenderSecurityManager.exitSafeRegion(token); } } return mNamespace; }
@Override public ILayoutPullParser getParser(String layoutName) { boolean token = RenderSecurityManager.enterSafeRegion(mCredential); try { // Try to compute the ResourceValue for this layout since layoutlib // must be an older version which doesn't pass the value: if (mResourceResolver != null) { ResourceValue value = mResourceResolver.getProjectResource(ResourceType.LAYOUT, layoutName); if (value != null) { return getParser(value); } } return getParser(layoutName, null); } finally { RenderSecurityManager.exitSafeRegion(token); } }
/** * {@inheritDoc} * * <p>This implementation goes through the output directory of the Eclipse project and loads the * <code>.class</code> file directly. */ @Override @SuppressWarnings("unchecked") public Object loadView( String className, Class[] constructorSignature, Object[] constructorParameters) throws ClassNotFoundException, Exception { mUsed = true; if (className == null) { // Just make a plain <View> if you specify <view> without a class= attribute. className = CLASS_VIEW; } // look for a cached version Class<?> clazz = mLoadedClasses.get(className); if (clazz != null) { return instantiateClass(clazz, constructorSignature, constructorParameters); } // load the class. try { if (mLoader == null) { // Allow creating class loaders during rendering; may be prevented by the // RenderSecurityManager boolean token = RenderSecurityManager.enterSafeRegion(mCredential); try { mLoader = new ProjectClassLoader(mParentClassLoader, mProject); } finally { RenderSecurityManager.exitSafeRegion(token); } } clazz = mLoader.loadClass(className); } catch (Exception e) { // Add the missing class to the list so that the renderer can print them later. // no need to log this. if (!className.equals(VIEW_FRAGMENT) && !className.equals(VIEW_INCLUDE)) { mMissingClasses.add(className); } } try { if (clazz != null) { // first try to instantiate it because adding it the list of loaded class so that // we don't add broken classes. Object view = instantiateClass(clazz, constructorSignature, constructorParameters); mLoadedClasses.put(className, clazz); return view; } } catch (Throwable e) { // Find root cause to log it. while (e.getCause() != null) { e = e.getCause(); } appendToIdeLog(e, "%1$s failed to instantiate.", className); // $NON-NLS-1$ // Add the missing class to the list so that the renderer can print them later. if (mLogger instanceof RenderLogger) { RenderLogger renderLogger = (RenderLogger) mLogger; renderLogger.recordThrowable(e); } mBrokenClasses.add(className); } // Create a mock view instead. We don't cache it in the mLoadedClasses map. // If any exception is thrown, we'll return a CFN with the original class name instead. try { clazz = mLoader.loadClass(SdkConstants.CLASS_MOCK_VIEW); Object view = instantiateClass(clazz, constructorSignature, constructorParameters); // Set the text of the mock view to the simplified name of the custom class Method m = view.getClass().getMethod("setText", new Class<?>[] {CharSequence.class}); String label = getShortClassName(className); if (label.equals(VIEW_FRAGMENT)) { label = "<fragment>\n" + "Pick preview layout from the \"Fragment Layout\" context menu"; } else if (label.equals(VIEW_INCLUDE)) { label = "Text"; } m.invoke(view, label); // Call MockView.setGravity(Gravity.CENTER) to get the text centered in // MockViews. // TODO: Do this in layoutlib's MockView class instead. try { // Look up android.view.Gravity#CENTER - or can we just hard-code // the value (17) here? Class<?> gravity = Class.forName( "android.view.Gravity", //$NON-NLS-1$ true, view.getClass().getClassLoader()); Field centerField = gravity.getField("CENTER"); // $NON-NLS-1$ int center = centerField.getInt(null); m = view.getClass().getMethod("setGravity", new Class<?>[] {Integer.TYPE}); // Center // int center = (0x0001 << 4) | (0x0001 << 0); m.invoke(view, Integer.valueOf(center)); } catch (Exception e) { // Not important to center views } return view; } catch (Exception e) { // We failed to create and return a mock view. // Just throw back a CNF with the original class name. throw new ClassNotFoundException(className, e); } }