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