1 2/* 3 * Copyright (C) 2011 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17package com.android.browser.homepages; 18 19import android.content.Context; 20import android.content.UriMatcher; 21import android.content.res.Resources; 22import android.database.Cursor; 23import android.net.Uri; 24import android.provider.Browser; 25import android.text.TextUtils; 26import android.util.Base64; 27import android.util.Log; 28 29import com.android.browser.R; 30 31import java.io.IOException; 32import java.io.InputStream; 33import java.io.OutputStream; 34import java.util.regex.Matcher; 35import java.util.regex.Pattern; 36 37public class RequestHandler extends Thread { 38 39 private static final String TAG = "RequestHandler"; 40 private static final int INDEX = 1; 41 private static final int RESOURCE = 2; 42 private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 43 44 Uri mUri; 45 Context mContext; 46 OutputStream mOutput; 47 48 static { 49 sUriMatcher.addURI(HomeProvider.AUTHORITY, "/", INDEX); 50 sUriMatcher.addURI(HomeProvider.AUTHORITY, "res/*/*", RESOURCE); 51 } 52 53 public RequestHandler(Context context, Uri uri, OutputStream out) { 54 mUri = uri; 55 mContext = context.getApplicationContext(); 56 mOutput = out; 57 } 58 59 @Override 60 public void run() { 61 super.run(); 62 try { 63 doHandleRequest(); 64 } catch (Exception e) { 65 Log.e(TAG, "Failed to handle request: " + mUri, e); 66 } finally { 67 cleanup(); 68 } 69 } 70 71 void doHandleRequest() throws IOException { 72 int match = sUriMatcher.match(mUri); 73 switch (match) { 74 case INDEX: 75 writeTemplatedIndex(); 76 break; 77 case RESOURCE: 78 writeResource(getUriResourcePath()); 79 break; 80 } 81 } 82 83 byte[] htmlEncode(String s) { 84 return TextUtils.htmlEncode(s).getBytes(); 85 } 86 87 void writeTemplatedIndex() throws IOException { 88 Template t = Template.getCachedTemplate(mContext, R.raw.most_visited); 89 Cursor cursor = mContext.getContentResolver().query(Browser.BOOKMARKS_URI, 90 new String[] { "DISTINCT url", "title", "thumbnail" }, 91 "(visits > 0 OR bookmark = 1) AND url NOT LIKE 'content:%' AND thumbnail IS NOT NULL", null, "visits DESC LIMIT 12"); 92 93 t.assignLoop("most_visited", new Template.CursorListEntityWrapper(cursor) { 94 @Override 95 public void writeValue(OutputStream stream, String key) throws IOException { 96 Cursor cursor = getCursor(); 97 if (key.equals("url")) { 98 stream.write(htmlEncode(cursor.getString(0))); 99 } else if (key.equals("title")) { 100 stream.write(htmlEncode(cursor.getString(1))); 101 } else if (key.equals("thumbnail")) { 102 stream.write("data:image/png;base64,".getBytes()); 103 byte[] thumb = cursor.getBlob(2); 104 stream.write(Base64.encode(thumb, Base64.DEFAULT)); 105 } 106 } 107 }); 108 t.write(mOutput); 109 } 110 111 String getUriResourcePath() { 112 final Pattern pattern = Pattern.compile("/?res/([\\w/]+)"); 113 Matcher m = pattern.matcher(mUri.getPath()); 114 if (m.matches()) { 115 return m.group(1); 116 } else { 117 return mUri.getPath(); 118 } 119 } 120 121 void writeResource(String fileName) throws IOException { 122 Resources res = mContext.getResources(); 123 String packageName = R.class.getPackage().getName(); 124 int id = res.getIdentifier(fileName, null, packageName); 125 if (id != 0) { 126 InputStream in = res.openRawResource(id); 127 byte[] buf = new byte[4096]; 128 int read; 129 while ((read = in.read(buf)) > 0) { 130 mOutput.write(buf, 0, read); 131 } 132 } 133 } 134 135 void writeString(String str) throws IOException { 136 mOutput.write(str.getBytes()); 137 } 138 139 void writeString(String str, int offset, int count) throws IOException { 140 mOutput.write(str.getBytes(), offset, count); 141 } 142 143 void cleanup() { 144 try { 145 mOutput.close(); 146 } catch (Exception e) { 147 Log.e(TAG, "Failed to close pipe!", e); 148 } 149 } 150 151} 152