michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.preferences; michael@0: michael@0: import org.json.JSONException; michael@0: import org.json.JSONObject; michael@0: import org.mozilla.gecko.R; michael@0: import org.mozilla.gecko.favicons.Favicons; michael@0: import org.mozilla.gecko.favicons.decoders.FaviconDecoder; michael@0: import org.mozilla.gecko.util.ThreadUtils; michael@0: import org.mozilla.gecko.widget.FaviconView; michael@0: michael@0: import android.app.AlertDialog; michael@0: import android.content.Context; michael@0: import android.graphics.Bitmap; michael@0: import android.graphics.drawable.BitmapDrawable; michael@0: import android.text.SpannableString; michael@0: import android.util.Log; michael@0: import android.view.View; michael@0: import android.widget.Toast; michael@0: michael@0: /** michael@0: * Represents an element in the list of search engines on the preferences menu. michael@0: */ michael@0: public class SearchEnginePreference extends CustomListPreference { michael@0: protected String LOGTAG = "SearchEnginePreference"; michael@0: michael@0: protected static final int INDEX_REMOVE_BUTTON = 1; michael@0: michael@0: // The icon to display in the prompt when clicked. michael@0: private BitmapDrawable mPromptIcon; michael@0: michael@0: // The bitmap backing the drawable above - needed separately for the FaviconView. michael@0: private Bitmap mIconBitmap; michael@0: michael@0: private FaviconView mFaviconView; michael@0: michael@0: public SearchEnginePreference(Context context, SearchPreferenceCategory parentCategory) { michael@0: super(context, parentCategory); michael@0: } michael@0: michael@0: /** michael@0: * Called by Android when we're bound to the custom view. Allows us to set the custom properties michael@0: * of our custom view elements as we desire (We can now use findViewById on them). michael@0: * michael@0: * @param view The view instance for this Preference object. michael@0: */ michael@0: @Override michael@0: protected void onBindView(View view) { michael@0: super.onBindView(view); michael@0: michael@0: // Set the icon in the FaviconView. michael@0: mFaviconView = ((FaviconView) view.findViewById(R.id.search_engine_icon)); michael@0: mFaviconView.updateAndScaleImage(mIconBitmap, getTitle().toString()); michael@0: } michael@0: michael@0: @Override michael@0: protected int getPreferenceLayoutResource() { michael@0: return R.layout.preference_search_engine; michael@0: } michael@0: michael@0: /** michael@0: * Returns the strings to be displayed in the dialog. michael@0: */ michael@0: @Override michael@0: protected String[] createDialogItems() { michael@0: return new String[] { LABEL_SET_AS_DEFAULT, michael@0: LABEL_REMOVE }; michael@0: } michael@0: michael@0: @Override michael@0: public void showDialog() { michael@0: // If this is the last engine, then we are the default, and none of the options michael@0: // on this menu can do anything. michael@0: if (mParentCategory.getPreferenceCount() == 1) { michael@0: ThreadUtils.postToUiThread(new Runnable() { michael@0: @Override michael@0: public void run() { michael@0: Toast.makeText(getContext(), R.string.pref_search_last_toast, Toast.LENGTH_SHORT).show(); michael@0: } michael@0: }); michael@0: return; michael@0: } michael@0: michael@0: super.showDialog(); michael@0: } michael@0: michael@0: @Override michael@0: protected void configureDialogBuilder(AlertDialog.Builder builder) { michael@0: // Copy the icon from this object to the prompt we produce. We lazily create the drawable, michael@0: // as the user may not ever actually tap this object. michael@0: if (mPromptIcon == null && mIconBitmap != null) { michael@0: mPromptIcon = new BitmapDrawable(getContext().getResources(), mFaviconView.getBitmap()); michael@0: } michael@0: michael@0: builder.setIcon(mPromptIcon); michael@0: } michael@0: michael@0: @Override michael@0: protected void onDialogIndexClicked(int index) { michael@0: switch (index) { michael@0: case INDEX_SET_DEFAULT_BUTTON: michael@0: mParentCategory.setDefault(this); michael@0: break; michael@0: michael@0: case INDEX_REMOVE_BUTTON: michael@0: mParentCategory.uninstall(this); michael@0: break; michael@0: michael@0: default: michael@0: Log.w(LOGTAG, "Selected index out of range."); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Configure this Preference object from the Gecko search engine JSON object. michael@0: * @param geckoEngineJSON The Gecko-formatted JSON object representing the search engine. michael@0: * @throws JSONException If the JSONObject is invalid. michael@0: */ michael@0: public void setSearchEngineFromJSON(JSONObject geckoEngineJSON) throws JSONException { michael@0: final String engineName = geckoEngineJSON.getString("name"); michael@0: final SpannableString titleSpannable = new SpannableString(engineName); michael@0: michael@0: setTitle(titleSpannable); michael@0: michael@0: final String iconURI = geckoEngineJSON.getString("iconURI"); michael@0: // Keep a reference to the bitmap - we'll need it later in onBindView. michael@0: try { michael@0: final int desiredWidth; michael@0: if (mFaviconView != null) { michael@0: desiredWidth = mFaviconView.getWidth(); michael@0: } else { michael@0: // largestFaviconSize is initialized when Favicons is attached to a michael@0: // context, which occurs during GeckoApp.onCreate. That might not michael@0: // ever happen (leaving it at 0), so we fall back. michael@0: if (Favicons.largestFaviconSize == 0) { michael@0: desiredWidth = 128; michael@0: } else { michael@0: desiredWidth = Favicons.largestFaviconSize; michael@0: } michael@0: } michael@0: michael@0: // TODO: use the cache. Bug 961600. michael@0: mIconBitmap = FaviconDecoder.getMostSuitableBitmapFromDataURI(iconURI, desiredWidth); michael@0: michael@0: } catch (IllegalArgumentException e) { michael@0: Log.e(LOGTAG, "IllegalArgumentException creating Bitmap. Most likely a zero-length bitmap.", e); michael@0: } catch (NullPointerException e) { michael@0: Log.e(LOGTAG, "NullPointerException creating Bitmap. Most likely a zero-length bitmap.", e); michael@0: } michael@0: } michael@0: }