1 /* 2 * Copyright (C) 2009 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 17 package com.android.browser; 18 19 import org.apache.http.HttpEntity; 20 import org.apache.http.HttpHost; 21 import org.apache.http.HttpResponse; 22 import org.apache.http.client.methods.HttpGet; 23 import org.apache.http.client.params.HttpClientParams; 24 import org.apache.http.conn.params.ConnRouteParams; 25 26 import android.content.ContentResolver; 27 import android.content.ContentValues; 28 import android.content.Context; 29 import android.database.Cursor; 30 import android.graphics.Bitmap; 31 import android.graphics.BitmapFactory; 32 import android.net.Proxy; 33 import android.net.http.AndroidHttpClient; 34 import android.os.AsyncTask; 35 import android.os.Bundle; 36 import android.os.Message; 37 import android.provider.BrowserContract; 38 import android.provider.BrowserContract.Images; 39 import android.webkit.WebView; 40 41 import java.io.ByteArrayOutputStream; 42 import java.io.InputStream; 43 44 class DownloadTouchIcon extends AsyncTask<String, Void, Void> { 45 46 private final ContentResolver mContentResolver; 47 private Cursor mCursor; 48 private final String mOriginalUrl; 49 private final String mUrl; 50 private final String mUserAgent; // Sites may serve a different icon to different UAs 51 private Message mMessage; 52 53 private final Context mContext; 54 /* package */ Tab mTab; 55 56 /** 57 * Use this ctor to store the touch icon in the bookmarks database for 58 * the originalUrl so we take account of redirects. Used when the user 59 * bookmarks a page from outside the bookmarks activity. 60 */ 61 public DownloadTouchIcon(Tab tab, Context ctx, ContentResolver cr, WebView view) { 62 mTab = tab; 63 mContext = ctx.getApplicationContext(); 64 mContentResolver = cr; 65 // Store these in case they change. 66 mOriginalUrl = view.getOriginalUrl(); 67 mUrl = view.getUrl(); 68 mUserAgent = view.getSettings().getUserAgentString(); 69 } 70 71 /** 72 * Use this ctor to download the touch icon and update the bookmarks database 73 * entry for the given url. Used when the user creates a bookmark from 74 * within the bookmarks activity and there haven't been any redirects. 75 * TODO: Would be nice to set the user agent here so that there is no 76 * potential for the three different ctors here to return different icons. 77 */ 78 public DownloadTouchIcon(Context ctx, ContentResolver cr, String url) { 79 mTab = null; 80 mContext = ctx.getApplicationContext(); 81 mContentResolver = cr; 82 mOriginalUrl = null; 83 mUrl = url; 84 mUserAgent = null; 85 } 86 87 /** 88 * Use this ctor to not store the touch icon in a database, rather add it to 89 * the passed Message's data bundle with the key 90 * {@link BrowserContract.Bookmarks#TOUCH_ICON} and then send the message. 91 */ 92 public DownloadTouchIcon(Context context, Message msg, String userAgent) { 93 mMessage = msg; 94 mContext = context.getApplicationContext(); 95 mContentResolver = null; 96 mOriginalUrl = null; 97 mUrl = null; 98 mUserAgent = userAgent; 99 } 100 101 @Override 102 public Void doInBackground(String... values) { 103 if (mContentResolver != null) { 104 mCursor = Bookmarks.queryCombinedForUrl(mContentResolver, 105 mOriginalUrl, mUrl); 106 } 107 108 boolean inDatabase = mCursor != null && mCursor.getCount() > 0; 109 110 String url = values[0]; 111 112 if (inDatabase || mMessage != null) { 113 AndroidHttpClient client = null; 114 HttpGet request = null; 115 116 try { 117 client = AndroidHttpClient.newInstance(mUserAgent); 118 HttpHost httpHost = Proxy.getPreferredHttpHost(mContext, url); 119 if (httpHost != null) { 120 ConnRouteParams.setDefaultProxy(client.getParams(), httpHost); 121 } 122 123 request = new HttpGet(url); 124 125 // Follow redirects 126 HttpClientParams.setRedirecting(client.getParams(), true); 127 128 HttpResponse response = client.execute(request); 129 if (response.getStatusLine().getStatusCode() == 200) { 130 HttpEntity entity = response.getEntity(); 131 if (entity != null) { 132 InputStream content = entity.getContent(); 133 if (content != null) { 134 Bitmap icon = BitmapFactory.decodeStream( 135 content, null, null); 136 if (inDatabase) { 137 storeIcon(icon); 138 } else if (mMessage != null) { 139 Bundle b = mMessage.getData(); 140 b.putParcelable(BrowserContract.Bookmarks.TOUCH_ICON, icon); 141 } 142 } 143 } 144 } 145 } catch (Exception ex) { 146 if (request != null) { 147 request.abort(); 148 } 149 } finally { 150 if (client != null) { 151 client.close(); 152 } 153 } 154 } 155 156 if (mCursor != null) { 157 mCursor.close(); 158 } 159 160 if (mMessage != null) { 161 mMessage.sendToTarget(); 162 } 163 164 return null; 165 } 166 167 @Override 168 protected void onCancelled() { 169 if (mCursor != null) { 170 mCursor.close(); 171 } 172 } 173 174 private void storeIcon(Bitmap icon) { 175 // Do this first in case the download failed. 176 if (mTab != null) { 177 // Remove the touch icon loader from the BrowserActivity. 178 mTab.mTouchIconLoader = null; 179 } 180 181 if (icon == null || mCursor == null || isCancelled()) { 182 return; 183 } 184 185 if (mCursor.moveToFirst()) { 186 final ByteArrayOutputStream os = new ByteArrayOutputStream(); 187 icon.compress(Bitmap.CompressFormat.PNG, 100, os); 188 189 ContentValues values = new ContentValues(); 190 values.put(Images.TOUCH_ICON, os.toByteArray()); 191 192 do { 193 values.put(Images.URL, mCursor.getString(0)); 194 mContentResolver.update(Images.CONTENT_URI, values, null, null); 195 } while (mCursor.moveToNext()); 196 } 197 } 198 } 199