Home | History | Annotate | Download | only in browser
      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 android.content.ContentResolver;
     20 import android.content.ContentUris;
     21 import android.content.ContentValues;
     22 import android.content.Context;
     23 import android.content.SharedPreferences;
     24 import android.database.Cursor;
     25 import android.graphics.Bitmap;
     26 import android.net.Uri;
     27 import android.os.AsyncTask;
     28 import android.preference.PreferenceManager;
     29 import android.provider.BrowserContract;
     30 import android.provider.BrowserContract.Combined;
     31 import android.provider.BrowserContract.Images;
     32 import android.text.TextUtils;
     33 import android.util.Log;
     34 import android.webkit.WebIconDatabase;
     35 import android.widget.Toast;
     36 
     37 import java.io.ByteArrayOutputStream;
     38 
     39 /**
     40  *  This class is purely to have a common place for adding/deleting bookmarks.
     41  */
     42 public class Bookmarks {
     43     // We only want the user to be able to bookmark content that
     44     // the browser can handle directly.
     45     private static final String acceptableBookmarkSchemes[] = {
     46             "http:",
     47             "https:",
     48             "about:",
     49             "data:",
     50             "javascript:",
     51             "file:",
     52             "content:"
     53     };
     54 
     55     private final static String LOGTAG = "Bookmarks";
     56     /**
     57      *  Add a bookmark to the database.
     58      *  @param context Context of the calling Activity.  This is used to make
     59      *          Toast confirming that the bookmark has been added.  If the
     60      *          caller provides null, the Toast will not be shown.
     61      *  @param url URL of the website to be bookmarked.
     62      *  @param name Provided name for the bookmark.
     63      *  @param thumbnail A thumbnail for the bookmark.
     64      *  @param retainIcon Whether to retain the page's icon in the icon database.
     65      *          This will usually be <code>true</code> except when bookmarks are
     66      *          added by a settings restore agent.
     67      *  @param parent ID of the parent folder.
     68      */
     69     /* package */ static void addBookmark(Context context, boolean showToast, String url,
     70             String name, Bitmap thumbnail, long parent) {
     71         // Want to append to the beginning of the list
     72         ContentValues values = new ContentValues();
     73         try {
     74             SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
     75             values.put(BrowserContract.Bookmarks.TITLE, name);
     76             values.put(BrowserContract.Bookmarks.URL, url);
     77             values.put(BrowserContract.Bookmarks.IS_FOLDER, 0);
     78             values.put(BrowserContract.Bookmarks.THUMBNAIL,
     79                     bitmapToBytes(thumbnail));
     80             values.put(BrowserContract.Bookmarks.PARENT, parent);
     81             context.getContentResolver().insert(BrowserContract.Bookmarks.CONTENT_URI, values);
     82         } catch (IllegalStateException e) {
     83             Log.e(LOGTAG, "addBookmark", e);
     84         }
     85         if (showToast) {
     86             Toast.makeText(context, R.string.added_to_bookmarks,
     87                     Toast.LENGTH_LONG).show();
     88         }
     89     }
     90 
     91     /**
     92      *  Remove a bookmark from the database.  If the url is a visited site, it
     93      *  will remain in the database, but only as a history item, and not as a
     94      *  bookmarked site.
     95      *  @param context Context of the calling Activity.  This is used to make
     96      *          Toast confirming that the bookmark has been removed and to
     97      *          lookup the correct content uri.  It must not be null.
     98      *  @param cr The ContentResolver being used to remove the bookmark.
     99      *  @param url URL of the website to be removed.
    100      */
    101     /* package */ static void removeFromBookmarks(Context context,
    102             ContentResolver cr, String url, String title) {
    103         Cursor cursor = null;
    104         try {
    105             Uri uri = BookmarkUtils.getBookmarksUri(context);
    106             cursor = cr.query(uri,
    107                     new String[] { BrowserContract.Bookmarks._ID },
    108                     BrowserContract.Bookmarks.URL + " = ? AND " +
    109                             BrowserContract.Bookmarks.TITLE + " = ?",
    110                     new String[] { url, title },
    111                     null);
    112 
    113             if (!cursor.moveToFirst()) {
    114                 return;
    115             }
    116 
    117             // Remove from bookmarks
    118             WebIconDatabase.getInstance().releaseIconForPageUrl(url);
    119             uri = ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI,
    120                     cursor.getLong(0));
    121             cr.delete(uri, null, null);
    122             if (context != null) {
    123                 Toast.makeText(context, R.string.removed_from_bookmarks,
    124                         Toast.LENGTH_LONG).show();
    125             }
    126         } catch (IllegalStateException e) {
    127             Log.e(LOGTAG, "removeFromBookmarks", e);
    128         } finally {
    129             if (cursor != null) cursor.close();
    130         }
    131     }
    132 
    133     private static byte[] bitmapToBytes(Bitmap bm) {
    134         if (bm == null) {
    135             return null;
    136         }
    137 
    138         final ByteArrayOutputStream os = new ByteArrayOutputStream();
    139         bm.compress(Bitmap.CompressFormat.PNG, 100, os);
    140         return os.toByteArray();
    141     }
    142 
    143     /* package */ static boolean urlHasAcceptableScheme(String url) {
    144         if (url == null) {
    145             return false;
    146         }
    147 
    148         for (int i = 0; i < acceptableBookmarkSchemes.length; i++) {
    149             if (url.startsWith(acceptableBookmarkSchemes[i])) {
    150                 return true;
    151             }
    152         }
    153         return false;
    154     }
    155 
    156     static final String QUERY_BOOKMARKS_WHERE =
    157             Combined.URL + " == ? OR " +
    158             Combined.URL + " == ?";
    159 
    160     public static Cursor queryCombinedForUrl(ContentResolver cr,
    161             String originalUrl, String url) {
    162         if (cr == null || url == null) {
    163             return null;
    164         }
    165 
    166         // If originalUrl is null, just set it to url.
    167         if (originalUrl == null) {
    168             originalUrl = url;
    169         }
    170 
    171         // Look for both the original url and the actual url. This takes in to
    172         // account redirects.
    173 
    174         final String[] selArgs = new String[] { originalUrl, url };
    175         final String[] projection = new String[] { Combined.URL };
    176         return cr.query(Combined.CONTENT_URI, projection, QUERY_BOOKMARKS_WHERE, selArgs, null);
    177     }
    178 
    179     // Strip the query from the given url.
    180     static String removeQuery(String url) {
    181         if (url == null) {
    182             return null;
    183         }
    184         int query = url.indexOf('?');
    185         String noQuery = url;
    186         if (query != -1) {
    187             noQuery = url.substring(0, query);
    188         }
    189         return noQuery;
    190     }
    191 
    192     /**
    193      * Update the bookmark's favicon. This is a convenience method for updating
    194      * a bookmark favicon for the originalUrl and url of the passed in WebView.
    195      * @param cr The ContentResolver to use.
    196      * @param originalUrl The original url before any redirects.
    197      * @param url The current url.
    198      * @param favicon The favicon bitmap to write to the db.
    199      */
    200     /* package */ static void updateFavicon(final ContentResolver cr,
    201             final String originalUrl, final String url, final Bitmap favicon) {
    202         new AsyncTask<Void, Void, Void>() {
    203             @Override
    204             protected Void doInBackground(Void... unused) {
    205                 final ByteArrayOutputStream os = new ByteArrayOutputStream();
    206                 favicon.compress(Bitmap.CompressFormat.PNG, 100, os);
    207 
    208                 // The Images update will insert if it doesn't exist
    209                 ContentValues values = new ContentValues();
    210                 values.put(Images.FAVICON, os.toByteArray());
    211                 updateImages(cr, originalUrl, values);
    212                 updateImages(cr, url, values);
    213                 return null;
    214             }
    215 
    216             private void updateImages(final ContentResolver cr,
    217                     final String url, ContentValues values) {
    218                 String iurl = removeQuery(url);
    219                 if (!TextUtils.isEmpty(iurl)) {
    220                     values.put(Images.URL, iurl);
    221                     cr.update(BrowserContract.Images.CONTENT_URI, values, null, null);
    222                 }
    223             }
    224         }.execute();
    225     }
    226 }
    227