// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.android_webview; import android.content.res.Resources; import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; import java.io.IOException; import java.io.InputStreamReader; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; import java.util.Scanner; /** * A class that defines a set of resource IDs and functionality to resolve * those IDs to concrete resources. */ @JNINamespace("android_webview::AwResource") public class AwResource { // The following resource ID's must be initialized by the embedder. // Raw resource ID for an HTML page to be displayed in the case of // a specific load error. private static int RAW_LOAD_ERROR; // Raw resource ID for an HTML page to be displayed in the case of // a generic load error. (It's called NO_DOMAIN for legacy reasons). private static int RAW_NO_DOMAIN; // String resource ID for the default text encoding to use. private static int STRING_DEFAULT_TEXT_ENCODING; // The embedder should inject a Resources object that will be used // to resolve Resource IDs into the actual resources. private static Resources sResources; // Loading some resources is expensive, so cache the results. private static Map<Integer, SoftReference<String> > sResourceCache; private static final int TYPE_STRING = 0; private static final int TYPE_RAW = 1; public static void setResources(Resources resources) { sResources = resources; sResourceCache = new HashMap<Integer, SoftReference<String> >(); } public static void setErrorPageResources(int loaderror, int nodomain) { RAW_LOAD_ERROR = loaderror; RAW_NO_DOMAIN = nodomain; } public static void setDefaultTextEncoding(int encoding) { STRING_DEFAULT_TEXT_ENCODING = encoding; } @CalledByNative public static String getDefaultTextEncoding() { return getResource(STRING_DEFAULT_TEXT_ENCODING, TYPE_STRING); } @CalledByNative public static String getNoDomainPageContent() { return getResource(RAW_NO_DOMAIN, TYPE_RAW); } @CalledByNative public static String getLoadErrorPageContent() { return getResource(RAW_LOAD_ERROR, TYPE_RAW); } private static String getResource(int resid, int type) { assert resid != 0; assert sResources != null; assert sResourceCache != null; String result = sResourceCache.get(resid) == null ? null : sResourceCache.get(resid).get(); if (result == null) { switch (type) { case TYPE_STRING: result = sResources.getString(resid); break; case TYPE_RAW: result = getRawFileResourceContent(resid); break; default: throw new IllegalArgumentException("Unknown resource type"); } sResourceCache.put(resid, new SoftReference<String>(result)); } return result; } private static String getRawFileResourceContent(int resid) { assert resid != 0; assert sResources != null; InputStreamReader isr = null; String result = null; try { isr = new InputStreamReader( sResources.openRawResource(resid)); // \A tells the scanner to use the beginning of the input // as the delimiter, hence causes it to read the entire text. result = new Scanner(isr).useDelimiter("\\A").next(); } catch (Resources.NotFoundException e) { return ""; } catch (NoSuchElementException e) { return ""; } finally { try { if (isr != null) { isr.close(); } } catch (IOException e) { // Nothing to do if close() fails. } } return result; } }