19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.webkit; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 198af3cfc2a45334bfe936fcfc79c6e1cab06e104bPatrick Scottimport android.content.Context; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.http.EventHandler; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.http.Headers; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.InputStream; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This abstract class is used for all content loaders that rely on streaming 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * content into the rendering engine loading framework. 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The class implements a state machine to load the content into the frame in 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a similar manor to the way content arrives from the network. The class uses 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * messages to move from one state to the next, which enables async. loading of 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the streamed content. 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Classes that inherit from this class must implement two methods, the first 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * method is used to setup the InputStream and notify the loading framework if 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * it can load it's content. The other method allows the derived class to add 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * additional HTTP headers to the response. 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * By default, content loaded with a StreamLoader is marked with a HTTP header 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * that indicates the content should not be cached. 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 46ac75f56600691d318d40301204baaf840c9586f2Grace Klobaabstract class StreamLoader implements Handler.Callback { 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_STATUS = 100; // Send status to loader 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_HEADERS = 101; // Send headers to loader 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_DATA = 102; // Send data to loader 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_END = 103; // Send endData to loader 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 538af3cfc2a45334bfe936fcfc79c6e1cab06e104bPatrick Scott protected final Context mContext; 54ac75f56600691d318d40301204baaf840c9586f2Grace Kloba protected final LoadListener mLoadListener; // loader class 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected InputStream mDataStream; // stream to read data from 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected long mContentLength; // content length of data 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private byte [] mData; // buffer to pass data to loader with. 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 59ac75f56600691d318d40301204baaf840c9586f2Grace Kloba // Handler which will be initialized in the thread where load() is called. 60ac75f56600691d318d40301204baaf840c9586f2Grace Kloba private Handler mHandler; 61ac75f56600691d318d40301204baaf840c9586f2Grace Kloba 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor. Although this class calls the LoadListener, it only calls 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the EventHandler Interface methods. LoadListener concrete class is used 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to avoid the penality of calling an interface. 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param loadlistener The LoadListener to call with the data. 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StreamLoader(LoadListener loadlistener) { 70ac75f56600691d318d40301204baaf840c9586f2Grace Kloba mLoadListener = loadlistener; 718af3cfc2a45334bfe936fcfc79c6e1cab06e104bPatrick Scott mContext = loadlistener.getContext(); 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method is called when the derived class should setup mDataStream, 76ac75f56600691d318d40301204baaf840c9586f2Grace Kloba * and call mLoadListener.status() to indicate that the load can occur. If it 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * fails to setup, it should still call status() with the error code. 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if stream was successfully setup 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected abstract boolean setupStreamAndSendStatus(); 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method is called when the headers are about to be sent to the 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * load framework. The derived class has the opportunity to add addition 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * headers. 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param headers Map of HTTP headers that will be sent to the loader. 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project abstract protected void buildHeaders(Headers headers); 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 92ac75f56600691d318d40301204baaf840c9586f2Grace Kloba /** 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Calling this method starts the load of the content for this StreamLoader. 94ac75f56600691d318d40301204baaf840c9586f2Grace Kloba * This method simply creates a Handler in the current thread and posts a 95ac75f56600691d318d40301204baaf840c9586f2Grace Kloba * message to send the status and returns immediately. 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 97ac75f56600691d318d40301204baaf840c9586f2Grace Kloba final void load() { 98ac75f56600691d318d40301204baaf840c9586f2Grace Kloba synchronized (this) { 99ac75f56600691d318d40301204baaf840c9586f2Grace Kloba if (mHandler == null) { 100ac75f56600691d318d40301204baaf840c9586f2Grace Kloba mHandler = new Handler(this); 101ac75f56600691d318d40301204baaf840c9586f2Grace Kloba } 102ac75f56600691d318d40301204baaf840c9586f2Grace Kloba } 103ac75f56600691d318d40301204baaf840c9586f2Grace Kloba 104ac75f56600691d318d40301204baaf840c9586f2Grace Kloba if (!mLoadListener.isSynchronous()) { 105ac75f56600691d318d40301204baaf840c9586f2Grace Kloba mHandler.sendEmptyMessage(MSG_STATUS); 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Load the stream synchronously. 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (setupStreamAndSendStatus()) { 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We were able to open the stream, create the array 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to pass data to the loader 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mData = new byte[8192]; 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sendHeaders(); 113ac75f56600691d318d40301204baaf840c9586f2Grace Kloba while (!sendData() && !mLoadListener.cancelled()); 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closeStreamAndSendEndData(); 115ac75f56600691d318d40301204baaf840c9586f2Grace Kloba mLoadListener.loadSynchronousMessages(); 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 120ac75f56600691d318d40301204baaf840c9586f2Grace Kloba public boolean handleMessage(Message msg) { 121ac75f56600691d318d40301204baaf840c9586f2Grace Kloba if (mLoadListener.isSynchronous()) { 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new AssertionError(); 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 124ac75f56600691d318d40301204baaf840c9586f2Grace Kloba if (mLoadListener.cancelled()) { 125e82dc4205285a40d6c2227e362c30ce24c96a552Patrick Scott closeStreamAndSendEndData(); 126ac75f56600691d318d40301204baaf840c9586f2Grace Kloba return true; 127e82dc4205285a40d6c2227e362c30ce24c96a552Patrick Scott } 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch(msg.what) { 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_STATUS: 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (setupStreamAndSendStatus()) { 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We were able to open the stream, create the array 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to pass data to the loader 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mData = new byte[8192]; 134ac75f56600691d318d40301204baaf840c9586f2Grace Kloba mHandler.sendEmptyMessage(MSG_HEADERS); 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_HEADERS: 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sendHeaders(); 139ac75f56600691d318d40301204baaf840c9586f2Grace Kloba mHandler.sendEmptyMessage(MSG_DATA); 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_DATA: 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sendData()) { 143ac75f56600691d318d40301204baaf840c9586f2Grace Kloba mHandler.sendEmptyMessage(MSG_END); 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 145ac75f56600691d318d40301204baaf840c9586f2Grace Kloba mHandler.sendEmptyMessage(MSG_DATA); 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_END: 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closeStreamAndSendEndData(); 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 152ac75f56600691d318d40301204baaf840c9586f2Grace Kloba return false; 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 154ac75f56600691d318d40301204baaf840c9586f2Grace Kloba return true; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Construct the headers and pass them to the EventHandler. 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void sendHeaders() { 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Headers headers = new Headers(); 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mContentLength > 0) { 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project headers.setContentLength(mContentLength); 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project buildHeaders(headers); 166ac75f56600691d318d40301204baaf840c9586f2Grace Kloba mLoadListener.headers(headers); 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Read data from the stream and pass it to the EventHandler. 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If an error occurs reading the stream, then an error is sent to the 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * EventHandler, and moves onto the next state - end of data. 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return True if all the data has been read. False if sendData should be 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * called again. 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean sendData() { 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDataStream != null) { 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int amount = mDataStream.read(mData); 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (amount > 0) { 181ac75f56600691d318d40301204baaf840c9586f2Grace Kloba mLoadListener.data(mData, amount); 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException ex) { 185ac75f56600691d318d40301204baaf840c9586f2Grace Kloba mLoadListener.error(EventHandler.FILE_ERROR, ex.getMessage()); 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Close the stream and inform the EventHandler that load is complete. 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void closeStreamAndSendEndData() { 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDataStream != null) { 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDataStream.close(); 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException ex) { 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ignore. 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 202ac75f56600691d318d40301204baaf840c9586f2Grace Kloba mLoadListener.endData(); 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 205