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 | |
5 | /** |
6 | * Content provider for testing content URLs. |
7 | */ |
8 | |
9 | package org.chromium.android_webview.test; |
10 | |
11 | import android.content.ContentProvider; |
12 | import android.content.ContentValues; |
13 | import android.content.Context; |
14 | import android.content.res.AssetFileDescriptor; |
15 | import android.database.AbstractCursor; |
16 | import android.database.Cursor; |
17 | import android.net.Uri; |
18 | import android.os.ParcelFileDescriptor; |
19 | import android.util.Log; |
20 | |
21 | import java.io.FileOutputStream; |
22 | import java.io.IOException; |
23 | import java.util.HashMap; |
24 | import java.util.Map; |
25 | |
26 | // Note: if you move this class, make sure you have also updated AndroidManifest.xml |
27 | public class TestContentProvider extends ContentProvider { |
28 | private static final String AUTHORITY = |
29 | "org.chromium.android_webview.test.TestContentProvider"; |
30 | private static final String CONTENT_SCHEME = "content://"; |
31 | private static final String CONTENT_TYPE = "image/png"; |
32 | private static final String GET_RESOURCE_REQUEST_COUNT = "get_resource_request_count"; |
33 | private static final String RESET_RESOURCE_REQUEST_COUNT = "reset_resource_request_count"; |
34 | private static final String TAG = "TestContentProvider"; |
35 | private enum ColumnIndex { |
36 | RESOURCE_REQUEST_COUNT_COLUMN, |
37 | }; |
38 | private final Map<String, Integer> mResourceRequestCount; |
39 | |
40 | public static String createContentUrl(String target) { |
41 | return CONTENT_SCHEME + AUTHORITY + "/" + target; |
42 | } |
43 | |
44 | private static Uri createRequestUri(final String target, String resource) { |
45 | return Uri.parse(createContentUrl(target) + "?" + resource); |
46 | } |
47 | |
48 | public static int getResourceRequestCount(Context context, String resource) { |
49 | Uri uri = createRequestUri(GET_RESOURCE_REQUEST_COUNT, resource); |
50 | final Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); |
51 | try { |
52 | cursor.moveToFirst(); |
53 | return cursor.getInt(ColumnIndex.RESOURCE_REQUEST_COUNT_COLUMN.ordinal()); |
54 | } finally { |
55 | cursor.close(); |
56 | } |
57 | } |
58 | |
59 | public static void resetResourceRequestCount(Context context, String resource) { |
60 | Uri uri = createRequestUri(RESET_RESOURCE_REQUEST_COUNT, resource); |
61 | // A null cursor is returned for this request. |
62 | context.getContentResolver().query(uri, null, null, null, null); |
63 | } |
64 | |
65 | public TestContentProvider() { |
66 | super(); |
67 | mResourceRequestCount = new HashMap<String, Integer>(); |
68 | } |
69 | |
70 | @Override |
71 | public boolean onCreate() { |
72 | return true; |
73 | } |
74 | |
75 | @Override |
76 | public AssetFileDescriptor openAssetFile(Uri uri, String mode) { |
77 | String resource = uri.getLastPathSegment(); |
78 | if (mResourceRequestCount.containsKey(resource)) { |
79 | mResourceRequestCount.put(resource, mResourceRequestCount.get(resource) + 1); |
80 | } else { |
81 | mResourceRequestCount.put(resource, 1); |
82 | } |
83 | return createImage(); |
84 | } |
85 | |
86 | @Override |
87 | public String getType(Uri uri) { |
88 | return CONTENT_TYPE; |
89 | } |
90 | |
91 | @Override |
92 | public int update(Uri uri, ContentValues values, String where, |
93 | String[] whereArgs) { |
94 | return 0; |
95 | } |
96 | |
97 | @Override |
98 | public int delete(Uri uri, String selection, String[] selectionArgs) { |
99 | return 0; |
100 | } |
101 | |
102 | @Override |
103 | public Uri insert(Uri uri, ContentValues values) { |
104 | return null; |
105 | } |
106 | |
107 | /** |
108 | * Cursor object for retrieving resource request counters. |
109 | */ |
110 | private static class ProviderStateCursor extends AbstractCursor { |
111 | private final int mResourceRequestCount; |
112 | |
113 | public ProviderStateCursor(int resourceRequestCount) { |
114 | mResourceRequestCount = resourceRequestCount; |
115 | } |
116 | |
117 | @Override |
118 | public boolean isNull(int columnIndex) { |
119 | return columnIndex != ColumnIndex.RESOURCE_REQUEST_COUNT_COLUMN.ordinal(); |
120 | } |
121 | |
122 | @Override |
123 | public int getCount() { |
124 | return 1; |
125 | } |
126 | |
127 | @Override |
128 | public int getType(int columnIndex) { |
129 | if (columnIndex == ColumnIndex.RESOURCE_REQUEST_COUNT_COLUMN.ordinal()) { |
130 | return Cursor.FIELD_TYPE_INTEGER; |
131 | } |
132 | return Cursor.FIELD_TYPE_NULL; |
133 | } |
134 | |
135 | private void unsupported() { |
136 | throw new UnsupportedOperationException(); |
137 | } |
138 | |
139 | @Override |
140 | public double getDouble(int columnIndex) { |
141 | unsupported(); |
142 | return 0.0; |
143 | } |
144 | |
145 | @Override |
146 | public float getFloat(int columnIndex) { |
147 | unsupported(); |
148 | return 0.0f; |
149 | } |
150 | |
151 | @Override |
152 | public int getInt(int columnIndex) { |
153 | if (columnIndex == ColumnIndex.RESOURCE_REQUEST_COUNT_COLUMN.ordinal()) { |
154 | return mResourceRequestCount; |
155 | } |
156 | return -1; |
157 | } |
158 | |
159 | @Override |
160 | public short getShort(int columnIndex) { |
161 | unsupported(); |
162 | return 0; |
163 | } |
164 | |
165 | @Override |
166 | public long getLong(int columnIndex) { |
167 | return getInt(columnIndex); |
168 | } |
169 | |
170 | @Override |
171 | public String getString(int columnIndex) { |
172 | unsupported(); |
173 | return null; |
174 | } |
175 | |
176 | @Override |
177 | public String[] getColumnNames() { |
178 | return new String[] { GET_RESOURCE_REQUEST_COUNT }; |
179 | } |
180 | } |
181 | |
182 | @Override |
183 | public Cursor query(Uri uri, String[] projection, String selection, |
184 | String[] selectionArgs, String sortOrder) { |
185 | String action = uri.getLastPathSegment(); |
186 | String resource = uri.getQuery(); |
187 | if (GET_RESOURCE_REQUEST_COUNT.equals(action)) { |
188 | return new ProviderStateCursor( |
189 | mResourceRequestCount.containsKey(resource) ? |
190 | mResourceRequestCount.get(resource) : 0); |
191 | } else if (RESET_RESOURCE_REQUEST_COUNT.equals(action)) { |
192 | mResourceRequestCount.put(resource, 0); |
193 | } |
194 | return null; |
195 | } |
196 | |
197 | // 1x1 black dot png image. |
198 | private static final byte[] IMAGE = { |
199 | (byte)0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, |
200 | 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, |
201 | 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x7e, (byte)0x9b, 0x55, 0x00, |
202 | 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, (byte)0xae, (byte)0xce, |
203 | 0x1c, (byte)0xe9, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x44, 0x41, 0x54, 0x08, |
204 | 0x1d, 0x01, 0x02, 0x00, (byte)0xfd, (byte)0xff, 0x00, 0x00, 0x00, 0x02, |
205 | 0x00, 0x01, (byte)0xcd, (byte)0xe3, (byte)0xd1, 0x2b, 0x00, 0x00, 0x00, |
206 | 0x00, 0x49, 0x45, 0x4e, 0x44, (byte)0xae, 0x42, 0x60, (byte)0x82 |
207 | }; |
208 | |
209 | private static AssetFileDescriptor createImage() { |
210 | ParcelFileDescriptor[] pfds = null; |
211 | FileOutputStream fileOut = null; |
212 | try { |
213 | try { |
214 | pfds = ParcelFileDescriptor.createPipe(); |
215 | fileOut = new FileOutputStream(pfds[1].getFileDescriptor()); |
216 | fileOut.write(IMAGE); |
217 | fileOut.flush(); |
218 | return new AssetFileDescriptor(pfds[0], 0, -1); |
219 | } finally { |
220 | if (fileOut != null) fileOut.close(); |
221 | if (pfds != null && pfds[1] != null) pfds[1].close(); |
222 | } |
223 | } catch (IOException e) { |
224 | Log.e(TAG, e.getMessage(), e); |
225 | } |
226 | return null; |
227 | } |
228 | } |