1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.android_webview;
6
7import android.content.res.Resources;
8
9import org.chromium.base.CalledByNative;
10import org.chromium.base.JNINamespace;
11
12import java.io.IOException;
13import java.io.InputStreamReader;
14import java.lang.ref.SoftReference;
15import java.util.HashMap;
16import java.util.Map;
17import java.util.NoSuchElementException;
18import java.util.Scanner;
19
20@JNINamespace("android_webview::AwResource")
21public class AwResource {
22    // The following resource ID's must be initialized by the embedder.
23
24    // Raw resource ID for an HTML page to be displayed in the case of
25    // a specific load error.
26    public static int RAW_LOAD_ERROR;
27
28    // Raw resource ID for an HTML page to be displayed in the case of
29    // a generic load error. (It's called NO_DOMAIN for legacy reasons).
30    public static int RAW_NO_DOMAIN;
31
32    // String resource ID for the default text encoding to use.
33    public static int STRING_DEFAULT_TEXT_ENCODING;
34
35    // The embedder should inject a Resources object that will be used
36    // to resolve Resource IDs into the actual resources.
37    private static Resources sResources;
38
39    // Loading some resources is expensive, so cache the results.
40    private static Map<Integer, SoftReference<String> > sResourceCache;
41
42    private static final int TYPE_STRING = 0;
43    private static final int TYPE_RAW = 1;
44
45    public static void setResources(Resources resources) {
46        sResources = resources;
47        sResourceCache = new HashMap<Integer, SoftReference<String> >();
48    }
49
50    @CalledByNative
51    public static String getDefaultTextEncoding() {
52        return getResource(STRING_DEFAULT_TEXT_ENCODING, TYPE_STRING);
53    }
54
55    @CalledByNative
56    public static String getNoDomainPageContent() {
57        return getResource(RAW_NO_DOMAIN, TYPE_RAW);
58    }
59
60    @CalledByNative
61    public static String getLoadErrorPageContent() {
62        return getResource(RAW_LOAD_ERROR, TYPE_RAW);
63    }
64
65    private static String getResource(int resid, int type) {
66        assert resid != 0;
67        assert sResources != null;
68        assert sResourceCache != null;
69
70        String result = sResourceCache.get(resid) == null ?
71                null : sResourceCache.get(resid).get();
72        if (result == null) {
73            switch (type) {
74                case TYPE_STRING:
75                    result = sResources.getString(resid);
76                    break;
77                case TYPE_RAW:
78                    result = getRawFileResourceContent(resid);
79                    break;
80                default:
81                    throw new IllegalArgumentException("Unknown resource type");
82            }
83
84            sResourceCache.put(resid, new SoftReference<String>(result));
85        }
86        return result;
87    }
88
89    private static String getRawFileResourceContent(int resid) {
90        assert resid != 0;
91        assert sResources != null;
92
93        InputStreamReader isr = null;
94        String result = null;
95
96        try {
97            isr = new InputStreamReader(
98                    sResources.openRawResource(resid));
99            // \A tells the scanner to use the beginning of the input
100            // as the delimiter, hence causes it to read the entire text.
101            result = new Scanner(isr).useDelimiter("\\A").next();
102        } catch (Resources.NotFoundException e) {
103            return "";
104        } catch (NoSuchElementException e) {
105            return "";
106        } finally {
107            try {
108                if (isr != null) {
109                    isr.close();
110                }
111            } catch (IOException e) {
112            }
113        }
114        return result;
115    }
116}
117