1/*
2 * Copyright (C) 2010 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
17package android.webkit;
18
19import android.app.ActivityManager;
20import android.content.Context;
21import android.net.Uri;
22import android.provider.Settings;
23import android.util.Log;
24
25import java.io.File;
26import java.io.InputStream;
27
28class JniUtil {
29
30    static {
31        System.loadLibrary("webcore");
32        System.loadLibrary("chromium_net");
33    }
34    private static final String LOGTAG = "webkit";
35    private JniUtil() {} // Utility class, do not instantiate.
36
37    // Used by the Chromium HTTP stack.
38    private static String sDatabaseDirectory;
39    private static String sCacheDirectory;
40    private static Context sContext;
41
42    private static void checkInitialized() {
43        if (sContext == null) {
44            throw new IllegalStateException("Call CookieSyncManager::createInstance() or create a webview before using this class");
45        }
46    }
47
48    protected static synchronized void setContext(Context context) {
49        if (sContext != null) {
50            return;
51        }
52
53        sContext = context.getApplicationContext();
54    }
55
56    protected static synchronized Context getContext() {
57        return sContext;
58    }
59
60    /**
61     * Called by JNI. Gets the application's database directory, excluding the trailing slash.
62     * @return String The application's database directory
63     */
64    private static synchronized String getDatabaseDirectory() {
65        checkInitialized();
66
67        if (sDatabaseDirectory == null) {
68            sDatabaseDirectory = sContext.getDatabasePath("dummy").getParent();
69        }
70
71        return sDatabaseDirectory;
72    }
73
74    /**
75     * Called by JNI. Gets the application's cache directory, excluding the trailing slash.
76     * @return String The application's cache directory
77     */
78    private static synchronized String getCacheDirectory() {
79        checkInitialized();
80
81        if (sCacheDirectory == null) {
82            File cacheDir = sContext.getCacheDir();
83            if (cacheDir == null) {
84                sCacheDirectory = "";
85            } else {
86                sCacheDirectory = cacheDir.getAbsolutePath();
87            }
88        }
89
90        return sCacheDirectory;
91    }
92
93    /**
94     * Called by JNI. Gets the application's package name.
95     * @return String The application's package name
96     */
97    private static synchronized String getPackageName() {
98        checkInitialized();
99
100        return sContext.getPackageName();
101    }
102
103    private static final String ANDROID_CONTENT = URLUtil.CONTENT_BASE;
104
105    /**
106     * Called by JNI. Calculates the size of an input stream by reading it.
107     * @return long The size of the stream
108     */
109    private static synchronized long contentUrlSize(String url) {
110        // content://
111        if (url.startsWith(ANDROID_CONTENT)) {
112            try {
113                // Strip off MIME type. If we don't do this, we can fail to
114                // load Gmail attachments, because the URL being loaded doesn't
115                // exactly match the URL we have permission to read.
116                int mimeIndex = url.lastIndexOf('?');
117                if (mimeIndex != -1) {
118                    url = url.substring(0, mimeIndex);
119                }
120                Uri uri = Uri.parse(url);
121                InputStream is = sContext.getContentResolver().openInputStream(uri);
122                byte[] buffer = new byte[1024];
123                int n;
124                long size = 0;
125                try {
126                    while ((n = is.read(buffer)) != -1) {
127                        size += n;
128                    }
129                } finally {
130                    is.close();
131                }
132                return size;
133            } catch (Exception e) {
134                Log.e(LOGTAG, "Exception: " + url);
135                return 0;
136            }
137        } else {
138            return 0;
139        }
140    }
141
142    /**
143     * Called by JNI.
144     *
145     * @return  Opened input stream to content
146     * TODO: Make all content loading use this instead of BrowserFrame.java
147     */
148    private static synchronized InputStream contentUrlStream(String url) {
149        // content://
150        if (url.startsWith(ANDROID_CONTENT)) {
151            try {
152                // Strip off mimetype, for compatibility with ContentLoader.java
153                // (used with Android HTTP stack, now removed).
154                // If we don't do this, we can fail to load Gmail attachments,
155                // because the URL being loaded doesn't exactly match the URL we
156                // have permission to read.
157                int mimeIndex = url.lastIndexOf('?');
158                if (mimeIndex != -1) {
159                    url = url.substring(0, mimeIndex);
160                }
161                Uri uri = Uri.parse(url);
162                return sContext.getContentResolver().openInputStream(uri);
163            } catch (Exception e) {
164                Log.e(LOGTAG, "Exception: " + url);
165                return null;
166            }
167        } else {
168            return null;
169        }
170    }
171
172    private static synchronized String getAutofillQueryUrl() {
173        checkInitialized();
174        // If the device has not checked in it won't have pulled down the system setting for the
175        // Autofill Url. In that case we will not make autofill server requests.
176        return Settings.Global.getString(sContext.getContentResolver(),
177                Settings.Global.WEB_AUTOFILL_QUERY_URL);
178    }
179
180    private static boolean canSatisfyMemoryAllocation(long bytesRequested) {
181        checkInitialized();
182        ActivityManager manager = (ActivityManager) sContext.getSystemService(
183                Context.ACTIVITY_SERVICE);
184        ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
185        manager.getMemoryInfo(memInfo);
186        long leftToAllocate = memInfo.availMem - memInfo.threshold;
187        return !memInfo.lowMemory && bytesRequested < leftToAllocate;
188    }
189}
190