Android 4.4 Browser set most visited at home page 實現

     本文只分析當主頁爲Most Visited時的實現。

Tab.java中實現了WebViewClient的shouldInterceptRequest接口,該函數爲回調函數,最終由native代碼調用。調用過程爲

shouldInterceptRequest() CallbackProxy.java <- shouldInterceptRequest() BrowserFrame.java <- shouldInterceptRequest() WebCoreFrameBridge.cpp

Tab.java

  1. public WebResourceResponse shouldInterceptRequest(WebView view,  
  2.         String url) {  
  3.     WebResourceResponse res = HomeProvider.shouldInterceptRequest(  
  4.             mContext, url);  
  5.     return res;  
  6. }     


HomeProvider

       home page中的數據是從數據庫中讀取的,HomeProvider提供了數據。

HomeProvider.java

public static final String MOST_VISITED = "content://" + "com.android.browser.home" + "/index";  //android4.3

public static final String MOST_VISITED = "content://" + "com.android.browser.home" + "/";   //android 4.4

重要區別。


  1. public static WebResourceResponse shouldInterceptRequest(Context context,  
  2.         String url) {  
  3.     try {  
  4.         boolean useMostVisited = BrowserSettings.getInstance().useMostVisitedHomepage();  
  5.         if (useMostVisited && url.startsWith("content://")) {  
  6.             Uri uri = Uri.parse(url);  
  7.             if (AUTHORITY.equals(uri.getAuthority())) {  
  8.                 InputStream ins = context.getContentResolver()  
  9.                         .openInputStream(uri);  
  10.                 return new WebResourceResponse("text/html""utf-8", ins);  
  11.             }  
  12.         }  
  13.     } catch (Exception e) {}  
  14.     return null;  
  15. }  
 

@Override

  1. public ParcelFileDescriptor openFile(Uri uri, String mode) {  
  2.     try {  
  3.         ParcelFileDescriptor[] pipes = ParcelFileDescriptor.createPipe();  
  4.         final ParcelFileDescriptor write = pipes[1];  
  5.         AssetFileDescriptor afd = new AssetFileDescriptor(write, 0, -1);  
  6.         new RequestHandler(getContext(), uri, afd.createOutputStream()).start();  
  7.         return pipes[0];  
  8.     } catch (IOException e) {  
  9.         Log.e(TAG, "Failed to handle request: " + uri, e);  
  10.         return null;  
  11.     }  
  12. }  

        pipes[0]即爲shouldInterceptRequest中的ins。


WebResourceResponse

       先來看WebResourceResponse。

        WebResourceResponse位於framework中,它繼承了StreamLoader ,具體就不在分析了,在這裏它的作用就是把文件作爲一個流讀出來模擬HTTP協議。


RequestHandler

       數據是由RequestHandler寫入HomeProvider讀出的。

  1. public class RequestHandler extends Thread {  
  2.   
  3.     private static final String TAG = "RequestHandler";  
  4.     private static final int INDEX = 1;  
  5.     private static final int RESOURCE = 2;  
  6.     private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);  
  7.   
  8.     Uri mUri;  
  9.     Context mContext;  
  10.     OutputStream mOutput;  
  11.   
  12.     static {  
  13.         sUriMatcher.addURI(HomeProvider.AUTHORITY, "/", INDEX);  //android 4.4
  14.          sUriMatcher.addURI(HomeProvider.AUTHORITY, "index", INDEX);  //android 4.3
  15.       //就是這個匹配字符串引起在android 4.4 中設置最長訪問 的是主頁。報出的ERR_ACCESS_DENIED 錯誤 同時還需要在BrowserSettings裏面設置可以讀取content的權限。android 4.4 默認把它給關閉了
  16.         sUriMatcher.addURI(HomeProvider.AUTHORITY, "res/*/*", RESOURCE);  
  17.     }  
  18.   
  19.     public RequestHandler(Context context, Uri uri, OutputStream out) {  
  20.         mUri = uri;  
  21.         mContext = context.getApplicationContext();  
  22.         mOutput = out;  
  23.     }  
  24.   
  25.     @Override  
  26.     public void run() {  
  27.         super.run();  
  28.         try {  
  29.             doHandleRequest();  
  30.         } catch (Exception e) {  
  31.             Log.e(TAG, "Failed to handle request: " + mUri, e);  
  32.         } finally {  
  33.             cleanup();  
  34.         }  
  35.     }  
  36.   
  37.     void doHandleRequest() throws IOException {  
  38.         int match = sUriMatcher.match(mUri);  
  39.         switch (match) {  
  40.         case INDEX:  
  41.             writeTemplatedIndex();  
  42.             break;  
  43.         case RESOURCE:  
  44.             writeResource(getUriResourcePath());  
  45.             break;  
  46.         }  
  47.     }  

        訪問主頁時執行writeTemplatedIndex()

  1. void writeTemplatedIndex() throws IOException {  
  2.     Template t = Template.getCachedTemplate(mContext, R.raw.most_visited);  
  3.     Cursor cursor = mContext.getContentResolver().query(Browser.BOOKMARKS_URI,  
  4.             new String[] { "DISTINCT url", "title", "thumbnail" },  
  5.             "(visits > 0 OR bookmark = 1) AND url NOT LIKE 'content:%' AND thumbnail IS NOT NULL", null, "visits DESC LIMIT 12");  
  6.   
  7.     t.assignLoop("most_visited", new Template.CursorListEntityWrapper(cursor) {  
  8.         @Override  
  9.         public void writeValue(OutputStream stream, String key) throws IOException {  
  10.             Cursor cursor = getCursor();  
  11.             if (key.equals("url")) {  
  12.                 stream.write(htmlEncode(cursor.getString(0)));  
  13.             } else if (key.equals("title")) {  
  14.                 stream.write(htmlEncode(cursor.getString(1)));  
  15.             } else if (key.equals("thumbnail")) {  
  16.                 stream.write("data:image/png;base64,".getBytes());  
  17.                 byte[] thumb = cursor.getBlob(2);  
  18.                 stream.write(Base64.encode(thumb, Base64.DEFAULT));  
  19.             }  
  20.         }  
  21.     });  
  22.     t.write(mOutput);  
  23. }  

        writeTemplatedIndex()中首先從database中讀取數據,
  1. Template t = Template.getCachedTemplate(mContext, R.raw.most_visited);  

        是從文件中讀出HTML文件並進行解析writeValue則將從數據庫中讀出的數據加入解析後的數據中。

最後t.write(mOutput)則將數據寫入pipes[1]中。


在BrowserSettings裏面的syncStaticSettings 設置 settings.setAllowContentAccess(true);避免出現ERR_ACCESS_DENIED


發佈了20 篇原創文章 · 獲贊 11 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章