1 /* 2 * Copyright (C) 2006 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.app.Activity; 20 import android.content.ContentResolver; 21 import android.content.Intent; 22 import android.content.res.Resources; 23 import android.database.Cursor; 24 import android.graphics.Bitmap; 25 import android.net.ParseException; 26 import android.net.WebAddress; 27 import android.os.Bundle; 28 import android.os.Handler; 29 import android.os.Message; 30 import android.provider.Browser; 31 import android.view.View; 32 import android.view.Window; 33 import android.widget.EditText; 34 import android.widget.TextView; 35 import android.widget.Toast; 36 37 import java.net.URI; 38 import java.net.URISyntaxException; 39 import java.util.Date; 40 41 public class AddBookmarkPage extends Activity { 42 43 private final String LOGTAG = "Bookmarks"; 44 45 private EditText mTitle; 46 private EditText mAddress; 47 private TextView mButton; 48 private View mCancelButton; 49 private boolean mEditingExisting; 50 private Bundle mMap; 51 private String mTouchIconUrl; 52 private Bitmap mThumbnail; 53 private String mOriginalUrl; 54 55 // Message IDs 56 private static final int SAVE_BOOKMARK = 100; 57 58 private Handler mHandler; 59 60 private View.OnClickListener mSaveBookmark = new View.OnClickListener() { 61 public void onClick(View v) { 62 if (save()) { 63 finish(); 64 } 65 } 66 }; 67 68 private View.OnClickListener mCancel = new View.OnClickListener() { 69 public void onClick(View v) { 70 finish(); 71 } 72 }; 73 onCreate(Bundle icicle)74 protected void onCreate(Bundle icicle) { 75 super.onCreate(icicle); 76 requestWindowFeature(Window.FEATURE_LEFT_ICON); 77 setContentView(R.layout.browser_add_bookmark); 78 setTitle(R.string.save_to_bookmarks); 79 getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.ic_list_bookmark); 80 81 String title = null; 82 String url = null; 83 mMap = getIntent().getExtras(); 84 if (mMap != null) { 85 Bundle b = mMap.getBundle("bookmark"); 86 if (b != null) { 87 mMap = b; 88 mEditingExisting = true; 89 setTitle(R.string.edit_bookmark); 90 } 91 title = mMap.getString("title"); 92 url = mOriginalUrl = mMap.getString("url"); 93 mTouchIconUrl = mMap.getString("touch_icon_url"); 94 mThumbnail = (Bitmap) mMap.getParcelable("thumbnail"); 95 } 96 97 mTitle = (EditText) findViewById(R.id.title); 98 mTitle.setText(title); 99 mAddress = (EditText) findViewById(R.id.address); 100 mAddress.setText(url); 101 102 View.OnClickListener accept = mSaveBookmark; 103 mButton = (TextView) findViewById(R.id.OK); 104 mButton.setOnClickListener(accept); 105 106 mCancelButton = findViewById(R.id.cancel); 107 mCancelButton.setOnClickListener(mCancel); 108 109 if (!getWindow().getDecorView().isInTouchMode()) { 110 mButton.requestFocus(); 111 } 112 } 113 114 /** 115 * Runnable to save a bookmark, so it can be performed in its own thread. 116 */ 117 private class SaveBookmarkRunnable implements Runnable { 118 private Message mMessage; SaveBookmarkRunnable(Message msg)119 public SaveBookmarkRunnable(Message msg) { 120 mMessage = msg; 121 } run()122 public void run() { 123 // Unbundle bookmark data. 124 Bundle bundle = mMessage.getData(); 125 String title = bundle.getString("title"); 126 String url = bundle.getString("url"); 127 boolean invalidateThumbnail = bundle.getBoolean( 128 "invalidateThumbnail"); 129 Bitmap thumbnail = invalidateThumbnail ? null 130 : (Bitmap) bundle.getParcelable("thumbnail"); 131 String touchIconUrl = bundle.getString("touchIconUrl"); 132 133 // Save to the bookmarks DB. 134 try { 135 final ContentResolver cr = getContentResolver(); 136 Bookmarks.addBookmark(null, cr, url, title, thumbnail, true); 137 if (touchIconUrl != null) { 138 new DownloadTouchIcon(cr, url).execute(mTouchIconUrl); 139 } 140 mMessage.arg1 = 1; 141 } catch (IllegalStateException e) { 142 mMessage.arg1 = 0; 143 } 144 mMessage.sendToTarget(); 145 } 146 } 147 createHandler()148 private void createHandler() { 149 if (mHandler == null) { 150 mHandler = new Handler() { 151 @Override 152 public void handleMessage(Message msg) { 153 switch (msg.what) { 154 case SAVE_BOOKMARK: 155 if (1 == msg.arg1) { 156 Toast.makeText(AddBookmarkPage.this, R.string.bookmark_saved, 157 Toast.LENGTH_LONG).show(); 158 } else { 159 Toast.makeText(AddBookmarkPage.this, R.string.bookmark_not_saved, 160 Toast.LENGTH_LONG).show(); 161 } 162 break; 163 } 164 } 165 }; 166 } 167 } 168 169 /** 170 * Parse the data entered in the dialog and post a message to update the bookmarks database. 171 */ save()172 boolean save() { 173 createHandler(); 174 175 String title = mTitle.getText().toString().trim(); 176 String unfilteredUrl = 177 BrowserActivity.fixUrl(mAddress.getText().toString()); 178 boolean emptyTitle = title.length() == 0; 179 boolean emptyUrl = unfilteredUrl.trim().length() == 0; 180 Resources r = getResources(); 181 if (emptyTitle || emptyUrl) { 182 if (emptyTitle) { 183 mTitle.setError(r.getText(R.string.bookmark_needs_title)); 184 } 185 if (emptyUrl) { 186 mAddress.setError(r.getText(R.string.bookmark_needs_url)); 187 } 188 return false; 189 } 190 String url = unfilteredUrl.trim(); 191 try { 192 // We allow bookmarks with a javascript: scheme, but these will in most cases 193 // fail URI parsing, so don't try it if that's the kind of bookmark we have. 194 195 if (!url.toLowerCase().startsWith("javascript:")) { 196 URI uriObj = new URI(url); 197 String scheme = uriObj.getScheme(); 198 if (!Bookmarks.urlHasAcceptableScheme(url)) { 199 // If the scheme was non-null, let the user know that we 200 // can't save their bookmark. If it was null, we'll assume 201 // they meant http when we parse it in the WebAddress class. 202 if (scheme != null) { 203 mAddress.setError(r.getText(R.string.bookmark_cannot_save_url)); 204 return false; 205 } 206 WebAddress address; 207 try { 208 address = new WebAddress(unfilteredUrl); 209 } catch (ParseException e) { 210 throw new URISyntaxException("", ""); 211 } 212 if (address.mHost.length() == 0) { 213 throw new URISyntaxException("", ""); 214 } 215 url = address.toString(); 216 } 217 } 218 } catch (URISyntaxException e) { 219 mAddress.setError(r.getText(R.string.bookmark_url_not_valid)); 220 return false; 221 } 222 223 if (mEditingExisting) { 224 mMap.putString("title", title); 225 mMap.putString("url", url); 226 mMap.putBoolean("invalidateThumbnail", !url.equals(mOriginalUrl)); 227 setResult(RESULT_OK, (new Intent()).setAction( 228 getIntent().toString()).putExtras(mMap)); 229 } else { 230 // Post a message to write to the DB. 231 Bundle bundle = new Bundle(); 232 bundle.putString("title", title); 233 bundle.putString("url", url); 234 bundle.putParcelable("thumbnail", mThumbnail); 235 bundle.putBoolean("invalidateThumbnail", !url.equals(mOriginalUrl)); 236 bundle.putString("touchIconUrl", mTouchIconUrl); 237 Message msg = Message.obtain(mHandler, SAVE_BOOKMARK); 238 msg.setData(bundle); 239 // Start a new thread so as to not slow down the UI 240 Thread t = new Thread(new SaveBookmarkRunnable(msg)); 241 t.start(); 242 setResult(RESULT_OK); 243 LogTag.logBookmarkAdded(url, "bookmarkview"); 244 } 245 return true; 246 } 247 } 248