diff options
Diffstat (limited to 'core')
| -rw-r--r-- | core/java/android/app/SearchDialog.java | 4 | ||||
| -rw-r--r-- | core/java/android/app/SuggestionsAdapter.java | 145 | ||||
| -rw-r--r-- | core/java/android/webkit/WebSettings.java | 170 | ||||
| -rw-r--r-- | core/res/res/color/search_url_text.xml | 21 | ||||
| -rw-r--r-- | core/res/res/values/colors.xml | 4 |
5 files changed, 318 insertions, 26 deletions
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index 022a9d9..6d6aca4 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -991,7 +991,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS }; @Override - public void cancel() { + public void dismiss() { if (!isShowing()) return; // We made sure the IME was displayed, so also make sure it is closed @@ -1003,7 +1003,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS getWindow().getDecorView().getWindowToken(), 0); } - super.cancel(); + super.dismiss(); } /** diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java index 49c94d1..c8e952f 100644 --- a/core/java/android/app/SuggestionsAdapter.java +++ b/core/java/android/app/SuggestionsAdapter.java @@ -18,7 +18,8 @@ package android.app; import android.content.ContentResolver; import android.content.Context; -import android.content.res.Resources.NotFoundException; +import android.content.res.ColorStateList; +import android.content.res.Resources; import android.database.Cursor; import android.graphics.Canvas; import android.graphics.drawable.Drawable; @@ -300,29 +301,17 @@ class SuggestionsAdapter extends ResourceCursorAdapter { ((SuggestionItemView)view).setColor(backgroundColor); final boolean isHtml = mFormatCol > 0 && "html".equals(cursor.getString(mFormatCol)); - setViewText(cursor, views.mText1, mText1Col, isHtml); - setViewText(cursor, views.mText2, mText2Col, isHtml); - setViewIcon(cursor, views.mIcon1, mIconName1Col); - setViewIcon(cursor, views.mIcon2, mIconName2Col); - } - - private void setViewText(Cursor cursor, TextView v, int textCol, boolean isHtml) { - if (v == null) { - return; - } - CharSequence text = null; - if (textCol >= 0) { - String str = cursor.getString(textCol); - text = (str != null && isHtml) ? Html.fromHtml(str) : str; + String text1 = null; + if (mText1Col >= 0) { + text1 = cursor.getString(mText1Col); } - // Set the text even if it's null, since we need to clear any previous text. - v.setText(text); - - if (TextUtils.isEmpty(text)) { - v.setVisibility(View.GONE); - } else { - v.setVisibility(View.VISIBLE); + String text2 = null; + if (mText2Col >= 0) { + text2 = cursor.getString(mText2Col); } + ((SuggestionItemView)view).setTextStrings(text1, text2, isHtml, mProviderContext); + setViewIcon(cursor, views.mIcon1, mIconName1Col); + setViewIcon(cursor, views.mIcon2, mIconName2Col); } private void setViewIcon(Cursor cursor, ImageView v, int iconNameCol) { @@ -476,7 +465,7 @@ class SuggestionsAdapter extends ResourceCursorAdapter { if (drawable != null) { mOutsideDrawablesCache.put(drawableId, drawable); } - } catch (NotFoundException nfe) { + } catch (Resources.NotFoundException nfe) { if (DBG) Log.d(LOG_TAG, "Icon resource not found: " + drawableId); // drawable = null; } @@ -509,8 +498,82 @@ class SuggestionsAdapter extends ResourceCursorAdapter { * draws on top of the list view selection highlight). */ private class SuggestionItemView extends ViewGroup { + /** + * Parses a given HTMl string and manages Spannable variants of the string for different + * states of the suggestion item (selected, pressed and normal). Colors for these different + * states are specified in the html font tag color attribute in the format '@<RESOURCEID>' + * where RESOURCEID is the ID of a ColorStateList or Color resource. + */ + private class MultiStateText { + private CharSequence mNormal = null; // text to display in normal state. + private CharSequence mSelected = null; // text to display in selected state. + private CharSequence mPressed = null; // text to display in pressed state. + private String mPlainText = null; // valid if the text is stateless plain text. + + public MultiStateText(boolean isHtml, String text, Context context) { + if (!isHtml || text == null) { + mPlainText = text; + return; + } + + String textNormal = text; + String textSelected = text; + String textPressed = text; + int textLength = text.length(); + int start = text.indexOf("\"@"); + + // For each font color attribute which has the value in the form '@<RESOURCEID>', + // try to load the resource and create the display strings for the 3 states. + while (start >= 0) { + start++; + int end = text.indexOf("\"", start); + if (end == -1) break; + + String colorIdString = text.substring(start, end); + int colorId = Integer.parseInt(colorIdString.substring(1)); + try { + // The following call works both for color lists and colors. + ColorStateList csl = context.getResources().getColorStateList(colorId); + int normalColor = csl.getColorForState( + View.EMPTY_STATE_SET, csl.getDefaultColor()); + int selectedColor = csl.getColorForState( + View.SELECTED_STATE_SET, csl.getDefaultColor()); + int pressedColor = csl.getColorForState( + View.PRESSED_STATE_SET, csl.getDefaultColor()); + + // Convert the int color values into a hex string, and strip the first 2 + // characters which will be the alpha (html doesn't want this). + textNormal = textNormal.replace(colorIdString, + "#" + Integer.toHexString(normalColor).substring(2)); + textSelected = textSelected.replace(colorIdString, + "#" + Integer.toHexString(selectedColor).substring(2)); + textPressed = textPressed.replace(colorIdString, + "#" + Integer.toHexString(pressedColor).substring(2)); + } catch (Resources.NotFoundException e) { + // Nothing to do. + } + + start = text.indexOf("\"@", end); + } + mNormal = Html.fromHtml(textNormal); + mSelected = Html.fromHtml(textSelected); + mPressed = Html.fromHtml(textPressed); + } + public CharSequence normal() { + return (mPlainText != null) ? mPlainText : mNormal; + } + public CharSequence selected() { + return (mPlainText != null) ? mPlainText : mSelected; + } + public CharSequence pressed() { + return (mPlainText != null) ? mPlainText : mPressed; + } + } + private int mBackgroundColor; // the background color to draw in normal state. private View mView; // the suggestion item's view. + private MultiStateText mText1Strings = null; + private MultiStateText mText2Strings = null; protected SuggestionItemView(Context context, Cursor cursor) { // Initialize ourselves @@ -537,12 +600,48 @@ class SuggestionsAdapter extends ResourceCursorAdapter { } } + private void setInitialTextForView(TextView view, MultiStateText multiState, + String plainText) { + // Set the text even if it's null, since we need to clear any previous text. + CharSequence text = (multiState != null) ? multiState.normal() : plainText; + view.setText(text); + + if (TextUtils.isEmpty(text)) { + view.setVisibility(View.GONE); + } else { + view.setVisibility(View.VISIBLE); + } + } + + public void setTextStrings(String text1, String text2, boolean isHtml, Context context) { + mText1Strings = new MultiStateText(isHtml, text1, context); + mText2Strings = new MultiStateText(isHtml, text2, context); + + ChildViewCache views = (ChildViewCache) getTag(); + setInitialTextForView(views.mText1, mText1Strings, text1); + setInitialTextForView(views.mText2, mText2Strings, text2); + } + + public void updateTextViewContentIfRequired() { + // Check if the pressed or selected state has changed since the last call. + boolean isPressedNow = isPressed(); + boolean isSelectedNow = isSelected(); + + ChildViewCache views = (ChildViewCache) getTag(); + views.mText1.setText((isPressedNow ? mText1Strings.pressed() : + (isSelectedNow ? mText1Strings.selected() : mText1Strings.normal()))); + views.mText2.setText((isPressedNow ? mText2Strings.pressed() : + (isSelectedNow ? mText2Strings.selected() : mText2Strings.normal()))); + } + public void setColor(int backgroundColor) { mBackgroundColor = backgroundColor; } @Override public void dispatchDraw(Canvas canvas) { + updateTextViewContentIfRequired(); + if (mBackgroundColor != 0 && !isPressed() && !isSelected()) { canvas.drawColor(mBackgroundColor); } diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index ec671d5..9f01923 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -16,15 +16,27 @@ package android.webkit; +import android.content.ContentValues; import android.content.Context; +import android.content.SharedPreferences; import android.os.Build; import android.os.Handler; import android.os.Message; +import android.preference.PreferenceManager; import android.provider.Checkin; +import android.provider.Settings; +import android.util.Log; +import java.io.File; import java.lang.SecurityException; + +import android.content.SharedPreferences.Editor; import android.content.pm.PackageManager; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.database.sqlite.SQLiteStatement; +import java.util.HashSet; import java.util.Locale; /** @@ -176,6 +188,43 @@ public class WebSettings { private boolean mBuiltInZoomControls = false; private boolean mAllowFileAccess = true; + // Donut-specific hack to keep Gears permissions in sync with the + // system location setting. + // TODO: Make sure this hack is removed in Eclair, when Gears + // is also removed. + // Used to remember if we checked the Gears permissions already. + static boolean mCheckedGearsPermissions = false; + // The Gears permissions database directory. + private final static String GEARS_DATABASE_DIR = "gears"; + // The Gears permissions database file name. + private final static String GEARS_DATABASE_FILE = "permissions.db"; + // The Gears location permissions table. + private final static String GEARS_LOCATION_ACCESS_TABLE_NAME = + "LocationAccess"; + // The Gears storage access permissions table. + private final static String GEARS_STORAGE_ACCESS_TABLE_NAME = "Access"; + // The Gears permissions db schema version table. + private final static String GEARS_SCHEMA_VERSION_TABLE_NAME = + "VersionInfo"; + // The shared pref name. + private static final String LAST_KNOWN_LOCATION_SETTING = + "lastKnownLocationSystemSetting"; + // The Browser package name. + private static final String BROWSER_PACKAGE_NAME = "com.android.browser"; + // The Google URLs whitelisted for Gears location access. + private static HashSet<String> sGearsWhiteList; + + static { + sGearsWhiteList = new HashSet<String>(); + // NOTE: DO NOT ADD A "/" AT THE END! + sGearsWhiteList.add("http://www.google.com"); + sGearsWhiteList.add("http://www.google.co.uk"); + } + + private static final String LOGTAG = "webcore"; + static final boolean DEBUG = false; + static final boolean LOGV_ENABLED = DEBUG; + // Class to handle messages before WebCore is ready. private class EventHandler { // Message id for syncing @@ -196,6 +245,7 @@ public class WebSettings { switch (msg.what) { case SYNC: synchronized (WebSettings.this) { + checkGearsPermissions(); if (mBrowserFrame.mNativeFrame != 0) { nativeSync(mBrowserFrame.mNativeFrame); } @@ -1163,6 +1213,126 @@ public class WebSettings { return size; } + private void checkGearsPermissions() { + // Did we already check the permissions? + if (mCheckedGearsPermissions) { + return; + } + // Are we running in the browser? + if (!BROWSER_PACKAGE_NAME.equals(mContext.getPackageName())) { + return; + } + // Is the pluginsPath sane? + if (mPluginsPath == null || mPluginsPath.length() == 0) { + // We don't yet have a meaningful plugin path, so + // we can't do anything about the Gears permissions. + return; + } + // Remember we checked the Gears permissions. + mCheckedGearsPermissions = true; + // Get the current system settings. + int setting = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.USE_LOCATION_FOR_SERVICES, -1); + // Check if we need to set the Gears permissions. + if (setting != -1 && locationSystemSettingChanged(setting)) { + setGearsPermissionForGoogleDomains(setting); + } + } + + private boolean locationSystemSettingChanged(int newSetting) { + SharedPreferences prefs = + PreferenceManager.getDefaultSharedPreferences(mContext); + int oldSetting = 0; + oldSetting = prefs.getInt(LAST_KNOWN_LOCATION_SETTING, oldSetting); + if (oldSetting == newSetting) { + return false; + } + Editor ed = prefs.edit(); + ed.putInt(LAST_KNOWN_LOCATION_SETTING, newSetting); + ed.commit(); + return true; + } + + private void setGearsPermissionForGoogleDomains(int systemPermission) { + // Transform the system permission into a Gears permission + int gearsPermission = (systemPermission == 1 ? 1 : 2); + // Build the path to the Gears library. + + File file = new File(mPluginsPath).getParentFile(); + if (file == null) { + return; + } + // Build the Gears database file name. + file = new File(file.getAbsolutePath() + File.separator + + GEARS_DATABASE_DIR + File.separator + GEARS_DATABASE_FILE); + // Remember whether or not we need to create the LocationAccess table. + boolean needToCreateTables = !file.exists(); + // Try opening the Gears database. + SQLiteDatabase permissions; + try { + permissions = SQLiteDatabase.openOrCreateDatabase(file, null); + } catch (SQLiteException e) { + if (LOGV_ENABLED) { + Log.v(LOGTAG, "Could not open Gears permission DB: " + + e.getMessage()); + } + // Just bail out. + return; + } + // We now have a database open. Begin a transaction. + permissions.beginTransaction(); + try { + if (needToCreateTables) { + // Create the tables. Note that this creates the + // Gears tables for the permissions DB schema version 2. + // The Gears schema upgrade process will take care of the rest. + // First, the storage access table. + SQLiteStatement statement = permissions.compileStatement( + "CREATE TABLE IF NOT EXISTS " + + GEARS_STORAGE_ACCESS_TABLE_NAME + + " (Name TEXT UNIQUE, Value)"); + statement.execute(); + // Next the location access table. + statement = permissions.compileStatement( + "CREATE TABLE IF NOT EXISTS " + + GEARS_LOCATION_ACCESS_TABLE_NAME + + " (Name TEXT UNIQUE, Value)"); + statement.execute(); + // Finally, the schema version table. + statement = permissions.compileStatement( + "CREATE TABLE IF NOT EXISTS " + + GEARS_SCHEMA_VERSION_TABLE_NAME + + " (Name TEXT UNIQUE, Value)"); + statement.execute(); + // Set the schema version to 2. + ContentValues schema = new ContentValues(); + schema.put("Name", "Version"); + schema.put("Value", 2); + permissions.insert(GEARS_SCHEMA_VERSION_TABLE_NAME, null, + schema); + } + + ContentValues permissionValues = new ContentValues(); + + for (String url : sGearsWhiteList) { + permissionValues.put("Name", url); + permissionValues.put("Value", gearsPermission); + permissions.replace(GEARS_LOCATION_ACCESS_TABLE_NAME, null, + permissionValues); + permissionValues.clear(); + } + // Commit the transaction. + permissions.setTransactionSuccessful(); + } catch (SQLiteException e) { + if (LOGV_ENABLED) { + Log.v(LOGTAG, "Could not set the Gears permissions: " + + e.getMessage()); + } + } finally { + permissions.endTransaction(); + permissions.close(); + } + } /* Post a SYNC message to handle syncing the native settings. */ private synchronized void postSync() { // Only post if a sync is not pending diff --git a/core/res/res/color/search_url_text.xml b/core/res/res/color/search_url_text.xml new file mode 100644 index 0000000..449fdf0 --- /dev/null +++ b/core/res/res/color/search_url_text.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:color="@android:color/search_url_text_pressed"/> + <item android:state_selected="true" android:color="@android:color/search_url_text_selected"/> + <item android:color="@android:color/search_url_text_normal"/> <!-- not selected --> +</selector> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index d284d0f..b7de997 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -74,7 +74,9 @@ <color name="perms_normal_perm_color">#c0c0c0</color> <!-- For search-related UIs --> - <color name="search_url_text">#7fa87f</color> + <color name="search_url_text_normal">#7fa87f</color> + <color name="search_url_text_selected">@android:color/black</color> + <color name="search_url_text_pressed">@android:color/black</color> <color name="search_widget_corpus_item_background">@android:color/lighter_gray</color> </resources> |
