Merge change 482 into donut

* changes:
  location: Location Manager wakelock cleanup, phase 2
diff --git a/api/current.xml b/api/current.xml
index 9708388..37e391c 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -848,6 +848,17 @@
  visibility="public"
 >
 </field>
+<field name="SDCARD_WRITE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.SDCARD_WRITE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SEND_SMS"
  type="java.lang.String"
  transient="false"
@@ -1283,6 +1294,17 @@
  visibility="public"
 >
 </field>
+<field name="STORAGE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission-group.STORAGE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SYSTEM_TOOLS"
  type="java.lang.String"
  transient="false"
@@ -58025,7 +58047,7 @@
  type="float"
  transient="false"
  volatile="false"
- value="0.0010f"
+ value="0.001f"
  static="true"
  final="true"
  deprecated="not deprecated"
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index a0cdb63..3d89ad7 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -16,24 +16,24 @@
 
 package android.app;
 
+import static android.app.SuggestionsAdapter.getColumnString;
+
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.server.search.SearchableInfo;
 import android.speech.RecognizerIntent;
@@ -45,7 +45,10 @@
 import android.util.Log;
 import android.view.Gravity;
 import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
@@ -53,17 +56,14 @@
 import android.widget.AdapterView;
 import android.widget.AutoCompleteTextView;
 import android.widget.Button;
-import android.widget.CursorAdapter;
 import android.widget.ImageButton;
-import android.widget.ImageView;
 import android.widget.ListView;
-import android.widget.SimpleCursorAdapter;
 import android.widget.TextView;
-import android.widget.WrapperListAdapter;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemSelectedListener;
 
-import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.WeakHashMap;
 import java.util.concurrent.atomic.AtomicLong;
 
 /**
@@ -75,59 +75,66 @@
 public class SearchDialog extends Dialog implements OnItemClickListener, OnItemSelectedListener {
 
     // Debugging support
-    final static String LOG_TAG = "SearchDialog";
-    private static final int DBG_LOG_TIMING = 0;
-    final static int DBG_JAM_THREADING = 0;
+    private static final boolean DBG = false;
+    private static final String LOG_TAG = "SearchDialog";
+    private static final boolean DBG_LOG_TIMING = false;
 
-    // interaction with runtime
-    IntentFilter mCloseDialogsFilter;
-    IntentFilter mPackageFilter;
-    
     private static final String INSTANCE_KEY_COMPONENT = "comp";
     private static final String INSTANCE_KEY_APPDATA = "data";
     private static final String INSTANCE_KEY_GLOBALSEARCH = "glob";
     private static final String INSTANCE_KEY_DISPLAY_QUERY = "dQry";
     private static final String INSTANCE_KEY_DISPLAY_SEL_START = "sel1";
     private static final String INSTANCE_KEY_DISPLAY_SEL_END = "sel2";
-    private static final String INSTANCE_KEY_USER_QUERY = "uQry";
-    private static final String INSTANCE_KEY_SUGGESTION_QUERY = "sQry";
     private static final String INSTANCE_KEY_SELECTED_ELEMENT = "slEl";
     private static final int INSTANCE_SELECTED_BUTTON = -2;
     private static final int INSTANCE_SELECTED_QUERY = -1;
-
+    
+    // interaction with runtime
+    private IntentFilter mCloseDialogsFilter;
+    private IntentFilter mPackageFilter;
+    
     // views & widgets
     private TextView mBadgeLabel;
-    private AutoCompleteTextView mSearchTextField;
+    private SearchAutoComplete mSearchAutoComplete;
     private Button mGoButton;
     private ImageButton mVoiceButton;
+    private View mSearchPlate;
 
     // interaction with searchable application
+    private SearchableInfo mSearchable;
     private ComponentName mLaunchComponent;
     private Bundle mAppSearchData;
     private boolean mGlobalSearchMode;
     private Context mActivityContext;
+    
+    // stack of previous searchables, to support the BACK key after
+    // SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE.
+    // The top of the stack (= previous searchable) is the last element of the list,
+    // since adding and removing is efficient at the end of an ArrayList.
+    private ArrayList<ComponentName> mPreviousComponents;
 
-    // interaction with the search manager service
-    private SearchableInfo mSearchable;
-    
-    // support for suggestions 
-    private String mUserQuery = null;
-    private int mUserQuerySelStart;
-    private int mUserQuerySelEnd;
-    private boolean mLeaveJammedQueryOnRefocus = false;
-    private String mPreviousSuggestionQuery = null;
-    private int mPresetSelection = -1;
-    private String mSuggestionAction = null;
-    private Uri mSuggestionData = null;
-    private String mSuggestionQuery = null;
-    
     // For voice searching
     private Intent mVoiceWebSearchIntent;
     private Intent mVoiceAppSearchIntent;
 
     // support for AutoCompleteTextView suggestions display
     private SuggestionsAdapter mSuggestionsAdapter;
-
+    
+    // Whether to rewrite queries when selecting suggestions
+    // TODO: This is disabled because of problems with persistent selections
+    // causing non-user-initiated rewrites.
+    private static final boolean REWRITE_QUERIES = false;
+    
+    // The query entered by the user. This is not changed when selecting a suggestion
+    // that modifies the contents of the text field. But if the user then edits
+    // the suggestion, the resulting string is saved.
+    private String mUserQuery;
+    
+    // A weak map of drawables we've gotten from other packages, so we don't load them
+    // more than once.
+    private final WeakHashMap<String, Drawable> mOutsideDrawablesCache =
+            new WeakHashMap<String, Drawable>();
+    
     /**
      * Constructor - fires it up and makes it look like the search UI.
      * 
@@ -153,25 +160,29 @@
         theWindow.setLayout(ViewGroup.LayoutParams.FILL_PARENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT);
         WindowManager.LayoutParams lp = theWindow.getAttributes();
-        lp.setTitle("Search Dialog");
         lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE;
         theWindow.setAttributes(lp);
 
         // get the view elements for local access
         mBadgeLabel = (TextView) findViewById(com.android.internal.R.id.search_badge);
-        mSearchTextField = (AutoCompleteTextView) 
+        mSearchAutoComplete = (SearchAutoComplete)
                 findViewById(com.android.internal.R.id.search_src_text);
         mGoButton = (Button) findViewById(com.android.internal.R.id.search_go_btn);
         mVoiceButton = (ImageButton) findViewById(com.android.internal.R.id.search_voice_btn);
+        mSearchPlate = findViewById(com.android.internal.R.id.search_plate);
         
         // attach listeners
-        mSearchTextField.addTextChangedListener(mTextWatcher);
-        mSearchTextField.setOnKeyListener(mTextKeyListener);
+        mSearchAutoComplete.addTextChangedListener(mTextWatcher);
+        mSearchAutoComplete.setOnKeyListener(mTextKeyListener);
+        mSearchAutoComplete.setOnItemClickListener(this);
+        mSearchAutoComplete.setOnItemSelectedListener(this);
         mGoButton.setOnClickListener(mGoButtonClickListener);
         mGoButton.setOnKeyListener(mButtonsKeyListener);
         mVoiceButton.setOnClickListener(mVoiceButtonClickListener);
         mVoiceButton.setOnKeyListener(mButtonsKeyListener);
 
+        mSearchAutoComplete.setSearchDialog(this);
+        
         // pre-hide all the extraneous elements
         mBadgeLabel.setVisibility(View.GONE);
 
@@ -199,7 +210,7 @@
     /**
      * Set up the search dialog
      * 
-     * @param Returns true if search dialog launched, false if not
+     * @return true if search dialog launched, false if not
      */
     public boolean show(String initialQuery, boolean selectInitialQuery,
             ComponentName componentName, Bundle appSearchData, boolean globalSearch) {
@@ -208,75 +219,65 @@
             // in this case, just discard the "show" request
             return true;
         }
-
-        // Get searchable info from search manager and use to set up other elements of UI
-        // Do this first so we can get out quickly if there's nothing to search
-        ISearchManager sms;
-        sms = ISearchManager.Stub.asInterface(ServiceManager.getService(Context.SEARCH_SERVICE));
-        try {
-            mSearchable = sms.getSearchableInfo(componentName, globalSearch);
-        } catch (RemoteException e) {
-            mSearchable = null;
+        
+        // set up the searchable and show the dialog
+        if (!show(componentName, appSearchData, globalSearch)) {
+            return false;
         }
+        
+        // finally, load the user's initial text (which may trigger suggestions)
+        setUserQuery(initialQuery);
+        if (selectInitialQuery) {
+            mSearchAutoComplete.selectAll();
+        }
+        
+        return true;
+    }
+    
+    /**
+     * Sets up the search dialog and shows it.
+     * 
+     * @return <code>true</code> if search dialog launched
+     */
+    private boolean show(ComponentName componentName, Bundle appSearchData, 
+            boolean globalSearch) {
+        
+        if (DBG) { 
+            Log.d(LOG_TAG, "show(" + componentName + ", " 
+                    + appSearchData + ", " + globalSearch + ")");
+        }
+        
+        mSearchable = SearchManager.getSearchableInfo(componentName, globalSearch);
         if (mSearchable == null) {
             // unfortunately, we can't log here.  it would be logspam every time the user
             // clicks the "search" key on a non-search app
             return false;
         }
         
-        // OK, we're going to show ourselves
-        super.show();
-
-        setupSearchableInfo();
-        
         mLaunchComponent = componentName;
         mAppSearchData = appSearchData;
-        mGlobalSearchMode = globalSearch;
+        // Using globalSearch here is just an optimization, just calling
+        // isDefaultSearchable() should always give the same result.
+        mGlobalSearchMode = globalSearch || SearchManager.isDefaultSearchable(mSearchable); 
+        mActivityContext = mSearchable.getActivityContext(getContext());
+        
+        // show the dialog. this will call onStart().
+        if (!isShowing()) {
+            show();
+        }
 
+        updateUI();
+        
+        return true;
+    }
+    
+    @Override
+    protected void onStart() {
+        super.onStart();
+        
         // receive broadcasts
         getContext().registerReceiver(mBroadcastReceiver, mCloseDialogsFilter);
         getContext().registerReceiver(mBroadcastReceiver, mPackageFilter);
-        
-        // configure the autocomplete aspects of the input box
-        mSearchTextField.setOnItemClickListener(this);
-        mSearchTextField.setOnItemSelectedListener(this);
-
-        // This conversion is necessary to force a preload of the EditText and thus force
-        // suggestions to be presented (even for an empty query)
-        if (initialQuery == null) {
-            initialQuery = "";     // This forces the preload to happen, triggering suggestions
-        }
-
-        // attach the suggestions adapter, if suggestions are available
-        // The existence of a suggestions authority is the proxy for "suggestions available here"
-        if (mSearchable.getSuggestAuthority() == null) {
-            mSuggestionsAdapter = null;
-            mSearchTextField.setAdapter(mSuggestionsAdapter);
-            mSearchTextField.setText(initialQuery);
-        } else {
-            mSuggestionsAdapter = new SuggestionsAdapter(getContext(), mSearchable, 
-                    mSearchTextField);
-            mSearchTextField.setAdapter(mSuggestionsAdapter);
-
-            // finally, load the user's initial text (which may trigger suggestions)
-            mSuggestionsAdapter.setNonUserQuery(false);
-            mSearchTextField.setText(initialQuery);
-        }
-        
-        if (selectInitialQuery) {
-            mSearchTextField.selectAll();
-        } else {
-            mSearchTextField.setSelection(initialQuery.length());
-        }
-        return true;
-    }
-
-    /**
-     * The default show() for this Dialog is not supported.
-     */
-    @Override
-    public void show() {
-        return;
     }
 
     /**
@@ -289,6 +290,8 @@
     public void onStop() {
         super.onStop();
         
+        // TODO: Removing the listeners means that they never get called, since 
+        // Dialog.dismissDialog() calls onStop() before sendDismissMessage().
         setOnCancelListener(null);
         setOnDismissListener(null);
         
@@ -299,26 +302,36 @@
             // This is OK - it just means we didn't have any registered
         }
         
-        // close any leftover cursor
-        if (mSuggestionsAdapter != null) {
-            mSuggestionsAdapter.changeCursor(null);
-        }
+        closeSuggestionsAdapter();
         
         // dump extra memory we're hanging on to
         mLaunchComponent = null;
         mAppSearchData = null;
         mSearchable = null;
-        mSuggestionAction = null;
-        mSuggestionData = null;
-        mSuggestionQuery = null;
         mActivityContext = null;
-        mPreviousSuggestionQuery = null;
         mUserQuery = null;
+        mPreviousComponents = null;
+    }
+    
+    /**
+     * Closes and gets rid of the suggestions adapter.
+     */
+    private void closeSuggestionsAdapter() {
+        // remove the adapter from the autocomplete first, to avoid any updates
+        // when we drop the cursor
+        mSearchAutoComplete.setAdapter((SuggestionsAdapter)null);
+        // close any leftover cursor
+        if (mSuggestionsAdapter != null) {
+            mSuggestionsAdapter.changeCursor(null);
+        }
+        mSuggestionsAdapter = null;
     }
     
     /**
      * Save the minimal set of data necessary to recreate the search
      * 
+     * TODO: go through this and make sure that it saves everything that is needed
+     * 
      * @return A bundle with the state of the dialog.
      */
     @Override
@@ -331,16 +344,14 @@
         bundle.putBoolean(INSTANCE_KEY_GLOBALSEARCH, mGlobalSearchMode);
         
         // UI state
-        bundle.putString(INSTANCE_KEY_DISPLAY_QUERY, mSearchTextField.getText().toString());
-        bundle.putInt(INSTANCE_KEY_DISPLAY_SEL_START, mSearchTextField.getSelectionStart());
-        bundle.putInt(INSTANCE_KEY_DISPLAY_SEL_END, mSearchTextField.getSelectionEnd());
-        bundle.putString(INSTANCE_KEY_USER_QUERY, mUserQuery);
-        bundle.putString(INSTANCE_KEY_SUGGESTION_QUERY, mPreviousSuggestionQuery);
+        bundle.putString(INSTANCE_KEY_DISPLAY_QUERY, mSearchAutoComplete.getText().toString());
+        bundle.putInt(INSTANCE_KEY_DISPLAY_SEL_START, mSearchAutoComplete.getSelectionStart());
+        bundle.putInt(INSTANCE_KEY_DISPLAY_SEL_END, mSearchAutoComplete.getSelectionEnd());
         
         int selectedElement = INSTANCE_SELECTED_QUERY;
         if (mGoButton.isFocused()) {
             selectedElement = INSTANCE_SELECTED_BUTTON;
-        } else if (mSearchTextField.isPopupShowing()) {
+        } else if (mSearchAutoComplete.isPopupShowing()) {
             selectedElement = 0; // TODO mSearchTextField.getListSelection()    // 0..n
         }
         bundle.putInt(INSTANCE_KEY_SELECTED_ELEMENT, selectedElement);
@@ -350,6 +361,8 @@
 
     /**
      * Restore the state of the dialog from a previously saved bundle.
+     * 
+     * TODO: go through this and make sure that it saves everything that is saved
      *
      * @param savedInstanceState The state of the dialog previously saved by
      *     {@link #onSaveInstanceState()}.
@@ -365,26 +378,17 @@
         String displayQuery = savedInstanceState.getString(INSTANCE_KEY_DISPLAY_QUERY);
         int querySelStart = savedInstanceState.getInt(INSTANCE_KEY_DISPLAY_SEL_START, -1);
         int querySelEnd = savedInstanceState.getInt(INSTANCE_KEY_DISPLAY_SEL_END, -1);
-        String userQuery = savedInstanceState.getString(INSTANCE_KEY_USER_QUERY);
         int selectedElement = savedInstanceState.getInt(INSTANCE_KEY_SELECTED_ELEMENT);
-        String suggestionQuery = savedInstanceState.getString(INSTANCE_KEY_SUGGESTION_QUERY);
         
         // show the dialog.  skip any show/hide animation, we want to go fast.
         // send the text that actually generates the suggestions here;  we'll replace the display
         // text as necessary in a moment.
-        if (!show(suggestionQuery, false, launchComponent, appSearchData, globalSearch)) {
+        if (!show(displayQuery, false, launchComponent, appSearchData, globalSearch)) {
             // for some reason, we couldn't re-instantiate
             return;
         }
         
-        if (mSuggestionsAdapter != null) {
-            mSuggestionsAdapter.setNonUserQuery(true);
-        }
-        mSearchTextField.setText(displayQuery);
-        // TODO because the new query is (not) processed in another thread, we can't just
-        // take away this flag (yet).  The better solution here is going to require a new API
-        // in AutoCompleteTextView which allows us to change the text w/o changing the suggestions.
-//      mSuggestionsAdapter.setNonUserQuery(false);
+        mSearchAutoComplete.setText(displayQuery);
         
         // clean up the selection state
         switch (selectedElement) {
@@ -395,21 +399,19 @@
             break;
         case INSTANCE_SELECTED_QUERY:
             if (querySelStart >= 0 && querySelEnd >= 0) {
-                mSearchTextField.requestFocus();
-                mSearchTextField.setSelection(querySelStart, querySelEnd);
+                mSearchAutoComplete.requestFocus();
+                mSearchAutoComplete.setSelection(querySelStart, querySelEnd);
             }
             break;
         default:
-            // defer selecting a list element until suggestion list appears
-            mPresetSelection = selectedElement;
-            // TODO mSearchTextField.setListSelection(selectedElement)
+            // TODO: defer selecting a list element until suggestion list appears
+//            mSearchAutoComplete.setListSelection(selectedElement)
             break;
         }
     }
     
     /**
-     * Hook for updating layout on a rotation
-     * 
+     * Called after resources have changed, e.g. after screen rotation or locale change.
      */
     public void onConfigurationChanged(Configuration newConfig) {
         if (isShowing()) {
@@ -419,15 +421,13 @@
             updateQueryHint();
         } 
     }
-
+    
     /**
-     * Use SearchableInfo record (from search manager service) to preconfigure the UI in various
-     * ways.
+     * Update the UI according to the info in the current value of {@link #mSearchable}.
      */
-    private void setupSearchableInfo() {
+    private void updateUI() {
         if (mSearchable != null) {
-            mActivityContext = mSearchable.getActivityContext(getContext());
-            
+            updateSearchAutoComplete();
             updateSearchButton();
             updateSearchBadge();
             updateQueryHint();
@@ -449,24 +449,38 @@
                     inputType |= InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE;
                 }
             }
-            mSearchTextField.setInputType(inputType);
-            mSearchTextField.setImeOptions(mSearchable.getImeOptions());
+            mSearchAutoComplete.setInputType(inputType);
+            mSearchAutoComplete.setImeOptions(mSearchable.getImeOptions());
+        }
+    }
+    
+    /**
+     * Updates the auto-complete text view.
+     */
+    private void updateSearchAutoComplete() {
+        // close any existing suggestions adapter
+        closeSuggestionsAdapter();
+        
+        mSearchAutoComplete.setDropDownAnimationStyle(0); // no animation
+        mSearchAutoComplete.setThreshold(0);  // always allow zero-query suggestions
+
+        if (mGlobalSearchMode) {
+            mSearchAutoComplete.setDropDownAlwaysVisible(true);  // fill space until results come in
+            mSearchAutoComplete.setDropDownDismissedOnCompletion(false);
+        } else {
+            mSearchAutoComplete.setDropDownAlwaysVisible(false);
+            mSearchAutoComplete.setDropDownDismissedOnCompletion(true);
+        }
+
+        // attach the suggestions adapter, if suggestions are available
+        // The existence of a suggestions authority is the proxy for "suggestions available here"
+        if (mSearchable.getSuggestAuthority() != null) {
+            mSuggestionsAdapter = new SuggestionsAdapter(getContext(), mSearchable, 
+                    mOutsideDrawablesCache);
+            mSearchAutoComplete.setAdapter(mSuggestionsAdapter);
         }
     }
 
-    /**
-     * The list of installed packages has just changed.  This means that our current context
-     * may no longer be valid.  This would only happen if a package is installed/removed exactly
-     * when the search bar is open.  So for now we're just going to close the search
-     * bar.  
-     * 
-     * Anything fancier would require some checks to see if the user's context was still valid.
-     * Which would be messier.
-     */
-    public void onPackageListChange() {
-        cancel();
-    }
-    
     /**    
      * Update the text in the search button.  Note: This is deprecated functionality, for 
      * 1.0 compatibility only.
@@ -481,26 +495,40 @@
             iconLabel = getContext().getResources().
                     getDrawable(com.android.internal.R.drawable.ic_btn_search);
         }
-        mGoButton.setText(textLabel);  
+        mGoButton.setText(textLabel);
         mGoButton.setCompoundDrawablesWithIntrinsicBounds(iconLabel, null, null, null);
     }
     
     /**
-     * Setup the search "Badge" if request by mode flags.
+     * Setup the search "Badge" if requested by mode flags.
      */
     private void updateSearchBadge() {
         // assume both hidden
         int visibility = View.GONE;
         Drawable icon = null;
-        String text = null;
+        CharSequence text = null;
         
         // optionally show one or the other.
         if (mSearchable.mBadgeIcon) {
             icon = mActivityContext.getResources().getDrawable(mSearchable.getIconId());
             visibility = View.VISIBLE;
+            if (DBG) Log.d(LOG_TAG, "Using badge icon: " + mSearchable.getIconId());
         } else if (mSearchable.mBadgeLabel) {
             text = mActivityContext.getResources().getText(mSearchable.getLabelId()).toString();
             visibility = View.VISIBLE;
+            if (DBG) Log.d(LOG_TAG, "Using badge label: " + mSearchable.getLabelId());
+        } else if (!mGlobalSearchMode) {
+            // Get the localized name of the application which we are doing search in.
+            try {
+                PackageManager pm = getContext().getPackageManager();
+                ActivityInfo info = pm.getActivityInfo(mLaunchComponent, 0);
+                text = pm.getApplicationLabel(info.applicationInfo);
+                visibility = View.VISIBLE;
+                if (DBG) Log.d(LOG_TAG, "Using application label: " + text);
+            } catch (NameNotFoundException e) {
+                // app not found, fine, don't use its name for the label
+                Log.w(LOG_TAG, mLaunchComponent + " not found.");
+            }
         }
         
         mBadgeLabel.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
@@ -520,7 +548,7 @@
                     hint = mActivityContext.getString(hintId);
                 }
             }
-            mSearchTextField.setHint(hint);
+            mSearchAutoComplete.setHint(hint);
         }
     }
 
@@ -548,63 +576,129 @@
         mVoiceButton.setVisibility(visibility);
     }
     
+    /*
+     * Menu.
+     */
+    
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Show search settings menu item if anyone handles the intent for it
+        Intent settingsIntent = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS);
+        PackageManager pm = getContext().getPackageManager();
+        ActivityInfo activityInfo = settingsIntent.resolveActivityInfo(pm, 0);
+        if (activityInfo != null) {
+            settingsIntent.setClassName(activityInfo.applicationInfo.packageName,
+                    activityInfo.name);
+            String label = getActivityLabel(activityInfo);
+            menu.add(Menu.NONE, Menu.NONE, Menu.NONE, label)
+                    .setIcon(android.R.drawable.ic_menu_preferences)
+                    .setAlphabeticShortcut('P')
+                    .setIntent(settingsIntent);
+            return true;
+        }
+        return super.onCreateOptionsMenu(menu);
+    }
+    
+    // TODO: shouldn't this be in PackageManager?
+    private String getActivityLabel(ActivityInfo activityInfo) {
+        PackageManager pm = getContext().getPackageManager();
+        try {
+            int labelRes = activityInfo.labelRes;
+            if (labelRes == 0) {
+                return null;
+            }
+            Resources r = pm.getResourcesForApplication(activityInfo.applicationInfo);
+            return r.getString(labelRes);
+        } catch (NameNotFoundException ex) {
+            return null;
+        }
+    }
+    
     /**
      * Listeners of various types
      */
 
     /**
+     * {@link Dialog#onTouchEvent(MotionEvent)} will cancel the dialog only when the
+     * touch is outside the window. But the window includes space for the drop-down,
+     * so we also cancel on taps outside the search bar when the drop-down is not showing.
+     */
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        // cancel if the drop-down is not showing and the touch event was outside the search plate
+        if (!mSearchAutoComplete.isPopupShowing() && isOutOfBounds(mSearchPlate, event)) {
+            if (DBG) Log.d(LOG_TAG, "Pop-up not showing and outside of search plate.");
+            cancel();
+            return true;
+        }
+        // Let Dialog handle events outside the window while the pop-up is showing.
+        return super.onTouchEvent(event);
+    }
+    
+    private boolean isOutOfBounds(View v, MotionEvent event) {
+        final int x = (int) event.getX();
+        final int y = (int) event.getY();
+        final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop();
+        return (x < -slop) || (y < -slop)
+                || (x > (v.getWidth()+slop))
+                || (y > (v.getHeight()+slop));
+    }
+    
+    /**
      * Dialog's OnKeyListener implements various search-specific functionality
      *
      * @param keyCode This is the keycode of the typed key, and is the same value as
-     * found in the KeyEvent parameter.
+     *        found in the KeyEvent parameter.
      * @param event The complete event record for the typed key
      *
      * @return Return true if the event was handled here, or false if not.
      */
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        switch (keyCode) {
-        case KeyEvent.KEYCODE_BACK:
-            cancel();
+        if (DBG) Log.d(LOG_TAG, "onKeyDown(" + keyCode + "," + event + ")");
+        
+        // handle back key to go back to previous searchable, etc.
+        if (handleBackKey(keyCode, event)) {
             return true;
-        case KeyEvent.KEYCODE_SEARCH:
-            if (TextUtils.getTrimmedLength(mSearchTextField.getText()) != 0) {
-                launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null);
+        }
+        
+        // search or cancel on search key
+        if (keyCode == KeyEvent.KEYCODE_SEARCH) {
+            if (!mSearchAutoComplete.isEmpty()) {
+                launchQuerySearch();
             } else {
                 cancel();
             }
             return true;
-        default:
-            SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode);
-            if ((actionKey != null) && (actionKey.mQueryActionMsg != null)) {
-                launchQuerySearch(keyCode, actionKey.mQueryActionMsg);
-                return true;
-            }
-            break;
         }
+
+        // if it's an action specified by the searchable activity, launch the
+        // entered query with the action key
+        SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode);
+        if ((actionKey != null) && (actionKey.mQueryActionMsg != null)) {
+            launchQuerySearch(keyCode, actionKey.mQueryActionMsg);
+            return true;
+        }
+        
         return false;
     }
-
+    
     /**
      * Callback to watch the textedit field for empty/non-empty
      */
     private TextWatcher mTextWatcher = new TextWatcher() {
 
-        public void beforeTextChanged(CharSequence s, int start, int
-                before, int after) { }
+        public void beforeTextChanged(CharSequence s, int start, int before, int after) { }
 
         public void onTextChanged(CharSequence s, int start,
                 int before, int after) {
-            if (DBG_LOG_TIMING == 1) {
+            if (DBG_LOG_TIMING) {
                 dbgLogTiming("onTextChanged()");
             }
             updateWidgetState();
-            // Only do suggestions if actually typed by user
-            if ((mSuggestionsAdapter != null) && !mSuggestionsAdapter.getNonUserQuery()) {
-                mPreviousSuggestionQuery = s.toString();
-                mUserQuery = mSearchTextField.getText().toString();
-                mUserQuerySelStart = mSearchTextField.getSelectionStart();
-                mUserQuerySelEnd = mSearchTextField.getSelectionEnd();
+            if (!mSearchAutoComplete.isPerformingCompletion()) {
+                // The user changed the query, remember it.
+                mUserQuery = s == null ? "" : s.toString();
             }
         }
 
@@ -616,64 +710,34 @@
      */
     private void updateWidgetState() {
         // enable the button if we have one or more non-space characters
-        boolean enabled =
-            TextUtils.getTrimmedLength(mSearchTextField.getText()) != 0;
-
+        boolean enabled = !mSearchAutoComplete.isEmpty();
         mGoButton.setEnabled(enabled);
         mGoButton.setFocusable(enabled);
     }
 
-    private final static String[] ONE_LINE_FROM =       {SearchManager.SUGGEST_COLUMN_TEXT_1 };
-    private final static String[] ONE_LINE_ICONS_FROM = {SearchManager.SUGGEST_COLUMN_TEXT_1,
-                                                         SearchManager.SUGGEST_COLUMN_ICON_1,
-                                                         SearchManager.SUGGEST_COLUMN_ICON_2};
-    private final static String[] TWO_LINE_FROM =       {SearchManager.SUGGEST_COLUMN_TEXT_1,
-                                                         SearchManager.SUGGEST_COLUMN_TEXT_2 };
-    private final static String[] TWO_LINE_ICONS_FROM = {SearchManager.SUGGEST_COLUMN_TEXT_1,
-                                                         SearchManager.SUGGEST_COLUMN_TEXT_2,
-                                                         SearchManager.SUGGEST_COLUMN_ICON_1,
-                                                         SearchManager.SUGGEST_COLUMN_ICON_2 };
-    
-    private final static int[] ONE_LINE_TO =       {com.android.internal.R.id.text1};
-    private final static int[] ONE_LINE_ICONS_TO = {com.android.internal.R.id.text1,
-                                                    com.android.internal.R.id.icon1, 
-                                                    com.android.internal.R.id.icon2};
-    private final static int[] TWO_LINE_TO =       {com.android.internal.R.id.text1, 
-                                                    com.android.internal.R.id.text2};
-    private final static int[] TWO_LINE_ICONS_TO = {com.android.internal.R.id.text1, 
-                                                    com.android.internal.R.id.text2,
-                                                    com.android.internal.R.id.icon1, 
-                                                    com.android.internal.R.id.icon2};
-    
-    /**
-     * Safely retrieve the suggestions cursor adapter from the ListView
-     * 
-     * @param adapterView The ListView containing our adapter
-     * @result The CursorAdapter that we installed, or null if not set
-     */
-    private static CursorAdapter getSuggestionsAdapter(AdapterView<?> adapterView) {
-        CursorAdapter result = null;
-        if (adapterView != null) {
-            Object ad = adapterView.getAdapter();
-            if (ad instanceof CursorAdapter) {
-                result = (CursorAdapter) ad;
-            } else if (ad instanceof WrapperListAdapter) {
-                result = (CursorAdapter) ((WrapperListAdapter)ad).getWrappedAdapter();
-            }
-        }
-        return result;
-    }
-
     /**
      * React to typing in the GO search button by refocusing to EditText. 
      * Continue typing the query.
      */
     View.OnKeyListener mButtonsKeyListener = new View.OnKeyListener() {
         public boolean onKey(View v, int keyCode, KeyEvent event) {
-            // also guard against possible race conditions (late arrival after dismiss)
-            if (mSearchable != null) {
-                return refocusingKeyListener(v, keyCode, event);
+            // guard against possible race conditions
+            if (mSearchable == null) {
+                return false;
             }
+            
+            if (!event.isSystem() && 
+                    (keyCode != KeyEvent.KEYCODE_DPAD_UP) &&
+                    (keyCode != KeyEvent.KEYCODE_DPAD_DOWN) &&
+                    (keyCode != KeyEvent.KEYCODE_DPAD_LEFT) &&
+                    (keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) &&
+                    (keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) {
+                // restore focus and give key to EditText ...
+                if (mSearchAutoComplete.requestFocus()) {
+                    return mSearchAutoComplete.dispatchKeyEvent(event);
+                }
+            }
+
             return false;
         }
     };
@@ -683,10 +747,11 @@
      */
     View.OnClickListener mGoButtonClickListener = new View.OnClickListener() {
         public void onClick(View v) {
-            // also guard against possible race conditions (late arrival after dismiss)
-            if (mSearchable != null) {
-                launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null);
+            // guard against possible race conditions
+            if (mSearchable == null) {
+                return;
             }
+            launchQuerySearch();
         }
     };
     
@@ -695,14 +760,16 @@
      */
     View.OnClickListener mVoiceButtonClickListener = new View.OnClickListener() {
         public void onClick(View v) {
+            // guard against possible race conditions
+            if (mSearchable == null) {
+                return;
+            }
             try {
                 if (mSearchable.getVoiceSearchLaunchWebSearch()) {
                     getContext().startActivity(mVoiceWebSearchIntent);
-                    dismiss();
                 } else if (mSearchable.getVoiceSearchLaunchRecognizer()) {
                     Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent);
                     getContext().startActivity(appSearchIntent);
-                    dismiss();
                 }
             } catch (ActivityNotFoundException e) {
                 // Should not happen, since we check the availability of
@@ -778,136 +845,56 @@
      */
     View.OnKeyListener mTextKeyListener = new View.OnKeyListener() {
         public boolean onKey(View v, int keyCode, KeyEvent event) {
-            if (keyCode == KeyEvent.KEYCODE_BACK) {
-                cancel();
-                return true;
+            // guard against possible race conditions
+            if (mSearchable == null) {
+                return false;
             }
-            // also guard against possible race conditions (late arrival after dismiss)
-            if (mSearchable != null && 
-                    TextUtils.getTrimmedLength(mSearchTextField.getText()) > 0) {
-                if (DBG_LOG_TIMING == 1) {
-                    dbgLogTiming("doTextKey()");
+
+            if (DBG_LOG_TIMING) dbgLogTiming("doTextKey()");
+            if (DBG) { 
+                Log.d(LOG_TAG, "mTextListener.onKey(" + keyCode + "," + event 
+                        + "), selection: " + mSearchAutoComplete.getListSelection());
+            }
+            
+            // If a suggestion is selected, handle enter, search key, and action keys 
+            // as presses on the selected suggestion
+            if (mSearchAutoComplete.isPopupShowing() && 
+                    mSearchAutoComplete.getListSelection() != ListView.INVALID_POSITION) {
+                return onSuggestionsKey(v, keyCode, event);
+            }
+
+            // If there is text in the query box, handle enter, and action keys
+            // The search key is handled by the dialog's onKeyDown(). 
+            if (!mSearchAutoComplete.isEmpty()) {
+                if (keyCode == KeyEvent.KEYCODE_ENTER 
+                        && event.getAction() == KeyEvent.ACTION_UP) {
+                    v.cancelLongPress();
+                    launchQuerySearch();                    
+                    return true;
                 }
-                // dispatch "typing in the list" first
-                if (mSearchTextField.isPopupShowing() && 
-                        mSearchTextField.getListSelection() != ListView.INVALID_POSITION) {
-                     return onSuggestionsKey(v, keyCode, event);
-                }
-                // otherwise, dispatch an "edit view" key
-                switch (keyCode) {
-                case KeyEvent.KEYCODE_ENTER:
-                    if (event.getAction() == KeyEvent.ACTION_UP) {
-                        v.cancelLongPress();
-                        launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null);                    
+                if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                    SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode);
+                    if ((actionKey != null) && (actionKey.mQueryActionMsg != null)) {
+                        launchQuerySearch(keyCode, actionKey.mQueryActionMsg);
                         return true;
                     }
-                    break;
-                case KeyEvent.KEYCODE_DPAD_DOWN:                    
-                    // capture the EditText state, so we can restore the user entry later
-                    mUserQuery = mSearchTextField.getText().toString();
-                    mUserQuerySelStart = mSearchTextField.getSelectionStart();
-                    mUserQuerySelEnd = mSearchTextField.getSelectionEnd();
-                    // pass through - we're just watching here
-                    break;
-                default:
-                    if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                        SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode);
-                        if ((actionKey != null) && (actionKey.mQueryActionMsg != null)) {
-                            launchQuerySearch(keyCode, actionKey.mQueryActionMsg);
-                            return true;
-                        }
-                    }
-                    break;
                 }
             }
             return false;
         }
     };
-
+        
     /**
-     * React to the user typing while the suggestions are focused.  First, check for action
-     * keys.  If not handled, try refocusing regular characters into the EditText.  In this case,
-     * replace the query text (start typing fresh text).
-     */
-    private boolean onSuggestionsKey(View v, int keyCode, KeyEvent event) {
-        boolean handled = false;
-        // also guard against possible race conditions (late arrival after dismiss)
-        if (mSearchable != null) {
-            handled = doSuggestionsKey(v, keyCode, event);
-        }
-        return handled;
-    }
-    
-    /**
-     * Per UI design, we're going to "steer" any typed keystrokes back into the EditText
-     * box, even if the user has navigated the focus to the dropdown or to the GO button.
-     * 
-     * @param v The view into which the keystroke was typed
-     * @param keyCode keyCode of entered key
-     * @param event Full KeyEvent record of entered key
-     */
-    private boolean refocusingKeyListener(View v, int keyCode, KeyEvent event) {
-        boolean handled = false;
-
-        if (!event.isSystem() && 
-                (keyCode != KeyEvent.KEYCODE_DPAD_UP) &&
-                (keyCode != KeyEvent.KEYCODE_DPAD_DOWN) &&
-                (keyCode != KeyEvent.KEYCODE_DPAD_LEFT) &&
-                (keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) &&
-                (keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) {
-            // restore focus and give key to EditText ...
-            // but don't replace the user's query
-            mLeaveJammedQueryOnRefocus = true;
-            if (mSearchTextField.requestFocus()) {
-                handled = mSearchTextField.dispatchKeyEvent(event);
-            }
-            mLeaveJammedQueryOnRefocus = false;
-        }
-        return handled;
-    }
-    
-    /**
-     * Update query text based on transitions in and out of suggestions list.
-     */
-    /*
-     * TODO - figure out if this logic is required for the autocomplete text view version
-
-    OnFocusChangeListener mSuggestFocusListener = new OnFocusChangeListener() {
-        public void onFocusChange(View v, boolean hasFocus) {
-            // also guard against possible race conditions (late arrival after dismiss)
-            if (mSearchable == null) {
-                return;
-            }
-            // Update query text based on navigation in to/out of the suggestions list
-            if (hasFocus) {
-                // Entering the list view - record selection point from user's query
-                mUserQuery = mSearchTextField.getText().toString();
-                mUserQuerySelStart = mSearchTextField.getSelectionStart();
-                mUserQuerySelEnd = mSearchTextField.getSelectionEnd();
-                // then update the query to match the entered selection
-                jamSuggestionQuery(true, mSuggestionsList, 
-                                    mSuggestionsList.getSelectedItemPosition());
-            } else {
-                // Exiting the list view
-                
-                if (mSuggestionsList.getSelectedItemPosition() < 0) {
-                    // Direct exit - Leave new suggestion in place (do nothing)
-                } else {
-                    // Navigation exit - restore user's query text
-                    if (!mLeaveJammedQueryOnRefocus) {
-                        jamSuggestionQuery(false, null, -1);
-                    }
-                }
-            }
-
-        }
-    };
-    */
-    
-    /**
-     * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent.  It's an indication that
-     * we should close ourselves immediately, in order to allow a higher-priority UI to take over
+     * When the ACTION_CLOSE_SYSTEM_DIALOGS intent is received, we should close ourselves 
+     * immediately, in order to allow a higher-priority UI to take over
      * (e.g. phone call received).
+     * 
+     * When a package is added, removed or changed, our current context
+     * may no longer be valid.  This would only happen if a package is installed/removed exactly
+     * when the search bar is open.  So for now we're just going to close the search
+     * bar.  
+     * Anything fancier would require some checks to see if the user's context was still valid.
+     * Which would be messier.
      */
     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -918,7 +905,7 @@
             } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)
                     || Intent.ACTION_PACKAGE_REMOVED.equals(action)
                     || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
-                onPackageListChange();
+                cancel();
             }
         }
     };
@@ -938,58 +925,45 @@
     }
     
     /**
-     * Various ways to launch searches
+     * React to the user typing while in the suggestions list. First, check for action
+     * keys. If not handled, try refocusing regular characters into the EditText. 
      */
-
-    /**
-     * React to the user clicking the "GO" button.  Hide the UI and launch a search.
-     *
-     * @param actionKey Pass a keycode if the launch was triggered by an action key.  Pass
-     * KeyEvent.KEYCODE_UNKNOWN for no actionKey code.
-     * @param actionMsg Pass the suggestion-provided message if the launch was triggered by an
-     * action key.  Pass null for no actionKey message.
-     */
-    private void launchQuerySearch(int actionKey, final String actionMsg)  {
-        final String query = mSearchTextField.getText().toString();
-        final Bundle appData = mAppSearchData;
-        final SearchableInfo si = mSearchable;      // cache briefly (dismiss() nulls it)
-        dismiss();
-        sendLaunchIntent(Intent.ACTION_SEARCH, null, query, appData, actionKey, actionMsg, si);
-    }
-
-    /**
-     * React to the user typing an action key while in the suggestions list
-     */
-    private boolean doSuggestionsKey(View v, int keyCode, KeyEvent event) {
-        // Exit early in case of race condition
+    private boolean onSuggestionsKey(View v, int keyCode, KeyEvent event) {
+        // guard against possible race conditions (late arrival after dismiss)
+        if (mSearchable == null) {
+            return false;
+        }
         if (mSuggestionsAdapter == null) {
             return false;
         }
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
-            if (DBG_LOG_TIMING == 1) {
-                dbgLogTiming("doSuggestionsKey()");
+            if (DBG_LOG_TIMING) {
+                dbgLogTiming("onSuggestionsKey()");
             }
             
             // First, check for enter or search (both of which we'll treat as a "click")
             if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH) {
-                int position = mSearchTextField.getListSelection();
-                return launchSuggestion(mSuggestionsAdapter, position);
+                int position = mSearchAutoComplete.getListSelection();
+                return launchSuggestion(position);
             }
             
             // Next, check for left/right moves, which we use to "return" the user to the edit view
             if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
-                // give "focus" to text editor, but don't restore the user's original query
+                // give "focus" to text editor, with cursor at the beginning if
+                // left key, at end if right key
+                // TODO: Reverse left/right for right-to-left languages, e.g. Arabic
                 int selPoint = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ? 
-                        0 : mSearchTextField.length();
-                mSearchTextField.setSelection(selPoint);
-                mSearchTextField.setListSelection(0);
-                mSearchTextField.clearListSelection();
+                        0 : mSearchAutoComplete.length();
+                mSearchAutoComplete.setSelection(selPoint);
+                mSearchAutoComplete.setListSelection(0);
+                mSearchAutoComplete.clearListSelection();
                 return true;
             }
             
             // Next, check for an "up and out" move
-            if (keyCode == KeyEvent.KEYCODE_DPAD_UP && 0 == mSearchTextField.getListSelection()) {
-                jamSuggestionQuery(false, null, -1);
+            if (keyCode == KeyEvent.KEYCODE_DPAD_UP 
+                    && 0 == mSearchAutoComplete.getListSelection()) {
+                restoreUserQuery();
                 // let ACTV complete the move
                 return false;
             }
@@ -999,222 +973,239 @@
             if ((actionKey != null) && 
                     ((actionKey.mSuggestActionMsg != null) || 
                      (actionKey.mSuggestActionMsgColumn != null))) {
-                //   launch suggestion using action key column
-                int position = mSearchTextField.getListSelection();
-                if (position >= 0) {
+                // launch suggestion using action key column
+                int position = mSearchAutoComplete.getListSelection();
+                if (position != ListView.INVALID_POSITION) {
                     Cursor c = mSuggestionsAdapter.getCursor();
                     if (c.moveToPosition(position)) {
                         final String actionMsg = getActionKeyMessage(c, actionKey);
                         if (actionMsg != null && (actionMsg.length() > 0)) {
-                            // shut down search bar and launch the activity
-                            // cache everything we need because dismiss releases mems
-                            setupSuggestionIntent(c, mSearchable);
-                            final String query = mSearchTextField.getText().toString();
-                            final Bundle appData =  mAppSearchData;
-                            SearchableInfo si = mSearchable;
-                            String suggestionAction = mSuggestionAction;
-                            Uri suggestionData = mSuggestionData;
-                            String suggestionQuery = mSuggestionQuery;
-                            dismiss();
-                            sendLaunchIntent(suggestionAction, suggestionData,
-                                    suggestionQuery, appData,
-                                             keyCode, actionMsg, si);
-                            return true;
+                            return launchSuggestion(position, keyCode, actionMsg);
                         }
                     }
                 }
             }
         }
         return false;
-    }    
-
+    }
+    
     /**
-     * Set or reset the user query to follow the selections in the suggestions
-     * 
-     * @param jamQuery True means to set the query, false means to reset it to the user's choice
+     * Launch a search for the text in the query text field.
      */
-    private void jamSuggestionQuery(boolean jamQuery, AdapterView<?> parent, int position) {
-        // quick check against race conditions
-        if (mSearchable == null) {
-            return;
-        }
-        
-        mSuggestionsAdapter.setNonUserQuery(true);       // disables any suggestions processing
-        if (jamQuery) {
-            CursorAdapter ca = getSuggestionsAdapter(parent);
-            Cursor c = ca.getCursor();
-            if (c.moveToPosition(position)) {
-                setupSuggestionIntent(c, mSearchable);
-                String jamText = null;
-
-                // Simple heuristic for selecting text with which to rewrite the query.
-                if (mSuggestionQuery != null) {
-                    jamText = mSuggestionQuery;
-                } else if (mSearchable.mQueryRewriteFromData && (mSuggestionData != null)) {
-                    jamText = mSuggestionData.toString();
-                } else if (mSearchable.mQueryRewriteFromText) {
-                    try {
-                        int column = c.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_TEXT_1);
-                        jamText = c.getString(column);
-                    } catch (RuntimeException e) {
-                        // no work here, jamText is null
-                    }
-                }
-                if (jamText != null) {
-                    mSearchTextField.setText(jamText);
-                    /* mSearchTextField.selectAll(); */ // this didn't work anyway in the old UI
-                    // TODO this is only needed in the model where we have a selection in the ACTV
-                    // and in the dropdown at the same time.
-                    mSearchTextField.setSelection(jamText.length());
-                }
-            }
-        } else {
-            // reset user query
-            mSearchTextField.setText(mUserQuery);
-            try {
-                mSearchTextField.setSelection(mUserQuerySelStart, mUserQuerySelEnd);
-            } catch (IndexOutOfBoundsException e) {
-                // In case of error, just select all
-                Log.e(LOG_TAG, "Caught IndexOutOfBoundsException while setting selection.  " +
-                        "start=" + mUserQuerySelStart + " end=" + mUserQuerySelEnd +
-                        " text=\"" + mUserQuery + "\"");
-                mSearchTextField.selectAll();
-            }
-        }
-        // TODO because the new query is (not) processed in another thread, we can't just
-        // take away this flag (yet).  The better solution here is going to require a new API
-        // in AutoCompleteTextView which allows us to change the text w/o changing the suggestions.
-//      mSuggestionsAdapter.setNonUserQuery(false);
+    protected void launchQuerySearch()  {
+        launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null);
     }
 
     /**
-     * Assemble a search intent and send it.
+     * Launch a search for the text in the query text field.
      *
-     * @param action The intent to send, typically Intent.ACTION_SEARCH
-     * @param data The data for the intent
-     * @param query The user text entered (so far)
-     * @param appData The app data bundle (if supplied)
-     * @param actionKey If the intent was triggered by an action key, e.g. KEYCODE_CALL, it will
-     * be sent here.  Pass KeyEvent.KEYCODE_UNKNOWN for no actionKey code.
-     * @param actionMsg If the intent was triggered by an action key, e.g. KEYCODE_CALL, the
-     * corresponding tag message will be sent here.  Pass null for no actionKey message.
-     * @param si Reference to the current SearchableInfo.  Passed here so it can be used even after
-     * we've called dismiss(), which attempts to null mSearchable.
+     * @param actionKey The key code of the action key that was pressed,
+     *        or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
+     * @param actionMsg The message for the action key that was pressed,
+     *        or <code>null</code> if none.
      */
-    private void sendLaunchIntent(final String action, final Uri data, final String query,
-            final Bundle appData, int actionKey, final String actionMsg, final SearchableInfo si) {
-        Intent launcher = new Intent(action);
-
-        if (query != null) {
-            launcher.putExtra(SearchManager.QUERY, query);
-        }
-
-        if (data != null) {
-            launcher.setData(data);
-        }
-
-        if (appData != null) {
-            launcher.putExtra(SearchManager.APP_DATA, appData);
-        }
-
-        // add launch info (action key, etc.)
-        if (actionKey != KeyEvent.KEYCODE_UNKNOWN) {
-            launcher.putExtra(SearchManager.ACTION_KEY, actionKey);
-            launcher.putExtra(SearchManager.ACTION_MSG, actionMsg);
-        }
-
-        // attempt to enforce security requirement (no 3rd-party intents)
-        launcher.setComponent(si.mSearchActivity);
-
-        getContext().startActivity(launcher);
+    protected void launchQuerySearch(int actionKey, String actionMsg)  {
+        String query = mSearchAutoComplete.getText().toString();
+        Intent intent = createIntent(Intent.ACTION_SEARCH, null, query, null, 
+                actionKey, actionMsg);
+        launchIntent(intent);
     }
-
+    
     /**
-     * Shared code for launching a query from a suggestion.
-     * @param ca The cursor adapter containing the suggestions
-     * @param position The suggestion we'll be launching from
-     * @return true if a successful launch, false if could not (e.g. bad position)
+     * Launches an intent based on a suggestion.
+     * 
+     * @param position The index of the suggestion to create the intent from.
+     * @return true if a successful launch, false if could not (e.g. bad position).
      */
-    private boolean launchSuggestion(CursorAdapter ca, int position) {
-        Cursor c = ca.getCursor();
+    protected boolean launchSuggestion(int position) {
+        return launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null);
+    }
+    
+    /**
+     * Launches an intent based on a suggestion.
+     * 
+     * @param position The index of the suggestion to create the intent from.
+     * @param actionKey The key code of the action key that was pressed,
+     *        or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
+     * @param actionMsg The message for the action key that was pressed,
+     *        or <code>null</code> if none.
+     * @return true if a successful launch, false if could not (e.g. bad position).
+     */
+    protected boolean launchSuggestion(int position, int actionKey, String actionMsg) {
+        Cursor c = mSuggestionsAdapter.getCursor();
         if ((c != null) && c.moveToPosition(position)) {
-            setupSuggestionIntent(c, mSearchable);
-            
-            final Bundle appData =  mAppSearchData;
-            SearchableInfo si = mSearchable;
-            String suggestionAction = mSuggestionAction;
-            Uri suggestionData = mSuggestionData;
-            String suggestionQuery = mSuggestionQuery;
-            dismiss();
-            sendLaunchIntent(suggestionAction, suggestionData, suggestionQuery, appData,
-                                KeyEvent.KEYCODE_UNKNOWN, null, si);
+            Intent intent = createIntentFromSuggestion(c, actionKey, actionMsg);
+            launchIntent(intent);
             return true;
         }
         return false;
     }
     
     /**
+     * Launches an intent. Also dismisses the search dialog if not in global search mode.
+     */
+    private void launchIntent(Intent intent) {
+        if (intent == null) {
+            return;
+        }
+        if (handleSpecialIntent(intent)){
+            return;
+        }
+        if (!mGlobalSearchMode) {
+            dismiss();
+        }
+        getContext().startActivity(intent);
+    }
+    
+    /**
+     * Handles the special intent actions declared in {@link SearchManager}.
+     * 
+     * @return <code>true</code> if the intent was handled.
+     */
+    private boolean handleSpecialIntent(Intent intent) {
+        String action = intent.getAction();
+        if (SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE.equals(action)) {
+            handleChangeSourceIntent(intent);
+            return true;
+        } else if (SearchManager.INTENT_ACTION_CURSOR_RESPOND.equals(action)) {
+            handleCursorRespondIntent(intent);
+            return true;
+        }
+        return false;
+    }
+    
+    /**
+     * Handles SearchManager#INTENT_ACTION_CHANGE_SOURCE.
+     */
+    private void handleChangeSourceIntent(Intent intent) {
+        Uri dataUri = intent.getData();
+        if (dataUri == null) {
+            Log.w(LOG_TAG, "SearchManager.INTENT_ACTION_CHANGE_SOURCE without intent data.");
+            return;
+        }
+        ComponentName componentName = ComponentName.unflattenFromString(dataUri.toString());
+        if (componentName == null) {
+            Log.w(LOG_TAG, "Invalid ComponentName: " + dataUri);
+            return;
+        }
+        if (DBG) Log.d(LOG_TAG, "Switching to " + componentName);
+        
+        ComponentName previous = mLaunchComponent;
+        if (!show(componentName, mAppSearchData, false)) {
+            Log.w(LOG_TAG, "Failed to switch to source " + componentName);
+            return;
+        }
+        pushPreviousComponent(previous);
+
+        String query = intent.getStringExtra(SearchManager.QUERY);
+        setUserQuery(query);
+    }
+    
+    /**
+     * Handles {@link SearchManager#INTENT_ACTION_CURSOR_RESPOND}.
+     */
+    private void handleCursorRespondIntent(Intent intent) {
+        Cursor c = mSuggestionsAdapter.getCursor();
+        if (c != null) {
+            c.respond(intent.getExtras());
+        }
+    }
+    
+    /**
+     * Saves the previous component that was searched, so that we can go
+     * back to it.
+     */
+    private void pushPreviousComponent(ComponentName componentName) {
+        if (mPreviousComponents == null) {
+            mPreviousComponents = new ArrayList<ComponentName>();
+        }
+        mPreviousComponents.add(componentName);
+    }
+    
+    /**
+     * Pops the previous component off the stack and returns it.
+     * 
+     * @return The component name, or <code>null</code> if there was
+     *         no previous component.
+     */
+    private ComponentName popPreviousComponent() {
+        if (mPreviousComponents == null) {
+            return null;
+        }
+        int size = mPreviousComponents.size();
+        if (size == 0) {
+            return null;
+        }
+        return mPreviousComponents.remove(size - 1);
+    }
+    
+    /**
+     * Goes back to the previous component that was searched, if any.
+     * 
+     * @return <code>true</code> if there was a previous component that we could go back to.
+     */
+    private boolean backToPreviousComponent() {
+        ComponentName previous = popPreviousComponent();
+        if (previous == null) {
+            return false;
+        }
+        if (!show(previous, mAppSearchData, false)) {
+            Log.w(LOG_TAG, "Failed to switch to source " + previous);
+            return false;
+        }
+        
+        // must touch text to trigger suggestions
+        // TODO: should this be the text as it was when the user left
+        // the source that we are now going back to?
+        String query = mSearchAutoComplete.getText().toString();
+        setUserQuery(query);
+        
+        return true;
+    }
+    
+    /**
      * When a particular suggestion has been selected, perform the various lookups required
      * to use the suggestion.  This includes checking the cursor for suggestion-specific data,
      * and/or falling back to the XML for defaults;  It also creates REST style Uri data when
      * the suggestion includes a data id.
      * 
-     * NOTE:  Return values are in member variables mSuggestionAction & mSuggestionData.
-     * 
      * @param c The suggestions cursor, moved to the row of the user's selection
-     * @param si The searchable activity's info record
+     * @param actionKey The key code of the action key that was pressed,
+     *        or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
+     * @param actionMsg The message for the action key that was pressed,
+     *        or <code>null</code> if none.
+     * @return An intent for the suggestion at the cursor's position.
      */
-    void setupSuggestionIntent(Cursor c, SearchableInfo si) {
+    private Intent createIntentFromSuggestion(Cursor c, int actionKey, String actionMsg) {
         try {
             // use specific action if supplied, or default action if supplied, or fixed default
-            mSuggestionAction = null;
-            int mColumn = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_INTENT_ACTION);
-            if (mColumn >= 0) {
-                final String action = c.getString(mColumn);
-                if (action != null) {
-                    mSuggestionAction = action;
-                }
+            String action = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_ACTION);
+            if (action == null) {
+                action = mSearchable.getSuggestIntentAction();
             }
-            if (mSuggestionAction == null) {
-                mSuggestionAction = si.getSuggestIntentAction();
-            }
-            if (mSuggestionAction == null) {
-                mSuggestionAction = Intent.ACTION_SEARCH;
+            if (action == null) {
+                action = Intent.ACTION_SEARCH;
             }
             
             // use specific data if supplied, or default data if supplied
-            String data = null;
-            mColumn = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_INTENT_DATA);
-            if (mColumn >= 0) {
-                final String rowData = c.getString(mColumn);
-                if (rowData != null) {
-                    data = rowData;
-                }
-            }
+            String data = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA);
             if (data == null) {
-                data = si.getSuggestIntentData();
+                data = mSearchable.getSuggestIntentData();
             }
-            
             // then, if an ID was provided, append it.
             if (data != null) {
-                mColumn = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
-                if (mColumn >= 0) {
-                    final String id = c.getString(mColumn);
-                    if (id != null) {
-                        data = data + "/" + Uri.encode(id);
-                    }
+                String id = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
+                if (id != null) {
+                    data = data + "/" + Uri.encode(id);
                 }
             }
-            mSuggestionData = (data == null) ? null : Uri.parse(data);
+            Uri dataUri = (data == null) ? null : Uri.parse(data);
+
+            String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
             
-            mSuggestionQuery = null;
-            mColumn = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY);
-            if (mColumn >= 0) {
-                final String query = c.getString(mColumn);
-                if (query != null) {
-                    mSuggestionQuery = query;
-                }
-            }
+            String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY);
+
+            return createIntent(action, dataUri, query, extraData, actionKey, actionMsg);
         } catch (RuntimeException e ) {
             int rowNum;
             try {                       // be really paranoid now
@@ -1224,10 +1215,49 @@
             }
             Log.w(LOG_TAG, "Search Suggestions cursor at row " + rowNum + 
                             " returned exception" + e.toString());
+            return null;
         }
     }
     
     /**
+     * Constructs an intent from the given information and the search dialog state.
+     * 
+     * @param action Intent action.
+     * @param data Intent data, or <code>null</code>.
+     * @param query Intent query, or <code>null</code>.
+     * @param extraData Data for {@link SearchManager#EXTRA_DATA_KEY} or <code>null</code>.
+     * @param actionKey The key code of the action key that was pressed,
+     *        or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
+     * @param actionMsg The message for the action key that was pressed,
+     *        or <code>null</code> if none.
+     * @return The intent.
+     */
+    private Intent createIntent(String action, Uri data, String query, String extraData,
+            int actionKey, String actionMsg) {
+        // Now build the Intent
+        Intent intent = new Intent(action);
+        if (data != null) {
+            intent.setData(data);
+        }
+        if (query != null) {
+            intent.putExtra(SearchManager.QUERY, query);
+        }
+        if (extraData != null) {
+            intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData);
+        }
+        if (mAppSearchData != null) {
+            intent.putExtra(SearchManager.APP_DATA, mAppSearchData);
+        }
+        if (actionKey != KeyEvent.KEYCODE_UNKNOWN) {
+            intent.putExtra(SearchManager.ACTION_KEY, actionKey);
+            intent.putExtra(SearchManager.ACTION_MSG, actionMsg);
+        }
+        // attempt to enforce security requirement (no 3rd-party intents)
+        intent.setComponent(mSearchable.mSearchActivity);
+        return intent;
+    }
+    
+    /**
      * For a given suggestion and a given cursor row, get the action message.  If not provided
      * by the specific row/column, also check for a single definition (for the action key).
      * 
@@ -1236,17 +1266,12 @@
      * 
      * @return Returns a string, or null if no action key message for this suggestion
      */
-    private String getActionKeyMessage(Cursor c, final SearchableInfo.ActionKeyInfo actionKey) {
+    private static String getActionKeyMessage(Cursor c, SearchableInfo.ActionKeyInfo actionKey) {
         String result = null;
         // check first in the cursor data, for a suggestion-specific message
         final String column = actionKey.mSuggestActionMsgColumn;
         if (column != null) {
-            try {
-                int colId = c.getColumnIndexOrThrow(column);
-                result = c.getString(colId);
-            } catch (RuntimeException e) {
-                // OK - result is already null
-            }
+            result = SuggestionsAdapter.getColumnString(c, column);
         }
         // If the cursor didn't give us a message, see if there's a single message defined
         // for the actionkey (for all suggestions)
@@ -1257,343 +1282,178 @@
     }
         
     /**
-     * Local subclass for AutoCompleteTextView
-     * 
-     * This exists entirely to override the threshold method.  Otherwise we just use the class
-     * as-is.
+     * Local subclass for AutoCompleteTextView.
      */
     public static class SearchAutoComplete extends AutoCompleteTextView {
 
+        private int mThreshold;
+        private SearchDialog mSearchDialog;
+        
         public SearchAutoComplete(Context context) {
             super(null);
+            mThreshold = getThreshold();
         }
         
         public SearchAutoComplete(Context context, AttributeSet attrs) {
             super(context, attrs);
+            mThreshold = getThreshold();
         }
 
         public SearchAutoComplete(Context context, AttributeSet attrs, int defStyle) {
             super(context, attrs, defStyle);
+            mThreshold = getThreshold();
+        }
+
+        private void setSearchDialog(SearchDialog searchDialog) {
+            mSearchDialog = searchDialog;
+        }
+        
+        @Override
+        public void setThreshold(int threshold) {
+            super.setThreshold(threshold);
+            mThreshold = threshold;
+        }
+
+        /**
+         * Returns true if the text field is empty, or contains only whitespace.
+         */
+        private boolean isEmpty() {
+            return TextUtils.getTrimmedLength(getText()) == 0;
         }
         
         /**
-         * We never allow ACTV to automatically replace the text, since we use "jamSuggestionQuery"
-         * to do that.  There's no point in letting ACTV do this here, because in the search UI,
-         * as soon as we click a suggestion, we're going to start shutting things down.
+         * Clears the entered text.
+         */
+        private void clear() {
+            setText("");
+        }
+        
+        /**
+         * We override this method to avoid replacing the query box text
+         * when a suggestion is clicked.
          */
         @Override
-        public void replaceText(CharSequence text) {
+        protected void replaceText(CharSequence text) {
         }
         
         /**
-         * We always return true, so that the effective threshold is "zero".  This allows us
-         * to provide "null" suggestions such as "just show me some recent entries".
+         * We override this method so that we can allow a threshold of zero, which ACTV does not.
          */
         @Override
         public boolean enoughToFilter() {
-            return true;
+            return mThreshold <= 0 || super.enoughToFilter();
+        }
+        
+        /**
+         * {@link AutoCompleteTextView#onKeyPreIme(int, KeyEvent)}) dismisses the drop-down on BACK,
+         * so we must override this method to modify the BACK behavior.
+         */
+        @Override
+        public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+            return mSearchDialog.handleBackKey(keyCode, event);
         }
     }
     
-    /**
-     * Support for AutoCompleteTextView-based suggestions
-     */
-    /**
-     * This class provides the filtering-based interface to suggestions providers.
-     * It is hardwired in a couple of places to support GoogleSearch - for example, it supports
-     * two-line suggestions, but it does not support icons.
-     */
-    private static class SuggestionsAdapter extends SimpleCursorAdapter {
-        private final String TAG = "SuggestionsAdapter";
-        
-        SearchableInfo mSearchable;
-        private Resources mProviderResources;
-        
-        // These private variables are shared by the filter thread and must be protected
-        private WeakReference<Cursor> mRecentCursor = new WeakReference<Cursor>(null);
-        private boolean mNonUserQuery = false;
-        private AutoCompleteTextView mParentView;
-
-        public SuggestionsAdapter(Context context, SearchableInfo searchable,
-                AutoCompleteTextView actv) {
-            super(context, -1, null, null, null);
-            mSearchable = searchable;
-            mParentView = actv;
-            
-            // set up provider resources (gives us icons, etc.)
-            Context activityContext = mSearchable.getActivityContext(mContext);
-            Context providerContext = mSearchable.getProviderContext(mContext, activityContext);
-            mProviderResources = providerContext.getResources();
+    protected boolean handleBackKey(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
+            mSearchAutoComplete.dismissDropDown();
+            if (backToPreviousComponent()) {
+                return true;
+            }
+            if (!mSearchAutoComplete.isEmpty()) {
+                mSearchAutoComplete.clear();
+                return true;
+            }
+            cancel();
+            return true;
         }
-        
-        /**
-         * Set this field (temporarily!) to disable suggestions updating.  This allows us
-         * to change the string in the text view without changing the suggestions list.
-         */
-        public void setNonUserQuery(boolean nonUserQuery) {
-            synchronized (this) {
-                mNonUserQuery = nonUserQuery;
-            }
-        }
-        
-        public boolean getNonUserQuery() {
-            synchronized (this) {
-                return mNonUserQuery;
-            }
-        }
-
-        /**
-         * Use the search suggestions provider to obtain a live cursor.  This will be called
-         * in a worker thread, so it's OK if the query is slow (e.g. round trip for suggestions).
-         * The results will be processed in the UI thread and changeCursor() will be called.
-         * 
-         * In order to provide the Search Mgr functionality of seeing your query change as you
-         * scroll through the list, we have to be able to jam new text into the string without
-         * retriggering the suggestions.  We do that here via the "nonUserQuery" flag.  In that
-         * case we simply return the existing cursor.
-         * 
-         * TODO: Dianne suggests that this should simply be promoted into an AutoCompleteTextView
-         * behavior (perhaps optionally).
-         * 
-         * TODO: The "nonuserquery" logic has a race condition because it happens in another thread.
-         * This also needs to be fixed.
-         */
-        @Override
-        public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
-            String query = (constraint == null) ? "" : constraint.toString();
-            Cursor c = null;
-            synchronized (this) {
-                if (mNonUserQuery) {
-                    c = mRecentCursor.get();
-                    mNonUserQuery = false;
-                }
-            }
-            if (c == null) {
-                c = getSuggestions(mSearchable, query);
-                synchronized (this) {
-                    mRecentCursor = new WeakReference<Cursor>(c);
-                }
-            }
-            return c;
-        }
-        
-        /**
-         * Overriding changeCursor() allows us to change not only the cursor, but by sampling
-         * the cursor's columns, the actual display characteristics of the list.
-         */
-        @Override
-        public void changeCursor(Cursor c) {
-            
-            // first, check for various conditions that disqualify this cursor
-            if ((c == null) || (c.getCount() == 0)) {
-                // no cursor, or cursor with no data
-                changeCursorAndColumns(null, null, null);
-                if (c != null) {
-                    c.close();
-                }
-                return;
-            }
-
-            // check cursor before trying to create list views from it
-            int colId = c.getColumnIndex("_id");
-            int col1 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
-            int col2 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2);
-            int colIc1 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
-            int colIc2 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2);
-
-            boolean minimal = (colId >= 0) && (col1 >= 0);
-            boolean hasIcons = (colIc1 >= 0) && (colIc2 >= 0);
-            boolean has2Lines = col2 >= 0;
-
-            if (minimal) {
-                int layout;
-                String[] from;
-                int[] to;
-
-                if (hasIcons) {
-                    if (has2Lines) {
-                        layout = com.android.internal.R.layout.search_dropdown_item_icons_2line;
-                        from = TWO_LINE_ICONS_FROM;
-                        to = TWO_LINE_ICONS_TO;
-                    } else {
-                        layout = com.android.internal.R.layout.search_dropdown_item_icons_1line;
-                        from = ONE_LINE_ICONS_FROM;
-                        to = ONE_LINE_ICONS_TO;
-                    }
-                } else {
-                    if (has2Lines) {
-                        layout = com.android.internal.R.layout.search_dropdown_item_2line;
-                        from = TWO_LINE_FROM;
-                        to = TWO_LINE_TO;
-                    } else {
-                        layout = com.android.internal.R.layout.search_dropdown_item_1line;
-                        from = ONE_LINE_FROM;
-                        to = ONE_LINE_TO;
-                    }
-                }
-                // Force the underlying ListView to discard and reload all layouts
-                // (Note, this should be optimized for cases where layout/cursor remain same)
-                mParentView.resetListAndClearViews();
-                // Now actually set up the cursor, columns, and the list view
-                changeCursorAndColumns(c, from, to);
-                setViewResource(layout);          
-            } else {
-                // Provide some help for developers instead of just silently discarding
-                Log.w(LOG_TAG, "Suggestions cursor discarded due to missing required columns.");
-                changeCursorAndColumns(null, null, null);
-                c.close();
-            }
-            if ((colIc1 >= 0) != (colIc2 >= 0)) {
-                Log.w(LOG_TAG, "Suggestion icon column(s) discarded, must be 0 or 2 columns.");
-            }    
-        }
-        
-        /**
-         * Overriding this allows us to write the selected query back into the box.
-         * NOTE:  This is a vastly simplified version of SearchDialog.jamQuery() and does
-         * not universally support the search API.  But it is sufficient for Google Search.
-         */
-        @Override
-        public CharSequence convertToString(Cursor cursor) {
-            CharSequence result = null;
-            if (cursor != null) {
-                int column = cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY);
-                if (column >= 0) {
-                    final String query = cursor.getString(column);
-                    if (query != null) {
-                        result = query;
-                    }
-                }
-            }
-            return result;
-        }
-
-        /**
-         * Get the query cursor for the search suggestions.
-         * 
-         * TODO this is functionally identical to the version in SearchDialog.java.  Perhaps it 
-         * could be hoisted into SearchableInfo or some other shared spot.
-         * 
-         * @param query The search text entered (so far)
-         * @return Returns a cursor with suggestions, or null if no suggestions 
-         */
-        private Cursor getSuggestions(final SearchableInfo searchable, final String query) {
-            Cursor cursor = null;
-            if (searchable.getSuggestAuthority() != null) {
-                try {
-                    StringBuilder uriStr = new StringBuilder("content://");
-                    uriStr.append(searchable.getSuggestAuthority());
-
-                    // if content path provided, insert it now
-                    final String contentPath = searchable.getSuggestPath();
-                    if (contentPath != null) {
-                        uriStr.append('/');
-                        uriStr.append(contentPath);
-                    }
-
-                    // append standard suggestion query path 
-                    uriStr.append('/' + SearchManager.SUGGEST_URI_PATH_QUERY);
-
-                    // inject query, either as selection args or inline
-                    String[] selArgs = null;
-                    if (searchable.getSuggestSelection() != null) {    // use selection if provided
-                        selArgs = new String[] {query};
-                    } else {
-                        uriStr.append('/');                             // no sel, use REST pattern
-                        uriStr.append(Uri.encode(query));
-                    }
-
-                    // finally, make the query
-                    cursor = mContext.getContentResolver().query(
-                                                        Uri.parse(uriStr.toString()), null, 
-                                                        searchable.getSuggestSelection(), selArgs,
-                                                        null);
-                } catch (RuntimeException e) {
-                    Log.w(TAG, "Search Suggestions query returned exception " + e.toString());
-                    cursor = null;
-                }
-            }
-            
-            return cursor;
-        }
-
-        /**
-         * Overriding this allows us to affect the way that an icon is loaded.  Specifically,
-         * we can be more controlling about the resource path (and allow icons to come from other
-         * packages).
-         * 
-         * TODO: This is 100% identical to the version in SearchDialog.java
-         *
-         * @param v ImageView to receive an image
-         * @param value the value retrieved from the cursor
-         */
-        @Override
-        public void setViewImage(ImageView v, String value) {
-            int resID;
-            Drawable img = null;
-
-            try {
-                resID = Integer.parseInt(value);
-                if (resID != 0) {
-                    img = mProviderResources.getDrawable(resID);
-                }
-            } catch (NumberFormatException nfe) {
-                // img = null;
-            } catch (NotFoundException e2) {
-                // img = null;
-            }
-            
-            // finally, set the image to whatever we've gotten
-            v.setImageDrawable(img);
-        }
-        
-        /**
-         * This method is overridden purely to provide a bit of protection against
-         * flaky content providers.
-         * 
-         * TODO: This is 100% identical to the version in SearchDialog.java
-         * 
-         * @see android.widget.ListAdapter#getView(int, View, ViewGroup)
-         */
-        @Override 
-        public View getView(int position, View convertView, ViewGroup parent) {
-            try {
-                return super.getView(position, convertView, parent);
-            } catch (RuntimeException e) {
-                Log.w(TAG, "Search Suggestions cursor returned exception " + e.toString());
-                // what can I return here?
-                View v = newView(mContext, mCursor, parent);
-                if (v != null) {
-                    TextView tv = (TextView) v.findViewById(com.android.internal.R.id.text1);
-                    tv.setText(e.toString());
-                }
-                return v;
-            }
-        }
-
+        return false;
     }
     
     /**
      * Implements OnItemClickListener
      */
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        // Log.d(LOG_TAG, "onItemClick() position " + position);
-        launchSuggestion(mSuggestionsAdapter, position);
+        if (DBG) Log.d(LOG_TAG, "onItemClick() position " + position);
+        launchSuggestion(position);
     }
-    
+
     /** 
      * Implements OnItemSelectedListener
      */
      public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-         // Log.d(LOG_TAG, "onItemSelected() position " + position);
-         jamSuggestionQuery(true, parent, position);
+         if (DBG) Log.d(LOG_TAG, "onItemSelected() position " + position);
+         // A suggestion has been selected, rewrite the query if possible,
+         // otherwise the restore the original query.
+         if (REWRITE_QUERIES) {
+             rewriteQueryFromSuggestion(position);
+         }
      }
 
      /** 
       * Implements OnItemSelectedListener
       */
      public void onNothingSelected(AdapterView<?> parent) {
-         // Log.d(LOG_TAG, "onNothingSelected()");
+         if (DBG) Log.d(LOG_TAG, "onNothingSelected()");
+     }
+     
+     /**
+      * Query rewriting.
+      */
+
+     private void rewriteQueryFromSuggestion(int position) {
+         Cursor c = mSuggestionsAdapter.getCursor();
+         if (c == null) {
+             return;
+         }
+         if (c.moveToPosition(position)) {
+             // Get the new query from the suggestion.
+             CharSequence newQuery = mSuggestionsAdapter.convertToString(c);
+             if (newQuery != null) {
+                 // The suggestion rewrites the query.
+                 if (DBG) Log.d(LOG_TAG, "Rewriting query to '" + newQuery + "'");
+                 // Update the text field, without getting new suggestions.
+                 setQuery(newQuery);
+             } else {
+                 // The suggestion does not rewrite the query, restore the user's query.
+                 if (DBG) Log.d(LOG_TAG, "Suggestion gives no rewrite, restoring user query.");
+                 restoreUserQuery();
+             }
+         } else {
+             // We got a bad position, restore the user's query.
+             Log.w(LOG_TAG, "Bad suggestion position: " + position);
+             restoreUserQuery();
+         }
+     }
+     
+     /** 
+      * Restores the query entered by the user if needed.
+      */
+     private void restoreUserQuery() {
+         if (DBG) Log.d(LOG_TAG, "Restoring query to '" + mUserQuery + "'");
+         setQuery(mUserQuery);
+     }
+     
+     /**
+      * Sets the text in the query box, without updating the suggestions.
+      */
+     private void setQuery(CharSequence query) {
+         mSearchAutoComplete.setText(query, false);
+         if (query != null) {
+             mSearchAutoComplete.setSelection(query.length());
+         }
+     }
+     
+     /**
+      * Sets the text in the query box, updating the suggestions.
+      */
+     private void setUserQuery(String query) {
+         if (query == null) {
+             query = "";
+         }
+         mUserQuery = query;
+         mSearchAutoComplete.setText(query);
+         mSearchAutoComplete.setSelection(query.length());
      }
 
     /**
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index ecdd3f8..3e9f3dd 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -17,12 +17,17 @@
 package android.app;
 
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.Configuration;
+import android.database.Cursor;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.server.search.SearchableInfo;
 import android.view.KeyEvent;
 
 /**
@@ -439,20 +444,18 @@
  *     
  *     <tr><th>{@link #SUGGEST_COLUMN_ICON_1}</th>
  *         <td>If your cursor includes this column, then all suggestions will be provided in an
- *             icons+text format.  This value should be a reference (resource ID) of the icon to
+ *             icons+text format.  This value should be a reference to the icon to
  *             draw on the left side, or it can be null or zero to indicate no icon in this row.
- *             You must provide both cursor columns, or neither.
  *             </td>
- *         <td align="center">No, but required if you also have {@link #SUGGEST_COLUMN_ICON_2}</td>
+ *         <td align="center">No.</td>
  *     </tr>
  *     
  *     <tr><th>{@link #SUGGEST_COLUMN_ICON_2}</th>
  *         <td>If your cursor includes this column, then all suggestions will be provided in an
- *             icons+text format.  This value should be a reference (resource ID) of the icon to
+ *             icons+text format.  This value should be a reference to the icon to
  *             draw on the right side, or it can be null or zero to indicate no icon in this row.
- *             You must provide both cursor columns, or neither.
  *             </td>
- *         <td align="center">No, but required if you also have {@link #SUGGEST_COLUMN_ICON_1}</td>
+ *         <td align="center">No.</td>
  *     </tr>
  *     
  *     <tr><th>{@link #SUGGEST_COLUMN_INTENT_ACTION}</th>
@@ -1155,6 +1158,13 @@
     public final static String ACTION_KEY = "action_key";
     
     /**
+     * Intent extra data key: This key will be used for the extra populated by the
+     * {@link #SUGGEST_COLUMN_INTENT_EXTRA_DATA} column.
+     * {@hide}
+     */
+    public final static String EXTRA_DATA_KEY = "intent_extra_data_key";
+    
+    /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getStringExtra content.Intent.getStringExtra()}
      * to obtain the action message that was defined for a particular search action key and/or
@@ -1195,21 +1205,59 @@
     public final static String SUGGEST_COLUMN_TEXT_2 = "suggest_text_2";
     /**
      * Column name for suggestions cursor.  <i>Optional.</i>  If your cursor includes this column,
-     *  then all suggestions will be provided in format that includes space for two small icons,
+     *  then all suggestions will be provided in a format that includes space for two small icons,
      *  one at the left and one at the right of each suggestion.  The data in the column must
-     *  be a a resource ID for the icon you wish to have displayed.  If you include this column,
-     *  you must also include {@link #SUGGEST_COLUMN_ICON_2}.
+     *  be a resource ID of a drawable, or a URI in one of the following formats:
+     *
+     * <ul>
+     * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+     * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})</li>
+     * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+     * </ul>
+     *
+     * See {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)} 
+     * for more information on these schemes. 
      */
     public final static String SUGGEST_COLUMN_ICON_1 = "suggest_icon_1";
     /**
      * Column name for suggestions cursor.  <i>Optional.</i>  If your cursor includes this column,
-     *  then all suggestions will be provided in format that includes space for two small icons,
+     *  then all suggestions will be provided in a format that includes space for two small icons,
      *  one at the left and one at the right of each suggestion.  The data in the column must
-     *  be a a resource ID for the icon you wish to have displayed.  If you include this column,
-     *  you must also include {@link #SUGGEST_COLUMN_ICON_1}.
+     *  be a resource ID of a drawable, or a URI in one of the following formats:
+     *
+     * <ul>
+     * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+     * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})</li>
+     * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+     * </ul>
+     *
+     * See {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)} 
+     * for more information on these schemes. 
      */
     public final static String SUGGEST_COLUMN_ICON_2 = "suggest_icon_2";
     /**
+     * Column name for suggestions cursor.  <i>Optional.</i>  If your cursor includes this column,
+     *  then all suggestions will be provided in a format that includes space for two small icons,
+     *  one at the left and one at the right of each suggestion.  The data in the column must
+     *  be a blob that contains a bitmap.
+     * 
+     * This column overrides any icon provided in the {@link #SUGGEST_COLUMN_ICON_1} column.
+     *
+     * @hide
+     */
+    public final static String SUGGEST_COLUMN_ICON_1_BITMAP = "suggest_icon_1_bitmap";
+    /**
+     * Column name for suggestions cursor.  <i>Optional.</i>  If your cursor includes this column,
+     *  then all suggestions will be provided in a format that includes space for two small icons,
+     *  one at the left and one at the right of each suggestion.  The data in the column must
+     *  be a blob that contains a bitmap.
+     * 
+     * This column overrides any icon provided in the {@link #SUGGEST_COLUMN_ICON_2} column.
+     *
+     * @hide
+     */
+    public final static String SUGGEST_COLUMN_ICON_2_BITMAP = "suggest_icon_2_bitmap";
+    /**
      * Column name for suggestions cursor.  <i>Optional.</i>  If this column exists <i>and</i>
      * this element exists at the given row, this is the action that will be used when
      * forming the suggestion's intent.  If the element is not provided, the action will be taken
@@ -1230,6 +1278,14 @@
      */
     public final static String SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data";
     /**
+     * Column name for suggestions cursor.  <i>Optional.</i>  This column allows suggestions
+     *  to provide additional arbitrary data which will be included as an extra under the key
+     *  {@link #EXTRA_DATA_KEY}.
+     * 
+     * @hide pending API council approval
+     */
+    public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
+    /**
      * Column name for suggestions cursor.  <i>Optional.</i>  If this column exists <i>and</i>
      * this element exists at the given row, then "/" and this value will be appended to the data
      * field in the Intent.  This should only be used if the data field has already been set to an
@@ -1244,6 +1300,54 @@
      */
     public final static String SUGGEST_COLUMN_QUERY = "suggest_intent_query";
 
+    /**
+     * If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION},
+     * the search dialog will switch to a different suggestion source when the
+     * suggestion is clicked. 
+     * 
+     * {@link #SUGGEST_COLUMN_INTENT_DATA} must contain
+     * the flattened {@link ComponentName} of the activity which is to be searched.
+     * 
+     * TODO: Should {@link #SUGGEST_COLUMN_INTENT_DATA} instead contain a URI in the format
+     * used by {@link android.provider.Applications}?
+     * 
+     * TODO: This intent should be protected by the same permission that we use
+     * for replacing the global search provider.
+     * 
+     * The query text field will be set to the value of {@link #SUGGEST_COLUMN_QUERY}.
+     * 
+     * @hide Pending API council approval.
+     */
+    public final static String INTENT_ACTION_CHANGE_SEARCH_SOURCE 
+            = "android.search.action.CHANGE_SEARCH_SOURCE";
+    
+    /**
+     * If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION},
+     * the search dialog will call {@link Cursor#respond(Bundle)} when the
+     * suggestion is clicked. 
+     * 
+     * The {@link Bundle} argument will be constructed
+     * in the same way as the "extra" bundle included in an Intent constructed 
+     * from the suggestion.
+     * 
+     * @hide Pending API council approval.
+     */
+    public final static String INTENT_ACTION_CURSOR_RESPOND
+            = "android.search.action.CURSOR_RESPOND";
+    
+    /**
+     * Intent action for starting the global search settings activity.
+     * The global search provider should handle this intent.
+     * 
+     * @hide Pending API council approval.
+     */
+    public final static String INTENT_ACTION_SEARCH_SETTINGS 
+            = "android.search.action.SEARCH_SETTINGS";
+    
+    /**
+     * Reference to the shared system search service.
+     */
+    private static ISearchManager sService = getSearchManagerService();
 
     private final Context mContext;
     private final Handler mHandler;
@@ -1257,12 +1361,6 @@
         mContext = context;
         mHandler = handler;
     }
-    private static ISearchManager mService;
-
-    static {
-        mService = ISearchManager.Stub.asInterface(
-                    ServiceManager.getService(Context.SEARCH_SERVICE));
-    }
     
     /**
      * Launch search UI.
@@ -1459,5 +1557,93 @@
             mSearchDialog.onConfigurationChanged(newConfig);
         }
     }
-      
+    
+    private static ISearchManager getSearchManagerService() {
+        return ISearchManager.Stub.asInterface(
+            ServiceManager.getService(Context.SEARCH_SERVICE));
+    }
+    
+    /**
+     * Gets information about a searchable activity. This method is static so that it can
+     * be used from non-Activity contexts.
+     *
+     * @param componentName The activity to get searchable information for.
+     * @param globalSearch If <code>false</code>, return information about the given activity.
+     *        If <code>true</code>, return information about the global search activity. 
+     * @return Searchable information, or <code>null</code> if the activity is not searchable.
+     * 
+     * @hide because SearchableInfo is not part of the API.
+     */
+    public static SearchableInfo getSearchableInfo(ComponentName componentName, 
+            boolean globalSearch) {
+        try {
+            return sService.getSearchableInfo(componentName, globalSearch);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+    
+    /**
+     * Checks whether the given searchable is the default searchable.
+     * 
+     * @hide because SearchableInfo is not part of the API.
+     */
+    public static boolean isDefaultSearchable(SearchableInfo searchable) {
+        SearchableInfo defaultSearchable = SearchManager.getSearchableInfo(null, true);
+        return defaultSearchable != null 
+                && defaultSearchable.mSearchActivity.equals(searchable.mSearchActivity);
+    }
+    
+    /**
+     * Gets a cursor with search suggestions. This method is static so that it can
+     * be used from non-Activity context.
+     *
+     * @param searchable Information about how to get the suggestions.
+     * @param query The search text entered (so far).
+     * @return a cursor with suggestions, or <code>null</null> the suggestion query failed. 
+     * 
+     * @hide because SearchableInfo is not part of the API.
+     */
+    public static Cursor getSuggestions(Context context, SearchableInfo searchable, String query) {
+        if (searchable == null) {
+            return null;
+        }
+
+        String authority = searchable.getSuggestAuthority();
+        if (authority == null) {
+            return null;
+        }
+
+        Uri.Builder uriBuilder = new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(authority);
+
+        // if content path provided, insert it now
+        final String contentPath = searchable.getSuggestPath();
+        if (contentPath != null) {
+            uriBuilder.appendEncodedPath(contentPath);
+        }
+
+        // append standard suggestion query path 
+        uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY);
+
+        // get the query selection, may be null
+        String selection = searchable.getSuggestSelection();
+        // inject query, either as selection args or inline
+        String[] selArgs = null;
+        if (selection != null) {    // use selection if provided
+            selArgs = new String[] { query };
+        } else {                    // no selection, use REST pattern
+            uriBuilder.appendPath(query);
+        }
+
+        Uri uri = uriBuilder
+                .query("")     // TODO: Remove, workaround for a bug in Uri.writeToParcel()
+                .fragment("")  // TODO: Remove, workaround for a bug in Uri.writeToParcel()
+                .build();
+
+        // finally, make the query
+        return context.getContentResolver().query(uri, null, selection, selArgs, null);
+    }
+     
 }
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
new file mode 100644
index 0000000..0513fe1
--- /dev/null
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -0,0 +1,344 @@
+/*
+ * 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.
+ */
+
+package android.app;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources.NotFoundException;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.server.search.SearchableInfo;
+import android.text.Html;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CursorAdapter;
+import android.widget.ImageView;
+import android.widget.ResourceCursorAdapter;
+import android.widget.TextView;
+
+import java.io.FileNotFoundException;
+import java.util.WeakHashMap;
+
+/**
+ * Provides the contents for the suggestion drop-down list.in {@link SearchDialog}.
+ * 
+ * @hide
+ */
+class SuggestionsAdapter extends ResourceCursorAdapter {
+    private static final boolean DBG = false;
+    private static final String LOG_TAG = "SuggestionsAdapter";
+    
+    private SearchableInfo mSearchable;
+    private Context mProviderContext;
+    private WeakHashMap<String, Drawable> mOutsideDrawablesCache;
+
+    // Cached column indexes, updated when the cursor changes. 
+    private int mFormatCol;
+    private int mText1Col;
+    private int mText2Col;
+    private int mIconName1Col;
+    private int mIconName2Col;
+    private int mIconBitmap1Col;
+    private int mIconBitmap2Col;
+    
+    public SuggestionsAdapter(Context context, SearchableInfo searchable,
+            WeakHashMap<String, Drawable> outsideDrawablesCache) {
+        super(context,
+                com.android.internal.R.layout.search_dropdown_item_icons_2line,
+                null,   // no initial cursor
+                true);  // auto-requery
+        mSearchable = searchable;
+        
+        // set up provider resources (gives us icons, etc.)
+        Context activityContext = mSearchable.getActivityContext(mContext);
+        mProviderContext = mSearchable.getProviderContext(mContext, activityContext);
+        
+        mOutsideDrawablesCache = outsideDrawablesCache;
+    }
+    
+    /**
+     * Overridden to always return <code>false</code>, since we cannot be sure that
+     * suggestion sources return stable IDs.
+     */
+    @Override
+    public boolean hasStableIds() {
+        return false;
+    }
+
+    /**
+     * Use the search suggestions provider to obtain a live cursor.  This will be called
+     * in a worker thread, so it's OK if the query is slow (e.g. round trip for suggestions).
+     * The results will be processed in the UI thread and changeCursor() will be called.
+     */
+    @Override
+    public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
+        if (DBG) Log.d(LOG_TAG, "runQueryOnBackgroundThread(" + constraint + ")");
+        String query = (constraint == null) ? "" : constraint.toString();
+        try {
+            return SearchManager.getSuggestions(mContext, mSearchable, query);
+        } catch (RuntimeException e) {
+            Log.w(LOG_TAG, "Search suggestions query threw an exception.", e);
+            return null;
+        }
+    }
+    
+    /**
+     * Cache columns.
+     */
+    @Override
+    public void changeCursor(Cursor c) {
+        if (DBG) Log.d(LOG_TAG, "changeCursor(" + c + ")");
+        super.changeCursor(c);
+        if (c != null) {
+            mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT);
+            mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
+            mText2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2);
+            mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
+            mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2);
+            mIconBitmap1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1_BITMAP);
+            mIconBitmap2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2_BITMAP);
+        }
+    }
+    
+    /**
+     * Tags the view with cached child view look-ups.
+     */
+    @Override
+    public View newView(Context context, Cursor cursor, ViewGroup parent) {
+        View v = super.newView(context, cursor, parent);
+        v.setTag(new ChildViewCache(v));
+        return v;
+    }
+    
+    /**
+     * Cache of the child views of drop-drown list items, to avoid looking up the children
+     * each time the contents of a list item are changed.
+     */
+    private final static class ChildViewCache {
+        public final TextView mText1;
+        public final TextView mText2;
+        public final ImageView mIcon1;
+        public final ImageView mIcon2;
+        
+        public ChildViewCache(View v) {
+            mText1 = (TextView) v.findViewById(com.android.internal.R.id.text1);
+            mText2 = (TextView) v.findViewById(com.android.internal.R.id.text2);
+            mIcon1 = (ImageView) v.findViewById(com.android.internal.R.id.icon1);
+            mIcon2 = (ImageView) v.findViewById(com.android.internal.R.id.icon2);
+        }
+    }
+    
+    @Override
+    public void bindView(View view, Context context, Cursor cursor) {
+        ChildViewCache views = (ChildViewCache) view.getTag();            
+        String format = cursor.getString(mFormatCol);
+        boolean isHtml = "html".equals(format); 
+        setViewText(cursor, views.mText1, mText1Col, isHtml);
+        setViewText(cursor, views.mText2, mText2Col, isHtml);
+        setViewIcon(cursor, views.mIcon1, mIconBitmap1Col, mIconName1Col);
+        setViewIcon(cursor, views.mIcon2, mIconBitmap2Col, 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;
+        }
+        // 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);
+        }
+    }
+    
+    private void setViewIcon(Cursor cursor, ImageView v, int iconBitmapCol, int iconNameCol) {
+        if (v == null) {
+            return;
+        }
+        Drawable drawable = null;
+        // First try the bitmap column
+        if (iconBitmapCol >= 0) {
+            byte[] data = cursor.getBlob(iconBitmapCol);
+            if (data != null) {
+                Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
+                if (bitmap != null) {
+                    drawable = new BitmapDrawable(bitmap);
+                }
+            }
+        }
+        // If there was no bitmap, try the icon resource column.
+        if (drawable == null && iconNameCol >= 0) {
+            String value = cursor.getString(iconNameCol);
+            drawable = getDrawableFromResourceValue(value);
+        }
+        // Set the icon even if the drawable is null, since we need to clear any
+        // previous icon.
+        v.setImageDrawable(drawable);
+        
+        if (drawable == null) {
+            v.setVisibility(View.GONE);
+        } else {
+            v.setVisibility(View.VISIBLE);
+        }
+    }
+    
+    /**
+     * Gets the text to show in the query field when a suggestion is selected.
+     * 
+     * @param cursor The Cursor to read the suggestion data from. The Cursor should already 
+     *        be moved to the suggestion that is to be read from.
+     * @return The text to show, or <code>null</code> if the query should not be
+     *         changed when selecting this suggestion.
+     */
+    @Override
+    public CharSequence convertToString(Cursor cursor) {
+        if (cursor == null) {
+            return null;
+        }
+        
+        String query = getColumnString(cursor, SearchManager.SUGGEST_COLUMN_QUERY);
+        if (query != null) {
+            return query;
+        }
+        
+        if (mSearchable.mQueryRewriteFromData) {
+            String data = getColumnString(cursor, SearchManager.SUGGEST_COLUMN_INTENT_DATA);
+            if (data != null) {
+                return data;
+            }
+        }
+        
+        if (mSearchable.mQueryRewriteFromText) {
+            String text1 = getColumnString(cursor, SearchManager.SUGGEST_COLUMN_TEXT_1);
+            if (text1 != null) {
+                return text1;
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * This method is overridden purely to provide a bit of protection against
+     * flaky content providers.
+     * 
+     * @see android.widget.ListAdapter#getView(int, View, ViewGroup)
+     */
+    @Override 
+    public View getView(int position, View convertView, ViewGroup parent) {
+        try {
+            return super.getView(position, convertView, parent);
+        } catch (RuntimeException e) {
+            Log.w(LOG_TAG, "Search suggestions cursor threw exception.", e);
+            // Put exception string in item title
+            View v = newView(mContext, mCursor, parent);
+            if (v != null) {
+                ChildViewCache views = (ChildViewCache) v.getTag(); 
+                TextView tv = views.mText1;
+                tv.setText(e.toString());
+            }
+            return v;
+        }
+    }
+    
+    /**
+     * Gets a drawable given a value provided by a suggestion provider.
+     * 
+     * This value could be just the string value of a resource id
+     * (e.g., "2130837524"), in which case we will try to retrieve a drawable from
+     * the provider's resources. If the value is not an integer, it is
+     * treated as a Uri and opened with  
+     * {@link ContentResolver#openOutputStream(android.net.Uri, String)}.
+     *
+     * All resources and URIs are read using the suggestion provider's context.
+     *
+     * If the string is not formatted as expected, or no drawable can be found for
+     * the provided value, this method returns null.
+     * 
+     * @param drawableId a string like "2130837524",
+     *        "android.resource://com.android.alarmclock/2130837524",
+     *        or "content://contacts/photos/253".
+     * @return a Drawable, or null if none found
+     */
+    private Drawable getDrawableFromResourceValue(String drawableId) {
+        if (drawableId == null || drawableId.length() == 0 || "0".equals(drawableId)) {
+            return null;
+        }
+        
+        // First, check the cache.
+        Drawable drawable = mOutsideDrawablesCache.get(drawableId);
+        if (drawable != null) return drawable;
+
+        try {
+            // Not cached, try using it as a plain resource ID in the provider's context.
+            int resourceId = Integer.parseInt(drawableId);
+            drawable = mProviderContext.getResources().getDrawable(resourceId);
+        } catch (NumberFormatException nfe) {
+            // The id was not an integer resource id.
+            // Let the ContentResolver handle content, android.resource and file URIs.
+            try {
+                Uri uri = Uri.parse(drawableId);
+                drawable = Drawable.createFromStream(
+                        mProviderContext.getContentResolver().openInputStream(uri),
+                        null);
+            } catch (FileNotFoundException fnfe) {
+                // drawable = null;
+            }
+                    
+            // If we got a drawable for this resource id, then stick it in the
+            // map so we don't do this lookup again.
+            if (drawable != null) {
+                mOutsideDrawablesCache.put(drawableId, drawable);
+            }
+        } catch (NotFoundException nfe) {
+            // Resource could not be found
+            // drawable = null;
+        }
+        
+        return drawable;
+    }
+    
+    /**
+     * Gets the value of a string column by name.
+     * 
+     * @param cursor Cursor to read the value from.
+     * @param columnName The name of the column to read.
+     * @return The value of the given column, or <code>null</null>
+     *         if the cursor does not contain the given column.
+     */
+    public static String getColumnString(Cursor cursor, String columnName) {
+        int col = cursor.getColumnIndex(columnName);
+        if (col == -1) {
+            return null;
+        }
+        return cursor.getString(col);
+    }
+
+}
diff --git a/core/java/android/provider/Applications.java b/core/java/android/provider/Applications.java
new file mode 100644
index 0000000..0b0ce58
--- /dev/null
+++ b/core/java/android/provider/Applications.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+package android.provider;
+
+import android.app.SearchManager;
+import android.net.Uri;
+import android.widget.SimpleCursorAdapter;
+
+/**
+ * <p>The Applications provider gives information about installed applications.</p>
+ * 
+ * <p>This provider provides the following columns:
+ * 
+ * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
+ *
+ *     <thead>
+ *     <tr><th>Column Name</th> <th>Description</th> </tr>
+ *     </thead>
+ *
+ * <tbody>
+ * <tr><th>{@link SearchManager#SUGGEST_COLUMN_TEXT_1}</th>
+ *     <td>The application name.</td>
+ * </tr>
+ * 
+ * <tr><th>{@link SearchManager#SUGGEST_COLUMN_INTENT_COMPONENT}</th>
+ *     <td>The component to be used when forming the intent.</td>
+ * </tr>
+ * 
+ * <tr><th>{@link SearchManager#SUGGEST_COLUMN_ICON_1}</th>
+ *     <td>The application's icon resource id, prepended by its package name and
+ *         separated by a colon, e.g., "com.android.alarmclock:2130837524". The
+ *         package name is required for an activity interpreting this value to
+ *         be able to correctly access the icon drawable, for example, in an override of
+ *         {@link SimpleCursorAdapter#setViewImage(android.widget.ImageView, String)}.</td>
+ * </tr>
+ * 
+ * <tr><th>{@link SearchManager#SUGGEST_COLUMN_ICON_2}</th>
+ *     <td><i>Unused - column provided to conform to the {@link SearchManager} stipulation
+ *            that all providers provide either both or neither of
+ *            {@link SearchManager#SUGGEST_COLUMN_ICON_1} and
+ *            {@link SearchManager#SUGGEST_COLUMN_ICON_2}.</td>
+ * </tr>
+ * 
+ * @hide pending API council approval - should be unhidden at the same time as
+ *       {@link SearchManager#SUGGEST_COLUMN_INTENT_COMPONENT}
+ */
+public class Applications {
+    private static final String TAG = "Applications";
+
+    /**
+     * The content authority for this provider.
+     *
+     * @hide
+     */
+    public static final String AUTHORITY = "applications";
+
+    /**
+     * The content:// style URL for this provider
+     *
+     * @hide
+     */
+    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
+
+    /**
+     * no public constructor since this is a utility class
+     */
+    private Applications() {}
+}
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index fe15553..eaace6b 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -22,8 +22,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Handler;
-import android.util.Config;
 
 /**
  * This is a simplified version of the Search Manager service.  It no longer handles
@@ -36,7 +36,6 @@
         // general debugging support
     private static final String TAG = "SearchManagerService";
     private static final boolean DEBUG = false;
-    private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
     
         // configuration choices
     private static final boolean IMMEDIATE_SEARCHABLES_UPDATE = true;
@@ -45,9 +44,10 @@
     private final Context mContext;
     private final Handler mHandler;
     private boolean mSearchablesDirty;
+    private Searchables mSearchables;
     
     /**
-     * Initialize the Search Manager service in the provided system context.
+     * Initializes the Search Manager service in the provided system context.
      * Only one instance of this object should be created!
      *
      * @param context to use for accessing DB, window manager, etc.
@@ -55,6 +55,8 @@
     public SearchManagerService(Context context)  {     
         mContext = context;
         mHandler = new Handler();
+        mSearchablesDirty = true;
+        mSearchables = new Searchables(context);
         
         // Setup the infrastructure for updating and maintaining the list
         // of searchable activities.
@@ -64,7 +66,6 @@
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addDataScheme("package");
         mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
-        mSearchablesDirty = true;
         
         // After startup settles down, preload the searchables list,
         // which will reduce the delay when the search UI is invoked.
@@ -109,34 +110,41 @@
     };
 
     /**
-     * Update the list of searchables, either at startup or in response to
+     * Updates the list of searchables, either at startup or in response to
      * a package add/remove broadcast message.
      */
     private void updateSearchables() {
-        SearchableInfo.buildSearchableList(mContext);
+        mSearchables.buildSearchableList();
         mSearchablesDirty = false;
         
-        // TODO This is a hack.  This shouldn't be hardcoded here, it's probably
-        // a policy.
-//      ComponentName defaultSearch = new ComponentName( 
-//              "com.android.contacts", 
-//              "com.android.contacts.ContactsListActivity" );
-        ComponentName defaultSearch = new ComponentName( 
-                "com.android.googlesearch", 
-                "com.android.googlesearch.GoogleSearch" );
-        SearchableInfo.setDefaultSearchable(mContext, defaultSearch);
+        // TODO SearchableInfo should be the source of truth about whether a searchable exists.
+        // As it stands, if the package exists but is misconfigured in some way, then this
+        // would fail, and needs to be fixed.
+        ComponentName defaultSearch = new ComponentName(
+                "com.android.globalsearch", 
+                "com.android.globalsearch.GlobalSearch");
+        
+        try {
+            mContext.getPackageManager().getActivityInfo(defaultSearch, 0);
+        } catch (NameNotFoundException e) {
+            defaultSearch = new ComponentName(
+                    "com.android.googlesearch",
+                    "com.android.googlesearch.GoogleSearch");
+        }
+        
+        mSearchables.setDefaultSearchable(defaultSearch);
     }
 
     /**
-     * Return the searchableinfo for a given activity
+     * Returns the SearchableInfo for a given activity
      *
      * @param launchActivity The activity from which we're launching this search.
-     * @return Returns a SearchableInfo record describing the parameters of the search,
-     * or null if no searchable metadata was available.
      * @param globalSearch If false, this will only launch the search that has been specifically
      * defined by the application (which is usually defined as a local search).  If no default 
      * search is defined in the current application or activity, no search will be launched.
      * If true, this will always launch a platform-global (e.g. web-based) search instead.
+     * @return Returns a SearchableInfo record describing the parameters of the search,
+     * or null if no searchable metadata was available.
      */
     public SearchableInfo getSearchableInfo(ComponentName launchActivity, boolean globalSearch) {
         // final check.  however we should try to avoid this, because
@@ -146,11 +154,12 @@
         }
         SearchableInfo si = null;
         if (globalSearch) {
-            si = SearchableInfo.getDefaultSearchable();
+            si = mSearchables.getDefaultSearchable();
         } else {
-            si = SearchableInfo.getSearchableInfo(mContext, launchActivity);
+            si = mSearchables.getSearchableInfo(launchActivity);
         }
 
         return si;
     }
+
 }
diff --git a/core/java/android/server/search/SearchableInfo.java b/core/java/android/server/search/SearchableInfo.java
index 0c04839..22abd1b 100644
--- a/core/java/android/server/search/SearchableInfo.java
+++ b/core/java/android/server/search/SearchableInfo.java
@@ -21,14 +21,11 @@
 
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.InputType;
@@ -38,9 +35,6 @@
 import android.view.inputmethod.EditorInfo;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
 
 public final class SearchableInfo implements Parcelable {
 
@@ -50,19 +44,12 @@
     // set this flag to 1 to prevent any apps from providing suggestions
     final static int DBG_INHIBIT_SUGGESTIONS = 0;
 
-    // static strings used for XML lookups, etc.
+    // static strings used for XML lookups.
     // TODO how should these be documented for the developer, in a more structured way than 
     // the current long wordy javadoc in SearchManager.java ?
-    private static final String MD_LABEL_DEFAULT_SEARCHABLE = "android.app.default_searchable";
     private static final String MD_LABEL_SEARCHABLE = "android.app.searchable";
-    private static final String MD_SEARCHABLE_SYSTEM_SEARCH = "*";
     private static final String MD_XML_ELEMENT_SEARCHABLE = "searchable";
     private static final String MD_XML_ELEMENT_SEARCHABLE_ACTION_KEY = "actionkey";
-
-    // class maintenance and general shared data
-    private static HashMap<ComponentName, SearchableInfo> sSearchablesMap = null;
-    private static ArrayList<SearchableInfo> sSearchablesList = null;
-    private static SearchableInfo sDefaultSearchable = null;
     
     // true member variables - what we know about the searchability
     // TO-DO replace public with getters
@@ -86,7 +73,6 @@
     private String mSuggestIntentData = null;
     private ActionKeyInfo mActionKeyList = null;
     private String mSuggestProviderPackage = null;
-    private Context mCacheActivityContext = null;   // use during setup only - don't hold memory!
     
     // Flag values for Searchable_voiceSearchMode
     private static int VOICE_SEARCH_SHOW_BUTTON = 1;
@@ -97,37 +83,7 @@
     private int mVoicePromptTextId;         // voicePromptText
     private int mVoiceLanguageId;           // voiceLanguage
     private int mVoiceMaxResults;           // voiceMaxResults
-    
-    /**
-     * Set the default searchable activity (when none is specified).
-     */
-    public static void setDefaultSearchable(Context context, 
-                                            ComponentName activity) {
-        synchronized (SearchableInfo.class) {
-            SearchableInfo si = null;
-            if (activity != null) {
-                si = getSearchableInfo(context, activity);
-                if (si != null) {
-                    // move to front of list
-                    sSearchablesList.remove(si);
-                    sSearchablesList.add(0, si);
-                }
-            }
-            sDefaultSearchable = si;
-        }
-    }
-    
-    /**
-     * Provides the system-default search activity, which you can use
-     * whenever getSearchableInfo() returns null;
-     * 
-     * @return Returns the system-default search activity, null if never defined
-     */
-    public static SearchableInfo getDefaultSearchable() {
-        synchronized (SearchableInfo.class) {
-            return sDefaultSearchable;
-        }
-    }
+
     
     /**
      * Retrieve the authority for obtaining search suggestions.
@@ -193,9 +149,16 @@
      * @return Returns a context related to the searchable activity
      */
     public Context getActivityContext(Context context) {
+        return createActivityContext(context, mSearchActivity);
+    }
+    
+    /**
+     * Creates a context for another activity.
+     */
+    private static Context createActivityContext(Context context, ComponentName activity) {
         Context theirContext = null;
         try {
-            theirContext = context.createPackageContext(mSearchActivity.getPackageName(), 0);
+            theirContext = context.createPackageContext(activity.getPackageName(), 0);
         } catch (PackageManager.NameNotFoundException e) {
             // unexpected, but we deal with this by null-checking theirContext
         } catch (java.lang.SecurityException e) {
@@ -234,242 +197,68 @@
     }
     
     /**
-     * Factory.  Look up, or construct, based on the activity.
-     * 
-     * The activities fall into three cases, based on meta-data found in 
-     * the manifest entry:
-     * <ol>
-     * <li>The activity itself implements search.  This is indicated by the
-     * presence of a "android.app.searchable" meta-data attribute.
-     * The value is a reference to an XML file containing search information.</li>
-     * <li>A related activity implements search.  This is indicated by the
-     * presence of a "android.app.default_searchable" meta-data attribute.
-     * The value is a string naming the activity implementing search.  In this
-     * case the factory will "redirect" and return the searchable data.</li>
-     * <li>No searchability data is provided.  We return null here and other
-     * code will insert the "default" (e.g. contacts) search.
-     * 
-     * TODO: cache the result in the map, and check the map first.
-     * TODO: it might make sense to implement the searchable reference as
-     * an application meta-data entry.  This way we don't have to pepper each
-     * and every activity.
-     * TODO: can we skip the constructor step if it's a non-searchable?
-     * TODO: does it make sense to plug the default into a slot here for 
-     * automatic return?  Probably not, but it's one way to do it.
-     *
-     * @param activity The name of the current activity, or null if the 
-     * activity does not define any explicit searchable metadata.
-     */
-    public static SearchableInfo getSearchableInfo(Context context, 
-                                                   ComponentName activity) {
-        // Step 1.  Is the result already hashed?  (case 1)
-        SearchableInfo result;
-        synchronized (SearchableInfo.class) {
-            result = sSearchablesMap.get(activity);
-            if (result != null) return result;
-        }
-        
-        // Step 2.  See if the current activity references a searchable.
-        // Note:  Conceptually, this could be a while(true) loop, but there's
-        // no point in implementing reference chaining here and risking a loop.  
-        // References must point directly to searchable activities.
-       
-        ActivityInfo ai = null;
-        XmlPullParser xml = null;
-        try {
-            ai = context.getPackageManager().
-                       getActivityInfo(activity, PackageManager.GET_META_DATA );
-            String refActivityName = null;
-            
-            // First look for activity-specific reference
-            Bundle md = ai.metaData;
-            if (md != null) {
-                refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
-            }
-            // If not found, try for app-wide reference
-            if (refActivityName == null) {
-                md = ai.applicationInfo.metaData;
-                if (md != null) {
-                    refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
-                }
-            }
-            
-            // Irrespective of source, if a reference was found, follow it.
-            if (refActivityName != null)
-            {
-                // An app or activity can declare that we should simply launch 
-                // "system default search" if search is invoked.
-                if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) {
-                    return getDefaultSearchable();
-                }
-                String pkg = activity.getPackageName();
-                ComponentName referredActivity;
-                if (refActivityName.charAt(0) == '.') {
-                    referredActivity = new ComponentName(pkg, pkg + refActivityName);
-                } else {
-                    referredActivity = new ComponentName(pkg, refActivityName);
-                }
-
-                // Now try the referred activity, and if found, cache
-                // it against the original name so we can skip the check
-                synchronized (SearchableInfo.class) {
-                    result = sSearchablesMap.get(referredActivity);
-                    if (result != null) {
-                        sSearchablesMap.put(activity, result);
-                        return result;
-                    }
-                }
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            // case 3: no metadata
-        }
- 
-        // Step 3.  None found. Return null.
-        return null;
-        
-    }
-    
-    /**
-     * Super-factory.  Builds an entire list (suitable for display) of 
-     * activities that are searchable, by iterating the entire set of 
-     * ACTION_SEARCH intents.  
-     * 
-     * Also clears the hash of all activities -> searches which will
-     * refill as the user clicks "search".
-     * 
-     * This should only be done at startup and again if we know that the
-     * list has changed.
-     * 
-     * TODO: every activity that provides a ACTION_SEARCH intent should
-     * also provide searchability meta-data.  There are a bunch of checks here
-     * that, if data is not found, silently skip to the next activity.  This
-     * won't help a developer trying to figure out why their activity isn't
-     * showing up in the list, but an exception here is too rough.  I would
-     * like to find a better notification mechanism.
-     * 
-     * TODO: sort the list somehow?  UI choice.
-     * 
-     * @param context a context we can use during this work
-     */
-    public static void buildSearchableList(Context context) {
-        
-        // create empty hash & list
-        HashMap<ComponentName, SearchableInfo> newSearchablesMap 
-                                = new HashMap<ComponentName, SearchableInfo>();
-        ArrayList<SearchableInfo> newSearchablesList
-                                = new ArrayList<SearchableInfo>();
-
-        // use intent resolver to generate list of ACTION_SEARCH receivers
-        final PackageManager pm = context.getPackageManager();
-        List<ResolveInfo> infoList;
-        final Intent intent = new Intent(Intent.ACTION_SEARCH);
-        infoList = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA);
-        
-        // analyze each one, generate a Searchables record, and record
-        if (infoList != null) {
-            int count = infoList.size();
-            for (int ii = 0; ii < count; ii++) {
-                // for each component, try to find metadata
-                ResolveInfo info = infoList.get(ii);
-                ActivityInfo ai = info.activityInfo;
-                XmlResourceParser xml = ai.loadXmlMetaData(context.getPackageManager(), 
-                                                       MD_LABEL_SEARCHABLE);
-                if (xml == null) {
-                    continue;
-                }
-                ComponentName cName = new ComponentName(
-                        info.activityInfo.packageName, 
-                        info.activityInfo.name);
-                
-                SearchableInfo searchable = getActivityMetaData(context, xml, cName);
-                xml.close();
-                
-                if (searchable != null) {
-                    // no need to keep the context any longer.  setup time is over.
-                    searchable.mCacheActivityContext  = null;
-                    
-                    newSearchablesList.add(searchable);
-                    newSearchablesMap.put(cName, searchable);
-                }
-            }
-        }
-        
-        // record the final values as a coherent pair
-        synchronized (SearchableInfo.class) {
-            sSearchablesList = newSearchablesList;
-            sSearchablesMap = newSearchablesMap;
-        }
-    }
-    
-    /**
      * Constructor
      * 
      * Given a ComponentName, get the searchability info
      * and build a local copy of it.  Use the factory, not this.
      * 
-     * @param context runtime context
+     * @param activityContext runtime context for the activity that the searchable info is about.
      * @param attr The attribute set we found in the XML file, contains the values that are used to
      * construct the object.
      * @param cName The component name of the searchable activity
      */
-    private SearchableInfo(Context context, AttributeSet attr, final ComponentName cName) {
+    private SearchableInfo(Context activityContext, AttributeSet attr, final ComponentName cName) {
         // initialize as an "unsearchable" object
         mSearchable = false;
         mSearchActivity = cName;
         
-        // to access another activity's resources, I need its context.
-        // BE SURE to release the cache sometime after construction - it's a large object to hold
-        mCacheActivityContext = getActivityContext(context);
-        if (mCacheActivityContext != null) {
-            TypedArray a = mCacheActivityContext.obtainStyledAttributes(attr,
-                    com.android.internal.R.styleable.Searchable);
-            mSearchMode = a.getInt(com.android.internal.R.styleable.Searchable_searchMode, 0);
-            mLabelId = a.getResourceId(com.android.internal.R.styleable.Searchable_label, 0);
-            mHintId = a.getResourceId(com.android.internal.R.styleable.Searchable_hint, 0);
-            mIconId = a.getResourceId(com.android.internal.R.styleable.Searchable_icon, 0);
-            mSearchButtonText = a.getResourceId(
-                    com.android.internal.R.styleable.Searchable_searchButtonText, 0);
-            mSearchInputType = a.getInt(com.android.internal.R.styleable.Searchable_inputType, 
-                    InputType.TYPE_CLASS_TEXT |
-                    InputType.TYPE_TEXT_VARIATION_NORMAL);
-            mSearchImeOptions = a.getInt(com.android.internal.R.styleable.Searchable_imeOptions, 
-                    EditorInfo.IME_ACTION_SEARCH);
+        TypedArray a = activityContext.obtainStyledAttributes(attr,
+                com.android.internal.R.styleable.Searchable);
+        mSearchMode = a.getInt(com.android.internal.R.styleable.Searchable_searchMode, 0);
+        mLabelId = a.getResourceId(com.android.internal.R.styleable.Searchable_label, 0);
+        mHintId = a.getResourceId(com.android.internal.R.styleable.Searchable_hint, 0);
+        mIconId = a.getResourceId(com.android.internal.R.styleable.Searchable_icon, 0);
+        mSearchButtonText = a.getResourceId(
+                com.android.internal.R.styleable.Searchable_searchButtonText, 0);
+        mSearchInputType = a.getInt(com.android.internal.R.styleable.Searchable_inputType, 
+                InputType.TYPE_CLASS_TEXT |
+                InputType.TYPE_TEXT_VARIATION_NORMAL);
+        mSearchImeOptions = a.getInt(com.android.internal.R.styleable.Searchable_imeOptions, 
+                EditorInfo.IME_ACTION_SEARCH);
 
-            setSearchModeFlags();
-            if (DBG_INHIBIT_SUGGESTIONS == 0) {
-                mSuggestAuthority = a.getString(
-                        com.android.internal.R.styleable.Searchable_searchSuggestAuthority);
-                mSuggestPath = a.getString(
-                        com.android.internal.R.styleable.Searchable_searchSuggestPath);
-                mSuggestSelection = a.getString(
-                        com.android.internal.R.styleable.Searchable_searchSuggestSelection);
-                mSuggestIntentAction = a.getString(
-                        com.android.internal.R.styleable.Searchable_searchSuggestIntentAction);
-                mSuggestIntentData = a.getString(
-                        com.android.internal.R.styleable.Searchable_searchSuggestIntentData);
-            }
-            mVoiceSearchMode = 
-                a.getInt(com.android.internal.R.styleable.Searchable_voiceSearchMode, 0);
-            // TODO this didn't work - came back zero from YouTube
-            mVoiceLanguageModeId = 
-                a.getResourceId(com.android.internal.R.styleable.Searchable_voiceLanguageModel, 0);
-            mVoicePromptTextId = 
-                a.getResourceId(com.android.internal.R.styleable.Searchable_voicePromptText, 0);
-            mVoiceLanguageId = 
-                a.getResourceId(com.android.internal.R.styleable.Searchable_voiceLanguage, 0);
-            mVoiceMaxResults = 
-                a.getInt(com.android.internal.R.styleable.Searchable_voiceMaxResults, 0);
+        setSearchModeFlags();
+        if (DBG_INHIBIT_SUGGESTIONS == 0) {
+            mSuggestAuthority = a.getString(
+                    com.android.internal.R.styleable.Searchable_searchSuggestAuthority);
+            mSuggestPath = a.getString(
+                    com.android.internal.R.styleable.Searchable_searchSuggestPath);
+            mSuggestSelection = a.getString(
+                    com.android.internal.R.styleable.Searchable_searchSuggestSelection);
+            mSuggestIntentAction = a.getString(
+                    com.android.internal.R.styleable.Searchable_searchSuggestIntentAction);
+            mSuggestIntentData = a.getString(
+                    com.android.internal.R.styleable.Searchable_searchSuggestIntentData);
+        }
+        mVoiceSearchMode = 
+            a.getInt(com.android.internal.R.styleable.Searchable_voiceSearchMode, 0);
+        // TODO this didn't work - came back zero from YouTube
+        mVoiceLanguageModeId = 
+            a.getResourceId(com.android.internal.R.styleable.Searchable_voiceLanguageModel, 0);
+        mVoicePromptTextId = 
+            a.getResourceId(com.android.internal.R.styleable.Searchable_voicePromptText, 0);
+        mVoiceLanguageId = 
+            a.getResourceId(com.android.internal.R.styleable.Searchable_voiceLanguage, 0);
+        mVoiceMaxResults = 
+            a.getInt(com.android.internal.R.styleable.Searchable_voiceMaxResults, 0);
 
-            a.recycle();
+        a.recycle();
 
-            // get package info for suggestions provider (if any)
-            if (mSuggestAuthority != null) {
-                ProviderInfo pi =
-                    context.getPackageManager().resolveContentProvider(mSuggestAuthority,
-                            0);
-                if (pi != null) {
-                    mSuggestProviderPackage = pi.packageName;
-                }
+        // get package info for suggestions provider (if any)
+        if (mSuggestAuthority != null) {
+            PackageManager pm = activityContext.getPackageManager();
+            ProviderInfo pi = pm.resolveContentProvider(mSuggestAuthority, 0);
+            if (pi != null) {
+                mSuggestProviderPackage = pi.packageName;
             }
         }
 
@@ -496,7 +285,7 @@
     /**
      * Private class used to hold the "action key" configuration
      */
-    public class ActionKeyInfo implements Parcelable {
+    public static class ActionKeyInfo implements Parcelable {
         
         public int mKeyCode = 0;
         public String mQueryActionMsg;
@@ -506,14 +295,15 @@
         
         /**
          * Create one object using attributeset as input data.
-         * @param context runtime context
+         * @param activityContext runtime context of the activity that the action key information
+         *        is about.
          * @param attr The attribute set we found in the XML file, contains the values that are used to
          * construct the object.
          * @param next We'll build these up using a simple linked list (since there are usually
          * just zero or one).
          */
-        public ActionKeyInfo(Context context, AttributeSet attr, ActionKeyInfo next) {
-            TypedArray a = mCacheActivityContext.obtainStyledAttributes(attr,
+        public ActionKeyInfo(Context activityContext, AttributeSet attr, ActionKeyInfo next) {
+            TypedArray a = activityContext.obtainStyledAttributes(attr,
                     com.android.internal.R.styleable.SearchableActionKey);
 
             mKeyCode = a.getInt(
@@ -584,6 +374,20 @@
         return null;
     }
     
+    public static SearchableInfo getActivityMetaData(Context context, ActivityInfo activityInfo) {
+        // for each component, try to find metadata
+        XmlResourceParser xml = 
+                activityInfo.loadXmlMetaData(context.getPackageManager(), MD_LABEL_SEARCHABLE);
+        if (xml == null) {
+            return null;
+        }
+        ComponentName cName = new ComponentName(activityInfo.packageName, activityInfo.name);
+        
+        SearchableInfo searchable = getActivityMetaData(context, xml, cName);
+        xml.close();
+        return searchable;
+    }
+    
     /**
      * Get the metadata for a given activity
      * 
@@ -598,6 +402,7 @@
     private static SearchableInfo getActivityMetaData(Context context, XmlPullParser xml,
             final ComponentName cName)  {
         SearchableInfo result = null;
+        Context activityContext = createActivityContext(context, cName);
         
         // in order to use the attributes mechanism, we have to walk the parser
         // forward through the file until it's reading the tag of interest.
@@ -608,7 +413,7 @@
                     if (xml.getName().equals(MD_XML_ELEMENT_SEARCHABLE)) {
                         AttributeSet attr = Xml.asAttributeSet(xml);
                         if (attr != null) {
-                            result = new SearchableInfo(context, attr, cName);
+                            result = new SearchableInfo(activityContext, attr, cName);
                             // if the constructor returned a bad object, exit now.
                             if (! result.mSearchable) {
                                 return null;
@@ -621,7 +426,7 @@
                         }
                         AttributeSet attr = Xml.asAttributeSet(xml);
                         if (attr != null) {
-                            ActionKeyInfo keyInfo = result.new ActionKeyInfo(context, attr, 
+                            ActionKeyInfo keyInfo = new ActionKeyInfo(activityContext, attr, 
                                     result.mActionKeyList);
                             // only add to list if it is was useable
                             if (keyInfo.mKeyCode != 0) {
@@ -637,6 +442,7 @@
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
+        
         return result;
     }
     
@@ -757,16 +563,6 @@
     }
     
     /**
-     * Return the list of searchable activities, for use in the drop-down.
-     */
-    public static ArrayList<SearchableInfo> getSearchablesList() {
-        synchronized (SearchableInfo.class) {
-            ArrayList<SearchableInfo> result = new ArrayList<SearchableInfo>(sSearchablesList);
-            return result;
-        }
-    }
-    
-    /**
      * Support for parcelable and aidl operations.
      */
     public static final Parcelable.Creator<SearchableInfo> CREATOR
diff --git a/core/java/android/server/search/Searchables.java b/core/java/android/server/search/Searchables.java
new file mode 100644
index 0000000..ba75d21
--- /dev/null
+++ b/core/java/android/server/search/Searchables.java
@@ -0,0 +1,243 @@
+/*
+ * 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.
+ */
+
+package android.server.search;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * This class maintains the information about all searchable activities. 
+ */
+public class Searchables {
+
+    // static strings used for XML lookups, etc.
+    // TODO how should these be documented for the developer, in a more structured way than 
+    // the current long wordy javadoc in SearchManager.java ?
+    private static final String MD_LABEL_DEFAULT_SEARCHABLE = "android.app.default_searchable";
+    private static final String MD_SEARCHABLE_SYSTEM_SEARCH = "*";
+    
+    private Context mContext;
+    
+    private HashMap<ComponentName, SearchableInfo> mSearchablesMap = null;
+    private ArrayList<SearchableInfo> mSearchablesList = null;
+    private SearchableInfo mDefaultSearchable = null;
+    
+    /**
+     * 
+     * @param context Context to use for looking up activities etc.
+     */
+    public Searchables (Context context) {
+        mContext = context;
+    }
+    
+    /**
+     * Look up, or construct, based on the activity.
+     * 
+     * The activities fall into three cases, based on meta-data found in 
+     * the manifest entry:
+     * <ol>
+     * <li>The activity itself implements search.  This is indicated by the
+     * presence of a "android.app.searchable" meta-data attribute.
+     * The value is a reference to an XML file containing search information.</li>
+     * <li>A related activity implements search.  This is indicated by the
+     * presence of a "android.app.default_searchable" meta-data attribute.
+     * The value is a string naming the activity implementing search.  In this
+     * case the factory will "redirect" and return the searchable data.</li>
+     * <li>No searchability data is provided.  We return null here and other
+     * code will insert the "default" (e.g. contacts) search.
+     * 
+     * TODO: cache the result in the map, and check the map first.
+     * TODO: it might make sense to implement the searchable reference as
+     * an application meta-data entry.  This way we don't have to pepper each
+     * and every activity.
+     * TODO: can we skip the constructor step if it's a non-searchable?
+     * TODO: does it make sense to plug the default into a slot here for 
+     * automatic return?  Probably not, but it's one way to do it.
+     *
+     * @param activity The name of the current activity, or null if the 
+     * activity does not define any explicit searchable metadata.
+     */
+    public SearchableInfo getSearchableInfo(ComponentName activity) {
+        // Step 1.  Is the result already hashed?  (case 1)
+        SearchableInfo result;
+        synchronized (this) {
+            result = mSearchablesMap.get(activity);
+            if (result != null) return result;
+        }
+        
+        // Step 2.  See if the current activity references a searchable.
+        // Note:  Conceptually, this could be a while(true) loop, but there's
+        // no point in implementing reference chaining here and risking a loop.  
+        // References must point directly to searchable activities.
+       
+        ActivityInfo ai = null;
+        try {
+            ai = mContext.getPackageManager().
+                       getActivityInfo(activity, PackageManager.GET_META_DATA );
+            String refActivityName = null;
+            
+            // First look for activity-specific reference
+            Bundle md = ai.metaData;
+            if (md != null) {
+                refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
+            }
+            // If not found, try for app-wide reference
+            if (refActivityName == null) {
+                md = ai.applicationInfo.metaData;
+                if (md != null) {
+                    refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE);
+                }
+            }
+            
+            // Irrespective of source, if a reference was found, follow it.
+            if (refActivityName != null)
+            {
+                // An app or activity can declare that we should simply launch 
+                // "system default search" if search is invoked.
+                if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) {
+                    return getDefaultSearchable();
+                }
+                String pkg = activity.getPackageName();
+                ComponentName referredActivity;
+                if (refActivityName.charAt(0) == '.') {
+                    referredActivity = new ComponentName(pkg, pkg + refActivityName);
+                } else {
+                    referredActivity = new ComponentName(pkg, refActivityName);
+                }
+
+                // Now try the referred activity, and if found, cache
+                // it against the original name so we can skip the check
+                synchronized (this) {
+                    result = mSearchablesMap.get(referredActivity);
+                    if (result != null) {
+                        mSearchablesMap.put(activity, result);
+                        return result;
+                    }
+                }
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            // case 3: no metadata
+        }
+ 
+        // Step 3.  None found. Return null.
+        return null;
+        
+    }
+    
+    /**
+     * Set the default searchable activity (when none is specified).
+     */
+    public synchronized void setDefaultSearchable(ComponentName activity) {
+        SearchableInfo si = null;
+        if (activity != null) {
+            si = getSearchableInfo(activity);
+            if (si != null) {
+                // move to front of list
+                mSearchablesList.remove(si);
+                mSearchablesList.add(0, si);
+            }
+        }
+        mDefaultSearchable = si;
+    }
+    
+    /**
+     * Provides the system-default search activity, which you can use
+     * whenever getSearchableInfo() returns null;
+     * 
+     * @return Returns the system-default search activity, null if never defined
+     */
+    public synchronized SearchableInfo getDefaultSearchable() {
+        return mDefaultSearchable;
+    }
+    
+    public synchronized boolean isDefaultSearchable(SearchableInfo searchable) {
+        return searchable == mDefaultSearchable;
+    }
+   
+    /**
+     * Builds an entire list (suitable for display) of 
+     * activities that are searchable, by iterating the entire set of 
+     * ACTION_SEARCH intents.  
+     * 
+     * Also clears the hash of all activities -> searches which will
+     * refill as the user clicks "search".
+     * 
+     * This should only be done at startup and again if we know that the
+     * list has changed.
+     * 
+     * TODO: every activity that provides a ACTION_SEARCH intent should
+     * also provide searchability meta-data.  There are a bunch of checks here
+     * that, if data is not found, silently skip to the next activity.  This
+     * won't help a developer trying to figure out why their activity isn't
+     * showing up in the list, but an exception here is too rough.  I would
+     * like to find a better notification mechanism.
+     * 
+     * TODO: sort the list somehow?  UI choice.
+     */
+    public void buildSearchableList() {
+        
+        // create empty hash & list
+        HashMap<ComponentName, SearchableInfo> newSearchablesMap 
+                                = new HashMap<ComponentName, SearchableInfo>();
+        ArrayList<SearchableInfo> newSearchablesList
+                                = new ArrayList<SearchableInfo>();
+
+        // use intent resolver to generate list of ACTION_SEARCH receivers
+        final PackageManager pm = mContext.getPackageManager();
+        List<ResolveInfo> infoList;
+        final Intent intent = new Intent(Intent.ACTION_SEARCH);
+        infoList = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA);
+        
+        // analyze each one, generate a Searchables record, and record
+        if (infoList != null) {
+            int count = infoList.size();
+            for (int ii = 0; ii < count; ii++) {
+                // for each component, try to find metadata
+                ResolveInfo info = infoList.get(ii);
+                ActivityInfo ai = info.activityInfo;
+                SearchableInfo searchable = SearchableInfo.getActivityMetaData(mContext, ai);
+                if (searchable != null) {
+                    newSearchablesList.add(searchable);
+                    newSearchablesMap.put(searchable.mSearchActivity, searchable);
+                }
+            }
+        }
+        
+        // record the final values as a coherent pair
+        synchronized (this) {
+            mSearchablesList = newSearchablesList;
+            mSearchablesMap = newSearchablesMap;
+        }
+    }
+    
+    /**
+     * Returns the list of searchable activities.
+     */
+    public synchronized ArrayList<SearchableInfo> getSearchablesList() {
+        ArrayList<SearchableInfo> result = new ArrayList<SearchableInfo>(mSearchablesList);
+        return result;
+    }
+}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 772ad89..b408f27 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -983,18 +983,6 @@
         mSelectorRect.setEmpty();
         invalidate();
     }
-    
-    /**
-     * The list is empty and we need to change the layout, so *really* clear everything out.
-     * @hide - for AutoCompleteTextView & SearchDialog only
-     */
-    /* package */ void resetListAndClearViews() {
-        rememberSyncState();
-        removeAllViewsInLayout();
-        mRecycler.clear();
-        mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
-        requestLayout();
-    }
 
     @Override
     protected int computeVerticalScrollExtent() {
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index dfb971e..e3186b0 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -110,6 +110,10 @@
     private final DropDownItemClickListener mDropDownItemClickListener =
             new DropDownItemClickListener();
 
+    private boolean mDropDownAlwaysVisible = false;
+
+    private boolean mDropDownDismissedOnCompletion = true;
+
     private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
     private boolean mOpenBefore;
 
@@ -211,6 +215,8 @@
      * {@link ViewGroup.LayoutParams#WRAP_CONTENT} to fit the width of its anchor view.</p>
      * 
      * @return the width for the drop down list
+     * 
+     * @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth
      */
     public int getDropDownWidth() {
         return mDropDownWidth;
@@ -222,6 +228,8 @@
      * {@link ViewGroup.LayoutParams#WRAP_CONTENT} to fit the width of its anchor view.</p>
      * 
      * @param width the width to use
+     * 
+     * @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth
      */
     public void setDropDownWidth(int width) {
         mDropDownWidth = width;
@@ -231,6 +239,8 @@
      * <p>Returns the id for the view that the auto-complete drop down list is anchored to.</p>
      *  
      * @return the view's id, or {@link View#NO_ID} if none specified
+     * 
+     * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor
      */
     public int getDropDownAnchor() {
         return mDropDownAnchorId;
@@ -242,13 +252,173 @@
      * loading a view which is not yet instantiated.</p>
      * 
      * @param id the id to anchor the drop down list view to
+     * 
+     * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor 
      */
     public void setDropDownAnchor(int id) {
         mDropDownAnchorId = id;
         mDropDownAnchorView = null;
     }
+    
+    /**
+     * <p>Gets the background of the auto-complete drop-down list.</p>
+     * 
+     * @return the background drawable
+     * 
+     * @attr ref android.R.styleable#PopupWindow_popupBackground
+     *
+     * @hide Pending API council approval
+     */
+    public Drawable getDropDownBackground() {
+        return mPopup.getBackground();
+    }
+    
+    /**
+     * <p>Sets the background of the auto-complete drop-down list.</p>
+     * 
+     * @param d the drawable to set as the background
+     * 
+     * @attr ref android.R.styleable#PopupWindow_popupBackground
+     *
+     * @hide Pending API council approval
+     */
+    public void setDropDownBackgroundDrawable(Drawable d) {
+        mPopup.setBackgroundDrawable(d);
+    }
+    
+    /**
+     * <p>Sets the background of the auto-complete drop-down list.</p>
+     * 
+     * @param id the id of the drawable to set as the background
+     * 
+     * @attr ref android.R.styleable#PopupWindow_popupBackground
+     *
+     * @hide Pending API council approval
+     */
+    public void setDropDownBackgroundResource(int id) {
+        mPopup.setBackgroundDrawable(getResources().getDrawable(id));
+    }
 
     /**
+     * <p>Sets the animation style of the auto-complete drop-down list.</p>
+     *
+     * <p>If the drop-down is showing, calling this method will take effect only
+     * the next time the drop-down is shown.</p>
+     *
+     * @param animationStyle animation style to use when the drop-down appears
+     *      and disappears.  Set to -1 for the default animation, 0 for no
+     *      animation, or a resource identifier for an explicit animation.
+     *
+     * @hide Pending API council approval
+     */
+    public void setDropDownAnimationStyle(int animationStyle) {
+        mPopup.setAnimationStyle(animationStyle);
+    }
+
+    /**
+     * <p>Returns the animation style that is used when the drop-down list appears and disappears
+     * </p>
+     *
+     * @return the animation style that is used when the drop-down list appears and disappears
+     *
+     * @hide Pending API council approval
+     */
+    public int getDropDownAnimationStyle() {
+        return mPopup.getAnimationStyle();
+    }
+    
+    /**
+     * <p>Sets the vertical offset used for the auto-complete drop-down list.</p>
+     * 
+     * @param offset the vertical offset
+     *
+     * @hide Pending API council approval
+     */
+    public void setDropDownVerticalOffset(int offset) {
+        mDropDownVerticalOffset = offset;
+    }
+    
+    /**
+     * <p>Gets the vertical offset used for the auto-complete drop-down list.</p>
+     * 
+     * @return the vertical offset
+     *
+     * @hide Pending API council approval
+     */
+    public int getDropDownVerticalOffset() {
+        return mDropDownVerticalOffset;
+    }
+    
+    /**
+     * <p>Sets the horizontal offset used for the auto-complete drop-down list.</p>
+     * 
+     * @param offset the horizontal offset
+     *
+     * @hide Pending API council approval
+     */
+    public void setDropDownHorizontalOffset(int offset) {
+        mDropDownHorizontalOffset = offset;
+    }
+    
+    /**
+     * <p>Gets the horizontal offset used for the auto-complete drop-down list.</p>
+     * 
+     * @return the horizontal offset
+     *
+     * @hide Pending API council approval
+     */
+    public int getDropDownHorizontalOffset() {
+        return mDropDownHorizontalOffset;
+    }
+
+    /**
+     * @return Whether the drop-down is visible as long as there is {@link #enoughToFilter()}
+     *
+     * @hide Pending API council approval
+     */
+    public boolean isDropDownAlwaysVisible() {
+        return mDropDownAlwaysVisible;
+    }
+
+    /**
+     * Sets whether the drop-down should remain visible as long as there is there is
+     * {@link #enoughToFilter()}.  This is useful if an unknown number of results are expected
+     * to show up in the adapter sometime in the future.
+     *
+     * The drop-down will occupy the entire screen below {@link #getDropDownAnchor} regardless
+     * of the size or content of the list.  {@link #getDropDownBackground()} will fill any space
+     * that is not used by the list.
+     *
+     * @param dropDownAlwaysVisible Whether to keep the drop-down visible.
+     *
+     * @hide Pending API council approval
+     */
+    public void setDropDownAlwaysVisible(boolean dropDownAlwaysVisible) {
+        mDropDownAlwaysVisible = dropDownAlwaysVisible;
+    }
+   
+    /**
+     * Checks whether the drop-down is dismissed when a suggestion is clicked.
+     * 
+     * @hide Pending API council approval
+     */
+    public boolean isDropDownDismissedOnCompletion() {
+        return mDropDownDismissedOnCompletion;
+    }
+    
+    /**
+     * Sets whether the drop-down is dismissed when a suggestion is clicked. This is 
+     * true by default.
+     * 
+     * @param dropDownDismissedOnCompletion Whether to dismiss the drop-down.
+     * 
+     * @hide Pending API council approval
+     */
+    public void setDropDownDismissedOnCompletion(boolean dropDownDismissedOnCompletion) {
+        mDropDownDismissedOnCompletion = dropDownDismissedOnCompletion;
+    }
+ 
+    /**
      * <p>Returns the number of characters the user must type before the drop
      * down list is shown.</p>
      *
@@ -628,16 +798,6 @@
         }
         return ListView.INVALID_POSITION;
     }
-    
-    /**
-     * We're changing the adapter and its views so really, really clear everything out
-     * @hide - for SearchDialog only
-     */
-    public void resetListAndClearViews() {
-        if (mDropDownList != null) {
-            mDropDownList.resetListAndClearViews();
-        }
-    }
 
     /**
      * <p>Starts filtering the content of the drop down list. The filtering
@@ -709,7 +869,9 @@
             }
         }
 
-        dismissDropDown();
+        if (mDropDownDismissedOnCompletion) {
+            dismissDropDown();
+        }
     }
     
     /**
@@ -721,6 +883,42 @@
     }
 
     /**
+     * Like {@link #setText(CharSequence)}, except that it can disable filtering.
+     *
+     * @param filter If <code>false</code>, no filtering will be performed
+     *        as a result of this call.
+     * 
+     * @hide Pending API council approval.
+     */
+    public void setText(CharSequence text, boolean filter) {
+        if (filter) {
+            setText(text);
+        } else {
+            mBlockCompletion = true;
+            setText(text);
+            mBlockCompletion = false;
+        }
+    }
+    
+    /**
+     * Like {@link #setTextKeepState(CharSequence)}, except that it can disable filtering.
+     *
+     * @param filter If <code>false</code>, no filtering will be performed
+     *        as a result of this call.
+     * 
+     * @hide Pending API council approval.
+     */
+    public void setTextKeepState(CharSequence text, boolean filter) {
+        if (filter) {
+            setTextKeepState(text);
+        } else {
+            mBlockCompletion = true;
+            setTextKeepState(text);
+            mBlockCompletion = false;
+        }
+    }
+    
+    /**
      * <p>Performs the text completion by replacing the current text by the
      * selected item. Subclasses should override this method to avoid replacing
      * the whole content of the edit box.</p>
@@ -734,6 +932,7 @@
         Selection.setSelection(spannable, spannable.length());
     }
 
+    /** {@inheritDoc} */
     public void onFilterComplete(int count) {
         if (mAttachCount <= 0) return;
 
@@ -744,7 +943,7 @@
          * to filter.
          */
 
-        if (count > 0 && enoughToFilter()) {
+        if ((count > 0 || mDropDownAlwaysVisible) && enoughToFilter()) {
             if (hasFocus() && hasWindowFocus()) {
                 showDropDown();
             }
@@ -809,22 +1008,6 @@
     }
     
     /**
-     * Set the horizontal offset with respect to {@link #setDropDownAnchor(int)}
-     * @hide pending API council review
-     */
-    public void setDropDownHorizontalOffset(int horizontalOffset) {
-        mDropDownHorizontalOffset = horizontalOffset;
-    }
-    
-    /**
-     * Set the vertical offset with respect to {@link #setDropDownAnchor(int)}
-     * @hide pending API council review
-     */
-    public void setDropDownVerticalOffset(int verticalOffset) {
-        mDropDownVerticalOffset = verticalOffset;
-    }
-
-    /**
      * <p>Used for lazy instantiation of the anchor view from the id we have. If the value of
      * the id is NO_ID or we can't find a view for the given id, we return this TextView as
      * the default anchoring point.</p>
@@ -856,10 +1039,9 @@
                     mDropDownVerticalOffset, widthSpec, height);
         } else {
             if (mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT) {
-                mPopup.setWindowLayoutMode(ViewGroup.LayoutParams.FILL_PARENT,
-                        ViewGroup.LayoutParams.WRAP_CONTENT);
+                mPopup.setWindowLayoutMode(ViewGroup.LayoutParams.FILL_PARENT, 0);
             } else {
-                mPopup.setWindowLayoutMode(0, ViewGroup.LayoutParams.WRAP_CONTENT);
+                mPopup.setWindowLayoutMode(0, 0);
                 if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
                     mPopup.setWidth(getDropDownAnchorView().getWidth());
                 } else {
@@ -966,8 +1148,10 @@
         final int maxHeight = mPopup.getMaxAvailableHeight(this, mDropDownVerticalOffset);
         //otherHeights += dropDownView.getPaddingTop() + dropDownView.getPaddingBottom();
 
-        return mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
+        final int measuredHeight = mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
                 0, ListView.NO_POSITION, maxHeight - otherHeights, 2) + otherHeights;
+
+        return mDropDownAlwaysVisible ? maxHeight : measuredHeight;
     }
 
     private View getHintView(Context context) {
diff --git a/core/java/com/android/internal/util/TypedProperties.java b/core/java/com/android/internal/util/TypedProperties.java
new file mode 100644
index 0000000..48479e3
--- /dev/null
+++ b/core/java/com/android/internal/util/TypedProperties.java
@@ -0,0 +1,692 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.util;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StreamTokenizer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * A {@code Map} that publishes a set of typed properties, defined by
+ * zero or more {@code Reader}s containing textual definitions and assignments.
+ */
+public class TypedProperties extends HashMap<String, Object> {
+    /**
+     * Instantiates a {@link java.io.StreamTokenizer} and sets its syntax tables
+     * appropriately for the {@code TypedProperties} file format.
+     *
+     * @param r The {@code Reader} that the {@code StreamTokenizer} will read from
+     * @return a newly-created and initialized {@code StreamTokenizer}
+     */
+    static StreamTokenizer initTokenizer(Reader r) {
+        StreamTokenizer st = new StreamTokenizer(r);
+
+        // Treat everything we don't specify as "ordinary".
+        st.resetSyntax();
+
+        /* The only non-quoted-string words we'll be reading are:
+         * - property names: [._$a-zA-Z0-9]
+         * - type names (case insensitive): [a-zA-Z]
+         * - number literals: [-0-9.eExXA-Za-z]  ('x' for 0xNNN hex literals. "NaN", "Infinity")
+         * - "true" or "false" (case insensitive): [a-zA-Z]
+         */
+        st.wordChars('0', '9');
+        st.wordChars('A', 'Z');
+        st.wordChars('a', 'z');
+        st.wordChars('_', '_');
+        st.wordChars('$', '$');
+        st.wordChars('.', '.');
+        st.wordChars('-', '-');
+        st.wordChars('+', '+');
+
+        // Single-character tokens
+        st.ordinaryChar('=');
+
+        // Other special characters
+        st.whitespaceChars(' ', ' ');
+        st.whitespaceChars('\t', '\t');
+
+        st.quoteChar('"');
+
+        st.commentChar('#');
+
+        st.eolIsSignificant(true);
+
+        return st;
+    }
+
+
+    /**
+     * An unchecked exception that is thrown when encountering a syntax
+     * or semantic error in the input.
+     */
+    public static class ParseException extends IllegalArgumentException {
+        ParseException(StreamTokenizer state, String expected) {
+            super("expected " + expected + ", saw " + state.toString());
+        }
+    }
+
+    // A sentinel instance used to indicate a null string.
+    static final String NULL_STRING = new String("<TypedProperties:NULL_STRING>");
+
+    // Constants used to represent the supported types.
+    static final int TYPE_UNSET = 'x';
+    static final int TYPE_BOOLEAN = 'Z';
+    static final int TYPE_BYTE = 'I' | 1 << 8;
+    // TYPE_CHAR: character literal syntax not supported; use short.
+    static final int TYPE_SHORT = 'I' | 2 << 8;
+    static final int TYPE_INT = 'I' | 4 << 8;
+    static final int TYPE_LONG = 'I' | 8 << 8;
+    static final int TYPE_FLOAT = 'F' | 4 << 8;
+    static final int TYPE_DOUBLE = 'F' | 8 << 8;
+    static final int TYPE_STRING = 'L' | 's' << 8;
+    static final int TYPE_ERROR = -1;
+
+    /**
+     * Converts a case-insensitive string to an internal type constant.
+     *
+     * @param typeName the type name to convert
+     * @return the type constant that corresponds to {@code typeName},
+     *         or {@code TYPE_ERROR} if the type is unknown
+     */
+    static int interpretType(String typeName) {
+        if ("unset".equalsIgnoreCase(typeName)) {
+            return TYPE_UNSET;
+        } else if ("boolean".equalsIgnoreCase(typeName)) {
+            return TYPE_BOOLEAN;
+        } else if ("byte".equalsIgnoreCase(typeName)) {
+            return TYPE_BYTE;
+        } else if ("short".equalsIgnoreCase(typeName)) {
+            return TYPE_SHORT;
+        } else if ("int".equalsIgnoreCase(typeName)) {
+            return TYPE_INT;
+        } else if ("long".equalsIgnoreCase(typeName)) {
+            return TYPE_LONG;
+        } else if ("float".equalsIgnoreCase(typeName)) {
+            return TYPE_FLOAT;
+        } else if ("double".equalsIgnoreCase(typeName)) {
+            return TYPE_DOUBLE;
+        } else if ("string".equalsIgnoreCase(typeName)) {
+            return TYPE_STRING;
+        }
+        return TYPE_ERROR;
+    }
+
+    /**
+     * Consumes EOL tokens.
+     * Returns when a non-EOL token is found.
+     *
+     * @param st The {@code StreamTokenizer} to read tokens from
+     * @return &gt; 0 if an EOL token was seen, &lt; 0 if EOF was seen,
+     *         0 if no tokens were consumed
+     */
+    static int eatEols(StreamTokenizer st) throws IOException {
+        int token;
+        boolean eolSeen = false;
+        do {
+            token = st.nextToken();
+            if (token == StreamTokenizer.TT_EOF) {
+                return -1;
+            } else if (token == StreamTokenizer.TT_EOL) {
+                eolSeen = true;
+            }
+        } while (token == StreamTokenizer.TT_EOL);
+        st.pushBack();
+        return eolSeen ? 1 : 0;
+    }
+
+    /**
+     * Parses the data in the reader.
+     *
+     * @param r The {@code Reader} containing input data to parse
+     * @param map The {@code Map} to insert parameter values into
+     * @throws ParseException if the input data is malformed
+     * @throws IOException if there is a problem reading from the {@code Reader}
+     */
+    static void parse(Reader r, Map<String, Object> map) throws ParseException, IOException {
+        final StreamTokenizer st = initTokenizer(r);
+
+        /* A property name must be a valid fully-qualified class + package name.
+         * We don't support Unicode, though.
+         */
+        final String identifierPattern = "[a-zA-Z_$][0-9a-zA-Z_$]*";
+        final Pattern propertyNamePattern =
+            Pattern.compile("(" + identifierPattern + "\\.)*" + identifierPattern);
+
+
+        boolean eolNeeded = false;
+        while (true) {
+            int token;
+
+            // Eat one or more EOL, or quit on EOF.
+            int eolStatus = eatEols(st);
+            if (eolStatus < 0) {
+                // EOF occurred.
+                break;
+            } else if (eolNeeded && eolStatus == 0) {
+                throw new ParseException(st, "end of line or end of file");
+            }
+
+            // Read the property name.
+            token = st.nextToken();
+            if (token != StreamTokenizer.TT_WORD) {
+                throw new ParseException(st, "property name");
+            }
+            final String propertyName = st.sval;
+            if (!propertyNamePattern.matcher(propertyName).matches()) {
+                throw new ParseException(st, "valid property name");
+            }
+            st.sval = null;
+
+            // Read the type.
+            token = st.nextToken();
+            if (token != StreamTokenizer.TT_WORD) {
+                throw new ParseException(st, "type name");
+            }
+            final int type = interpretType(st.sval);
+            if (type == TYPE_ERROR) {
+                throw new ParseException(st, "valid type name");
+            }
+            st.sval = null;
+
+            if (type == TYPE_UNSET) {
+                map.remove(propertyName);
+            } else {
+                // Expect '='.
+                token = st.nextToken();
+                if (token != '=') {
+                    throw new ParseException(st, "'='");
+                }
+
+                // Read a value of the appropriate type, and insert into the map.
+                final Object value = parseValue(st, type);
+                final Object oldValue = map.remove(propertyName);
+                if (oldValue != null) {
+                    // TODO: catch the case where a string is set to null and then
+                    //       the same property is defined with a different type.
+                    if (value.getClass() != oldValue.getClass()) {
+                        throw new ParseException(st,
+                            "(property previously declared as a different type)");
+                    }
+                }
+                map.put(propertyName, value);
+            }
+
+            // Require that we see at least one EOL before the next token.
+            eolNeeded = true;
+        }
+    }
+
+    /**
+     * Parses the next token in the StreamTokenizer as the specified type.
+     *
+     * @param st The token source
+     * @param type The type to interpret next token as
+     * @return a Boolean, Number subclass, or String representing the value.
+     *         Null strings are represented by the String instance NULL_STRING
+     * @throws IOException if there is a problem reading from the {@code StreamTokenizer}
+     */
+    static Object parseValue(StreamTokenizer st, final int type) throws IOException {
+        final int token = st.nextToken();
+
+        if (type == TYPE_BOOLEAN) {
+            if (token != StreamTokenizer.TT_WORD) {
+                throw new ParseException(st, "boolean constant");
+            }
+
+            if ("true".equalsIgnoreCase(st.sval)) {
+                return Boolean.TRUE;
+            } else if ("false".equalsIgnoreCase(st.sval)) {
+                return Boolean.FALSE;
+            }
+
+            throw new ParseException(st, "boolean constant");
+        } else if ((type & 0xff) == 'I') {
+            if (token != StreamTokenizer.TT_WORD) {
+                throw new ParseException(st, "integer constant");
+            }
+
+            /* Parse the string.  Long.decode() handles C-style integer constants
+             * ("0x" -> hex, "0" -> octal).  It also treats numbers with a prefix of "#" as
+             * hex, but our syntax intentionally does not list '#' as a word character.
+             */
+            long value;
+            try {
+                value = Long.decode(st.sval);
+            } catch (NumberFormatException ex) {
+                throw new ParseException(st, "integer constant");
+            }
+
+            // Ensure that the type can hold this value, and return.
+            int width = (type >> 8) & 0xff;
+            switch (width) {
+            case 1:
+                if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
+                    throw new ParseException(st, "8-bit integer constant");
+                }
+                return new Byte((byte)value);
+            case 2:
+                if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
+                    throw new ParseException(st, "16-bit integer constant");
+                }
+                return new Short((short)value);
+            case 4:
+                if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
+                    throw new ParseException(st, "32-bit integer constant");
+                }
+                return new Integer((int)value);
+            case 8:
+                if (value < Long.MIN_VALUE || value > Long.MAX_VALUE) {
+                    throw new ParseException(st, "64-bit integer constant");
+                }
+                return new Long(value);
+            default:
+                throw new IllegalStateException(
+                    "Internal error; unexpected integer type width " + width);
+            }
+        } else if ((type & 0xff) == 'F') {
+            if (token != StreamTokenizer.TT_WORD) {
+                throw new ParseException(st, "float constant");
+            }
+
+            // Parse the string.
+            /* TODO: Maybe just parse as float or double, losing precision if necessary.
+             *       Parsing as double and converting to float can change the value
+             *       compared to just parsing as float.
+             */
+            double value;
+            try {
+                /* TODO: detect if the string representation loses precision
+                 *       when being converted to a double.
+                 */
+                value = Double.parseDouble(st.sval);
+            } catch (NumberFormatException ex) {
+                throw new ParseException(st, "float constant");
+            }
+
+            // Ensure that the type can hold this value, and return.
+            if (((type >> 8) & 0xff) == 4) {
+                // This property is a float; make sure the value fits.
+                double absValue = Math.abs(value);
+                if (absValue != 0.0 && !Double.isInfinite(value) && !Double.isNaN(value)) {
+                    if (absValue < Float.MIN_VALUE || absValue > Float.MAX_VALUE) {
+                        throw new ParseException(st, "32-bit float constant");
+                    }
+                }
+                return new Float((float)value);
+            } else {
+                // This property is a double; no need to truncate.
+                return new Double(value);
+            }
+        } else if (type == TYPE_STRING) {
+            // Expect a quoted string or the word "null".
+            if (token == '"') {
+                return st.sval;
+            } else if (token == StreamTokenizer.TT_WORD && "null".equalsIgnoreCase(st.sval)) {
+                return NULL_STRING;
+            }
+            throw new ParseException(st, "double-quoted string or 'null'");
+        }
+
+        throw new IllegalStateException("Internal error; unknown type " + type);
+    }
+
+
+    /**
+     * Creates an empty TypedProperties instance.
+     */
+    public TypedProperties() {
+        super();
+    }
+
+    /**
+     * Loads zero or more properties from the specified Reader.
+     * Properties that have already been loaded are preserved unless
+     * the new Reader overrides or unsets earlier values for the
+     * same properties.
+     *
+     * File syntax:
+     *
+     *     &lt;property-name&gt; &lt;type&gt; = &lt;value&gt;
+     *     &lt;property-name&gt; unset
+     *
+     *     '#' is a comment character; it and anything appearing after it
+     *     on the line is ignored.
+     *
+     *     Blank lines are ignored.
+     *
+     *     The only required whitespace is between the property name
+     *     and the type.
+     *
+     *     Property assignments may not be split across multiple lines.
+     *
+     *     &lt;property-name&gt; is a valid fully-qualified class name
+     *     (one or more valid identifiers separated by dot characters).
+     *
+     *     &lt;type&gt; is one of {boolean, byte, short, int, long,
+     *     float, double, string}, and is case-insensitive.
+     *
+     *     &lt;value&gt; depends on the type:
+     *     - boolean: one of {true, false} (case-insensitive)
+     *     - byte, short, int, long: a valid Java integer constant
+     *       (including non-base-10 constants like 0xabc and 074)
+     *       whose value does not overflow the type.  NOTE: these are
+     *       interpreted as Java integer values, so they are all signed.
+     *     - float, double: a valid Java floating-point constant.
+     *       If the type is float, the value must fit in 32 bits.
+     *     - string: a double-quoted string value, or the word {@code null}.
+     *       NOTE: the contents of the string must be 7-bit clean ASCII;
+     *       C-style octal escapes are recognized, but Unicode escapes are not.
+     *
+     *
+     * @param r The Reader to load properties from
+     * @throws IOException if an error occurs when reading the data
+     * @throws IllegalArgumentException if the data is malformed
+     */
+    public void load(Reader r) throws IOException {
+        parse(r, this);
+    }
+
+    @Override
+    public Object get(Object key) {
+        Object value = super.get(key);
+        if (value == NULL_STRING) {
+            return null;
+        }
+        return value;
+    }
+
+    /*
+     * Getters with explicit defaults
+     */
+
+    /**
+     * An unchecked exception that is thrown if a {@code get&lt;TYPE&gt;()} method
+     * is used to retrieve a parameter whose type does not match the method name.
+     */
+    public static class TypeException extends IllegalArgumentException {
+        TypeException(String property, Object value, String requestedType) {
+            super(property + " has type " + value.getClass().getName() +
+                ", not " + requestedType);
+        }
+    }
+
+    /**
+     * Returns the value of a boolean property, or the default if the property
+     * has not been defined.
+     *
+     * @param property The name of the property to return
+     * @param def The default value to return if the property is not set
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a boolean
+     */
+    public boolean getBoolean(String property, boolean def) {
+        Object value = super.get(property);
+        if (value == null) {
+            return def;
+        }
+        if (value instanceof Boolean) {
+            return ((Boolean)value).booleanValue();
+        }
+        throw new TypeException(property, value, "boolean");
+    }
+
+    /**
+     * Returns the value of a byte property, or the default if the property
+     * has not been defined.
+     *
+     * @param property The name of the property to return
+     * @param def The default value to return if the property is not set
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a byte
+     */
+    public byte getByte(String property, byte def) {
+        Object value = super.get(property);
+        if (value == null) {
+            return def;
+        }
+        if (value instanceof Byte) {
+            return ((Byte)value).byteValue();
+        }
+        throw new TypeException(property, value, "byte");
+    }
+
+    /**
+     * Returns the value of a short property, or the default if the property
+     * has not been defined.
+     *
+     * @param property The name of the property to return
+     * @param def The default value to return if the property is not set
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a short
+     */
+    public short getShort(String property, short def) {
+        Object value = super.get(property);
+        if (value == null) {
+            return def;
+        }
+        if (value instanceof Short) {
+            return ((Short)value).shortValue();
+        }
+        throw new TypeException(property, value, "short");
+    }
+
+    /**
+     * Returns the value of an integer property, or the default if the property
+     * has not been defined.
+     *
+     * @param property The name of the property to return
+     * @param def The default value to return if the property is not set
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not an integer
+     */
+    public int getInt(String property, int def) {
+        Object value = super.get(property);
+        if (value == null) {
+            return def;
+        }
+        if (value instanceof Integer) {
+            return ((Integer)value).intValue();
+        }
+        throw new TypeException(property, value, "int");
+    }
+
+    /**
+     * Returns the value of a long property, or the default if the property
+     * has not been defined.
+     *
+     * @param property The name of the property to return
+     * @param def The default value to return if the property is not set
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a long
+     */
+    public long getLong(String property, long def) {
+        Object value = super.get(property);
+        if (value == null) {
+            return def;
+        }
+        if (value instanceof Long) {
+            return ((Long)value).longValue();
+        }
+        throw new TypeException(property, value, "long");
+    }
+
+    /**
+     * Returns the value of a float property, or the default if the property
+     * has not been defined.
+     *
+     * @param property The name of the property to return
+     * @param def The default value to return if the property is not set
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a float
+     */
+    public float getFloat(String property, float def) {
+        Object value = super.get(property);
+        if (value == null) {
+            return def;
+        }
+        if (value instanceof Float) {
+            return ((Float)value).floatValue();
+        }
+        throw new TypeException(property, value, "float");
+    }
+
+    /**
+     * Returns the value of a double property, or the default if the property
+     * has not been defined.
+     *
+     * @param property The name of the property to return
+     * @param def The default value to return if the property is not set
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a double
+     */
+    public double getDouble(String property, double def) {
+        Object value = super.get(property);
+        if (value == null) {
+            return def;
+        }
+        if (value instanceof Double) {
+            return ((Double)value).doubleValue();
+        }
+        throw new TypeException(property, value, "double");
+    }
+
+    /**
+     * Returns the value of a string property, or the default if the property
+     * has not been defined.
+     *
+     * @param property The name of the property to return
+     * @param def The default value to return if the property is not set
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a string
+     */
+    public String getString(String property, String def) {
+        Object value = super.get(property);
+        if (value == null) {
+            return def;
+        }
+        if (value == NULL_STRING) {
+            return null;
+        } else if (value instanceof String) {
+            return (String)value;
+        }
+        throw new TypeException(property, value, "string");
+    }
+
+    /*
+     * Getters with implicit defaults
+     */
+
+    /**
+     * Returns the value of a boolean property, or false
+     * if the property has not been defined.
+     *
+     * @param property The name of the property to return
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a boolean
+     */
+    public boolean getBoolean(String property) {
+        return getBoolean(property, false);
+    }
+
+    /**
+     * Returns the value of a byte property, or 0
+     * if the property has not been defined.
+     *
+     * @param property The name of the property to return
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a byte
+     */
+    public byte getByte(String property) {
+        return getByte(property, (byte)0);
+    }
+
+    /**
+     * Returns the value of a short property, or 0
+     * if the property has not been defined.
+     *
+     * @param property The name of the property to return
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a short
+     */
+    public short getShort(String property) {
+        return getShort(property, (short)0);
+    }
+
+    /**
+     * Returns the value of an integer property, or 0
+     * if the property has not been defined.
+     *
+     * @param property The name of the property to return
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not an integer
+     */
+    public int getInt(String property) {
+        return getInt(property, 0);
+    }
+
+    /**
+     * Returns the value of a long property, or 0
+     * if the property has not been defined.
+     *
+     * @param property The name of the property to return
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a long
+     */
+    public long getLong(String property) {
+        return getLong(property, 0L);
+    }
+
+    /**
+     * Returns the value of a float property, or 0.0
+     * if the property has not been defined.
+     *
+     * @param property The name of the property to return
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a float
+     */
+    public float getFloat(String property) {
+        return getFloat(property, 0.0f);
+    }
+
+    /**
+     * Returns the value of a double property, or 0.0
+     * if the property has not been defined.
+     *
+     * @param property The name of the property to return
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a double
+     */
+    public double getDouble(String property) {
+        return getDouble(property, 0.0);
+    }
+
+    /**
+     * Returns the value of a String property, or ""
+     * if the property has not been defined.
+     *
+     * @param property The name of the property to return
+     * @return the value of the property
+     * @throws TypeException if the property is set and is not a string
+     */
+    public String getString(String property) {
+        return getString(property, "");
+    }
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9f6ebed..caa1318 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -366,6 +366,23 @@
         android:label="@string/permlab_readPhoneState"
         android:description="@string/permdesc_readPhoneState" />
 
+    <!-- ================================== -->
+    <!-- Permissions for sdcard interaction -->
+    <!-- ================================== -->
+    <eat-comment />
+
+    <!-- Group of permissions that are related to SD card access. -->
+    <permission-group android:name="android.permission-group.STORAGE"
+        android:label="@string/permgrouplab_storage"
+        android:description="@string/permgroupdesc_storage" />
+
+    <!-- Allows an application to write to the SD card -->
+    <permission android:name="android.permission.SDCARD_WRITE"
+        android:permissionGroup="android.permission-group.STORAGE"
+        android:label="@string/permlab_sdcardWrite"
+        android:description="@string/permdesc_sdcardWrite"
+        android:protectionLevel="normal" />
+
     <!-- ============================================ -->
     <!-- Permissions for low-level system interaction -->
     <!-- ============================================ -->
diff --git a/core/res/res/drawable/btn_global_search.xml b/core/res/res/drawable/btn_global_search.xml
new file mode 100644
index 0000000..531f07e
--- /dev/null
+++ b/core/res/res/drawable/btn_global_search.xml
@@ -0,0 +1,33 @@
+<?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">
+    <!-- TODO Need different assets for some of these button states. -->
+    <item android:state_window_focused="false" android:state_enabled="true"
+        android:drawable="@drawable/btn_global_search_normal" />
+    <item android:state_window_focused="false" android:state_enabled="false"
+        android:drawable="@drawable/btn_global_search_normal" />
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/btn_default_pressed" />
+    <item android:state_focused="true" android:state_enabled="true"
+        android:drawable="@drawable/btn_default_selected" />
+    <item android:state_enabled="true"
+        android:drawable="@drawable/btn_global_search_normal" />
+    <item android:state_focused="true"
+        android:drawable="@drawable/btn_global_search_normal" />
+    <item
+         android:drawable="@drawable/btn_global_search_normal" />
+</selector>
diff --git a/core/res/res/drawable/btn_global_search_normal.9.png b/core/res/res/drawable/btn_global_search_normal.9.png
new file mode 100644
index 0000000..9b7d3e5
--- /dev/null
+++ b/core/res/res/drawable/btn_global_search_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog.xml b/core/res/res/drawable/btn_search_dialog.xml
new file mode 100644
index 0000000..b7f5187
--- /dev/null
+++ b/core/res/res/drawable/btn_search_dialog.xml
@@ -0,0 +1,33 @@
+<?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_window_focused="false" android:state_enabled="true"
+        android:drawable="@drawable/btn_search_dialog_default" />
+        
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/btn_search_dialog_pressed" />
+    
+    <item android:state_focused="true" android:state_enabled="true"
+        android:drawable="@drawable/btn_search_dialog_selected" />
+    
+    <item android:state_enabled="true"
+        android:drawable="@drawable/btn_search_dialog_default" />
+    
+    <item
+         android:drawable="@drawable/btn_search_dialog_default" />
+</selector>
diff --git a/core/res/res/drawable/btn_search_dialog_default.9.png b/core/res/res/drawable/btn_search_dialog_default.9.png
new file mode 100644
index 0000000..ec39178
--- /dev/null
+++ b/core/res/res/drawable/btn_search_dialog_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_pressed.9.png b/core/res/res/drawable/btn_search_dialog_pressed.9.png
new file mode 100644
index 0000000..5f52fef
--- /dev/null
+++ b/core/res/res/drawable/btn_search_dialog_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_selected.9.png b/core/res/res/drawable/btn_search_dialog_selected.9.png
new file mode 100644
index 0000000..9fc2fde
--- /dev/null
+++ b/core/res/res/drawable/btn_search_dialog_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_voice.xml b/core/res/res/drawable/btn_search_dialog_voice.xml
new file mode 100644
index 0000000..748aaf5
--- /dev/null
+++ b/core/res/res/drawable/btn_search_dialog_voice.xml
@@ -0,0 +1,33 @@
+<?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_window_focused="false" android:state_enabled="true"
+        android:drawable="@drawable/btn_search_dialog_voice_default" />
+        
+    <item android:state_pressed="true" 
+        android:drawable="@drawable/btn_search_dialog_voice_pressed" />
+    
+    <item android:state_focused="true" android:state_enabled="true"
+        android:drawable="@drawable/btn_search_dialog_voice_selected" />
+    
+    <item android:state_enabled="true"
+        android:drawable="@drawable/btn_search_dialog_voice_default" />
+    
+    <item
+         android:drawable="@drawable/btn_search_dialog_voice_default" />
+</selector>
diff --git a/core/res/res/drawable/btn_search_dialog_voice_default.9.png b/core/res/res/drawable/btn_search_dialog_voice_default.9.png
new file mode 100644
index 0000000..2a3366c
--- /dev/null
+++ b/core/res/res/drawable/btn_search_dialog_voice_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png b/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png
new file mode 100644
index 0000000..57d7a74
--- /dev/null
+++ b/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_voice_selected.9.png b/core/res/res/drawable/btn_search_dialog_voice_selected.9.png
new file mode 100644
index 0000000..db3187e
--- /dev/null
+++ b/core/res/res/drawable/btn_search_dialog_voice_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/search_dropdown_background.9.png b/core/res/res/drawable/search_dropdown_background.9.png
new file mode 100755
index 0000000..a6923b7
--- /dev/null
+++ b/core/res/res/drawable/search_dropdown_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/search_plate_global.9.png b/core/res/res/drawable/search_plate_global.9.png
new file mode 100644
index 0000000..126054b
--- /dev/null
+++ b/core/res/res/drawable/search_plate_global.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_search.xml b/core/res/res/drawable/textfield_search.xml
new file mode 100644
index 0000000..2923368
--- /dev/null
+++ b/core/res/res/drawable/textfield_search.xml
@@ -0,0 +1,31 @@
+<?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_window_focused="false" android:state_enabled="true"
+        android:drawable="@drawable/textfield_search_default" />
+        
+    <item android:state_pressed="true"
+        android:drawable="@drawable/textfield_search_pressed" />
+        
+    <item android:state_enabled="true" android:state_focused="true"
+        android:drawable="@drawable/textfield_search_selected" />
+    
+    <item android:drawable="@drawable/textfield_search_default" />
+    
+</selector>
+
diff --git a/core/res/res/drawable/textfield_search_default.9.png b/core/res/res/drawable/textfield_search_default.9.png
new file mode 100755
index 0000000..7dc5b27
--- /dev/null
+++ b/core/res/res/drawable/textfield_search_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_search_pressed.9.png b/core/res/res/drawable/textfield_search_pressed.9.png
new file mode 100644
index 0000000..da00c25
--- /dev/null
+++ b/core/res/res/drawable/textfield_search_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_search_selected.9.png b/core/res/res/drawable/textfield_search_selected.9.png
new file mode 100755
index 0000000..a9fd3b2
--- /dev/null
+++ b/core/res/res/drawable/textfield_search_selected.9.png
Binary files differ
diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml
index 5e296c5..4c5c456 100644
--- a/core/res/res/layout/resolve_list_item.xml
+++ b/core/res/res/layout/resolve_list_item.xml
@@ -23,7 +23,7 @@
     android:minHeight="?android:attr/listPreferredItemHeight"
     android:layout_height="wrap_content"
     android:layout_width="fill_parent"
-    android:paddingLeft="14dip"
+    android:paddingLeft="10dip"
     android:paddingRight="15dip">
 
     <!-- Activity icon when presenting dialog -->
@@ -42,13 +42,13 @@
             android:textAppearance="?android:attr/textAppearanceLargeInverse"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:paddingLeft="6dip" />
+            android:paddingLeft="10dip" />
         <!-- Extended activity info to distinguish between duplicate activity names -->
         <TextView android:id="@android:id/text2"
             android:textAppearance="?android:attr/textAppearanceMediumInverse"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:paddingLeft="6dip" />
+            android:paddingLeft="10dip" />
     </LinearLayout>
 </LinearLayout>
 
diff --git a/core/res/res/layout/search_bar.xml b/core/res/res/layout/search_bar.xml
index ef347da..6155626 100644
--- a/core/res/res/layout/search_bar.xml
+++ b/core/res/res/layout/search_bar.xml
@@ -26,79 +26,67 @@
     android:orientation="vertical" 
     android:focusable="true"
     android:descendantFocusability="afterDescendants">
-    <!-- android:paddingBottom="14dip"  TODO MUST FIX - it's a hack to get the popup to show -->
+    <!-- android:paddingBottom="200dip"  TODO MUST FIX - it's a hack to get the popup to show -->
 
     <!-- Outer layout defines the entire search bar at the top of the screen -->
-    <!-- Bottom padding of 16 is due to the graphic, with 9 extra pixels of drop
-         shadow, plus the desired padding of "8" against the user-visible (grey)
-         pixels, minus "1" to correct for positioning of the edittext & button. -->
     <LinearLayout
         android:id="@+id/search_plate"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical"
-        android:paddingLeft="8dip"
-        android:paddingRight="8dip"
-        android:paddingTop="6dip"
+        android:paddingLeft="12dip"
+        android:paddingRight="12dip"
+        android:paddingTop="7dip"
         android:paddingBottom="16dip"
-        android:baselineAligned="false"
-        android:background="@android:drawable/search_plate"
-        android:addStatesFromChildren="true" >
+        android:background="@drawable/search_plate_global" >
 
         <!-- This is actually used for the badge icon *or* the badge label (or neither) -->
         <TextView 
             android:id="@+id/search_badge"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:paddingLeft="2dip"
+            android:layout_marginBottom="2dip"
             android:drawablePadding="0dip"
             android:textAppearance="?android:attr/textAppearanceSmall"
-            android:textColor="?android:attr/textColorPrimary" />
+            android:textColor="?android:attr/textColorPrimaryInverse" />
 
         <!-- Inner layout contains the button(s) and EditText -->
-        <!-- The layout_marginTop of "1" corrects for the extra 1 pixel of padding at the top of 
-             textfield_selected.9.png.  The "real" margin as displayed is "2". -->
-        <!-- The layout_marginBottom of "-5" corrects for the spacing we see at the 
-             bottom of the edittext and button images.  The "real" margin as displayed is "8" -->
         <LinearLayout
             android:id="@+id/search_edit_frame"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="1dip"
-            android:layout_marginBottom="-5dip"
-            android:orientation="horizontal"
-            android:addStatesFromChildren="true"
-            android:gravity="center_vertical"
-            android:baselineAligned="false" >
-
+            android:orientation="horizontal">
+            
             <view class="android.app.SearchDialog$SearchAutoComplete"
                 android:id="@+id/search_src_text"
+                android:background="@drawable/textfield_search"
                 android:layout_height="wrap_content"
                 android:layout_width="0dip"
                 android:layout_weight="1.0"
                 android:paddingLeft="8dip"
                 android:paddingRight="6dip"
+                android:singleLine="true"
                 android:inputType="text|textAutoComplete"
                 android:dropDownWidth="fill_parent"
                 android:dropDownAnchor="@id/search_plate"
-                android:dropDownVerticalOffset="-15dip"
+                android:dropDownVerticalOffset="-9dip"
+                android:popupBackground="@android:drawable/search_dropdown_background"
                 />
-                <!-- android:focusableInTouchMode="false" -->
-                <!-- android:singleLine="true" -->
-                <!-- android:selectAllOnFocus="true" -->
                 
             <!-- This button can switch between text and icon "modes" -->
             <Button 
                 android:id="@+id/search_go_btn"
-                android:layout_marginLeft="1dip"
+                android:background="@drawable/btn_search_dialog"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:drawableLeft="@android:drawable/ic_btn_search"
+                android:layout_height="fill_parent"
             />
 
-            <ImageButton android:id="@+id/search_voice_btn"
+            <ImageButton
+                android:id="@+id/search_voice_btn"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_height="fill_parent"
+                android:layout_marginLeft="8dip"
+                android:background="@drawable/btn_search_dialog_voice"
                 android:src="@android:drawable/ic_btn_speak_now"
             />
         </LinearLayout>
diff --git a/core/res/res/layout/search_dropdown_item_1line.xml b/core/res/res/layout/search_dropdown_item_1line.xml
index 3827206..bf3dd48 100644
--- a/core/res/res/layout/search_dropdown_item_1line.xml
+++ b/core/res/res/layout/search_dropdown_item_1line.xml
@@ -20,7 +20,7 @@
 <TextView xmlns:android="http://schemas.android.com/apk/res/android" 
     android:id="@android:id/text1"
     style="?android:attr/dropDownItemStyle"
-    android:textAppearance="?android:attr/textAppearanceMediumInverse"
+    android:textAppearance="?android:attr/textAppearanceSearchResultTitle"
     android:singleLine="true"
     android:layout_width="fill_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight" />
+    android:layout_height="?android:attr/searchResultListItemHeight" />
\ No newline at end of file
diff --git a/core/res/res/layout/search_dropdown_item_2line.xml b/core/res/res/layout/search_dropdown_item_2line.xml
index 96d6005..5546b6636 100644
--- a/core/res/res/layout/search_dropdown_item_2line.xml
+++ b/core/res/res/layout/search_dropdown_item_2line.xml
@@ -20,15 +20,16 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
     android:layout_width="fill_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:layout_height="?android:attr/searchResultListItemHeight"
     android:orientation="horizontal"
     android:gravity="center_vertical"
     android:baselineAligned="false"
     >
     
     <TwoLineListItem
-        android:paddingTop="2dip"
-        android:paddingBottom="2dip"
+        android:paddingTop="1dip"
+        android:paddingBottom="1dip"
+        android:gravity="center_vertical"
         android:layout_width="0dip"
         android:layout_weight="1"
         android:layout_height="wrap_content"
@@ -37,7 +38,7 @@
         <TextView
             android:id="@android:id/text1"
             style="?android:attr/dropDownItemStyle"
-            android:textAppearance="?android:attr/textAppearanceMediumInverse"
+            android:textAppearance="?android:attr/textAppearanceSearchResultTitle"
             android:singleLine="true"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content" />
@@ -45,7 +46,7 @@
         <TextView
             android:id="@android:id/text2"
             style="?android:attr/dropDownItemStyle"
-            android:textAppearance="?android:attr/textAppearanceSmallInverse"
+            android:textAppearance="?android:attr/textAppearanceSearchResultSubtitle"
             android:textColor="?android:attr/textColorSecondaryInverse"
             android:singleLine="true"
             android:layout_width="fill_parent"
diff --git a/core/res/res/layout/search_dropdown_item_icons_1line.xml b/core/res/res/layout/search_dropdown_item_icons_1line.xml
index c0713d5..4f65d74 100644
--- a/core/res/res/layout/search_dropdown_item_icons_1line.xml
+++ b/core/res/res/layout/search_dropdown_item_icons_1line.xml
@@ -22,31 +22,33 @@
     <!-- of the text element in apps/common/res/layout/simple_dropdown_item_1line.xml -->
     
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
+    android:paddingLeft="4dip"
+    android:paddingRight="2dip"
     android:layout_width="fill_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:layout_height="?android:attr/searchResultListItemHeight"
     android:orientation="horizontal"
     android:gravity="center_vertical"
     android:baselineAligned="false"
     >
     
     <ImageView android:id="@android:id/icon1"
-        android:layout_width="32dip"
-        android:layout_height="32dip"
+        android:layout_width="48dip"
+        android:layout_height="48dip"
         android:layout_gravity="center_vertical"
-        android:scaleType="fitCenter" />
+        android:scaleType="centerInside" />
 
     <TextView android:id="@android:id/text1"
         style="?android:attr/dropDownItemStyle"
-        android:textAppearance="?android:attr/textAppearanceMediumInverse"
+        android:textAppearance="?android:attr/textAppearanceSearchResultTitle"
         android:singleLine="true"
         android:layout_height="wrap_content"
         android:layout_width="0dip"
         android:layout_weight="1"  />
 
     <ImageView android:id="@android:id/icon2"
-        android:layout_width="32dip"
-        android:layout_height="32dip"
+        android:layout_width="48dip"
+        android:layout_height="48dip"
         android:layout_gravity="center_vertical"
-        android:scaleType="fitCenter" />
+        android:scaleType="centerInside" />
 
 </LinearLayout>
diff --git a/core/res/res/layout/search_dropdown_item_icons_2line.xml b/core/res/res/layout/search_dropdown_item_icons_2line.xml
index ad1c905..0d07490 100644
--- a/core/res/res/layout/search_dropdown_item_icons_2line.xml
+++ b/core/res/res/layout/search_dropdown_item_icons_2line.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml
+/* 
 **
 ** Copyright 2008, The Android Open Source Project
 **
@@ -18,56 +18,62 @@
 */
 -->
 
-    <!-- NOTE: The appearance of the inner text element must match the appearance -->
-    <!-- of the text element in apps/common/res/layout/simple_dropdown_item_2line.xml -->
-    
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
+    android:paddingLeft="4dip"
+    android:paddingRight="2dip"
     android:layout_width="fill_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight"
-    android:orientation="horizontal"
-    android:gravity="center_vertical"
-    android:baselineAligned="false"
-    >
-    
-    <ImageView android:id="@android:id/icon1"
-        android:layout_width="32dip"
-        android:layout_height="32dip"
-        android:layout_gravity="center_vertical"
-        android:scaleType="fitCenter" />
+    android:layout_height="?android:attr/searchResultListItemHeight" >
 
-    <TwoLineListItem
-        android:paddingTop="2dip"
-        android:paddingBottom="2dip"
-        android:layout_width="0dip"
-        android:layout_weight="1"
-        android:layout_height="wrap_content"
-        android:mode="twoLine" >
-    
-        <TextView
-            android:id="@android:id/text1"
-            style="?android:attr/dropDownItemStyle"
-            android:textAppearance="?android:attr/textAppearanceMediumInverse"
-            android:singleLine="true"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content" />
-    
-        <TextView
-            android:id="@android:id/text2"
-            style="?android:attr/dropDownItemStyle"
-            android:textAppearance="?android:attr/textAppearanceSmallInverse"
-            android:textColor="?android:attr/textColorSecondaryInverse"
-            android:singleLine="true"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_below="@android:id/text1"
-            android:layout_alignLeft="@android:id/text1" />
-    
-    </TwoLineListItem>
+    <!-- Icons come first in the layout, since their placement doesn't depend on
+         the placement of the text views. -->    
+    <ImageView android:id="@android:id/icon1"
+        android:layout_width="48dip"
+        android:layout_height="48dip"
+        android:scaleType="centerInside"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentBottom="true"
+        android:visibility="gone" />
 
     <ImageView android:id="@android:id/icon2"
-        android:layout_width="32dip"
-        android:layout_height="32dip"
-        android:layout_gravity="center_vertical"
-        android:scaleType="fitCenter" />
+        android:layout_width="48dip"
+        android:layout_height="48dip"
+        android:scaleType="centerInside"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentBottom="true"
+        android:visibility="gone" />
 
-</LinearLayout>
+    <!-- The subtitle comes before the title, since the height of the title depends on whether the
+         subtitle is visible or gone. --> 
+    <TextView android:id="@android:id/text2"
+        style="?android:attr/dropDownItemStyle"
+        android:textAppearance="?android:attr/textAppearanceSearchResultSubtitle"
+        android:singleLine="true"
+        android:layout_width="fill_parent"
+        android:layout_height="29dip" 
+        android:paddingBottom="4dip"
+        android:gravity="top"
+        android:layout_toRightOf="@android:id/icon1"
+        android:layout_toLeftOf="@android:id/icon2"
+        android:layout_alignWithParentIfMissing="true" 
+        android:layout_alignParentBottom="true"
+        android:visibility="gone" />
+    
+    <!-- The title is placed above the subtitle, if there is one. If there is no
+         subtitle, it fills the parent. -->
+    <TextView android:id="@android:id/text1"
+        style="?android:attr/dropDownItemStyle"
+        android:textAppearance="?android:attr/textAppearanceSearchResultTitle"
+        android:singleLine="true"
+        android:layout_width="fill_parent"
+        android:layout_height="29dip"
+        android:paddingTop="4dip"
+        android:gravity="center_vertical"
+        android:layout_alignParentTop="true"
+        android:layout_toRightOf="@android:id/icon1"
+        android:layout_toLeftOf="@android:id/icon2"
+        android:layout_above="@android:id/text2"
+        android:layout_alignWithParentIfMissing="true" />
+    
+</RelativeLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b98558e..972953b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -94,6 +94,11 @@
         <!-- Text color, typeface, size, and style for "small" inverse text. Defaults to secondary inverse text color. -->
         <attr name="textAppearanceSmallInverse" format="reference" />
 
+        <!-- Text color, typeface, size, and style for system search result title. Defaults to primary inverse text color. @hide -->	
+        <attr name="textAppearanceSearchResultTitle" format="reference" />	
+        <!-- Text color, typeface, size, and style for system search result subtitle. Defaults to primary inverse text color. @hide -->	
+        <attr name="textAppearanceSearchResultSubtitle" format="reference" />
+
         <!-- Text color, typeface, size, and style for the text inside of a button. -->
         <attr name="textAppearanceButton" format="reference" />
         
@@ -147,6 +152,8 @@
         <!-- The preferred list item height -->
         <attr name="listPreferredItemHeight" format="dimension" />
         <!-- The drawable for the list divider -->
+	<!-- The list item height for search results. @hide -->
+	<attr name="searchResultListItemHeight" format="dimension" />
         <attr name="listDivider" format="reference" />
         <!-- TextView style for list separators. -->
         <attr name="listSeparatorTextViewStyle" format="reference" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8150a96..c35676c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -335,6 +335,11 @@
     <string name="permgroupdesc_developmentTools">Features only needed for
         application developers.</string>
 
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permgrouplab_storage">Storage</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permgroupdesc_storage">Access the SD card.</string>
+
     <!--  Permissions -->
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1045,6 +1050,11 @@
     <string name="permdesc_writeDictionary">Allows an application to write new words into the
       user dictionary.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_sdcardWrite">write to SD card</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_sdcardWrite">Allows an application to write to the SD card.</string>
+
     <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
     <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
     <string-array name="phoneTypes">
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index d7b654e..a436f61 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -138,6 +138,7 @@
     </style>
 
     <!-- Window animations that are applied to the search bar overlay window.
+	Previously used, but currently unused.
          {@hide Pending API council approval} -->
     <style name="Animation.SearchBar">
         <item name="windowEnterAnimation">@anim/search_bar_enter</item>
@@ -574,6 +575,24 @@
         <item name="android:textColor">@android:color/primary_text_light_disable_only</item>
     </style>
 
+    <!-- @hide -->	
+     <style name="TextAppearance.SearchResult">	
+         <item name="android:textStyle">normal</item>	
+         <item name="android:textColor">?textColorPrimaryInverse</item>	
+         <item name="android:textColorHint">?textColorHintInverse</item>	
+     </style>	
+     	
+     <!-- @hide -->	
+     <style name="TextAppearance.SearchResult.Title">	
+         <item name="android:textSize">16sp</item>	
+     </style>	
+     	
+     <!-- @hide -->	
+     <style name="TextAppearance.SearchResult.Subtitle">	
+         <item name="android:textSize">13sp</item>	
+         <item name="android:textColor">?textColorSecondaryInverse</item>	
+     </style>	
+
     <style name="TextAppearance.WindowTitle">
         <item name="android:textColor">#fff</item>
         <item name="android:textSize">14sp</item>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 6b3d740..dfd2391 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -57,6 +57,12 @@
         <item name="textAppearanceLargeInverse">@android:style/TextAppearance.Large.Inverse</item>
         <item name="textAppearanceMediumInverse">@android:style/TextAppearance.Medium.Inverse</item>
         <item name="textAppearanceSmallInverse">@android:style/TextAppearance.Small.Inverse</item>
+
+        <!-- @hide -->
+        <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.SearchResult.Title</item>
+        
+        <!-- @hide -->
+        <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.SearchResult.Subtitle</item>
         
         <item name="textAppearanceButton">@android:style/TextAppearance.Widget.Button</item>
         
@@ -75,6 +81,8 @@
 
         <!-- List attributes -->
         <item name="listPreferredItemHeight">64dip</item>
+        <!-- @hide -->
+        <item name="searchResultListItemHeight">58dip</item>
         <item name="listDivider">@drawable/divider_horizontal_dark</item>
         <item name="listSeparatorTextViewStyle">@android:style/Widget.TextView.ListSeparator</item>   
         
@@ -355,7 +363,6 @@
     <!-- Theme for the search input bar. -->
     <style name="Theme.SearchBar" parent="Theme.Panel">
         <item name="android:backgroundDimEnabled">true</item>
-        <item name="android:windowAnimationStyle">@android:style/Animation.SearchBar</item>
         <item name="windowContentOverlay">@null</item>        
     </style>
 
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index b13a292..f80bd6b 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -54,6 +54,10 @@
         <group gid="log" />
     </permission>
 
+    <permission name="android.permission.SDCARD_WRITE" >
+        <group gid="sdcard_rw" />
+    </permission>
+
     <!-- The group that /cache belongs to, linked to the permission
          set on the applications that can access /cache -->
     <permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index e593fea..12fa20f 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -78,8 +78,8 @@
 {
 public:
             // construct a camera client from an existing remote
-            Camera(const sp<ICamera>& camera);
-
+            Camera(const sp<ICamera>& camera);  // to be removed
+    static  sp<Camera>  create(const sp<ICamera>& camera);
     static  sp<Camera>  connect();
                         ~Camera();
             void        init();
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index d01d83f..9b8c302 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -988,119 +988,225 @@
         return diffs;
     }
     
-    // Return true if 'this' is more specific than 'o'.  Optionally, if
-    // 'requested' is null, then they will also be compared against the
-    // requested configuration and true will only be returned if 'this'
-    // is a better candidate than 'o' for the configuration.  This assumes that
-    // match() has already been used to remove any configurations that don't
-    // match the requested configuration at all; if they are not first filtered,
-    // non-matching results can be considered better than matching ones.
+    // Return true if 'this' is more specific than 'o'.
     inline bool
-    isBetterThan(const ResTable_config& o, const ResTable_config* requested = NULL) const {
+    isMoreSpecificThan(const ResTable_config& o) const {
         // The order of the following tests defines the importance of one
         // configuration parameter over another.  Those tests first are more
         // important, trumping any values in those following them.
-        if (imsi != 0 && (!requested || requested->imsi != 0)) {
-            if (mcc != 0 && (!requested || requested->mcc != 0)) {
-                if (o.mcc == 0) {
-                    return true;
-                }
+        if (imsi || o.imsi) {
+            if (mcc != o.mcc) {
+                if (!mcc) return false;
+                if (!o.mcc) return true;
             }
-            if (mnc != 0 && (!requested || requested->mnc != 0)) {
-                if (o.mnc == 0) {
-                    return true;
-                }
+
+            if (mnc != o.mnc) {
+                if (!mnc) return false;
+                if (!o.mnc) return true;
             }
         }
-        if (locale != 0 && (!requested || requested->locale != 0)) {
-            if (language[0] != 0 && (!requested || requested->language[0] != 0)) {
-                if (o.language[0] == 0) {
-                    return true;
-                }
+
+        if (locale || o.locale) {
+            if (language[0] != o.language[0]) {
+                if (!language[0]) return false;
+                if (!o.language[0]) return true;
             }
-            if (country[0] != 0 && (!requested || requested->country[0] != 0)) {
-                if (o.country[0] == 0) {
-                    return true;
-                }
+
+            if (country[0] != o.country[0]) {
+                if (!country[0]) return false;
+                if (!o.country[0]) return true;
             }
         }
-        if (screenType != 0 && (!requested || requested->screenType != 0)) {
-            if (orientation != 0 && (!requested || requested->orientation != 0)) {
-                if (o.orientation == 0) {
-                    return true;
-                }
+
+        if (screenType || o.screenType) {
+            if (orientation != o.orientation) {
+                if (!orientation) return false;
+                if (!o.orientation) return true;
             }
-            if (density != 0 && (!requested || requested->density != 0)) {
-                if (o.density == 0) {
-                    return true;
-                }
-            }
-            if (touchscreen != 0 && (!requested || requested->touchscreen != 0)) {
-                if (o.touchscreen == 0) {
-                    return true;
-                }
+
+            // density is never 'more specific'
+            // as the default just equals 160
+
+            if (touchscreen != o.touchscreen) {
+                if (!touchscreen) return false;
+                if (!o.touchscreen) return true;
             }
         }
-        if (input != 0 && (!requested || requested->input != 0)) {
-            const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
-            const int reqKeysHidden = requested
-                    ? requested->inputFlags&MASK_KEYSHIDDEN : 0;
-            if (keysHidden != 0 && reqKeysHidden != 0) {
-                const int oKeysHidden = o.inputFlags&MASK_KEYSHIDDEN;
-                //LOGI("isBetterThan keysHidden: cur=%d, given=%d, config=%d\n",
-                //        keysHidden, oKeysHidden, reqKeysHidden);
-                if (oKeysHidden == 0) {
-                    //LOGI("Better because 0!");
-                    return true;
-                }
-                // For compatibility, we count KEYSHIDDEN_NO as being
-                // the same as KEYSHIDDEN_SOFT.  Here we disambiguate these
-                // may making an exact match more specific.
-                if (keysHidden == reqKeysHidden && oKeysHidden != reqKeysHidden) {
-                    // The current configuration is an exact match, and
-                    // the given one is not, so the current one is better.
-                    //LOGI("Better because other not same!");
-                    return true;
-                }
+
+        if (input || o.input) {
+            if (inputFlags != o.inputFlags) {
+                if (!(inputFlags & MASK_KEYSHIDDEN)) return false;
+                if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true;
             }
-            if (keyboard != 0 && (!requested || requested->keyboard != 0)) {
-                if (o.keyboard == 0) {
-                    return true;
-                }
+
+            if (keyboard != o.keyboard) {
+                if (!keyboard) return false;
+                if (!o.keyboard) return true;
             }
-            if (navigation != 0 && (!requested || requested->navigation != 0)) {
-                if (o.navigation == 0) {
-                    return true;
-                }
+
+            if (navigation != o.navigation) {
+                if (!navigation) return false;
+                if (!o.navigation) return true;
             }
         }
-        if (screenSize != 0 && (!requested || requested->screenSize != 0)) {
-            if (screenWidth != 0 && (!requested || requested->screenWidth != 0)) {
-                if (o.screenWidth == 0) {
-                    return true;
-                }
+
+        if (screenSize || o.screenSize) {
+            if (screenWidth != o.screenWidth) {
+                if (!screenWidth) return false;
+                if (!o.screenWidth) return true;
             }
-            if (screenHeight != 0 && (!requested || requested->screenHeight != 0)) {
-                if (o.screenHeight == 0) {
-                    return true;
-                }
+
+            if (screenHeight != o.screenHeight) {
+                if (!screenHeight) return false;
+                if (!o.screenHeight) return true;
             }
         }
-        if (version != 0 && (!requested || requested->version != 0)) {
-            if (sdkVersion != 0 && (!requested || requested->sdkVersion != 0)) {
-                if (o.sdkVersion == 0) {
-                    return true;
-                }
+
+        if (version || o.version) {
+            if (sdkVersion != o.sdkVersion) {
+                if (!sdkVersion) return false;
+                if (!o.sdkVersion) return true;
             }
-            if (minorVersion != 0 && (!requested || requested->minorVersion != 0)) {
-                if (o.minorVersion == 0) {
-                    return true;
-                }
+
+            if (minorVersion != o.minorVersion) {
+                if (!minorVersion) return false;
+                if (!o.minorVersion) return true;
             }
         }
         return false;
     }
-    
+
+    // Return true if 'this' is a better match than 'o' for the 'requested'
+    // configuration.  This assumes that match() has already been used to
+    // remove any configurations that don't match the requested configuration
+    // at all; if they are not first filtered, non-matching results can be
+    // considered better than matching ones.
+    // The general rule per attribute: if the request cares about an attribute
+    // (it normally does), if the two (this and o) are equal it's a tie.  If
+    // they are not equal then one must be generic because only generic and
+    // '==requested' will pass the match() call.  So if this is not generic,
+    // it wins.  If this IS generic, o wins (return false).
+    inline bool
+    isBetterThan(const ResTable_config& o,
+            const ResTable_config* requested) const {
+        if (requested) {
+            if (imsi || o.imsi) {
+                if ((mcc != o.mcc) && requested->mcc) {
+                    return (mcc);
+                }
+
+                if ((mnc != o.mnc) && requested->mnc) {
+                    return (mnc);
+                }
+            }
+
+            if (locale || o.locale) {
+                if ((language[0] != o.language[0]) && requested->language[0]) {
+                    return (language[0]);
+                }
+
+                if ((country[0] != o.country[0]) && requested->country[0]) {
+                    return (country[0]);
+                }
+            }
+
+            if (screenType || o.screenType) {
+                if ((orientation != o.orientation) && requested->orientation) {
+                    return (orientation);
+                }
+
+                if (density != o.density) {
+                    // density is tough.  Any density is potentially useful
+                    // because the system will scale it.  Scaling down
+                    // is generally better than scaling up.
+                    // Default density counts as 160dpi (the system default)
+                    // TODO - remove 160 constants
+                    int h = (density?density:160);
+                    int l = (o.density?o.density:160);
+                    bool bImBigger = true;
+                    if (l > h) {
+                        int t = h;
+                        h = l;
+                        l = t;
+                        bImBigger = false;
+                    }
+ 
+                    int reqValue = (requested->density?requested->density:160);
+                    if (reqValue >= h) {
+                        // requested value higher than both l and h, give h
+                        return bImBigger;
+                    }
+                    if (l >= reqValue) {
+                        // requested value lower than both l and h, give l
+                        return !bImBigger;
+                    }
+                    // saying that scaling down is 2x better than up
+                    if (((2 * l) - reqValue) * h > reqValue * reqValue) {
+                        return !bImBigger;
+                    } else { 
+                        return bImBigger;
+                    }
+                }
+
+                if ((touchscreen != o.touchscreen) && requested->touchscreen) {
+                    return (touchscreen);
+                }
+            }
+
+            if (input || o.input) {
+                const int keysHidden = inputFlags & MASK_KEYSHIDDEN;
+                const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN;
+                if (keysHidden != oKeysHidden) {
+                    const int reqKeysHidden =
+                            requested->inputFlags & MASK_KEYSHIDDEN;
+                    if (reqKeysHidden) {
+
+                        if (!keysHidden) return false;
+                        if (!oKeysHidden) return true;
+                        // For compatibility, we count KEYSHIDDEN_NO as being
+                        // the same as KEYSHIDDEN_SOFT.  Here we disambiguate
+                        // these by making an exact match more specific.
+                        if (reqKeysHidden == keysHidden) return true;
+                        if (reqKeysHidden == oKeysHidden) return false;
+                    }
+                }
+
+                if ((keyboard != o.keyboard) && requested->keyboard) {
+                    return (keyboard);
+                }
+
+                if ((navigation != o.navigation) && requested->navigation) {
+                    return (navigation);
+                }
+            }
+
+            if (screenSize || o.screenSize) {
+                if ((screenWidth != o.screenWidth) && requested->screenWidth) {
+                    return (screenWidth);
+                }
+
+                if ((screenHeight != o.screenHeight) &&
+                        requested->screenHeight) {
+                    return (screenHeight);
+                }
+            }
+
+            if (version || o.version) {
+                if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
+                    return (sdkVersion);
+                }
+
+                if ((minorVersion != o.minorVersion) &&
+                        requested->minorVersion) {
+                    return (minorVersion);
+                }
+            }
+
+            return false;
+        }
+        return isMoreSpecificThan(o);
+    }
+
     // Return true if 'this' can be considered a match for the parameters in 
     // 'settings'.
     // Note this is asymetric.  A default piece of data will match every request
@@ -1137,8 +1243,7 @@
                 && orientation != settings.orientation) {
                 return false;
             }
-            // Density not taken into account, always match, no matter what
-            // density is specified for the resource
+            // density always matches - we can scale it.  See isBetterThan
             if (settings.touchscreen != 0 && touchscreen != 0
                 && touchscreen != settings.touchscreen) {
                 return false;
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index b3cbda1..0fba82c 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -75,6 +75,19 @@
     }
 }
 
+
+sp<Camera> Camera::create(const sp<ICamera>& camera)
+{
+    sp<Camera> c = new Camera();
+    // connect this client to existing camera remote
+    if (camera->connect(c) == NO_ERROR) {
+        c->mStatus = NO_ERROR;
+        c->mCamera = camera;
+        camera->asBinder()->linkToDeath(c);
+    }
+    return c;
+}
+
 void Camera::init()
 {
     mStatus = UNKNOWN_ERROR;
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 2ad3bfe..3d12dca 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -1820,7 +1820,7 @@
             }
         }
         
-        if (bestPackage != NULL && bestItem.isBetterThan(thisConfig)) {
+        if (bestPackage != NULL && bestItem.isMoreSpecificThan(thisConfig)) {
             continue;
         }
         
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 3b4c041..c44478d 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -1,17 +1,17 @@
-/* 
+/*
 **
 ** Copyright 2007 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -478,22 +478,38 @@
 };
 
 static const extention_map_t gExtentionMap[] = {
-    { "glDrawTexsOES",              (void(*)())&glDrawTexsOES },
-    { "glDrawTexiOES",              (void(*)())&glDrawTexiOES },
-    { "glDrawTexfOES",              (void(*)())&glDrawTexfOES },
-    { "glDrawTexxOES",              (void(*)())&glDrawTexxOES },
-    { "glDrawTexsvOES",             (void(*)())&glDrawTexsvOES },
-    { "glDrawTexivOES",             (void(*)())&glDrawTexivOES },
-    { "glDrawTexfvOES",             (void(*)())&glDrawTexfvOES },
-    { "glDrawTexxvOES",             (void(*)())&glDrawTexxvOES },
-    { "glQueryMatrixxOES",          (void(*)())&glQueryMatrixxOES },
-    { "glClipPlanef",               (void(*)())&glClipPlanef },
-    { "glClipPlanex",               (void(*)())&glClipPlanex },
-    { "glBindBuffer",               (void(*)())&glBindBuffer },
-    { "glBufferData",               (void(*)())&glBufferData },
-    { "glBufferSubData",            (void(*)())&glBufferSubData },
-    { "glDeleteBuffers",            (void(*)())&glDeleteBuffers },
-    { "glGenBuffers",               (void(*)())&glGenBuffers },
+    { "glDrawTexsOES",
+            (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES },
+    { "glDrawTexiOES",
+            (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES },
+    { "glDrawTexfOES",
+            (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES },
+    { "glDrawTexxOES",
+            (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES },
+    { "glDrawTexsvOES",
+            (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES },
+    { "glDrawTexivOES",
+            (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES },
+    { "glDrawTexfvOES",
+            (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES },
+    { "glDrawTexxvOES",
+            (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
+    { "glQueryMatrixxOES",
+            (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
+    { "glClipPlanef",
+            (__eglMustCastToProperFunctionPointerType)&glClipPlanef },
+    { "glClipPlanex",
+            (__eglMustCastToProperFunctionPointerType)&glClipPlanex },
+    { "glBindBuffer",
+            (__eglMustCastToProperFunctionPointerType)&glBindBuffer },
+    { "glBufferData",
+            (__eglMustCastToProperFunctionPointerType)&glBufferData },
+    { "glBufferSubData",
+            (__eglMustCastToProperFunctionPointerType)&glBufferSubData },
+    { "glDeleteBuffers",
+            (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
+    { "glGenBuffers",
+            (__eglMustCastToProperFunctionPointerType)&glGenBuffers },
 };
 
 /* 
@@ -1299,6 +1315,8 @@
         }
     }
 
+    // TODO: call connect / disconnect on the surface
+
     ogles_context_t* gl = (ogles_context_t*)ctx;
     if (makeCurrent(gl) == 0) {
         if (ctx) {
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 2ecc7768..d636d73 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -35,7 +35,6 @@
 
 LOCAL_SRC_FILES:= 	\
 	GLES_CM/gl.cpp.arm 		\
-	GLES_CM/gl_logger.cpp 	\
 #
 
 LOCAL_SHARED_LIBRARIES += libcutils libutils libui libEGL
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 0b4bcce..6fc0fed 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -14,7 +14,7 @@
  ** limitations under the License.
  */
 
-#define LOG_TAG "GLLogger"
+#define LOG_TAG "libEGL"
 
 #include <ctype.h>
 #include <string.h>
@@ -69,9 +69,9 @@
 
 struct egl_display_t : public egl_object_t<'_dpy'>
 {
-    EGLDisplay  dpys[2];
-    EGLConfig*  configs[2];
-    EGLint      numConfigs[2];
+    EGLDisplay  dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+    EGLConfig*  configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+    EGLint      numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
     EGLint      numTotalConfigs;
     char const* extensionsString;
     volatile int32_t refs;
@@ -81,7 +81,7 @@
         char const * clientApi;
         char const * extensions;
     };
-    strings_t   queryString[2];
+    strings_t   queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
 };
 
 struct egl_surface_t : public egl_object_t<'_srf'>
@@ -143,6 +143,7 @@
 
 static char const * const gl_names[] = {
     #include "gl_entries.in"
+    #include "glext_entries.in"
     NULL
 };
 
@@ -156,7 +157,7 @@
 
 // ----------------------------------------------------------------------------
 
-egl_connection_t gEGLImpl[2];
+egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
 static egl_display_t gDisplay[NUM_DISPLAYS];
 static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_key_t gEGLThreadLocalStorageKey = -1;
@@ -278,29 +279,51 @@
             driver, dlerror());
 
     if (dso) {
-        void** curr;
+        // first find the symbol for eglGetProcAddress
+        
+        typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
+                const char*);
+        
+        getProcAddressType getProcAddress = 
+            (getProcAddressType)dlsym(dso, "eglGetProcAddress");
+        
+        LOGE_IF(!getProcAddress, 
+                "can't find eglGetProcAddress() in %s", driver);        
+        
+        __eglMustCastToProperFunctionPointerType* curr;
         char const * const * api;
-        gl_hooks_t::gl_t* gl = &hooks->gl;
-        curr = (void**)gl;
-        api = gl_names;
+
+        gl_hooks_t::egl_t* egl = &hooks->egl;
+        curr = (__eglMustCastToProperFunctionPointerType*)egl;
+        api = egl_names;
         while (*api) {
-            void* f = dlsym(dso, *api);
-            //LOGD("<%s> @ 0x%p", *api, f);
+            char const * name = *api;
+            __eglMustCastToProperFunctionPointerType f = 
+                (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
             if (f == NULL) {
-                //LOGW("<%s> not found in %s", *api, driver);
-                f = (void*)gl_unimplemented;
+                // couldn't find the entry-point, use eglGetProcAddress()
+                f = getProcAddress(name);
+                if (f == NULL) {
+                    f = (__eglMustCastToProperFunctionPointerType)0;
+                }
             }
             *curr++ = f;
             api++;
         }
-        gl_hooks_t::egl_t* egl = &hooks->egl;
-        curr = (void**)egl;
-        api = egl_names;
+        
+        gl_hooks_t::gl_t* gl = &hooks->gl;
+        curr = (__eglMustCastToProperFunctionPointerType*)gl;
+        api = gl_names;
         while (*api) {
-            void* f = dlsym(dso, *api);
+            char const * name = *api;
+            __eglMustCastToProperFunctionPointerType f = 
+                (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
             if (f == NULL) {
-                //LOGW("<%s> not found in %s", *api, driver);
-                f = (void*)0;
+                // couldn't find the entry-point, use eglGetProcAddress()
+                f = getProcAddress(name);
+                if (f == NULL) {
+                    f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
+                }
             }
             *curr++ = f;
             api++;
@@ -429,18 +452,19 @@
     return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
 }
 
-static inline
-egl_surface_t* get_surface(EGLSurface surface)
-{
-    egl_surface_t* s = (egl_surface_t *)surface;
-    return s;
+template<typename NATIVE, typename EGL>
+static inline NATIVE* egl_to_native_cast(EGL arg) {
+    return reinterpret_cast<NATIVE*>(arg);
 }
 
 static inline
-egl_context_t* get_context(EGLContext context)
-{
-    egl_context_t* c = (egl_context_t *)context;
-    return c;
+egl_surface_t* get_surface(EGLSurface surface) {   
+    return egl_to_native_cast<egl_surface_t>(surface);
+}
+
+static inline
+egl_context_t* get_context(EGLContext context) {
+    return egl_to_native_cast<egl_context_t>(context);
 }
 
 static egl_connection_t* validate_display_config(
@@ -451,7 +475,7 @@
     if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
 
     impl = uintptr_t(config)>>24;
-    if (uint32_t(impl) >= 2) {
+    if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) {
         return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
     } 
     index = uintptr_t(config) & 0xFFFFFF;
@@ -491,13 +515,8 @@
     return EGL_TRUE;
 }
 
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
 
-using namespace android;
-
-EGLDisplay eglGetDisplay(NativeDisplayType display)
+EGLDisplay egl_init_displays(NativeDisplayType display)
 {
     if (sEarlyInitState) {
         return EGL_NO_DISPLAY;
@@ -510,7 +529,7 @@
     
     EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
     egl_display_t* d = &gDisplay[index];
-        
+
     // dynamically load all our EGL implementations for that display
     // and call into the real eglGetGisplay()
     egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
@@ -573,6 +592,18 @@
     return dpy;
 }
 
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+EGLDisplay eglGetDisplay(NativeDisplayType display)
+{
+    return egl_init_displays(display);
+}
+
 // ----------------------------------------------------------------------------
 // Initialization
 // ----------------------------------------------------------------------------
@@ -594,7 +625,7 @@
     // build our own extension string first, based on the extension we know
     // and the extension supported by our client implementation
     dp->extensionsString = strdup(gExtensionString);
-    for (int i=0 ; i<2 ; i++) {
+    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         cnx->major = -1;
         cnx->minor = -1;
@@ -624,7 +655,7 @@
     }
 
     EGLBoolean res = EGL_FALSE;
-    for (int i=0 ; i<2 ; i++) {
+    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
             EGLint n;
@@ -663,7 +694,7 @@
         return EGL_TRUE;
         
     EGLBoolean res = EGL_FALSE;
-    for (int i=0 ; i<2 ; i++) {
+    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
             cnx->hooks->egl.eglTerminate(dp->dpys[i]);
@@ -706,7 +737,7 @@
         return EGL_TRUE;
     }
     GLint n = 0;
-    for (int j=0 ; j<2 ; j++) {
+    for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
         for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
             *configs++ = MAKE_CONFIG(j, i);
             config_size--;
@@ -794,7 +825,7 @@
         return res;
     }
 
-    for (int i=0 ; i<2 ; i++) {
+    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
             if (cnx->hooks->egl.eglChooseConfig(
@@ -1107,7 +1138,7 @@
 EGLint eglGetError(void)
 {
     EGLint result = EGL_SUCCESS;
-    for (int i=0 ; i<2 ; i++) {
+    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
         EGLint err = EGL_SUCCESS;
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso)
@@ -1120,8 +1151,15 @@
     return result;
 }
 
-void (*eglGetProcAddress(const char *procname))()
+__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
 {
+    // eglGetProcAddress() could be the very first function called
+    // in which case we must make sure we've initialized ourselves, this
+    // happens the first time egl_get_display() is called.
+    
+    if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
+        return NULL;
+
     __eglMustCastToProperFunctionPointerType addr;
     addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
     if (addr) return addr;
@@ -1133,7 +1171,7 @@
     
     addr = 0;
     int slot = -1;
-    for (int i=0 ; i<2 ; i++) {
+    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
             if (cnx->hooks->egl.eglGetProcAddress) {
@@ -1266,7 +1304,7 @@
     if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
 
     EGLBoolean res = EGL_TRUE;
-    for (int i=0 ; i<2 ; i++) {
+    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
             if (cnx->hooks->egl.eglSwapInterval) {
@@ -1309,7 +1347,7 @@
 {
     // bind this API on all EGLs
     EGLBoolean res = EGL_TRUE;
-    for (int i=0 ; i<2 ; i++) {
+    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
             if (cnx->hooks->egl.eglBindAPI) {
@@ -1324,7 +1362,7 @@
 
 EGLenum eglQueryAPI(void)
 {
-    for (int i=0 ; i<2 ; i++) {
+    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
             if (cnx->hooks->egl.eglQueryAPI) {
@@ -1340,7 +1378,7 @@
 
 EGLBoolean eglReleaseThread(void)
 {
-    for (int i=0 ; i<2 ; i++) {
+    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
             if (cnx->hooks->egl.eglReleaseThread) {
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index 865cf44..0057168 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -29,6 +29,7 @@
 #include <cutils/properties.h>
 
 #include "hooks.h"
+#include "egl_impl.h"
 
 using namespace android;
 
@@ -57,13 +58,6 @@
 // Actual GL entry-points
 // ----------------------------------------------------------------------------
 
-#if GL_LOGGER
-#   include "gl_logger.h"
-#   define GL_LOGGER_IMPL(_x) _x
-#else
-#   define GL_LOGGER_IMPL(_x)
-#endif
-
 #undef API_ENTRY
 #undef CALL_GL_API
 #undef CALL_GL_API_RETURN
@@ -96,21 +90,36 @@
 
     #define CALL_GL_API(_api, ...)                                      \
         gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
-        GL_LOGGER_IMPL( log_##_api(__VA_ARGS__); )                      \
         _c->_api(__VA_ARGS__)
     
     #define CALL_GL_API_RETURN(_api, ...)                               \
         gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
-        GL_LOGGER_IMPL( log_##_api(__VA_ARGS__); )                      \
         return _c->_api(__VA_ARGS__)
 
 #endif
 
+
 extern "C" {
 #include "gl_api.in"
+#include "glext_api.in"
 }
 
 #undef API_ENTRY
 #undef CALL_GL_API
 #undef CALL_GL_API_RETURN
 
+
+/*
+ * These GL calls are special because they need to call into EGL to retrieve
+ * some informations before they can execute.
+ */
+
+
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
+{
+}
+
+void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
+{
+}
+
diff --git a/opengl/libs/GLES_CM/gl_api.in b/opengl/libs/GLES_CM/gl_api.in
index 9234ef2..5437d47 100644
--- a/opengl/libs/GLES_CM/gl_api.in
+++ b/opengl/libs/GLES_CM/gl_api.in
@@ -1,532 +1,285 @@
-void API_ENTRY(glActiveTexture)(GLenum texture) {
-    CALL_GL_API(glActiveTexture, texture);
-}
-
 void API_ENTRY(glAlphaFunc)(GLenum func, GLclampf ref) {
     CALL_GL_API(glAlphaFunc, func, ref);
 }
-
-void API_ENTRY(glAlphaFuncx)(GLenum func, GLclampx ref) {
-    CALL_GL_API(glAlphaFuncx, func, ref);
-}
-
-void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
-    CALL_GL_API(glBindTexture, target, texture);
-}
-
-void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
-    CALL_GL_API(glBlendFunc, sfactor, dfactor);
-}
-
-void API_ENTRY(glClear)(GLbitfield mask) {
-    CALL_GL_API(glClear, mask);
-}
-
 void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
     CALL_GL_API(glClearColor, red, green, blue, alpha);
 }
-
-void API_ENTRY(glClearColorx)(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) {
-    CALL_GL_API(glClearColorx, red, green, blue, alpha);
-}
-
 void API_ENTRY(glClearDepthf)(GLclampf depth) {
     CALL_GL_API(glClearDepthf, depth);
 }
-
-void API_ENTRY(glClearDepthx)(GLclampx depth) {
-    CALL_GL_API(glClearDepthx, depth);
-}
-
-void API_ENTRY(glClearStencil)(GLint s) {
-    CALL_GL_API(glClearStencil, s);
-}
-
-void API_ENTRY(glClientActiveTexture)(GLenum texture) {
-    CALL_GL_API(glClientActiveTexture, texture);
-}
-
-void API_ENTRY(glColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
-    CALL_GL_API(glColor4f, red, green, blue, alpha);
-}
-
-void API_ENTRY(glColor4x)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) {
-    CALL_GL_API(glColor4x, red, green, blue, alpha);
-}
-
-void API_ENTRY(glColorMask)(GLboolean r, GLboolean g, GLboolean b, GLboolean a) {
-    CALL_GL_API(glColorMask, r, g, b, a);
-}
-
-void API_ENTRY(glColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
-{
-    CALL_GL_API(glColorPointer, size, type, stride, ptr);
-}
-
-void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat,
-                            GLsizei width, GLsizei height, GLint border,
-                            GLsizei imageSize, const GLvoid *data) {
-    CALL_GL_API(glCompressedTexImage2D, target, level, internalformat,
-            width, height, border, imageSize, data);
-}
-
-void API_ENTRY(glCompressedTexSubImage2D)( GLenum target, GLint level, GLint xoffset,
-                                GLint yoffset, GLsizei width, GLsizei height,
-                                GLenum format, GLsizei imageSize,
-                                const GLvoid *data) {
-    CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset,
-            width, height, format, imageSize, data);
-}
-
-void API_ENTRY(glCopyTexImage2D)(  GLenum target, GLint level, GLenum internalformat,
-                        GLint x, GLint y, GLsizei width, GLsizei height,
-                        GLint border) {
-    CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y,
-            width, height, border);
-}
-
-void API_ENTRY(glCopyTexSubImage2D)(   GLenum target, GLint level, GLint xoffset,
-                            GLint yoffset, GLint x, GLint y, GLsizei width,
-                            GLsizei height) {
-    CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y,
-            width, height);
-}
-
-void API_ENTRY(glCullFace)(GLenum mode) {
-    CALL_GL_API(glCullFace, mode);
-}
-
-void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint *textures) {
-    CALL_GL_API(glDeleteTextures, n, textures);
-}
-
-void API_ENTRY(glDepthFunc)(GLenum func) {
-    CALL_GL_API(glDepthFunc, func);
-}
-
-void API_ENTRY(glDepthMask)(GLboolean flag) {
-    CALL_GL_API(glDepthMask, flag);
-}
-
-void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
-    CALL_GL_API(glDepthRangef, zNear, zFar);
-}
-
-void API_ENTRY(glDepthRangex)(GLclampx zNear, GLclampx zFar) {
-    CALL_GL_API(glDepthRangex, zNear, zFar);
-}
-
-void API_ENTRY(glDisable)(GLenum cap) {
-    CALL_GL_API(glDisable, cap);
-}
-
-void API_ENTRY(glDisableClientState)(GLenum array) {
-    CALL_GL_API(glDisableClientState, array);
-}
-
-void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
-    CALL_GL_API(glDrawArrays, mode, first, count);
-}
-
-void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count,
-                    GLenum type, const GLvoid *indices) {
-    CALL_GL_API(glDrawElements, mode, count, type, indices);
-}
-
-void API_ENTRY(glEnable)(GLenum cap) {
-    CALL_GL_API(glEnable, cap);
-}
-
-void API_ENTRY(glEnableClientState)(GLenum array) {
-    CALL_GL_API(glEnableClientState, array);
-}
-
-void API_ENTRY(glFinish)(void) {
-    CALL_GL_API(glFinish);
-}
-
-void API_ENTRY(glFlush)(void) {
-    CALL_GL_API(glFlush);
-}
-
-void API_ENTRY(glFogf)(GLenum pname, GLfloat param) {
-    CALL_GL_API(glFogf, pname, param);
-}
-
-void API_ENTRY(glFogfv)(GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glFogfv, pname, params);
-}
-
-void API_ENTRY(glFogx)(GLenum pname, GLfixed param) {
-    CALL_GL_API(glFogx, pname, param);
-}
-
-void API_ENTRY(glFogxv)(GLenum pname, const GLfixed *params) {
-    CALL_GL_API(glFogxv, pname, params);
-}
-
-void API_ENTRY(glFrontFace)(GLenum mode) {
-    CALL_GL_API(glFrontFace, mode);
-}
-
-void API_ENTRY(glFrustumf)(GLfloat left, GLfloat right,
-                GLfloat bottom, GLfloat top,
-                GLfloat zNear, GLfloat zFar) {
-    CALL_GL_API(glFrustumf, left, right, bottom, top, zNear, zFar);
-}
-
-void API_ENTRY(glFrustumx)(GLfixed left, GLfixed right,
-                GLfixed bottom, GLfixed top,
-                GLfixed zNear, GLfixed zFar) {
-    CALL_GL_API(glFrustumx, left, right, bottom, top, zNear, zFar);
-}
-
-void API_ENTRY(glGenTextures)(GLsizei n, GLuint *textures) {
-    CALL_GL_API(glGenTextures, n, textures);
-}
-
-GLenum API_ENTRY(glGetError)(void) {
-    CALL_GL_API_RETURN(glGetError);
-}
-
-void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *params) {
-    CALL_GL_API(glGetIntegerv, pname, params);
-}
-
-const GLubyte * API_ENTRY(glGetString)(GLenum name) {
-    CALL_GL_API_RETURN(glGetString, name);
-}
-
-void API_ENTRY(glHint)(GLenum target, GLenum mode) {
-    CALL_GL_API(glHint, target, mode);
-}
-
-void API_ENTRY(glLightModelf)(GLenum pname, GLfloat param) {
-    CALL_GL_API(glLightModelf, pname, param);
-}
-
-void API_ENTRY(glLightModelfv)(GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glLightModelfv, pname, params);
-}
-
-void API_ENTRY(glLightModelx)(GLenum pname, GLfixed param) {
-    CALL_GL_API(glLightModelx, pname, param);
-}
-
-void API_ENTRY(glLightModelxv)(GLenum pname, const GLfixed *params) {
-    CALL_GL_API(glLightModelxv, pname, params);
-}
-
-void API_ENTRY(glLightf)(GLenum light, GLenum pname, GLfloat param) {
-    CALL_GL_API(glLightf, light, pname, param);
-}
-
-void API_ENTRY(glLightfv)(GLenum light, GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glLightfv, light, pname, params);
-}
-
-void API_ENTRY(glLightx)(GLenum light, GLenum pname, GLfixed param) {
-    CALL_GL_API(glLightx, light, pname, param);
-}
-
-void API_ENTRY(glLightxv)(GLenum light, GLenum pname, const GLfixed *params) {
-    CALL_GL_API(glLightxv, light, pname, params);
-}
-
-void API_ENTRY(glLineWidth)(GLfloat width) {
-    CALL_GL_API(glLineWidth, width);
-}
-
-void API_ENTRY(glLineWidthx)(GLfixed width) {
-    CALL_GL_API(glLineWidthx, width);
-}
-
-void API_ENTRY(glLoadIdentity)(void) {
-    CALL_GL_API(glLoadIdentity);
-}
-
-void API_ENTRY(glLoadMatrixf)(const GLfloat *m) {
-    CALL_GL_API(glLoadMatrixf, m);
-}
-
-void API_ENTRY(glLoadMatrixx)(const GLfixed *m) {
-    CALL_GL_API(glLoadMatrixx, m);
-}
-
-void API_ENTRY(glLogicOp)(GLenum opcode) {
-    CALL_GL_API(glLogicOp, opcode);
-}
-
-void API_ENTRY(glMaterialf)(GLenum face, GLenum pname, GLfloat param) {
-    CALL_GL_API(glMaterialf, face, pname, param);
-}
-
-void API_ENTRY(glMaterialfv)(GLenum face, GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glMaterialfv, face, pname, params);
-}
-
-void API_ENTRY(glMaterialx)(GLenum face, GLenum pname, GLfixed param) {
-    CALL_GL_API(glMaterialx, face, pname, param);
-}
-
-void API_ENTRY(glMaterialxv)(GLenum face, GLenum pname, const GLfixed *params) {
-    CALL_GL_API(glMaterialxv, face, pname, params);
-}
-
-void API_ENTRY(glMatrixMode)(GLenum mode) {
-    CALL_GL_API(glMatrixMode, mode);
-}
-
-void API_ENTRY(glMultMatrixf)(const GLfloat *m) {
-    CALL_GL_API(glMultMatrixf, m);
-}
-
-void API_ENTRY(glMultMatrixx)(const GLfixed *m) {
-    CALL_GL_API(glMultMatrixx, m);
-}
-
-void API_ENTRY(glMultiTexCoord4f)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) {
-    CALL_GL_API(glMultiTexCoord4f, target, s, t, r, q);
-}
-
-void API_ENTRY(glMultiTexCoord4x)(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) {
-    CALL_GL_API(glMultiTexCoord4x, target, s, t, r, q);
-}
-
-void API_ENTRY(glNormal3f)(GLfloat nx, GLfloat ny, GLfloat nz) {
-    CALL_GL_API(glNormal3f, nx, ny, nz);
-}
-
-void API_ENTRY(glNormal3x)(GLfixed nx, GLfixed ny, GLfixed nz) {
-    CALL_GL_API(glNormal3x, nx, ny, nz);
-}
-
-void API_ENTRY(glNormalPointer)(GLenum type, GLsizei stride, const GLvoid *pointer) {
-    CALL_GL_API(glNormalPointer, type, stride, pointer);
-}
-
-void API_ENTRY(glOrthof)(  GLfloat left, GLfloat right,
-                GLfloat bottom, GLfloat top,
-                GLfloat zNear, GLfloat zFar) {
-    CALL_GL_API(glOrthof, left, right, bottom, top, zNear, zFar);
-}
-
-void API_ENTRY(glOrthox)(  GLfixed left, GLfixed right,
-                GLfixed bottom, GLfixed top,
-                GLfixed zNear, GLfixed zFar) {
-    CALL_GL_API(glOrthox, left, right, bottom, top, zNear, zFar);
-}
-
-void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
-    CALL_GL_API(glPixelStorei, pname, param);
-}
-
-void API_ENTRY(glPointSize)(GLfloat size) {
-    CALL_GL_API(glPointSize, size);
-}
-
-void API_ENTRY(glPointSizex)(GLfixed size) {
-    CALL_GL_API(glPointSizex, size);
-}
-
-void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
-    CALL_GL_API(glPolygonOffset, factor, units);
-}
-
-void API_ENTRY(glPolygonOffsetx)(GLfixed factor, GLfixed units) {
-    CALL_GL_API(glPolygonOffsetx, factor, units);
-}
-
-void API_ENTRY(glPopMatrix)(void) {
-    CALL_GL_API(glPopMatrix);
-}
-
-void API_ENTRY(glPushMatrix)(void) {
-    CALL_GL_API(glPushMatrix);
-}
-
-void API_ENTRY(glReadPixels)(  GLint x, GLint y, GLsizei width, GLsizei height,
-                    GLenum format, GLenum type, GLvoid *pixels) {
-    CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
-}
-
-void API_ENTRY(glRotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
-    CALL_GL_API(glRotatef, angle, x, y, z);
-}
-
-void API_ENTRY(glRotatex)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) {
-    CALL_GL_API(glRotatex, angle, x, y, z);
-}
-
-void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
-    CALL_GL_API(glSampleCoverage, value, invert);
-}
-
-void API_ENTRY(glSampleCoveragex)(GLclampx value, GLboolean invert) {
-    CALL_GL_API(glSampleCoveragex, value, invert);
-}
-
-void API_ENTRY(glScalef)(GLfloat x, GLfloat y, GLfloat z) {
-    CALL_GL_API(glScalef, x, y, z);
-}
-
-void API_ENTRY(glScalex)(GLfixed x, GLfixed y, GLfixed z) {
-    CALL_GL_API(glScalex, x, y, z);
-}
-
-void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
-    CALL_GL_API(glScissor, x, y, width, height);
-}
-
-void API_ENTRY(glShadeModel)(GLenum mode) {
-    CALL_GL_API(glShadeModel, mode);
-}
-
-void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
-    CALL_GL_API(glStencilFunc, func, ref, mask);
-}
-
-void API_ENTRY(glStencilMask)(GLuint mask) {
-    CALL_GL_API(glStencilMask, mask);
-}
-
-void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
-    CALL_GL_API(glStencilOp, fail, zfail, zpass);
-}
-
-void API_ENTRY(glTexCoordPointer)( GLint size, GLenum type,
-                        GLsizei stride, const GLvoid *pointer) {
-    CALL_GL_API(glTexCoordPointer, size, type, stride, pointer);
-}
-
-void API_ENTRY(glTexEnvf)(GLenum target, GLenum pname, GLfloat param) {
-    CALL_GL_API(glTexEnvf, target, pname, param);
-}
-
-void API_ENTRY(glTexEnvfv)(GLenum target, GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glTexEnvfv, target, pname, params);
-}
-
-void API_ENTRY(glTexEnvx)(GLenum target, GLenum pname, GLfixed param) {
-    CALL_GL_API(glTexEnvx, target, pname, param);
-}
-
-void API_ENTRY(glTexEnvxv)(GLenum target, GLenum pname, const GLfixed *params) {
-    CALL_GL_API(glTexEnvxv, target, pname, params);
-}
-
-void API_ENTRY(glTexImage2D)(  GLenum target, GLint level, GLint internalformat,
-                    GLsizei width, GLsizei height, GLint border, GLenum format,
-                    GLenum type, const GLvoid *pixels) {
-    CALL_GL_API(glTexImage2D, target, level, internalformat, width, height,
-            border, format, type, pixels);
-}
-
-void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
-    CALL_GL_API(glTexParameterf, target, pname, param);
-}
-
-void API_ENTRY(glTexParameterx)(GLenum target, GLenum pname, GLfixed param) {
-    CALL_GL_API(glTexParameterx, target, pname, param);
-}
-
-void API_ENTRY(glTexSubImage2D)(   GLenum target, GLint level, GLint xoffset,
-                        GLint yoffset, GLsizei width, GLsizei height,
-                        GLenum format, GLenum type, const GLvoid *pixels) {
-    CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset,
-            width, height, format, type, pixels);
-}
-
-void API_ENTRY(glTranslatef)(GLfloat x, GLfloat y, GLfloat z) {
-    CALL_GL_API(glTranslatef, x, y, z);
-}
-
-void API_ENTRY(glTranslatex)(GLfixed x, GLfixed y, GLfixed z) {
-    CALL_GL_API(glTranslatex, x, y, z);
-}
-
-void API_ENTRY(glVertexPointer)(   GLint size, GLenum type,
-                        GLsizei stride, const GLvoid *pointer) {
-    CALL_GL_API(glVertexPointer, size, type, stride, pointer);
-}
-
-void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
-    CALL_GL_API(glViewport, x, y, width, height);
-}
-
-// ES 1.1
 void API_ENTRY(glClipPlanef)(GLenum plane, const GLfloat *equation) {
     CALL_GL_API(glClipPlanef, plane, equation);
 }
-void API_ENTRY(glClipPlanex)(GLenum plane, const GLfixed *equation) {
-    CALL_GL_API(glClipPlanex, plane, equation);
+void API_ENTRY(glColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
+    CALL_GL_API(glColor4f, red, green, blue, alpha);
 }
-void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
-    CALL_GL_API(glBindBuffer, target, buffer);
+void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
+    CALL_GL_API(glDepthRangef, zNear, zFar);
 }
-void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) {
-    CALL_GL_API(glBufferData, target, size, data, usage);
+void API_ENTRY(glFogf)(GLenum pname, GLfloat param) {
+    CALL_GL_API(glFogf, pname, param);
 }
-void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) {
-    CALL_GL_API(glBufferSubData, target, offset, size, data);
+void API_ENTRY(glFogfv)(GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glFogfv, pname, params);
 }
-void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint* buffers) {
-    CALL_GL_API(glDeleteBuffers, n, buffers);
-}
-void API_ENTRY(glGenBuffers)(GLsizei n, GLuint* buffers) {
-    CALL_GL_API(glGenBuffers, n, buffers);
-}
-void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *params) {
-    CALL_GL_API(glGetBooleanv, pname, params);
-}
-void API_ENTRY(glGetFixedv)(GLenum pname, GLfixed *params) {
-    CALL_GL_API(glGetFixedv, pname, params);
-}
-void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *params) {
-    CALL_GL_API(glGetFloatv, pname, params);
-}
-void API_ENTRY(glGetPointerv)(GLenum pname, void **params) {
-    CALL_GL_API(glGetPointerv, pname, params);
-}
-void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) {
-    CALL_GL_API(glGetBufferParameteriv, target, pname, params);
+void API_ENTRY(glFrustumf)(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) {
+    CALL_GL_API(glFrustumf, left, right, bottom, top, zNear, zFar);
 }
 void API_ENTRY(glGetClipPlanef)(GLenum pname, GLfloat eqn[4]) {
     CALL_GL_API(glGetClipPlanef, pname, eqn);
 }
-void API_ENTRY(glGetClipPlanex)(GLenum pname, GLfixed eqn[4]) {
-    CALL_GL_API(glGetClipPlanex, pname, eqn);
-}
-void API_ENTRY(glGetLightxv)(GLenum light, GLenum pname, GLfixed *params) {
-    CALL_GL_API(glGetLightxv, light, pname, params);
+void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetFloatv, pname, params);
 }
 void API_ENTRY(glGetLightfv)(GLenum light, GLenum pname, GLfloat *params) {
     CALL_GL_API(glGetLightfv, light, pname, params);
 }
-void API_ENTRY(glGetMaterialxv)(GLenum face, GLenum pname, GLfixed *params) {
-    CALL_GL_API(glGetMaterialxv, face, pname, params);
-}
 void API_ENTRY(glGetMaterialfv)(GLenum face, GLenum pname, GLfloat *params) {
     CALL_GL_API(glGetMaterialfv, face, pname, params);
 }
 void API_ENTRY(glGetTexEnvfv)(GLenum env, GLenum pname, GLfloat *params) {
     CALL_GL_API(glGetTexEnvfv, env, pname, params);
 }
+void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glLightModelf)(GLenum pname, GLfloat param) {
+    CALL_GL_API(glLightModelf, pname, param);
+}
+void API_ENTRY(glLightModelfv)(GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glLightModelfv, pname, params);
+}
+void API_ENTRY(glLightf)(GLenum light, GLenum pname, GLfloat param) {
+    CALL_GL_API(glLightf, light, pname, param);
+}
+void API_ENTRY(glLightfv)(GLenum light, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glLightfv, light, pname, params);
+}
+void API_ENTRY(glLineWidth)(GLfloat width) {
+    CALL_GL_API(glLineWidth, width);
+}
+void API_ENTRY(glLoadMatrixf)(const GLfloat *m) {
+    CALL_GL_API(glLoadMatrixf, m);
+}
+void API_ENTRY(glMaterialf)(GLenum face, GLenum pname, GLfloat param) {
+    CALL_GL_API(glMaterialf, face, pname, param);
+}
+void API_ENTRY(glMaterialfv)(GLenum face, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glMaterialfv, face, pname, params);
+}
+void API_ENTRY(glMultMatrixf)(const GLfloat *m) {
+    CALL_GL_API(glMultMatrixf, m);
+}
+void API_ENTRY(glMultiTexCoord4f)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) {
+    CALL_GL_API(glMultiTexCoord4f, target, s, t, r, q);
+}
+void API_ENTRY(glNormal3f)(GLfloat nx, GLfloat ny, GLfloat nz) {
+    CALL_GL_API(glNormal3f, nx, ny, nz);
+}
+void API_ENTRY(glOrthof)(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) {
+    CALL_GL_API(glOrthof, left, right, bottom, top, zNear, zFar);
+}
+void API_ENTRY(glPointParameterf)(GLenum pname, GLfloat param) {
+    CALL_GL_API(glPointParameterf, pname, param);
+}
+void API_ENTRY(glPointParameterfv)(GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glPointParameterfv, pname, params);
+}
+void API_ENTRY(glPointSize)(GLfloat size) {
+    CALL_GL_API(glPointSize, size);
+}
+void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
+    CALL_GL_API(glPolygonOffset, factor, units);
+}
+void API_ENTRY(glRotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glRotatef, angle, x, y, z);
+}
+void API_ENTRY(glScalef)(GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glScalef, x, y, z);
+}
+void API_ENTRY(glTexEnvf)(GLenum target, GLenum pname, GLfloat param) {
+    CALL_GL_API(glTexEnvf, target, pname, param);
+}
+void API_ENTRY(glTexEnvfv)(GLenum target, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glTexEnvfv, target, pname, params);
+}
+void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
+    CALL_GL_API(glTexParameterf, target, pname, param);
+}
+void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glTranslatef)(GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glTranslatef, x, y, z);
+}
+void API_ENTRY(glActiveTexture)(GLenum texture) {
+    CALL_GL_API(glActiveTexture, texture);
+}
+void API_ENTRY(glAlphaFuncx)(GLenum func, GLclampx ref) {
+    CALL_GL_API(glAlphaFuncx, func, ref);
+}
+void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
+    CALL_GL_API(glBindBuffer, target, buffer);
+}
+void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
+    CALL_GL_API(glBindTexture, target, texture);
+}
+void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
+    CALL_GL_API(glBlendFunc, sfactor, dfactor);
+}
+void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) {
+    CALL_GL_API(glBufferData, target, size, data, usage);
+}
+void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) {
+    CALL_GL_API(glBufferSubData, target, offset, size, data);
+}
+void API_ENTRY(glClear)(GLbitfield mask) {
+    CALL_GL_API(glClear, mask);
+}
+void API_ENTRY(glClearColorx)(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) {
+    CALL_GL_API(glClearColorx, red, green, blue, alpha);
+}
+void API_ENTRY(glClearDepthx)(GLclampx depth) {
+    CALL_GL_API(glClearDepthx, depth);
+}
+void API_ENTRY(glClearStencil)(GLint s) {
+    CALL_GL_API(glClearStencil, s);
+}
+void API_ENTRY(glClientActiveTexture)(GLenum texture) {
+    CALL_GL_API(glClientActiveTexture, texture);
+}
+void API_ENTRY(glClipPlanex)(GLenum plane, const GLfixed *equation) {
+    CALL_GL_API(glClipPlanex, plane, equation);
+}
+void API_ENTRY(glColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) {
+    CALL_GL_API(glColor4ub, red, green, blue, alpha);
+}
+void API_ENTRY(glColor4x)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) {
+    CALL_GL_API(glColor4x, red, green, blue, alpha);
+}
+void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
+    CALL_GL_API(glColorMask, red, green, blue, alpha);
+}
+void API_ENTRY(glColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glColorPointer, size, type, stride, pointer);
+}
+void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) {
+    CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data);
+}
+void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) {
+    CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
+void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
+    CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, width, height, border);
+}
+void API_ENTRY(glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
+    CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height);
+}
+void API_ENTRY(glCullFace)(GLenum mode) {
+    CALL_GL_API(glCullFace, mode);
+}
+void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint *buffers) {
+    CALL_GL_API(glDeleteBuffers, n, buffers);
+}
+void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint *textures) {
+    CALL_GL_API(glDeleteTextures, n, textures);
+}
+void API_ENTRY(glDepthFunc)(GLenum func) {
+    CALL_GL_API(glDepthFunc, func);
+}
+void API_ENTRY(glDepthMask)(GLboolean flag) {
+    CALL_GL_API(glDepthMask, flag);
+}
+void API_ENTRY(glDepthRangex)(GLclampx zNear, GLclampx zFar) {
+    CALL_GL_API(glDepthRangex, zNear, zFar);
+}
+void API_ENTRY(glDisable)(GLenum cap) {
+    CALL_GL_API(glDisable, cap);
+}
+void API_ENTRY(glDisableClientState)(GLenum array) {
+    CALL_GL_API(glDisableClientState, array);
+}
+void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
+    CALL_GL_API(glDrawArrays, mode, first, count);
+}
+void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {
+    CALL_GL_API(glDrawElements, mode, count, type, indices);
+}
+void API_ENTRY(glEnable)(GLenum cap) {
+    CALL_GL_API(glEnable, cap);
+}
+void API_ENTRY(glEnableClientState)(GLenum array) {
+    CALL_GL_API(glEnableClientState, array);
+}
+void API_ENTRY(glFinish)(void) {
+    CALL_GL_API(glFinish);
+}
+void API_ENTRY(glFlush)(void) {
+    CALL_GL_API(glFlush);
+}
+void API_ENTRY(glFogx)(GLenum pname, GLfixed param) {
+    CALL_GL_API(glFogx, pname, param);
+}
+void API_ENTRY(glFogxv)(GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glFogxv, pname, params);
+}
+void API_ENTRY(glFrontFace)(GLenum mode) {
+    CALL_GL_API(glFrontFace, mode);
+}
+void API_ENTRY(glFrustumx)(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) {
+    CALL_GL_API(glFrustumx, left, right, bottom, top, zNear, zFar);
+}
+void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *params) {
+    CALL_GL_API(glGetBooleanv, pname, params);
+}
+void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) {
+    CALL_GL_API(glGetBufferParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetClipPlanex)(GLenum pname, GLfixed eqn[4]) {
+    CALL_GL_API(glGetClipPlanex, pname, eqn);
+}
+void API_ENTRY(glGenBuffers)(GLsizei n, GLuint *buffers) {
+    CALL_GL_API(glGenBuffers, n, buffers);
+}
+void API_ENTRY(glGenTextures)(GLsizei n, GLuint *textures) {
+    CALL_GL_API(glGenTextures, n, textures);
+}
+GLenum API_ENTRY(glGetError)(void) {
+    CALL_GL_API_RETURN(glGetError);
+}
+void API_ENTRY(glGetFixedv)(GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetFixedv, pname, params);
+}
+void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *params) {
+    CALL_GL_API(glGetIntegerv, pname, params);
+}
+void API_ENTRY(glGetLightxv)(GLenum light, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetLightxv, light, pname, params);
+}
+void API_ENTRY(glGetMaterialxv)(GLenum face, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetMaterialxv, face, pname, params);
+}
+void API_ENTRY(glGetPointerv)(GLenum pname, void **params) {
+    CALL_GL_API(glGetPointerv, pname, params);
+}
+const GLubyte * API_ENTRY(glGetString)(GLenum name) {
+    CALL_GL_API_RETURN(glGetString, name);
+}
 void API_ENTRY(glGetTexEnviv)(GLenum env, GLenum pname, GLint *params) {
     CALL_GL_API(glGetTexEnviv, env, pname, params);
 }
 void API_ENTRY(glGetTexEnvxv)(GLenum env, GLenum pname, GLfixed *params) {
     CALL_GL_API(glGetTexEnvxv, env, pname, params);
 }
-void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) {
-    CALL_GL_API(glGetTexParameterfv, target, pname, params);
-}
 void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint *params) {
     CALL_GL_API(glGetTexParameteriv, target, pname, params);
 }
 void API_ENTRY(glGetTexParameterxv)(GLenum target, GLenum pname, GLfixed *params) {
     CALL_GL_API(glGetTexParameterxv, target, pname, params);
 }
+void API_ENTRY(glHint)(GLenum target, GLenum mode) {
+    CALL_GL_API(glHint, target, mode);
+}
 GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) {
     CALL_GL_API_RETURN(glIsBuffer, buffer);
 }
@@ -536,11 +289,56 @@
 GLboolean API_ENTRY(glIsTexture)(GLuint texture) {
     CALL_GL_API_RETURN(glIsTexture, texture);
 }
-void API_ENTRY(glPointParameterf)(GLenum pname, GLfloat param) {
-    CALL_GL_API(glPointParameterf, pname, param);
+void API_ENTRY(glLightModelx)(GLenum pname, GLfixed param) {
+    CALL_GL_API(glLightModelx, pname, param);
 }
-void API_ENTRY(glPointParameterfv)(GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glPointParameterfv, pname, params);
+void API_ENTRY(glLightModelxv)(GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glLightModelxv, pname, params);
+}
+void API_ENTRY(glLightx)(GLenum light, GLenum pname, GLfixed param) {
+    CALL_GL_API(glLightx, light, pname, param);
+}
+void API_ENTRY(glLightxv)(GLenum light, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glLightxv, light, pname, params);
+}
+void API_ENTRY(glLineWidthx)(GLfixed width) {
+    CALL_GL_API(glLineWidthx, width);
+}
+void API_ENTRY(glLoadIdentity)(void) {
+    CALL_GL_API(glLoadIdentity);
+}
+void API_ENTRY(glLoadMatrixx)(const GLfixed *m) {
+    CALL_GL_API(glLoadMatrixx, m);
+}
+void API_ENTRY(glLogicOp)(GLenum opcode) {
+    CALL_GL_API(glLogicOp, opcode);
+}
+void API_ENTRY(glMaterialx)(GLenum face, GLenum pname, GLfixed param) {
+    CALL_GL_API(glMaterialx, face, pname, param);
+}
+void API_ENTRY(glMaterialxv)(GLenum face, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glMaterialxv, face, pname, params);
+}
+void API_ENTRY(glMatrixMode)(GLenum mode) {
+    CALL_GL_API(glMatrixMode, mode);
+}
+void API_ENTRY(glMultMatrixx)(const GLfixed *m) {
+    CALL_GL_API(glMultMatrixx, m);
+}
+void API_ENTRY(glMultiTexCoord4x)(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) {
+    CALL_GL_API(glMultiTexCoord4x, target, s, t, r, q);
+}
+void API_ENTRY(glNormal3x)(GLfixed nx, GLfixed ny, GLfixed nz) {
+    CALL_GL_API(glNormal3x, nx, ny, nz);
+}
+void API_ENTRY(glNormalPointer)(GLenum type, GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glNormalPointer, type, stride, pointer);
+}
+void API_ENTRY(glOrthox)(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) {
+    CALL_GL_API(glOrthox, left, right, bottom, top, zNear, zFar);
+}
+void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
+    CALL_GL_API(glPixelStorei, pname, param);
 }
 void API_ENTRY(glPointParameterx)(GLenum pname, GLfixed param) {
     CALL_GL_API(glPointParameterx, pname, param);
@@ -548,59 +346,90 @@
 void API_ENTRY(glPointParameterxv)(GLenum pname, const GLfixed *params) {
     CALL_GL_API(glPointParameterxv, pname, params);
 }
-void API_ENTRY(glColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) {
-    CALL_GL_API(glColor4ub, red, green, blue, alpha);
+void API_ENTRY(glPointSizex)(GLfixed size) {
+    CALL_GL_API(glPointSizex, size);
+}
+void API_ENTRY(glPolygonOffsetx)(GLfixed factor, GLfixed units) {
+    CALL_GL_API(glPolygonOffsetx, factor, units);
+}
+void API_ENTRY(glPopMatrix)(void) {
+    CALL_GL_API(glPopMatrix);
+}
+void API_ENTRY(glPushMatrix)(void) {
+    CALL_GL_API(glPushMatrix);
+}
+void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {
+    CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
+}
+void API_ENTRY(glRotatex)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) {
+    CALL_GL_API(glRotatex, angle, x, y, z);
+}
+void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
+    CALL_GL_API(glSampleCoverage, value, invert);
+}
+void API_ENTRY(glSampleCoveragex)(GLclampx value, GLboolean invert) {
+    CALL_GL_API(glSampleCoveragex, value, invert);
+}
+void API_ENTRY(glScalex)(GLfixed x, GLfixed y, GLfixed z) {
+    CALL_GL_API(glScalex, x, y, z);
+}
+void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
+    CALL_GL_API(glScissor, x, y, width, height);
+}
+void API_ENTRY(glShadeModel)(GLenum mode) {
+    CALL_GL_API(glShadeModel, mode);
+}
+void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
+    CALL_GL_API(glStencilFunc, func, ref, mask);
+}
+void API_ENTRY(glStencilMask)(GLuint mask) {
+    CALL_GL_API(glStencilMask, mask);
+}
+void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
+    CALL_GL_API(glStencilOp, fail, zfail, zpass);
+}
+void API_ENTRY(glTexCoordPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glTexCoordPointer, size, type, stride, pointer);
 }
 void API_ENTRY(glTexEnvi)(GLenum target, GLenum pname, GLint param) {
     CALL_GL_API(glTexEnvi, target, pname, param);
 }
+void API_ENTRY(glTexEnvx)(GLenum target, GLenum pname, GLfixed param) {
+    CALL_GL_API(glTexEnvx, target, pname, param);
+}
 void API_ENTRY(glTexEnviv)(GLenum target, GLenum pname, const GLint *params) {
     CALL_GL_API(glTexEnviv, target, pname, params);
 }
-
-void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glTexParameterfv, target, pname, params);
+void API_ENTRY(glTexEnvxv)(GLenum target, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glTexEnvxv, target, pname, params);
 }
-
-void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) {
-    CALL_GL_API(glTexParameteriv, target, pname, params);
+void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) {
+    CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels);
 }
-
 void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {
     CALL_GL_API(glTexParameteri, target, pname, param);
 }
+void API_ENTRY(glTexParameterx)(GLenum target, GLenum pname, GLfixed param) {
+    CALL_GL_API(glTexParameterx, target, pname, param);
+}
+void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) {
+    CALL_GL_API(glTexParameteriv, target, pname, params);
+}
 void API_ENTRY(glTexParameterxv)(GLenum target, GLenum pname, const GLfixed *params) {
     CALL_GL_API(glTexParameterxv, target, pname, params);
 }
+void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) {
+    CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+void API_ENTRY(glTranslatex)(GLfixed x, GLfixed y, GLfixed z) {
+    CALL_GL_API(glTranslatex, x, y, z);
+}
+void API_ENTRY(glVertexPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glVertexPointer, size, type, stride, pointer);
+}
+void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
+    CALL_GL_API(glViewport, x, y, width, height);
+}
 void API_ENTRY(glPointSizePointerOES)(GLenum type, GLsizei stride, const GLvoid *pointer) {
     CALL_GL_API(glPointSizePointerOES, type, stride, pointer);
 }
-
-// Extensions
-void API_ENTRY(glDrawTexsOES)(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
-    CALL_GL_API(glDrawTexsOES, x, y, z, w, h);
-}
-void API_ENTRY(glDrawTexiOES)(GLint x, GLint y, GLint z, GLint w, GLint h) {
-    CALL_GL_API(glDrawTexiOES, x, y, z, w, h);
-}
-void API_ENTRY(glDrawTexfOES)(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h) {
-    CALL_GL_API(glDrawTexfOES, x, y, z, w, h);
-}
-void API_ENTRY(glDrawTexxOES)(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
-    CALL_GL_API(glDrawTexxOES, x, y, z, w, h);
-}
-void API_ENTRY(glDrawTexsvOES)(const GLshort* coords) {
-    CALL_GL_API(glDrawTexsvOES, coords);
-}
-void API_ENTRY(glDrawTexivOES)(const GLint* coords) {
-    CALL_GL_API(glDrawTexivOES, coords);
-}
-void API_ENTRY(glDrawTexfvOES)(const GLfloat* coords) {
-    CALL_GL_API(glDrawTexfvOES, coords);
-}
-void API_ENTRY(glDrawTexxvOES)(const GLfixed* coords) {
-    CALL_GL_API(glDrawTexxvOES, coords);
-}
-GLbitfield API_ENTRY(glQueryMatrixxOES)(GLfixed* mantissa, GLint* exponent) {
-    CALL_GL_API_RETURN(glQueryMatrixxOES, mantissa, exponent);
-}
diff --git a/opengl/libs/GLES_CM/gl_logger.cpp b/opengl/libs/GLES_CM/gl_logger.cpp
deleted file mode 100644
index 27be5c9..0000000
--- a/opengl/libs/GLES_CM/gl_logger.cpp
+++ /dev/null
@@ -1,1060 +0,0 @@
-/*
- ** Copyright 2007, 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.
- */
-
-#define LOG_TAG "GLLogger"
-
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-#include <dlfcn.h>
-
-#include <sys/ioctl.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-#include <cutils/properties.h>
-
-#include <utils/String8.h>
-
-#include "gl_logger.h"
-
-#undef NELEM
-#define NELEM(x) (sizeof(x)/sizeof(*(x)))
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-template<typename T>
-static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
-{
-   while (first <= last) {
-       int mid = (first + last) / 2;
-       if (key > sortedArray[mid].key) {
-           first = mid + 1;
-       } else if (key < sortedArray[mid].key) {
-           last = mid - 1;
-       } else {
-           return mid;
-       }
-   }
-   return -1;
-}
-
-struct pair_t {
-    const char* name;
-    int         key;
-};
-
-static const pair_t gEnumMap[] = {
-    #define GLENUM(NAME, VALUE) { #NAME, VALUE },
-    #include "gl_enums.in"
-    #undef GLENUM
-};
-
-// ----------------------------------------------------------------------------
-
-template<typename TYPE>
-class GLLogValue {
-public:
-    GLLogValue(TYPE value) : mValue(value) { }
-    const TYPE& getValue() const { return mValue; }
-    String8 toString() const {
-        return convertToString(mValue);
-    }
-private:
-    const TYPE& mValue;
-    String8 convertToString(unsigned int v) const {
-        char buf[16];
-        snprintf(buf, 16, "%u", v);
-        return String8(buf);
-    }
-    String8 convertToString(unsigned long v) const {
-        char buf[16];
-        snprintf(buf, 16, "%lu", v);
-        return String8(buf);
-    }
-    String8 convertToString(int v) const {
-        char buf[16];
-        snprintf(buf, 16, "%d", v);
-        return String8(buf);
-    }
-    String8 convertToString(long v) const {
-        char buf[16];
-        snprintf(buf, 16, "%ld", v);
-        return String8(buf);
-    }
-    String8 convertToString(float v) const {
-        char buf[16];
-        snprintf(buf, 16, "%f", v);
-        return String8(buf);
-    }
-    String8 convertToString(void const* v) const {
-        char buf[16];
-        snprintf(buf, 16, "%p", v);
-        return String8(buf);
-    }
-};
-
-class GLLogEnum : public GLLogValue<GLenum> {
-public:
-    GLLogEnum(GLenum v) : GLLogValue<GLenum>(v) { }
-    String8 toString() const {
-        GLenum v = getValue();
-        int i = binarySearch<pair_t>(gEnumMap, 0, NELEM(gEnumMap)-1, v);
-        if (i >= 0) {
-            return String8(gEnumMap[i].name);
-        } else {
-            char buf[16];
-            snprintf(buf, 16, "0x%04x", v);
-            return String8(buf);
-        }
-    }
-};
-
-class GLLogClearBitfield : public GLLogValue<GLbitfield> {
-public:
-    GLLogClearBitfield(GLbitfield v) : GLLogValue<GLbitfield>(v) { }
-    String8 toString() const {
-        char buf[16];
-        snprintf(buf, 16, "0x%08x", getValue());
-        return String8(buf);
-    }
-};
-
-class GLLogBool : public GLLogValue<GLboolean> {
-public:
-    GLLogBool(GLboolean v) : GLLogValue<GLboolean>(v) { }
-    String8 toString() const {
-        GLboolean v = getValue();
-        if (v == GL_TRUE)   return String8("GL_TRUE");
-        if (v == GL_FALSE)  return String8("GL_FALSE");
-        return GLLogValue<GLboolean>::toString();
-    }
-};
-
-class GLLogFixed : public GLLogValue<GLfixed> {
-public:
-    GLLogFixed(GLfixed v) : GLLogValue<GLfixed>(v) { }
-    String8 toString() const {
-        char buf[16];
-        snprintf(buf, 16, "0x%08x", getValue());
-        return String8(buf);
-    }
-};
-
-
-template <typename TYPE>
-class GLLogBuffer : public GLLogValue<TYPE *> {
-public:
-    GLLogBuffer(TYPE* buffer, size_t count = -1)
-        : GLLogValue<TYPE*>(buffer)
-    { // output buffer
-    }
-    GLLogBuffer(TYPE const* buffer, size_t count = -1)
-    : GLLogValue<TYPE*>(const_cast<TYPE*>(buffer))
-    { // input buffer
-    }
-};
-
-class GLLog
-{
-public:
-    GLLog(const char* name) : mNumParams(0) {
-        mString.append(name);
-        mString.append("(");
-    }
-
-    ~GLLog() {
-        LOGD("%s);", mString.string());
-    }
-
-    GLLog& operator << (unsigned char v) {
-        return *this << GLLogValue<unsigned int>(v);
-    }
-    GLLog& operator << (short v) {
-        return *this << GLLogValue<unsigned int>(v);
-    }
-    GLLog& operator << (unsigned int v) {
-        return *this << GLLogValue<unsigned int>(v);
-    }
-    GLLog& operator << (int v) {
-        return *this << GLLogValue<int>(v);
-    }
-    GLLog& operator << (long v) {
-        return *this << GLLogValue<long>(v);
-    }
-    GLLog& operator << (unsigned long v) {
-        return *this << GLLogValue<unsigned long>(v);
-    }
-    GLLog& operator << (float v) {
-        return *this << GLLogValue<float>(v);
-    }
-    GLLog& operator << (const void* v) {
-        return *this << GLLogValue<const void* >(v);
-    }
-
-    template <typename TYPE>
-    GLLog& operator << (const TYPE& rhs) {
-        if (mNumParams > 0)
-            mString.append(", ");
-        mString.append(rhs.toString());
-        mNumParams++;
-        return *this;
-    }
-
-    const String8& string() const { return mString; }
-private:
-    GLLog(const GLLog&);
-
-    String8 mString;
-    int mNumParams;
-};
-
-#define API_ENTRY(api)                      log_##api
-#define CALL_GL_API(_x, ...)
-#define CALL_GL_API_RETURN(_x, ...)         return(0);
-
-void API_ENTRY(glActiveTexture)(GLenum texture) {
-    CALL_GL_API(glActiveTexture, texture);
-    GLLog("glActiveTexture") << GLLogEnum(texture);
-}
-
-void API_ENTRY(glAlphaFunc)(GLenum func, GLclampf ref) {
-    CALL_GL_API(glAlphaFunc, func, ref);
-    GLLog("glAlphaFunc") << GLLogEnum(func) << ref;
-}
-
-void API_ENTRY(glAlphaFuncx)(GLenum func, GLclampx ref) {
-    CALL_GL_API(glAlphaFuncx, func, ref);
-    GLLog("glAlphaFuncx") << GLLogEnum(func) << GLLogFixed(ref);
-}
-
-void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
-    CALL_GL_API(glBindTexture, target, texture);
-    GLLog("glBindTexture") << GLLogEnum(target) << texture;
-}
-
-void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
-    CALL_GL_API(glBlendFunc, sfactor, dfactor);
-    GLLog("glBlendFunc") << GLLogEnum(sfactor) << GLLogEnum(dfactor);
-}
-
-void API_ENTRY(glClear)(GLbitfield mask) {
-    CALL_GL_API(glClear, mask);
-    GLLog("glClear") << GLLogClearBitfield(mask);
-}
-
-void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
-    CALL_GL_API(glClearColor, red, green, blue, alpha);
-    GLLog("glClearColor") << red << green << blue << alpha;
-}
-
-void API_ENTRY(glClearColorx)(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) {
-    CALL_GL_API(glClearColorx, red, green, blue, alpha);
-    GLLog("glClearColorx") << GLLogFixed(red) << GLLogFixed(green) << GLLogFixed(blue) << GLLogFixed(alpha);
-}
-
-void API_ENTRY(glClearDepthf)(GLclampf depth) {
-    CALL_GL_API(glClearDepthf, depth);
-    GLLog("glClearDepthf") << depth;
-}
-
-void API_ENTRY(glClearDepthx)(GLclampx depth) {
-    CALL_GL_API(glClearDepthx, depth);
-    GLLog("glClearDepthx") << GLLogFixed(depth);
-}
-
-void API_ENTRY(glClearStencil)(GLint s) {
-    CALL_GL_API(glClearStencil, s);
-    GLLog("glClearStencil") << s;
-}
-
-void API_ENTRY(glClientActiveTexture)(GLenum texture) {
-    CALL_GL_API(glClientActiveTexture, texture);
-    GLLog("glClientActiveTexture") << GLLogEnum(texture);
-}
-
-void API_ENTRY(glColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
-    CALL_GL_API(glColor4f, red, green, blue, alpha);
-    GLLog("glColor4f") << red << green << blue << alpha;
-}
-
-void API_ENTRY(glColor4x)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) {
-    CALL_GL_API(glColor4x, red, green, blue, alpha);
-    GLLog("glColor4x") << GLLogFixed(red) << GLLogFixed(green) << GLLogFixed(blue) << GLLogFixed(alpha);
-}
-
-void API_ENTRY(glColorMask)(GLboolean r, GLboolean g, GLboolean b, GLboolean a) {
-    CALL_GL_API(glColorMask, r, g, b, a);
-    GLLog("glColorMask") << GLLogBool(r) << GLLogBool(g) << GLLogBool(b) << GLLogBool(a);
-}
-
-void API_ENTRY(glColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
-{
-    CALL_GL_API(glColorPointer, size, type, stride, ptr);
-    GLLog("glColorPointer") << size << GLLogEnum(type) << stride << ptr;
-}
-
-void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat,
-                            GLsizei width, GLsizei height, GLint border,
-                            GLsizei imageSize, const GLvoid *data) {
-    CALL_GL_API(glCompressedTexImage2D, target, level, internalformat,
-            width, height, border, imageSize, data);
-    GLLog("glCompressedTexImage2D")
-                << GLLogEnum(target) << level << GLLogEnum(internalformat)
-                << width << height << border << imageSize << data;
-}
-
-void API_ENTRY(glCompressedTexSubImage2D)( GLenum target, GLint level, GLint xoffset,
-                                GLint yoffset, GLsizei width, GLsizei height,
-                                GLenum format, GLsizei imageSize,
-                                const GLvoid *data) {
-    CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset,
-            width, height, format, imageSize, data);
-    GLLog("glCompressedTexSubImage2D")
-            << GLLogEnum(target) << level << xoffset << yoffset
-            << width << height << GLLogEnum(format) << imageSize << data;
-}
-
-void API_ENTRY(glCopyTexImage2D)(  GLenum target, GLint level, GLenum internalformat,
-                        GLint x, GLint y, GLsizei width, GLsizei height,
-                        GLint border) {
-    CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y,
-            width, height, border);
-    GLLog("glCopyTexImage2D")
-            << GLLogEnum(target) << level << GLLogEnum(internalformat)
-            << x << y << width << height << border;
-}
-
-void API_ENTRY(glCopyTexSubImage2D)(   GLenum target, GLint level, GLint xoffset,
-                            GLint yoffset, GLint x, GLint y, GLsizei width,
-                            GLsizei height) {
-    CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y,
-            width, height);
-    GLLog("glCopyTexSubImage2D")
-            << GLLogEnum(target) << level << xoffset << yoffset
-            << x << y << width << height;
-}
-
-void API_ENTRY(glCullFace)(GLenum mode) {
-    CALL_GL_API(glCullFace, mode);
-    GLLog("glCullFace") << GLLogEnum(mode);
-}
-
-void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint *textures) {
-    CALL_GL_API(glDeleteTextures, n, textures);
-    GLLog("glDeleteTextures") << n << GLLogBuffer<GLuint>(textures, n);
-}
-
-void API_ENTRY(glDepthFunc)(GLenum func) {
-    CALL_GL_API(glDepthFunc, func);
-    GLLog("glDepthFunc") << GLLogEnum(func);
-}
-
-void API_ENTRY(glDepthMask)(GLboolean flag) {
-    CALL_GL_API(glDepthMask, flag);
-    GLLog("glDepthMask") << GLLogBool(flag);
-}
-
-void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
-    CALL_GL_API(glDepthRangef, zNear, zFar);
-    GLLog("glDepthRangef") << zNear << zFar;
-}
-
-void API_ENTRY(glDepthRangex)(GLclampx zNear, GLclampx zFar) {
-    CALL_GL_API(glDepthRangex, zNear, zFar);
-    GLLog("glDepthRangex") << GLLogFixed(zNear) << GLLogFixed(zFar);
-}
-
-void API_ENTRY(glDisable)(GLenum cap) {
-    CALL_GL_API(glDisable, cap);
-    GLLog("glDisable") << GLLogEnum(cap);
-}
-
-void API_ENTRY(glDisableClientState)(GLenum array) {
-    CALL_GL_API(glDisableClientState, array);
-    GLLog("glDisableClientState") << GLLogEnum(array);
-}
-
-void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
-    CALL_GL_API(glDrawArrays, mode, first, count);
-    GLLog("glDrawArrays") << GLLogEnum(mode) << first << count;
-}
-
-void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count,
-                    GLenum type, const GLvoid *indices) {
-    CALL_GL_API(glDrawElements, mode, count, type, indices);
-    GLLog log("glDrawElements");
-    log << GLLogEnum(mode) << count << GLLogEnum(type);
-    if (type == GL_UNSIGNED_BYTE) {
-        log << GLLogBuffer<GLubyte>(static_cast<const GLubyte*>(indices), count);
-    } else {
-        log << GLLogBuffer<GLushort>(static_cast<const GLushort*>(indices), count);
-    }
-    log;
-}
-
-void API_ENTRY(glEnable)(GLenum cap) {
-    CALL_GL_API(glEnable, cap);
-    GLLog("glEnable") << GLLogEnum(cap);
-}
-
-void API_ENTRY(glEnableClientState)(GLenum array) {
-    CALL_GL_API(glEnableClientState, array);
-    GLLog("glEnableClientState") << GLLogEnum(array);
-}
-
-void API_ENTRY(glFinish)(void) {
-    CALL_GL_API(glFinish);
-    GLLog("glFinish");
-}
-
-void API_ENTRY(glFlush)(void) {
-    CALL_GL_API(glFlush);
-    GLLog("glFlush");
-}
-
-void API_ENTRY(glFogf)(GLenum pname, GLfloat param) {
-    CALL_GL_API(glFogf, pname, param);
-    GLLog("glFogf") << GLLogEnum(pname) << param;
-}
-
-void API_ENTRY(glFogfv)(GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glFogfv, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glFogfv") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
-}
-
-void API_ENTRY(glFogx)(GLenum pname, GLfixed param) {
-    CALL_GL_API(glFogx, pname, param);
-    GLLog("glFogx") << GLLogEnum(pname) << GLLogFixed(param);
-}
-
-void API_ENTRY(glFogxv)(GLenum pname, const GLfixed *params) {
-    CALL_GL_API(glFogxv, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glFogfx") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
-}
-
-void API_ENTRY(glFrontFace)(GLenum mode) {
-    CALL_GL_API(glFrontFace, mode);
-    GLLog("glFrontFace") << GLLogEnum(mode);
- }
-
-void API_ENTRY(glFrustumf)(GLfloat left, GLfloat right,
-                GLfloat bottom, GLfloat top,
-                GLfloat zNear, GLfloat zFar) {
-    CALL_GL_API(glFrustumf, left, right, bottom, top, zNear, zFar);
-    GLLog("glFrustumf") << left << right << bottom << top << zNear << zFar;
-}
-
-void API_ENTRY(glFrustumx)(GLfixed left, GLfixed right,
-                GLfixed bottom, GLfixed top,
-                GLfixed zNear, GLfixed zFar) {
-    CALL_GL_API(glFrustumx, left, right, bottom, top, zNear, zFar);
-    GLLog("glFrustumx")
-            << GLLogFixed(left) << GLLogFixed(right)
-            << GLLogFixed(bottom) << GLLogFixed(top)
-            << GLLogFixed(zNear) << GLLogFixed(zFar);
-}
-
-void API_ENTRY(glGenTextures)(GLsizei n, GLuint *textures) {
-    CALL_GL_API(glGenTextures, n, textures);
-    GLLog("glGenTextures") << n << GLLogBuffer<GLuint>(textures, n);
-}
-
-GLenum API_ENTRY(glGetError)(void) {
-    GLLog("glGetError");
-    CALL_GL_API_RETURN(glGetError);
-}
-
-void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *params) {
-    CALL_GL_API(glGetIntegerv, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetIntegerv") << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
-}
-
-const GLubyte * API_ENTRY(glGetString)(GLenum name) {
-    GLLog("glGetString") << GLLogEnum(name);
-    CALL_GL_API_RETURN(glGetString, name);
-}
-
-void API_ENTRY(glHint)(GLenum target, GLenum mode) {
-    CALL_GL_API(glHint, target, mode);
-    GLLog("GLenum") << GLLogEnum(target) << GLLogEnum(mode);
-}
-
-void API_ENTRY(glLightModelf)(GLenum pname, GLfloat param) {
-    CALL_GL_API(glLightModelf, pname, param);
-    GLLog("glLightModelf") << GLLogEnum(pname) << param;
-}
-
-void API_ENTRY(glLightModelfv)(GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glLightModelfv, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glLightModelfv") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
-}
-
-void API_ENTRY(glLightModelx)(GLenum pname, GLfixed param) {
-    CALL_GL_API(glLightModelx, pname, param);
-    GLLog("glLightModelx") << GLLogEnum(pname) << GLLogFixed(param);
-}
-
-void API_ENTRY(glLightModelxv)(GLenum pname, const GLfixed *params) {
-    CALL_GL_API(glLightModelxv, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glLightModelxv") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
-}
-
-void API_ENTRY(glLightf)(GLenum light, GLenum pname, GLfloat param) {
-    CALL_GL_API(glLightf, light, pname, param);
-    GLLog("glLightf") << GLLogEnum(light) << GLLogEnum(pname) << param;
-}
-
-void API_ENTRY(glLightfv)(GLenum light, GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glLightfv, light, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glLightfv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
-}
-
-void API_ENTRY(glLightx)(GLenum light, GLenum pname, GLfixed param) {
-   CALL_GL_API(glLightx, light, pname, param);
-   GLLog("glLightx") << GLLogEnum(light) << GLLogEnum(pname) << GLLogFixed(param);
-}
-
-void API_ENTRY(glLightxv)(GLenum light, GLenum pname, const GLfixed *params) {
-    CALL_GL_API(glLightxv, light, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glLightxv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
-}
-
-void API_ENTRY(glLineWidth)(GLfloat width) {
-    CALL_GL_API(glLineWidth, width);
-    GLLog("glLineWidth") << width;
-}
-
-void API_ENTRY(glLineWidthx)(GLfixed width) {
-    CALL_GL_API(glLineWidthx, width);
-    GLLog("glLineWidth") << GLLogFixed(width);
-}
-
-void API_ENTRY(glLoadIdentity)(void) {
-    CALL_GL_API(glLoadIdentity);
-    GLLog("glLoadIdentity");
-}
-
-void API_ENTRY(glLoadMatrixf)(const GLfloat *m) {
-    CALL_GL_API(glLoadMatrixf, m);
-    GLLog("glLoadMatrixf") << GLLogBuffer<GLfloat>(m, 16);
-}
-
-void API_ENTRY(glLoadMatrixx)(const GLfixed *m) {
-    CALL_GL_API(glLoadMatrixx, m);
-    GLLog("glLoadMatrixx") << GLLogBuffer<GLfixed>(m, 16);
-}
-
-void API_ENTRY(glLogicOp)(GLenum opcode) {
-    CALL_GL_API(glLogicOp, opcode);
-    GLLog("glLogicOp") << GLLogEnum(opcode);
-}
-
-void API_ENTRY(glMaterialf)(GLenum face, GLenum pname, GLfloat param) {
-    CALL_GL_API(glMaterialf, face, pname, param);
-    GLLog("glMaterialf") << GLLogEnum(face) << GLLogEnum(pname) << param;
-}
-
-void API_ENTRY(glMaterialfv)(GLenum face, GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glMaterialfv, face, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glMaterialfv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
-}
-
-void API_ENTRY(glMaterialx)(GLenum face, GLenum pname, GLfixed param) {
-    CALL_GL_API(glMaterialx, face, pname, param);
-    GLLog("glMaterialx") << GLLogEnum(face) << GLLogEnum(pname) << GLLogFixed(param);
-}
-
-void API_ENTRY(glMaterialxv)(GLenum face, GLenum pname, const GLfixed *params) {
-    CALL_GL_API(glMaterialxv, face, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glMaterialxv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
-}
-
-void API_ENTRY(glMatrixMode)(GLenum mode) {
-    CALL_GL_API(glMatrixMode, mode);
-    GLLog("glMatrixMode") << GLLogEnum(mode);
-}
-
-void API_ENTRY(glMultMatrixf)(const GLfloat *m) {
-    CALL_GL_API(glMultMatrixf, m);
-    GLLog("glMultMatrixf") << GLLogBuffer<GLfloat>(m, 16);
-}
-
-void API_ENTRY(glMultMatrixx)(const GLfixed *m) {
-    CALL_GL_API(glMultMatrixx, m);
-    GLLog("glMultMatrixx") << GLLogBuffer<GLfixed>(m, 16);
-}
-
-void API_ENTRY(glMultiTexCoord4f)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) {
-    CALL_GL_API(glMultiTexCoord4f, target, s, t, r, q);
-    GLLog("glMultiTexCoord4f") << GLLogEnum(target) << s << t << r << q;
-}
-
-void API_ENTRY(glMultiTexCoord4x)(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) {
-    CALL_GL_API(glMultiTexCoord4x, target, s, t, r, q);
-    GLLog("glMultiTexCoord4x") << GLLogEnum(target)
-        << GLLogFixed(s) << GLLogFixed(t) << GLLogFixed(r) << GLLogFixed(q);
-}
-
-void API_ENTRY(glNormal3f)(GLfloat nx, GLfloat ny, GLfloat nz) {
-    CALL_GL_API(glNormal3f, nx, ny, nz);
-    GLLog("glNormal3f") << nx << ny << nz;
-}
-
-void API_ENTRY(glNormal3x)(GLfixed nx, GLfixed ny, GLfixed nz) {
-    CALL_GL_API(glNormal3x, nx, ny, nz);
-    GLLog("glNormal3x") << GLLogFixed(nx) << GLLogFixed(ny) << GLLogFixed(nz);
-}
-
-void API_ENTRY(glNormalPointer)(GLenum type, GLsizei stride, const GLvoid *pointer) {
-    CALL_GL_API(glNormalPointer, type, stride, pointer);
-    GLLog("glNormalPointer") << GLLogEnum(type) << stride << pointer;
-}
-
-void API_ENTRY(glOrthof)(  GLfloat left, GLfloat right,
-                GLfloat bottom, GLfloat top,
-                GLfloat zNear, GLfloat zFar) {
-    CALL_GL_API(glOrthof, left, right, bottom, top, zNear, zFar);
-    GLLog("glOrthof") << left << right << bottom << top << zNear << zFar;
-}
-
-void API_ENTRY(glOrthox)(  GLfixed left, GLfixed right,
-                GLfixed bottom, GLfixed top,
-                GLfixed zNear, GLfixed zFar) {
-    CALL_GL_API(glOrthox, left, right, bottom, top, zNear, zFar);
-    GLLog("glOrthox") << GLLogFixed(left) << GLLogFixed(right)
-            << GLLogFixed(bottom) << GLLogFixed(top)
-            << GLLogFixed(zNear) << GLLogFixed(zFar);
-}
-
-void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
-    CALL_GL_API(glPixelStorei, pname, param);
-    GLLog("glPixelStorei") << GLLogEnum(pname) << param;
-}
-
-void API_ENTRY(glPointSize)(GLfloat size) {
-    CALL_GL_API(glPointSize, size);
-    GLLog("glPointSize") << size;
-}
-
-void API_ENTRY(glPointSizex)(GLfixed size) {
-    CALL_GL_API(glPointSizex, size);
-    GLLog("glPointSizex") << GLLogFixed(size);
-}
-
-void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
-    CALL_GL_API(glPolygonOffset, factor, units);
-    GLLog("glPolygonOffset") << factor << units;
-}
-
-void API_ENTRY(glPolygonOffsetx)(GLfixed factor, GLfixed units) {
-    CALL_GL_API(glPolygonOffsetx, factor, units);
-    GLLog("glPolygonOffsetx") << GLLogFixed(factor) << GLLogFixed(units);
-}
-
-void API_ENTRY(glPopMatrix)(void) {
-    CALL_GL_API(glPopMatrix);
-    GLLog("glPopMatrix");
-}
-
-void API_ENTRY(glPushMatrix)(void) {
-    CALL_GL_API(glPushMatrix);
-    GLLog("glPushMatrix");
-}
-
-void API_ENTRY(glReadPixels)(  GLint x, GLint y, GLsizei width, GLsizei height,
-                    GLenum format, GLenum type, GLvoid *pixels) {
-    CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glReadPixels") << x << y << width << height << GLLogEnum(format) << GLLogEnum(type)
-            << GLLogBuffer<unsigned char>(static_cast<unsigned char *>(pixels));
-}
-
-void API_ENTRY(glRotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
-    CALL_GL_API(glRotatef, angle, x, y, z);
-    GLLog("glRotatef") << angle << x << y << z;
-}
-
-void API_ENTRY(glRotatex)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) {
-    CALL_GL_API(glRotatex, angle, x, y, z);
-    GLLog("glRotatex") << GLLogFixed(angle) << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z);
-}
-
-void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
-    CALL_GL_API(glSampleCoverage, value, invert);
-    GLLog("glSampleCoverage") << value << GLLogBool(invert);
-}
-
-void API_ENTRY(glSampleCoveragex)(GLclampx value, GLboolean invert) {
-    CALL_GL_API(glSampleCoveragex, value, invert);
-    GLLog("glSampleCoveragex") << GLLogFixed(value) << GLLogBool(invert);
-}
-
-void API_ENTRY(glScalef)(GLfloat x, GLfloat y, GLfloat z) {
-    CALL_GL_API(glScalef, x, y, z);
-    GLLog("glScalef") << x << y << z;
-}
-
-void API_ENTRY(glScalex)(GLfixed x, GLfixed y, GLfixed z) {
-    CALL_GL_API(glScalex, x, y, z);
-    GLLog("glScalex") << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z);
-}
-
-void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
-    CALL_GL_API(glScissor, x, y, width, height);
-    GLLog("glScissor") << x << y << width << height;
-}
-
-void API_ENTRY(glShadeModel)(GLenum mode) {
-    CALL_GL_API(glShadeModel, mode);
-    GLLog("glShadeModel") << GLLogEnum(mode);
-}
-
-void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
-    CALL_GL_API(glStencilFunc, func, ref, mask);
-    GLLog("glStencilFunc") << GLLogEnum(func) << ref << mask;
-}
-
-void API_ENTRY(glStencilMask)(GLuint mask) {
-    CALL_GL_API(glStencilMask, mask);
-    GLLog("glStencilMask") << mask;
-}
-
-void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
-    CALL_GL_API(glStencilOp, fail, zfail, zpass);
-    GLLog("glStencilOp") << GLLogEnum(fail) << GLLogEnum(zfail) << GLLogEnum(zpass);
-}
-
-void API_ENTRY(glTexCoordPointer)( GLint size, GLenum type,
-                        GLsizei stride, const GLvoid *pointer) {
-    CALL_GL_API(glTexCoordPointer, size, type, stride, pointer);
-    GLLog("glTexCoordPointer") << size << GLLogEnum(type) << stride << pointer;
-}
-
-void API_ENTRY(glTexEnvf)(GLenum target, GLenum pname, GLfloat param) {
-    CALL_GL_API(glTexEnvf, target, pname, param);
-    GLLog("glTexEnvf") << GLLogEnum(target) << GLLogEnum(pname) << param;
-}
-
-void API_ENTRY(glTexEnvfv)(GLenum target, GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glTexEnvfv, target, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glTexEnvx") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
-}
-
-void API_ENTRY(glTexEnvx)(GLenum target, GLenum pname, GLfixed param) {
-    CALL_GL_API(glTexEnvx, target, pname, param);
-    GLLog("glTexEnvx") << GLLogEnum(target) << GLLogEnum(pname) << GLLogFixed(param);
-}
-
-void API_ENTRY(glTexEnvxv)(GLenum target, GLenum pname, const GLfixed *params) {
-    CALL_GL_API(glTexEnvxv, target, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glTexEnvxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
-}
-
-void API_ENTRY(glTexImage2D)(  GLenum target, GLint level, GLint internalformat,
-                    GLsizei width, GLsizei height, GLint border, GLenum format,
-                    GLenum type, const GLvoid *pixels) {
-    CALL_GL_API(glTexImage2D, target, level, internalformat, width, height,
-            border, format, type, pixels);
-    GLLog("glTexImage2D") << GLLogEnum(target) << level << GLLogEnum(internalformat)
-            << width << height << border << GLLogEnum(format) << GLLogEnum(type)
-            << GLLogBuffer<unsigned char>( static_cast<const unsigned char *>(pixels));
-}
-
-void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
-    CALL_GL_API(glTexParameterf, target, pname, param);
-    GLLog("glTexParameterf") << GLLogEnum(target) << GLLogEnum(pname) << param;
-}
-
-void API_ENTRY(glTexParameterx)(GLenum target, GLenum pname, GLfixed param) {
-    CALL_GL_API(glTexParameterx, target, pname, param);
-    GLLog("glTexParameterx") << GLLogEnum(target) << GLLogEnum(pname) << GLLogFixed(param);
-}
-
-void API_ENTRY(glTexSubImage2D)(   GLenum target, GLint level, GLint xoffset,
-                        GLint yoffset, GLsizei width, GLsizei height,
-                        GLenum format, GLenum type, const GLvoid *pixels) {
-    CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset,
-            width, height, format, type, pixels);
-    GLLog("glTexSubImage2D") << GLLogEnum(target) << level << xoffset << yoffset
-            << width << height << GLLogEnum(format) << GLLogEnum(type)
-            << GLLogBuffer<unsigned char>( static_cast<const unsigned char *>(pixels));
-}
-
-void API_ENTRY(glTranslatef)(GLfloat x, GLfloat y, GLfloat z) {
-    CALL_GL_API(glTranslatef, x, y, z);
-    GLLog("glTranslatef") << x << y << z;
-}
-
-void API_ENTRY(glTranslatex)(GLfixed x, GLfixed y, GLfixed z) {
-    CALL_GL_API(glTranslatex, x, y, z);
-    GLLog("glTranslatex") << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z);
-}
-
-void API_ENTRY(glVertexPointer)(   GLint size, GLenum type,
-                        GLsizei stride, const GLvoid *pointer) {
-    CALL_GL_API(glVertexPointer, size, type, stride, pointer);
-    GLLog("glVertexPointer") << size << GLLogEnum(type) << stride << pointer;
-}
-
-void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
-    CALL_GL_API(glViewport, x, y, width, height);
-    GLLog("glViewport") << x << y << width << height;
-}
-
-// ES 1.1
-void API_ENTRY(glClipPlanef)(GLenum plane, const GLfloat *equation) {
-    CALL_GL_API(glClipPlanef, plane, equation);
-    GLLog("glClipPlanef") << GLLogEnum(plane) << GLLogBuffer<GLfloat>(equation, 4);
-}
-void API_ENTRY(glClipPlanex)(GLenum plane, const GLfixed *equation) {
-    CALL_GL_API(glClipPlanex, plane, equation);
-    GLLog("glClipPlanex") << GLLogEnum(plane) << GLLogBuffer<GLfixed>(equation, 4);
-}
-void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
-    CALL_GL_API(glBindBuffer, target, buffer);
-    GLLog("glBindBuffer") << GLLogEnum(target) << buffer;
-}
-void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) {
-    CALL_GL_API(glBufferData, target, size, data, usage);
-    GLLog("glBufferData") << GLLogEnum(target) << size
-        << GLLogBuffer<unsigned char>(static_cast<const unsigned char*>(data), size);
-}
-void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) {
-    CALL_GL_API(glBufferSubData, target, offset, size, data);
-    GLLog("glBufferSubData") << GLLogEnum(target) << offset << size
-        << GLLogBuffer<unsigned char>(static_cast<const unsigned char*>(data), size);
-}
-void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint* buffers) {
-    CALL_GL_API(glDeleteBuffers, n, buffers);
-    GLLog("glDeleteBuffers") << n << GLLogBuffer<GLuint>(buffers, n);
-}
-void API_ENTRY(glGenBuffers)(GLsizei n, GLuint* buffers) {
-    CALL_GL_API(glGenBuffers, n, buffers);
-    GLLog("glGenBuffers") << n << GLLogBuffer<GLuint>(buffers, n);
-}
-void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *params) {
-    CALL_GL_API(glGetBooleanv, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetBooleanv") << GLLogEnum(pname) << GLLogBuffer<GLboolean>(params);
-}
-void API_ENTRY(glGetFixedv)(GLenum pname, GLfixed *params) {
-    CALL_GL_API(glGetFixedv, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetFixedv") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
-}
-void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *params) {
-    CALL_GL_API(glGetFloatv, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetFloatv") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
-}
-void API_ENTRY(glGetPointerv)(GLenum pname, void **params) {
-    CALL_GL_API(glGetPointerv, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetPointerv") << GLLogEnum(pname) << GLLogBuffer<void*>(params);
-}
-void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) {
-    // XXX: we need to compute the size of this buffer
-    CALL_GL_API(glGetBufferParameteriv, target, pname, params);
-    GLLog("glGetBufferParameteriv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
-}
-void API_ENTRY(glGetClipPlanef)(GLenum pname, GLfloat eqn[4]) {
-    CALL_GL_API(glGetClipPlanef, pname, eqn);
-    GLLog("glGetClipPlanef") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(eqn, 4);
-}
-void API_ENTRY(glGetClipPlanex)(GLenum pname, GLfixed eqn[4]) {
-    CALL_GL_API(glGetClipPlanex, pname, eqn);
-    GLLog("glGetClipPlanex") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(eqn, 4);
-}
-void API_ENTRY(glGetLightxv)(GLenum light, GLenum pname, GLfixed *params) {
-    CALL_GL_API(glGetLightxv, light, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetLightxv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
-}
-void API_ENTRY(glGetLightfv)(GLenum light, GLenum pname, GLfloat *params) {
-    CALL_GL_API(glGetLightfv, light, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetLightfv") << GLLogEnum(light) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
-}
-void API_ENTRY(glGetMaterialxv)(GLenum face, GLenum pname, GLfixed *params) {
-    CALL_GL_API(glGetMaterialxv, face, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetMaterialxv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
-}
-void API_ENTRY(glGetMaterialfv)(GLenum face, GLenum pname, GLfloat *params) {
-    CALL_GL_API(glGetMaterialfv, face, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetMaterialfv") << GLLogEnum(face) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
-}
-void API_ENTRY(glGetTexEnvfv)(GLenum env, GLenum pname, GLfloat *params) {
-    CALL_GL_API(glGetTexEnvfv, env, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetTexEnvfv") << GLLogEnum(env) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
-}
-void API_ENTRY(glGetTexEnviv)(GLenum env, GLenum pname, GLint *params) {
-    CALL_GL_API(glGetTexEnviv, env, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetTexEnviv") << GLLogEnum(env) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
-}
-void API_ENTRY(glGetTexEnvxv)(GLenum env, GLenum pname, GLfixed *params) {
-    CALL_GL_API(glGetTexEnvxv, env, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetTexEnvxv") << GLLogEnum(env) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
-}
-void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) {
-    CALL_GL_API(glGetTexParameterfv, target, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetTexParameterfv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
-}
-void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint *params) {
-    CALL_GL_API(glGetTexParameteriv, target, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetTexParameteriv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
-}
-void API_ENTRY(glGetTexParameterxv)(GLenum target, GLenum pname, GLfixed *params) {
-    CALL_GL_API(glGetTexParameterxv, target, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glGetTexParameterxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
-}
-GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) {
-    GLLog("glIsBuffer") << buffer;
-    CALL_GL_API_RETURN(glIsBuffer, buffer);
-}
-GLboolean API_ENTRY(glIsEnabled)(GLenum cap) {
-    GLLog("glIsEnabled") << GLLogEnum(cap);
-    CALL_GL_API_RETURN(glIsEnabled, cap);
-}
-GLboolean API_ENTRY(glIsTexture)(GLuint texture) {
-    GLLog("glIsTexture") << texture;
-    CALL_GL_API_RETURN(glIsTexture, texture);
-}
-void API_ENTRY(glPointParameterf)(GLenum pname, GLfloat param) {
-    CALL_GL_API(glPointParameterf, pname, param);
-    GLLog("glPointParameterf") << GLLogEnum(pname) << param;
-}
-void API_ENTRY(glPointParameterfv)(GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glPointParameterfv, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glPointParameterfv") << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
-}
-void API_ENTRY(glPointParameterx)(GLenum pname, GLfixed param) {
-    CALL_GL_API(glPointParameterx, pname, param);
-    GLLog("glPointParameterx") << GLLogEnum(pname) << GLLogFixed(param);
-}
-void API_ENTRY(glPointParameterxv)(GLenum pname, const GLfixed *params) {
-    CALL_GL_API(glPointParameterxv, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glPointParameterxv") << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
-}
-void API_ENTRY(glColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) {
-    CALL_GL_API(glColor4ub, red, green, blue, alpha);
-    GLLog("glColor4ub") << red << green << blue << alpha;
-}
-void API_ENTRY(glTexEnvi)(GLenum target, GLenum pname, GLint param) {
-    CALL_GL_API(glTexEnvi, target, pname, param);
-    GLLog("glTexEnvi") << GLLogEnum(target) << GLLogEnum(pname) << param;
-}
-void API_ENTRY(glTexEnviv)(GLenum target, GLenum pname, const GLint *params) {
-    CALL_GL_API(glTexEnviv, target, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glTexEnviv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
-}
-
-void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) {
-    CALL_GL_API(glTexParameterfv, target, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glTexParameterfv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfloat>(params);
-}
-
-void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) {
-    CALL_GL_API(glTexParameteriv, target, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glTexParameteriv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLint>(params);
-}
-
-void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {
-    CALL_GL_API(glTexParameteri, target, pname, param);
-    GLLog("glTexParameteri") << GLLogEnum(target) << GLLogEnum(pname) << param;
-}
-void API_ENTRY(glTexParameterxv)(GLenum target, GLenum pname, const GLfixed *params) {
-    CALL_GL_API(glTexParameterxv, target, pname, params);
-    // XXX: we need to compute the size of this buffer
-    GLLog("glTexParameterxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
-}
-void API_ENTRY(glPointSizePointerOES)(GLenum type, GLsizei stride, const GLvoid *pointer) {
-    CALL_GL_API(glPointSizePointerOES, type, stride, pointer);
-    GLLog("glPointSizePointerOES") << GLLogEnum(type) << stride << pointer;
-}
-
-// Extensions
-void API_ENTRY(glDrawTexsOES)(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
-    CALL_GL_API(glDrawTexsOES, x, y, z, w, h);
-    GLLog("glDrawTexsOES") << x << y << z << w << h;
-}
-void API_ENTRY(glDrawTexiOES)(GLint x, GLint y, GLint z, GLint w, GLint h) {
-    CALL_GL_API(glDrawTexiOES, x, y, z, w, h);
-    GLLog("glDrawTexiOES") << x << y << z << w << h;
-}
-void API_ENTRY(glDrawTexfOES)(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h) {
-    CALL_GL_API(glDrawTexfOES, x, y, z, w, h);
-    GLLog("glDrawTexfOES") << x << y << z << w << h;
-}
-void API_ENTRY(glDrawTexxOES)(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
-    CALL_GL_API(glDrawTexxOES, x, y, z, w, h);
-    GLLog("glDrawTexfOES") << GLLogFixed(x) << GLLogFixed(y) << GLLogFixed(z) << GLLogFixed(w) << GLLogFixed(h);
-}
-void API_ENTRY(glDrawTexsvOES)(const GLshort* coords) {
-    CALL_GL_API(glDrawTexsvOES, coords);
-    GLLog("glDrawTexsvOES") << GLLogBuffer<GLshort>(coords, 5);
-}
-void API_ENTRY(glDrawTexivOES)(const GLint* coords) {
-    CALL_GL_API(glDrawTexivOES, coords);
-    GLLog("glDrawTexivOES") << GLLogBuffer<GLint>(coords, 5);
-}
-void API_ENTRY(glDrawTexfvOES)(const GLfloat* coords) {
-    CALL_GL_API(glDrawTexfvOES, coords);
-    GLLog("glDrawTexfvOES") << GLLogBuffer<GLfloat>(coords, 5);
-}
-void API_ENTRY(glDrawTexxvOES)(const GLfixed* coords) {
-    CALL_GL_API(glDrawTexxvOES, coords);
-    GLLog("glDrawTexxvOES") << GLLogBuffer<GLfixed>(coords, 5);
-}
-GLbitfield API_ENTRY(glQueryMatrixxOES)(GLfixed* mantissa, GLint* exponent) {
-    GLLog("glQueryMatrixxOES") << GLLogBuffer<GLfixed>(mantissa, 16) << GLLogBuffer<GLfixed>(exponent, 16);
-    CALL_GL_API_RETURN(glQueryMatrixxOES, mantissa, exponent);
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/opengl/libs/GLES_CM/glext_api.in b/opengl/libs/GLES_CM/glext_api.in
new file mode 100644
index 0000000..2c8648e
--- /dev/null
+++ b/opengl/libs/GLES_CM/glext_api.in
@@ -0,0 +1,270 @@
+void API_ENTRY(glBlendEquationSeparateOES)(GLenum modeRGB, GLenum modeAlpha) {
+    CALL_GL_API(glBlendEquationSeparateOES, modeRGB, modeAlpha);
+}
+void API_ENTRY(glBlendFuncSeparateOES)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
+    CALL_GL_API(glBlendFuncSeparateOES, srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+void API_ENTRY(glBlendEquationOES)(GLenum mode) {
+    CALL_GL_API(glBlendEquationOES, mode);
+}
+void API_ENTRY(glDrawTexsOES)(GLshort x, GLshort y, GLshort z, GLshort width, GLshort height) {
+    CALL_GL_API(glDrawTexsOES, x, y, z, width, height);
+}
+void API_ENTRY(glDrawTexiOES)(GLint x, GLint y, GLint z, GLint width, GLint height) {
+    CALL_GL_API(glDrawTexiOES, x, y, z, width, height);
+}
+void API_ENTRY(glDrawTexxOES)(GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height) {
+    CALL_GL_API(glDrawTexxOES, x, y, z, width, height);
+}
+void API_ENTRY(glDrawTexsvOES)(const GLshort *coords) {
+    CALL_GL_API(glDrawTexsvOES, coords);
+}
+void API_ENTRY(glDrawTexivOES)(const GLint *coords) {
+    CALL_GL_API(glDrawTexivOES, coords);
+}
+void API_ENTRY(glDrawTexxvOES)(const GLfixed *coords) {
+    CALL_GL_API(glDrawTexxvOES, coords);
+}
+void API_ENTRY(glDrawTexfOES)(GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height) {
+    CALL_GL_API(glDrawTexfOES, x, y, z, width, height);
+}
+void API_ENTRY(glDrawTexfvOES)(const GLfloat *coords) {
+    CALL_GL_API(glDrawTexfvOES, coords);
+}
+void API_ENTRY(__glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) {
+    CALL_GL_API(glEGLImageTargetTexture2DOES, target, image);
+}
+void API_ENTRY(__glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) {
+    CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image);
+}
+void API_ENTRY(glAlphaFuncxOES)(GLenum func, GLclampx ref) {
+    CALL_GL_API(glAlphaFuncxOES, func, ref);
+}
+void API_ENTRY(glClearColorxOES)(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) {
+    CALL_GL_API(glClearColorxOES, red, green, blue, alpha);
+}
+void API_ENTRY(glClearDepthxOES)(GLclampx depth) {
+    CALL_GL_API(glClearDepthxOES, depth);
+}
+void API_ENTRY(glClipPlanexOES)(GLenum plane, const GLfixed *equation) {
+    CALL_GL_API(glClipPlanexOES, plane, equation);
+}
+void API_ENTRY(glColor4xOES)(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) {
+    CALL_GL_API(glColor4xOES, red, green, blue, alpha);
+}
+void API_ENTRY(glDepthRangexOES)(GLclampx zNear, GLclampx zFar) {
+    CALL_GL_API(glDepthRangexOES, zNear, zFar);
+}
+void API_ENTRY(glFogxOES)(GLenum pname, GLfixed param) {
+    CALL_GL_API(glFogxOES, pname, param);
+}
+void API_ENTRY(glFogxvOES)(GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glFogxvOES, pname, params);
+}
+void API_ENTRY(glFrustumxOES)(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) {
+    CALL_GL_API(glFrustumxOES, left, right, bottom, top, zNear, zFar);
+}
+void API_ENTRY(glGetClipPlanexOES)(GLenum pname, GLfixed eqn[4]) {
+    CALL_GL_API(glGetClipPlanexOES, pname, eqn);
+}
+void API_ENTRY(glGetFixedvOES)(GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetFixedvOES, pname, params);
+}
+void API_ENTRY(glGetLightxvOES)(GLenum light, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetLightxvOES, light, pname, params);
+}
+void API_ENTRY(glGetMaterialxvOES)(GLenum face, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetMaterialxvOES, face, pname, params);
+}
+void API_ENTRY(glGetTexEnvxvOES)(GLenum env, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetTexEnvxvOES, env, pname, params);
+}
+void API_ENTRY(glGetTexParameterxvOES)(GLenum target, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetTexParameterxvOES, target, pname, params);
+}
+void API_ENTRY(glLightModelxOES)(GLenum pname, GLfixed param) {
+    CALL_GL_API(glLightModelxOES, pname, param);
+}
+void API_ENTRY(glLightModelxvOES)(GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glLightModelxvOES, pname, params);
+}
+void API_ENTRY(glLightxOES)(GLenum light, GLenum pname, GLfixed param) {
+    CALL_GL_API(glLightxOES, light, pname, param);
+}
+void API_ENTRY(glLightxvOES)(GLenum light, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glLightxvOES, light, pname, params);
+}
+void API_ENTRY(glLineWidthxOES)(GLfixed width) {
+    CALL_GL_API(glLineWidthxOES, width);
+}
+void API_ENTRY(glLoadMatrixxOES)(const GLfixed *m) {
+    CALL_GL_API(glLoadMatrixxOES, m);
+}
+void API_ENTRY(glMaterialxOES)(GLenum face, GLenum pname, GLfixed param) {
+    CALL_GL_API(glMaterialxOES, face, pname, param);
+}
+void API_ENTRY(glMaterialxvOES)(GLenum face, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glMaterialxvOES, face, pname, params);
+}
+void API_ENTRY(glMultMatrixxOES)(const GLfixed *m) {
+    CALL_GL_API(glMultMatrixxOES, m);
+}
+void API_ENTRY(glMultiTexCoord4xOES)(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) {
+    CALL_GL_API(glMultiTexCoord4xOES, target, s, t, r, q);
+}
+void API_ENTRY(glNormal3xOES)(GLfixed nx, GLfixed ny, GLfixed nz) {
+    CALL_GL_API(glNormal3xOES, nx, ny, nz);
+}
+void API_ENTRY(glOrthoxOES)(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar) {
+    CALL_GL_API(glOrthoxOES, left, right, bottom, top, zNear, zFar);
+}
+void API_ENTRY(glPointParameterxOES)(GLenum pname, GLfixed param) {
+    CALL_GL_API(glPointParameterxOES, pname, param);
+}
+void API_ENTRY(glPointParameterxvOES)(GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glPointParameterxvOES, pname, params);
+}
+void API_ENTRY(glPointSizexOES)(GLfixed size) {
+    CALL_GL_API(glPointSizexOES, size);
+}
+void API_ENTRY(glPolygonOffsetxOES)(GLfixed factor, GLfixed units) {
+    CALL_GL_API(glPolygonOffsetxOES, factor, units);
+}
+void API_ENTRY(glRotatexOES)(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) {
+    CALL_GL_API(glRotatexOES, angle, x, y, z);
+}
+void API_ENTRY(glSampleCoveragexOES)(GLclampx value, GLboolean invert) {
+    CALL_GL_API(glSampleCoveragexOES, value, invert);
+}
+void API_ENTRY(glScalexOES)(GLfixed x, GLfixed y, GLfixed z) {
+    CALL_GL_API(glScalexOES, x, y, z);
+}
+void API_ENTRY(glTexEnvxOES)(GLenum target, GLenum pname, GLfixed param) {
+    CALL_GL_API(glTexEnvxOES, target, pname, param);
+}
+void API_ENTRY(glTexEnvxvOES)(GLenum target, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glTexEnvxvOES, target, pname, params);
+}
+void API_ENTRY(glTexParameterxOES)(GLenum target, GLenum pname, GLfixed param) {
+    CALL_GL_API(glTexParameterxOES, target, pname, param);
+}
+void API_ENTRY(glTexParameterxvOES)(GLenum target, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glTexParameterxvOES, target, pname, params);
+}
+void API_ENTRY(glTranslatexOES)(GLfixed x, GLfixed y, GLfixed z) {
+    CALL_GL_API(glTranslatexOES, x, y, z);
+}
+GLboolean API_ENTRY(glIsRenderbufferOES)(GLuint renderbuffer) {
+    CALL_GL_API_RETURN(glIsRenderbufferOES, renderbuffer);
+}
+void API_ENTRY(glBindRenderbufferOES)(GLenum target, GLuint renderbuffer) {
+    CALL_GL_API(glBindRenderbufferOES, target, renderbuffer);
+}
+void API_ENTRY(glDeleteRenderbuffersOES)(GLsizei n, const GLuint* renderbuffers) {
+    CALL_GL_API(glDeleteRenderbuffersOES, n, renderbuffers);
+}
+void API_ENTRY(glGenRenderbuffersOES)(GLsizei n, GLuint* renderbuffers) {
+    CALL_GL_API(glGenRenderbuffersOES, n, renderbuffers);
+}
+void API_ENTRY(glRenderbufferStorageOES)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
+    CALL_GL_API(glRenderbufferStorageOES, target, internalformat, width, height);
+}
+void API_ENTRY(glGetRenderbufferParameterivOES)(GLenum target, GLenum pname, GLint* params) {
+    CALL_GL_API(glGetRenderbufferParameterivOES, target, pname, params);
+}
+GLboolean API_ENTRY(glIsFramebufferOES)(GLuint framebuffer) {
+    CALL_GL_API_RETURN(glIsFramebufferOES, framebuffer);
+}
+void API_ENTRY(glBindFramebufferOES)(GLenum target, GLuint framebuffer) {
+    CALL_GL_API(glBindFramebufferOES, target, framebuffer);
+}
+void API_ENTRY(glDeleteFramebuffersOES)(GLsizei n, const GLuint* framebuffers) {
+    CALL_GL_API(glDeleteFramebuffersOES, n, framebuffers);
+}
+void API_ENTRY(glGenFramebuffersOES)(GLsizei n, GLuint* framebuffers) {
+    CALL_GL_API(glGenFramebuffersOES, n, framebuffers);
+}
+GLenum API_ENTRY(glCheckFramebufferStatusOES)(GLenum target) {
+    CALL_GL_API_RETURN(glCheckFramebufferStatusOES, target);
+}
+void API_ENTRY(glFramebufferRenderbufferOES)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {
+    CALL_GL_API(glFramebufferRenderbufferOES, target, attachment, renderbuffertarget, renderbuffer);
+}
+void API_ENTRY(glFramebufferTexture2DOES)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {
+    CALL_GL_API(glFramebufferTexture2DOES, target, attachment, textarget, texture, level);
+}
+void API_ENTRY(glGetFramebufferAttachmentParameterivOES)(GLenum target, GLenum attachment, GLenum pname, GLint* params) {
+    CALL_GL_API(glGetFramebufferAttachmentParameterivOES, target, attachment, pname, params);
+}
+void API_ENTRY(glGenerateMipmapOES)(GLenum target) {
+    CALL_GL_API(glGenerateMipmapOES, target);
+}
+void* API_ENTRY(glMapBufferOES)(GLenum target, GLenum access) {
+    CALL_GL_API_RETURN(glMapBufferOES, target, access);
+}
+GLboolean API_ENTRY(glUnmapBufferOES)(GLenum target) {
+    CALL_GL_API_RETURN(glUnmapBufferOES, target);
+}
+void API_ENTRY(glGetBufferPointervOES)(GLenum target, GLenum pname, void** params) {
+    CALL_GL_API(glGetBufferPointervOES, target, pname, params);
+}
+void API_ENTRY(glCurrentPaletteMatrixOES)(GLuint matrixpaletteindex) {
+    CALL_GL_API(glCurrentPaletteMatrixOES, matrixpaletteindex);
+}
+void API_ENTRY(glLoadPaletteFromModelViewMatrixOES)(void) {
+    CALL_GL_API(glLoadPaletteFromModelViewMatrixOES);
+}
+void API_ENTRY(glMatrixIndexPointerOES)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glMatrixIndexPointerOES, size, type, stride, pointer);
+}
+void API_ENTRY(glWeightPointerOES)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) {
+    CALL_GL_API(glWeightPointerOES, size, type, stride, pointer);
+}
+GLbitfield API_ENTRY(glQueryMatrixxOES)(GLfixed mantissa[16], GLint exponent[16]) {
+    CALL_GL_API_RETURN(glQueryMatrixxOES, mantissa, exponent);
+}
+void API_ENTRY(glDepthRangefOES)(GLclampf zNear, GLclampf zFar) {
+    CALL_GL_API(glDepthRangefOES, zNear, zFar);
+}
+void API_ENTRY(glFrustumfOES)(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) {
+    CALL_GL_API(glFrustumfOES, left, right, bottom, top, zNear, zFar);
+}
+void API_ENTRY(glOrthofOES)(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) {
+    CALL_GL_API(glOrthofOES, left, right, bottom, top, zNear, zFar);
+}
+void API_ENTRY(glClipPlanefOES)(GLenum plane, const GLfloat *equation) {
+    CALL_GL_API(glClipPlanefOES, plane, equation);
+}
+void API_ENTRY(glGetClipPlanefOES)(GLenum pname, GLfloat eqn[4]) {
+    CALL_GL_API(glGetClipPlanefOES, pname, eqn);
+}
+void API_ENTRY(glClearDepthfOES)(GLclampf depth) {
+    CALL_GL_API(glClearDepthfOES, depth);
+}
+void API_ENTRY(glTexGenfOES)(GLenum coord, GLenum pname, GLfloat param) {
+    CALL_GL_API(glTexGenfOES, coord, pname, param);
+}
+void API_ENTRY(glTexGenfvOES)(GLenum coord, GLenum pname, const GLfloat *params) {
+    CALL_GL_API(glTexGenfvOES, coord, pname, params);
+}
+void API_ENTRY(glTexGeniOES)(GLenum coord, GLenum pname, GLint param) {
+    CALL_GL_API(glTexGeniOES, coord, pname, param);
+}
+void API_ENTRY(glTexGenivOES)(GLenum coord, GLenum pname, const GLint *params) {
+    CALL_GL_API(glTexGenivOES, coord, pname, params);
+}
+void API_ENTRY(glTexGenxOES)(GLenum coord, GLenum pname, GLfixed param) {
+    CALL_GL_API(glTexGenxOES, coord, pname, param);
+}
+void API_ENTRY(glTexGenxvOES)(GLenum coord, GLenum pname, const GLfixed *params) {
+    CALL_GL_API(glTexGenxvOES, coord, pname, params);
+}
+void API_ENTRY(glGetTexGenfvOES)(GLenum coord, GLenum pname, GLfloat *params) {
+    CALL_GL_API(glGetTexGenfvOES, coord, pname, params);
+}
+void API_ENTRY(glGetTexGenivOES)(GLenum coord, GLenum pname, GLint *params) {
+    CALL_GL_API(glGetTexGenivOES, coord, pname, params);
+}
+void API_ENTRY(glGetTexGenxvOES)(GLenum coord, GLenum pname, GLfixed *params) {
+    CALL_GL_API(glGetTexGenxvOES, coord, pname, params);
+}
diff --git a/opengl/libs/egl_entries.in b/opengl/libs/egl_entries.in
index 33b4c65..3b4551b 100644
--- a/opengl/libs/egl_entries.in
+++ b/opengl/libs/egl_entries.in
@@ -43,3 +43,10 @@
 /* EGL 1.3 */
 
 /* EGL 1.4 */
+
+/* EGL_EGLEXT_VERSION 3 */
+
+EGL_ENTRY(EGLBoolean,  eglLockSurfaceKHR,   EGLDisplay, EGLSurface, const EGLint *)
+EGL_ENTRY(EGLBoolean,  eglUnlockSurfaceKHR, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLImageKHR, eglCreateImageKHR,   EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *)
+EGL_ENTRY(EGLBoolean,  eglDestroyImageKHR,  EGLDisplay, EGLImageKHR)
diff --git a/opengl/libs/gl_entries.in b/opengl/libs/gl_entries.in
index b97e8fe..d7cc5da 100644
--- a/opengl/libs/gl_entries.in
+++ b/opengl/libs/gl_entries.in
@@ -1,159 +1,145 @@
-GL_ENTRY(void, glColor4f, GLfloat, GLfloat, GLfloat, GLfloat)
-GL_ENTRY(void, glColor4x, GLfixed, GLfixed, GLfixed, GLfixed)
-GL_ENTRY(void, glNormal3f, GLfloat, GLfloat, GLfloat)
-GL_ENTRY(void, glNormal3x, GLfixed, GLfixed, GLfixed)
-GL_ENTRY(void, glCullFace, GLenum)
-GL_ENTRY(void, glFrontFace, GLenum)
-GL_ENTRY(void, glDisable, GLenum)
-GL_ENTRY(void, glEnable, GLenum)
-GL_ENTRY(void, glFinish, void)
-GL_ENTRY(void, glFlush, void)
-GL_ENTRY(GLenum, glGetError, void)
-GL_ENTRY(const GLubyte*, glGetString, GLenum)
-GL_ENTRY(void, glGetIntegerv, GLenum, GLint *)
-GL_ENTRY(void, glColorMask, GLboolean, GLboolean, GLboolean, GLboolean)
-GL_ENTRY(void, glDepthMask, GLboolean)
-GL_ENTRY(void, glStencilMask, GLuint)
-GL_ENTRY(void, glDepthFunc, GLenum)
-GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar)
-GL_ENTRY(void, glDepthRangex, GLclampx zNear, GLclampx zFar)
-GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
-GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
-GL_ENTRY(void, glLogicOp, GLenum opcode)
-GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref)
 GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref)
-GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
-GL_ENTRY(void, glClear, GLbitfield mask)
-GL_ENTRY(void, glClearColor, GLclampf r, GLclampf g, GLclampf b, GLclampf a)
-GL_ENTRY(void, glClearColorx, GLclampx r, GLclampx g, GLclampx b, GLclampx a)
+GL_ENTRY(void, glClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
 GL_ENTRY(void, glClearDepthf, GLclampf depth)
+GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat *equation)
+GL_ENTRY(void, glColor4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glFogf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glFogfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glFrustumf, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glGetClipPlanef, GLenum pname, GLfloat eqn[4])
+GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexEnvfv, GLenum env, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glLightf, GLenum light, GLenum pname, GLfloat param)
+GL_ENTRY(void, glLightfv, GLenum light, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glLineWidth, GLfloat width)
+GL_ENTRY(void, glLoadMatrixf, const GLfloat *m)
+GL_ENTRY(void, glMaterialf, GLenum face, GLenum pname, GLfloat param)
+GL_ENTRY(void, glMaterialfv, GLenum face, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glMultMatrixf, const GLfloat *m)
+GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+GL_ENTRY(void, glNormal3f, GLfloat nx, GLfloat ny, GLfloat nz)
+GL_ENTRY(void, glOrthof, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glPointParameterf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glPointParameterfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glPointSize, GLfloat size)
+GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
+GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glScalef, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glTexEnvf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexEnvfv, GLenum target, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glActiveTexture, GLenum texture)
+GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref)
+GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)
+GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture)
+GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
+GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
+GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)
+GL_ENTRY(void, glClear, GLbitfield mask)
+GL_ENTRY(void, glClearColorx, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)
 GL_ENTRY(void, glClearDepthx, GLclampx depth)
 GL_ENTRY(void, glClearStencil, GLint s)
-GL_ENTRY(void, glPointSize, GLfloat)
-GL_ENTRY(void, glPointSizex, GLfixed)
-GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert)
-GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert)
-GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
-GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
-GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
-GL_ENTRY(void, glHint, GLenum, GLenum mode)
-GL_ENTRY(void, glLineWidth, GLfloat width)
+GL_ENTRY(void, glClientActiveTexture, GLenum texture)
+GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed *equation)
+GL_ENTRY(void, glColor4ub, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)
+GL_ENTRY(void, glColor4x, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+GL_ENTRY(void, glColorPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
+GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data)
+GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glCullFace, GLenum mode)
+GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers)
+GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures)
+GL_ENTRY(void, glDepthFunc, GLenum func)
+GL_ENTRY(void, glDepthMask, GLboolean flag)
+GL_ENTRY(void, glDepthRangex, GLclampx zNear, GLclampx zFar)
+GL_ENTRY(void, glDisable, GLenum cap)
+GL_ENTRY(void, glDisableClientState, GLenum array)
+GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)
+GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+GL_ENTRY(void, glEnable, GLenum cap)
+GL_ENTRY(void, glEnableClientState, GLenum array)
+GL_ENTRY(void, glFinish, void)
+GL_ENTRY(void, glFlush, void)
+GL_ENTRY(void, glFogx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glFogxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glFrontFace, GLenum mode)
+GL_ENTRY(void, glFrustumx, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *params)
+GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetClipPlanex, GLenum pname, GLfixed eqn[4])
+GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint *buffers)
+GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures)
+GL_ENTRY(GLenum, glGetError, void)
+GL_ENTRY(void, glGetFixedv, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetPointerv, GLenum pname, void **params)
+GL_ENTRY(const GLubyte *, glGetString, GLenum name)
+GL_ENTRY(void, glGetTexEnviv, GLenum env, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexEnvxv, GLenum env, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glHint, GLenum target, GLenum mode)
+GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer)
+GL_ENTRY(GLboolean, glIsEnabled, GLenum cap)
+GL_ENTRY(GLboolean, glIsTexture, GLuint texture)
+GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightModelxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLightx, GLenum light, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightxv, GLenum light, GLenum pname, const GLfixed *params)
 GL_ENTRY(void, glLineWidthx, GLfixed width)
-GL_ENTRY(void, glShadeModel, GLenum)
-GL_ENTRY(void, glLightModelf, GLenum, GLfloat)
-GL_ENTRY(void, glLightModelfv, GLenum, const GLfloat *)
-GL_ENTRY(void, glLightModelx, GLenum, GLfixed)
-GL_ENTRY(void, glLightModelxv, GLenum, const GLfixed *)
-GL_ENTRY(void, glLightf, GLenum, GLenum, GLfloat)
-GL_ENTRY(void, glLightfv, GLenum, GLenum, const GLfloat *)
-GL_ENTRY(void, glLightx, GLenum, GLenum, GLfixed)
-GL_ENTRY(void, glLightxv, GLenum, GLenum, const GLfixed *)
-GL_ENTRY(void, glMaterialf, GLenum, GLenum, GLfloat)
-GL_ENTRY(void, glMaterialfv, GLenum, GLenum, const GLfloat *)
-GL_ENTRY(void, glMaterialx, GLenum, GLenum, GLfixed)
-GL_ENTRY(void, glMaterialxv, GLenum, GLenum, const GLfixed *)
-GL_ENTRY(void, glFogf, GLenum, GLfloat)
-GL_ENTRY(void, glFogfv, GLenum, const GLfloat *)
-GL_ENTRY(void, glFogx, GLenum, GLfixed)
-GL_ENTRY(void, glFogxv, GLenum, const GLfixed *)
-GL_ENTRY(void, glVertexPointer, GLint, GLenum, GLsizei, const GLvoid *)
-GL_ENTRY(void, glColorPointer, GLint, GLenum, GLsizei, const GLvoid *)
-GL_ENTRY(void, glNormalPointer, GLenum, GLsizei, const GLvoid *)
-GL_ENTRY(void, glTexCoordPointer, GLint, GLenum, GLsizei, const GLvoid *)
-GL_ENTRY(void, glEnableClientState, GLenum)
-GL_ENTRY(void, glDisableClientState, GLenum)
-GL_ENTRY(void, glClientActiveTexture, GLenum)
-GL_ENTRY(void, glDrawArrays, GLenum, GLint first, GLsizei)
-GL_ENTRY(void, glDrawElements, GLenum, GLsizei, GLenum, const GLvoid *)
 GL_ENTRY(void, glLoadIdentity, void)
-GL_ENTRY(void, glLoadMatrixf, const GLfloat*)
-GL_ENTRY(void, glLoadMatrixx, const GLfixed*)
+GL_ENTRY(void, glLoadMatrixx, const GLfixed *m)
+GL_ENTRY(void, glLogicOp, GLenum opcode)
+GL_ENTRY(void, glMaterialx, GLenum face, GLenum pname, GLfixed param)
+GL_ENTRY(void, glMaterialxv, GLenum face, GLenum pname, const GLfixed *params)
 GL_ENTRY(void, glMatrixMode, GLenum mode)
-GL_ENTRY(void, glMultMatrixf, const GLfloat*)
-GL_ENTRY(void, glMultMatrixx, const GLfixed*)
+GL_ENTRY(void, glMultMatrixx, const GLfixed *m)
+GL_ENTRY(void, glMultiTexCoord4x, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glNormal3x, GLfixed nx, GLfixed ny, GLfixed nz)
+GL_ENTRY(void, glNormalPointer, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glOrthox, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param)
+GL_ENTRY(void, glPointParameterx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glPointParameterxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glPointSizex, GLfixed size)
+GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
 GL_ENTRY(void, glPopMatrix, void)
 GL_ENTRY(void, glPushMatrix, void)
-GL_ENTRY(void, glFrustumf, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)
-GL_ENTRY(void, glFrustumx, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed)
-GL_ENTRY(void, glOrthof, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)
-GL_ENTRY(void, glOrthox, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed)
-GL_ENTRY(void, glRotatef, GLfloat, GLfloat, GLfloat, GLfloat)
-GL_ENTRY(void, glRotatex, GLfixed, GLfixed, GLfixed, GLfixed)
-GL_ENTRY(void, glScalef, GLfloat, GLfloat, GLfloat)
-GL_ENTRY(void, glScalex, GLfixed, GLfixed, GLfixed)
-GL_ENTRY(void, glTranslatef, GLfloat, GLfloat, GLfloat)
-GL_ENTRY(void, glTranslatex, GLfixed, GLfixed, GLfixed)
-GL_ENTRY(void, glViewport, GLint, GLint, GLsizei, GLsizei)
-GL_ENTRY(void, glActiveTexture, GLenum)
-GL_ENTRY(void, glBindTexture, GLenum, GLuint)
-GL_ENTRY(void, glGenTextures, GLsizei, GLuint*)
-GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *)
-GL_ENTRY(void, glMultiTexCoord4f, GLenum, GLfloat, GLfloat, GLfloat, GLfloat)
-GL_ENTRY(void, glMultiTexCoord4x, GLenum, GLfixed, GLfixed, GLfixed, GLfixed)
-GL_ENTRY(void, glPixelStorei, GLenum, GLint)
-GL_ENTRY(void, glTexEnvf, GLenum, GLenum, GLfloat)
-GL_ENTRY(void, glTexEnvfv, GLenum, GLenum, const GLfloat*)
-GL_ENTRY(void, glTexEnvx, GLenum, GLenum, GLfixed)
-GL_ENTRY(void, glTexEnvxv, GLenum, GLenum, const GLfixed*)
-GL_ENTRY(void, glTexParameterf, GLenum, GLenum, GLfloat)
-GL_ENTRY(void, glTexParameterx, GLenum, GLenum, GLfixed)
-GL_ENTRY(void, glCompressedTexImage2D,    GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)
-GL_ENTRY(void, glCompressedTexSubImage2D, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)
-GL_ENTRY(void, glCopyTexImage2D, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint)
-GL_ENTRY(void, glCopyTexSubImage2D, GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)
-GL_ENTRY(void, glTexImage2D, GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)
-GL_ENTRY(void, glTexSubImage2D, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)
-GL_ENTRY(void, glReadPixels, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid *)
-
-// 1.1 additions
-GL_ENTRY(void, glClipPlanef, GLenum plane, const GLfloat*)
-GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed*)
-GL_ENTRY(void, glBindBuffer, GLenum, GLuint)
-GL_ENTRY(void, glBufferData, GLenum, GLsizeiptr, const GLvoid*, GLenum)
-GL_ENTRY(void, glBufferSubData, GLenum, GLintptr, GLsizeiptr, const GLvoid*)
-GL_ENTRY(void, glDeleteBuffers, GLsizei, const GLuint*)
-GL_ENTRY(void, glGenBuffers, GLsizei, GLuint*)
-GL_ENTRY(void, glGetBooleanv, GLenum, GLboolean *)
-GL_ENTRY(void, glGetFixedv, GLenum, GLfixed *)
-GL_ENTRY(void, glGetFloatv, GLenum, GLfloat *)
-GL_ENTRY(void, glGetPointerv, GLenum, void **)
-GL_ENTRY(void, glGetBufferParameteriv, GLenum, GLenum, GLint *)
-GL_ENTRY(void, glGetClipPlanef, GLenum, GLfloat[4])
-GL_ENTRY(void, glGetClipPlanex, GLenum, GLfixed[4])
-GL_ENTRY(void, glGetLightxv, GLenum, GLenum, GLfixed *)
-GL_ENTRY(void, glGetLightfv, GLenum, GLenum, GLfloat *)
-GL_ENTRY(void, glGetMaterialxv, GLenum, GLenum, GLfixed *)
-GL_ENTRY(void, glGetMaterialfv, GLenum, GLenum, GLfloat *)
-GL_ENTRY(void, glGetTexEnvfv, GLenum, GLenum, GLfloat *)
-GL_ENTRY(void, glGetTexEnviv, GLenum, GLenum, GLint *)
-GL_ENTRY(void, glGetTexEnvxv, GLenum, GLenum, GLfixed *)
-GL_ENTRY(void, glGetTexParameterfv, GLenum, GLenum, GLfloat *)
-GL_ENTRY(void, glGetTexParameteriv, GLenum, GLenum, GLint *)
-GL_ENTRY(void, glGetTexParameterxv, GLenum, GLenum, GLfixed *)
-GL_ENTRY(GLboolean, glIsBuffer, GLuint)
-GL_ENTRY(GLboolean, glIsEnabled, GLenum)
-GL_ENTRY(GLboolean, glIsTexture, GLuint)
-GL_ENTRY(void, glPointParameterf, GLenum, GLfloat)
-GL_ENTRY(void, glPointParameterfv, GLenum, const GLfloat *)
-GL_ENTRY(void, glPointParameterx, GLenum, GLfixed)
-GL_ENTRY(void, glPointParameterxv, GLenum, const GLfixed *)
-GL_ENTRY(void, glColor4ub, GLubyte, GLubyte, GLubyte, GLubyte)
-GL_ENTRY(void, glTexEnvi, GLenum, GLenum, GLint)
-GL_ENTRY(void, glTexEnviv, GLenum, GLenum, const GLint *)
-GL_ENTRY(void, glTexParameterfv, GLenum, GLenum, const GLfloat *)
-GL_ENTRY(void, glTexParameteriv, GLenum, GLenum, const GLint *)
-GL_ENTRY(void, glTexParameteri, GLenum, GLenum, GLint)
-GL_ENTRY(void, glTexParameterxv, GLenum, GLenum, const GLfixed *)
-GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const GLvoid*)
-
-// Extensions
-GL_ENTRY(void, glDrawTexsOES, GLshort, GLshort, GLshort, GLshort, GLshort)
-GL_ENTRY(void, glDrawTexiOES, GLint, GLint, GLint, GLint, GLint)
-GL_ENTRY(void, glDrawTexfOES, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)
-GL_ENTRY(void, glDrawTexxOES, GLfixed, GLfixed, GLfixed, GLfixed, GLfixed)
-GL_ENTRY(void, glDrawTexsvOES, const GLshort*)
-GL_ENTRY(void, glDrawTexivOES, const GLint*)
-GL_ENTRY(void, glDrawTexfvOES, const GLfloat*)
-GL_ENTRY(void, glDrawTexxvOES, const GLfixed*)
-GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed* mantissa, GLint* exponent)
-
+GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
+GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert)
+GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glScalex, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glShadeModel, GLenum mode)
+GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilMask, GLuint mask)
+GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(void, glTexCoordPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glTexEnvi, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexEnvx, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexEnviv, GLenum target, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexEnvxv, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
+GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexParameterx, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
+GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const GLvoid *pointer)
diff --git a/opengl/libs/gl_logger.h b/opengl/libs/gl_logger.h
deleted file mode 100644
index ce85dd1..0000000
--- a/opengl/libs/gl_logger.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* 
- ** Copyright 2007, 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.
- */
-
-#ifndef ANDROID_GL_LOGGER_H
-#define ANDROID_GL_LOGGER_H
-
-namespace android {
-#define GL_ENTRY(r, api, ...) r log_##api(__VA_ARGS__);
-#include "gl_entries.in"
-#undef GL_ENTRY
-}; // namespace android
-
-#endif /* ANDROID_GL_LOGGER_H */
diff --git a/opengl/libs/glext_entries.in b/opengl/libs/glext_entries.in
new file mode 100644
index 0000000..dd09c71
--- /dev/null
+++ b/opengl/libs/glext_entries.in
@@ -0,0 +1,90 @@
+GL_ENTRY(void, glBlendEquationSeparateOES, GLenum modeRGB, GLenum modeAlpha)
+GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBlendEquationOES, GLenum mode)
+GL_ENTRY(void, glDrawTexsOES, GLshort x, GLshort y, GLshort z, GLshort width, GLshort height)
+GL_ENTRY(void, glDrawTexiOES, GLint x, GLint y, GLint z, GLint width, GLint height)
+GL_ENTRY(void, glDrawTexxOES, GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height)
+GL_ENTRY(void, glDrawTexsvOES, const GLshort *coords)
+GL_ENTRY(void, glDrawTexivOES, const GLint *coords)
+GL_ENTRY(void, glDrawTexxvOES, const GLfixed *coords)
+GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height)
+GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords)
+GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLclampx ref)
+GL_ENTRY(void, glClearColorxOES, GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)
+GL_ENTRY(void, glClearDepthxOES, GLclampx depth)
+GL_ENTRY(void, glClipPlanexOES, GLenum plane, const GLfixed *equation)
+GL_ENTRY(void, glColor4xOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glDepthRangexOES, GLclampx zNear, GLclampx zFar)
+GL_ENTRY(void, glFogxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glFrustumxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glGetClipPlanexOES, GLenum pname, GLfixed eqn[4])
+GL_ENTRY(void, glGetFixedvOES, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetLightxvOES, GLenum light, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexEnvxvOES, GLenum env, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glLightModelxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightModelxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLightxOES, GLenum light, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightxvOES, GLenum light, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLineWidthxOES, GLfixed width)
+GL_ENTRY(void, glLoadMatrixxOES, const GLfixed *m)
+GL_ENTRY(void, glMaterialxOES, GLenum face, GLenum pname, GLfixed param)
+GL_ENTRY(void, glMaterialxvOES, GLenum face, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glMultMatrixxOES, const GLfixed *m)
+GL_ENTRY(void, glMultiTexCoord4xOES, GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glNormal3xOES, GLfixed nx, GLfixed ny, GLfixed nz)
+GL_ENTRY(void, glOrthoxOES, GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+GL_ENTRY(void, glPointParameterxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glPointParameterxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glPointSizexOES, GLfixed size)
+GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glSampleCoveragexOES, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glScalexOES, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glTexEnvxOES, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexEnvxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer)
+GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer)
+GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint* renderbuffers)
+GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint* renderbuffers)
+GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer)
+GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint* framebuffers)
+GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint* framebuffers)
+GL_ENTRY(GLenum, glCheckFramebufferStatusOES, GLenum target)
+GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint* params)
+GL_ENTRY(void, glGenerateMipmapOES, GLenum target)
+GL_ENTRY(void*, glMapBufferOES, GLenum target, GLenum access)
+GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target)
+GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, void** params)
+GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex)
+GL_ENTRY(void, glLoadPaletteFromModelViewMatrixOES, void)
+GL_ENTRY(void, glMatrixIndexPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed mantissa[16], GLint exponent[16])
+GL_ENTRY(void, glDepthRangefOES, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glFrustumfOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glOrthofOES, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation)
+GL_ENTRY(void, glGetClipPlanefOES, GLenum pname, GLfloat eqn[4])
+GL_ENTRY(void, glClearDepthfOES, GLclampf depth)
+GL_ENTRY(void, glTexGenfOES, GLenum coord, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexGenfvOES, GLenum coord, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexGeniOES, GLenum coord, GLenum pname, GLint param)
+GL_ENTRY(void, glTexGenivOES, GLenum coord, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexGenxOES, GLenum coord, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexGenxvOES, GLenum coord, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glGetTexGenfvOES, GLenum coord, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexGenivOES, GLenum coord, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexGenxvOES, GLenum coord, GLenum pname, GLfixed *params)
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index 63fb017..fd97254 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -22,9 +22,10 @@
 #include <errno.h>
 
 #include <EGL/egl.h>
+#include <EGL/eglext.h>
 #include <GLES/gl.h>
+#include <GLES/glext.h>
 
-#define GL_LOGGER                   0
 #if !defined(__arm__)
 #define USE_SLOW_BINDING            1
 #else
@@ -35,7 +36,7 @@
 #define MAX_NUMBER_OF_GL_EXTENSIONS 32
 
 
-#if defined(HAVE_ANDROID_OS) && !USE_SLOW_BINDING && !GL_LOGGER && __OPTIMIZE__
+#if defined(HAVE_ANDROID_OS) && !USE_SLOW_BINDING && __OPTIMIZE__
 #define USE_FAST_TLS_KEY            1
 #else
 #define USE_FAST_TLS_KEY            0
@@ -55,7 +56,10 @@
 enum {
     IMPL_HARDWARE = 0,
     IMPL_SOFTWARE,
-    IMPL_CONTEXT_LOST,
+    
+    IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
+
+    IMPL_CONTEXT_LOST = IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
     IMPL_NO_CONTEXT,
     
     IMPL_NUM_IMPLEMENTATIONS
@@ -73,6 +77,7 @@
 struct gl_hooks_t {
     struct gl_t {
         #include "gl_entries.in"
+        #include "glext_entries.in"
     } gl;
     struct egl_t {
         #include "egl_entries.in"
diff --git a/opengl/libs/tools/genfiles b/opengl/libs/tools/genfiles
new file mode 100755
index 0000000..107768b
--- /dev/null
+++ b/opengl/libs/tools/genfiles
@@ -0,0 +1,20 @@
+#! /bin/sh
+#
+# Copyright (C) 2008 Google Inc.
+#
+# 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.
+
+./glapigen ../../include/GLES/gl.h > ../GLES_CM/gl_api.in 
+./glentrygen ../../include/GLES/gl.h > ../gl_entries.in 
+./glapigen ../../include/GLES/glext.h > ../GLES_CM/glext_api.in 
+./glentrygen ../../include/GLES/glext.h > ../glext_entries.in 
diff --git a/opengl/libs/tools/glapigen b/opengl/libs/tools/glapigen
new file mode 100755
index 0000000..a2c3a7b
--- /dev/null
+++ b/opengl/libs/tools/glapigen
@@ -0,0 +1,72 @@
+#! /usr/bin/perl
+#
+# Copyright (C) 2008 Google Inc.
+#
+# 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.
+
+use strict;
+
+while (my $line = <>) {
+  next if $line =~ /^\//;
+  next if $line =~ /^#/;
+  next if $line =~ /^\s*$/;
+  if ($line !~ /^GL_API\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
+    next;
+  }
+  my $type = $1;
+  my $name = $2;
+  my $args = $3;
+
+  #printf("%s", $line);
+  
+  my $prefix = "";
+  if ($name eq "glEGLImageTargetTexture2DOES") {
+    $prefix = "__";
+  }
+  if ($name eq "glEGLImageTargetRenderbufferStorageOES") {
+    $prefix = "__";
+  }
+  
+  printf("%s API_ENTRY(%s%s)(%s)", $type, $prefix, $name, $args);
+  
+  printf(" {\n");
+  if ($type eq "void") {
+    printf("    CALL_GL_API(%s", $name);
+  } else {
+    printf("    CALL_GL_API_RETURN(%s", $name);
+  }
+  my @args = split ',', $args;
+  my $len = scalar(@args);
+  for (my $num = 0; $num < $len; $num++) {
+    if ($args[$num] ne "void") {
+      print ", ";
+      #
+      # extract the name from the parameter
+      # type name
+      # const type *name
+      # type *name
+      # type name[4]
+      #
+      if ($args[$num] =~ /(\S+\s)+\**\s*([\w]+)/) {
+        printf("%s", $2);
+      }
+    }
+  }
+  printf(");\n");
+  printf("}\n");
+}
+
+
+
+
+
diff --git a/opengl/libs/tools/glentrygen b/opengl/libs/tools/glentrygen
new file mode 100755
index 0000000..5e0f7b6
--- /dev/null
+++ b/opengl/libs/tools/glentrygen
@@ -0,0 +1,31 @@
+#! /usr/bin/perl
+#
+# Copyright (C) 2008 Google Inc.
+#
+# 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.
+
+use strict;
+
+while (my $line = <>) {
+  next if $line =~ /^\//;
+  next if $line =~ /^#/;
+  next if $line =~ /^\s*$/;
+  if ($line !~ /^GL_API\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
+    next;
+  }
+  my $type = $1;
+  my $name = $2;
+  my $args = $3;
+
+  printf("GL_ENTRY(%s, %s, %s)\n", $type, $name, $args);
+}
diff --git a/tests/AndroidTests/res/values-320x200/configVarying.xml b/tests/AndroidTests/res/values-320x200/configVarying.xml
deleted file mode 100644
index ca2a286..0000000
--- a/tests/AndroidTests/res/values-320x200/configVarying.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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.
--->
-
-<resources>
-    <item type="configVarying" name="simple">simple 320x200</item>
-    <bag type="configVarying" name="bag">
-        <item name="testString">bag 320x200</item>
-    </bag>
-</resources>
diff --git a/tests/AndroidTests/res/values-finger/configVarying.xml b/tests/AndroidTests/res/values-32dpi/configVarying.xml
similarity index 86%
copy from tests/AndroidTests/res/values-finger/configVarying.xml
copy to tests/AndroidTests/res/values-32dpi/configVarying.xml
index 674787e..f903f0f 100644
--- a/tests/AndroidTests/res/values-finger/configVarying.xml
+++ b/tests/AndroidTests/res/values-32dpi/configVarying.xml
@@ -15,8 +15,8 @@
 -->
 
 <resources>
-    <item type="configVarying" name="simple">simple finger</item>
+    <item type="configVarying" name="simple">simple 32dpi</item>
     <bag type="configVarying" name="bag">
-        <item name="testString">bag finger</item>
+        <item name="testString">bag 32dpi</item>
     </bag>
 </resources>
diff --git a/tests/AndroidTests/res/values-finger/configVarying.xml b/tests/AndroidTests/res/values-640x400/configVarying.xml
similarity index 86%
copy from tests/AndroidTests/res/values-finger/configVarying.xml
copy to tests/AndroidTests/res/values-640x400/configVarying.xml
index 674787e..30332c0 100644
--- a/tests/AndroidTests/res/values-finger/configVarying.xml
+++ b/tests/AndroidTests/res/values-640x400/configVarying.xml
@@ -15,8 +15,8 @@
 -->
 
 <resources>
-    <item type="configVarying" name="simple">simple finger</item>
+    <item type="configVarying" name="simple">simple 640x400</item>
     <bag type="configVarying" name="bag">
-        <item name="testString">bag finger</item>
+        <item name="testString">bag 640x400</item>
     </bag>
 </resources>
diff --git a/tests/AndroidTests/res/values-finger/configVarying.xml b/tests/AndroidTests/res/values-fr-rFR/configVarying.xml
similarity index 86%
rename from tests/AndroidTests/res/values-finger/configVarying.xml
rename to tests/AndroidTests/res/values-fr-rFR/configVarying.xml
index 674787e..5ecac7c 100644
--- a/tests/AndroidTests/res/values-finger/configVarying.xml
+++ b/tests/AndroidTests/res/values-fr-rFR/configVarying.xml
@@ -15,8 +15,8 @@
 -->
 
 <resources>
-    <item type="configVarying" name="simple">simple finger</item>
+    <item type="configVarying" name="simple">simple fr FR</item>
     <bag type="configVarying" name="bag">
-        <item name="testString">bag finger</item>
+        <item name="testString">bag fr FR</item>
     </bag>
 </resources>
diff --git a/tests/AndroidTests/res/values-finger/configVarying.xml b/tests/AndroidTests/res/values-fr/configVarying.xml
similarity index 86%
copy from tests/AndroidTests/res/values-finger/configVarying.xml
copy to tests/AndroidTests/res/values-fr/configVarying.xml
index 674787e..8413b5a 100644
--- a/tests/AndroidTests/res/values-finger/configVarying.xml
+++ b/tests/AndroidTests/res/values-fr/configVarying.xml
@@ -15,8 +15,8 @@
 -->
 
 <resources>
-    <item type="configVarying" name="simple">simple finger</item>
+    <item type="configVarying" name="simple">simple fr</item>
     <bag type="configVarying" name="bag">
-        <item name="testString">bag finger</item>
+        <item name="testString">bag fr</item>
     </bag>
 </resources>
diff --git a/tests/AndroidTests/res/values-keyshidden/configVarying.xml b/tests/AndroidTests/res/values-keyshidden/configVarying.xml
deleted file mode 100644
index fdffc4d..0000000
--- a/tests/AndroidTests/res/values-keyshidden/configVarying.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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.
--->
-
-<resources>
-    <item type="configVarying" name="simple">simple keyshidden</item>
-    <bag type="configVarying" name="bag">
-        <item name="testString">bag keyshidden</item>
-    </bag>
-</resources>
diff --git a/tests/AndroidTests/res/values-trackball/configVarying.xml b/tests/AndroidTests/res/values-mcc110-xx/configVarying.xml
similarity index 86%
copy from tests/AndroidTests/res/values-trackball/configVarying.xml
copy to tests/AndroidTests/res/values-mcc110-xx/configVarying.xml
index 0dec300..82e2435 100644
--- a/tests/AndroidTests/res/values-trackball/configVarying.xml
+++ b/tests/AndroidTests/res/values-mcc110-xx/configVarying.xml
@@ -15,8 +15,8 @@
 -->
 
 <resources>
-    <item type="configVarying" name="simple">simple trackball</item>
+    <item type="configVarying" name="simple">simple mcc110 xx</item>
     <bag type="configVarying" name="bag">
-        <item name="testString">bag trackball</item>
+        <item name="testString">bag mcc110 xx</item>
     </bag>
 </resources>
diff --git a/tests/AndroidTests/res/values-finger/configVarying.xml b/tests/AndroidTests/res/values-mcc112/configVarying.xml
similarity index 86%
copy from tests/AndroidTests/res/values-finger/configVarying.xml
copy to tests/AndroidTests/res/values-mcc112/configVarying.xml
index 674787e..9c05d77 100644
--- a/tests/AndroidTests/res/values-finger/configVarying.xml
+++ b/tests/AndroidTests/res/values-mcc112/configVarying.xml
@@ -15,8 +15,8 @@
 -->
 
 <resources>
-    <item type="configVarying" name="simple">simple finger</item>
+    <item type="configVarying" name="simple">simple mcc112</item>
     <bag type="configVarying" name="bag">
-        <item name="testString">bag finger</item>
+        <item name="testString">bag mcc112</item>
     </bag>
 </resources>
diff --git a/tests/AndroidTests/res/values-trackball/configVarying.xml b/tests/AndroidTests/res/values-mnc220-xx/configVarying.xml
similarity index 86%
rename from tests/AndroidTests/res/values-trackball/configVarying.xml
rename to tests/AndroidTests/res/values-mnc220-xx/configVarying.xml
index 0dec300..fbc7888 100644
--- a/tests/AndroidTests/res/values-trackball/configVarying.xml
+++ b/tests/AndroidTests/res/values-mnc220-xx/configVarying.xml
@@ -15,8 +15,8 @@
 -->
 
 <resources>
-    <item type="configVarying" name="simple">simple trackball</item>
+    <item type="configVarying" name="simple">simple mnc220 xx</item>
     <bag type="configVarying" name="bag">
-        <item name="testString">bag trackball</item>
+        <item name="testString">bag mnc220 xx</item>
     </bag>
 </resources>
diff --git a/tests/AndroidTests/res/values-finger/configVarying.xml b/tests/AndroidTests/res/values-mnc222-32dpi/configVarying.xml
similarity index 85%
copy from tests/AndroidTests/res/values-finger/configVarying.xml
copy to tests/AndroidTests/res/values-mnc222-32dpi/configVarying.xml
index 674787e..03bea33 100644
--- a/tests/AndroidTests/res/values-finger/configVarying.xml
+++ b/tests/AndroidTests/res/values-mnc222-32dpi/configVarying.xml
@@ -15,8 +15,8 @@
 -->
 
 <resources>
-    <item type="configVarying" name="simple">simple finger</item>
+    <item type="configVarying" name="simple">simple mnc222 32dpi</item>
     <bag type="configVarying" name="bag">
-        <item name="testString">bag finger</item>
+        <item name="testString">bag mnc222 32dpi</item>
     </bag>
 </resources>
diff --git a/tests/AndroidTests/res/values-finger/configVarying.xml b/tests/AndroidTests/res/values-mnc223/configVarying.xml
similarity index 86%
copy from tests/AndroidTests/res/values-finger/configVarying.xml
copy to tests/AndroidTests/res/values-mnc223/configVarying.xml
index 674787e..8936cbc 100644
--- a/tests/AndroidTests/res/values-finger/configVarying.xml
+++ b/tests/AndroidTests/res/values-mnc223/configVarying.xml
@@ -15,8 +15,8 @@
 -->
 
 <resources>
-    <item type="configVarying" name="simple">simple finger</item>
+    <item type="configVarying" name="simple">simple mnc223</item>
     <bag type="configVarying" name="bag">
-        <item name="testString">bag finger</item>
+        <item name="testString">bag mnc223</item>
     </bag>
 </resources>
diff --git a/tests/AndroidTests/res/values-port/configVarying.xml b/tests/AndroidTests/res/values-port/configVarying.xml
deleted file mode 100644
index 0e1f247..0000000
--- a/tests/AndroidTests/res/values-port/configVarying.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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.
--->
-
-<resources>
-    <item type="configVarying" name="simple">simple portrait</item>
-    <bag type="configVarying" name="bag">
-        <item name="testString">bag portrait</item>
-    </bag>
-</resources>
diff --git a/tests/AndroidTests/res/values-qwerty/configVarying.xml b/tests/AndroidTests/res/values-qwerty/configVarying.xml
deleted file mode 100644
index 939f682..0000000
--- a/tests/AndroidTests/res/values-qwerty/configVarying.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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.
--->
-
-<resources>
-    <item type="configVarying" name="simple">simple qwerty</item>
-    <bag type="configVarying" name="bag">
-        <item name="testString">bag qwerty</item>
-    </bag>
-</resources>
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
index 09e3b02..f3c1542 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
@@ -23,27 +23,11 @@
 import android.app.SearchManager;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
 import android.os.ServiceManager;
-import android.server.search.SearchableInfo;
-import android.server.search.SearchableInfo.ActionKeyInfo;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.MoreAsserts;
-import android.test.mock.MockContext;
-import android.test.mock.MockPackageManager;
+import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.AndroidRuntimeException;
-import android.view.KeyEvent;
-
-import java.util.ArrayList;
-import java.util.List;
 
 /**
  * To launch this test from the command line:
@@ -52,7 +36,7 @@
  *   -e class com.android.unit_tests.SearchManagerTest \
  *   com.android.unit_tests/android.test.InstrumentationTestRunner
  */
-public class SearchManagerTest extends ActivityInstrumentationTestCase<LocalActivity> {
+public class SearchManagerTest extends ActivityInstrumentationTestCase2<LocalActivity> {
     
     // If non-zero, enable a set of tests that start and stop the search manager.
     // This is currently disabled because it's causing an unwanted jump from the unit test
@@ -71,18 +55,6 @@
      * testSearchManagerInvocations()
      *  FIX - make it work again
      *  stress test with a very long string
-     *  
-     * SearchableInfo tests
-     *  Mock the context so I can provide very specific input data
-     *  Confirm OK with "zero" searchables
-     *  Confirm "good" metadata read properly
-     *  Confirm "bad" metadata skipped properly
-     *  Confirm ordering of searchables
-     *  Confirm "good" actionkeys
-     *  confirm "bad" actionkeys are rejected
-     *  confirm XML ordering enforced (will fail today - bug in SearchableInfo)
-     *  findActionKey works
-     *  getIcon works
      * 
      * SearchManager tests
      *  confirm proper identification of "default" activity based on policy, not hardcoded contacts
@@ -195,348 +167,6 @@
             searchManager.stopSearch();
         }
      }
-    
-    /**
-     * The goal of this test is to confirm proper operation of the 
-     * SearchableInfo helper class.
-     * 
-     * TODO:  The metadata source needs to be mocked out because adding
-     * searchability metadata via this test is causing it to leak into the
-     * real system.  So for now I'm just going to test for existence of the
-     * GoogleSearch app (which is searchable).
-     */
-    @LargeTest
-    public void testSearchableGoogleSearch() {
-        // test basic array & hashmap
-        SearchableInfo.buildSearchableList(mContext);
 
-        // test linkage from another activity
-        // TODO inject this via mocking into the package manager.
-        // TODO for now, just check for searchable GoogleSearch app (this isn't really a unit test)
-        ComponentName thisActivity = new ComponentName(
-                "com.android.googlesearch", 
-                "com.android.googlesearch.GoogleSearch");
-
-        SearchableInfo si = SearchableInfo.getSearchableInfo(mContext, thisActivity);
-        assertNotNull(si);
-        assertTrue(si.mSearchable);
-        assertEquals(thisActivity, si.mSearchActivity);
-        
-        Context appContext = si.getActivityContext(mContext);
-        assertNotNull(appContext);
-        MoreAsserts.assertNotEqual(appContext, mContext);
-        assertEquals("Google Search", appContext.getString(si.getHintId()));
-        assertEquals("Google", appContext.getString(si.getLabelId()));
-    }
-    
-    /**
-     * Test that non-searchable activities return no searchable info (this would typically
-     * trigger the use of the default searchable e.g. contacts)
-     */
-    @LargeTest
-    public void testNonSearchable() {
-        // test basic array & hashmap
-        SearchableInfo.buildSearchableList(mContext);
-
-        // confirm that we return null for non-searchy activities
-        ComponentName nonActivity = new ComponentName(
-                            "com.android.unit_tests",
-                            "com.android.unit_tests.NO_SEARCH_ACTIVITY");
-        SearchableInfo si = SearchableInfo.getSearchableInfo(mContext, nonActivity);
-        assertNull(si);
-    }
-    
-    /**
-     * This is an attempt to run the searchable info list with a mocked context.  Here are some
-     * things I'd like to test.
-     *
-     *  Confirm OK with "zero" searchables
-     *  Confirm "good" metadata read properly
-     *  Confirm "bad" metadata skipped properly
-     *  Confirm ordering of searchables
-     *  Confirm "good" actionkeys
-     *  confirm "bad" actionkeys are rejected
-     *  confirm XML ordering enforced (will fail today - bug in SearchableInfo)
-     *  findActionKey works
-     *  getIcon works
-
-     */
-    @LargeTest
-    public void testSearchableMocked() {
-        MyMockPackageManager mockPM = new MyMockPackageManager(mContext.getPackageManager());
-        MyMockContext mockContext = new MyMockContext(mContext, mockPM);
-        ArrayList<SearchableInfo> searchables;
-        int count;
-
-        // build item list with real-world source data
-        mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_PASSTHROUGH);
-        SearchableInfo.buildSearchableList(mockContext);
-        // tests with "real" searchables (deprecate, this should be a unit test)
-        searchables = SearchableInfo.getSearchablesList();
-        count = searchables.size();
-        assertTrue(count >= 1);         // this isn't really a unit test
-        checkSearchables(searchables);
-
-        // build item list with mocked search data
-        // this round of tests confirms good operations with "zero" searchables found
-        // This should return either a null pointer or an empty list
-        mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_MOCK_ZERO);
-        SearchableInfo.buildSearchableList(mockContext);
-        searchables = SearchableInfo.getSearchablesList();
-        if (searchables != null) {
-            count = searchables.size();
-            assertTrue(count == 0);
-        }
-    }
-    
-    /**
-     * Generic health checker for an array of searchables.
-     * 
-     * This is designed to pass for any semi-legal searchable, without knowing much about
-     * the format of the underlying data.  It's fairly easy for a non-compliant application
-     * to provide meta-data that will pass here (e.g. a non-existent suggestions authority).
-     * 
-     * @param searchables The list of searchables to examine.
-     */
-    private void checkSearchables(ArrayList<SearchableInfo> searchablesList) {
-        assertNotNull(searchablesList);
-        int count = searchablesList.size();
-        for (int ii = 0; ii < count; ii++) {
-            SearchableInfo si = searchablesList.get(ii);
-            assertNotNull(si);
-            assertTrue(si.mSearchable);
-            assertTrue(si.getLabelId() != 0);        // This must be a useable string
-            assertNotEmpty(si.mSearchActivity.getClassName());
-            assertNotEmpty(si.mSearchActivity.getPackageName());
-            if (si.getSuggestAuthority() != null) {
-                // The suggestion fields are largely optional, so we'll just confirm basic health
-                assertNotEmpty(si.getSuggestAuthority());
-                assertNullOrNotEmpty(si.getSuggestPath());
-                assertNullOrNotEmpty(si.getSuggestSelection());
-                assertNullOrNotEmpty(si.getSuggestIntentAction());
-                assertNullOrNotEmpty(si.getSuggestIntentData());
-            }
-            /* Add a way to get the entire action key list, then explicitly test its elements */
-            /* For now, test the most common action key (CALL) */
-            ActionKeyInfo ai = si.findActionKey(KeyEvent.KEYCODE_CALL);
-            if (ai != null) {
-                assertEquals(ai.mKeyCode, KeyEvent.KEYCODE_CALL);
-                // one of these three fields must be non-null & non-empty
-                boolean m1 = (ai.mQueryActionMsg != null) && (ai.mQueryActionMsg.length() > 0);
-                boolean m2 = (ai.mSuggestActionMsg != null) && (ai.mSuggestActionMsg.length() > 0);
-                boolean m3 = (ai.mSuggestActionMsgColumn != null) && 
-                                (ai.mSuggestActionMsgColumn.length() > 0);
-                assertTrue(m1 || m2 || m3);
-            }
-            
-            /* 
-             * Find ways to test these:
-             * 
-             * private int mSearchMode
-             * private Drawable mIcon
-             */
-            
-            /*
-             * Explicitly not tested here:
-             * 
-             * Can be null, so not much to see:
-             * public String mSearchHint
-             * private String mZeroQueryBanner
-             * 
-             * To be deprecated/removed, so don't bother:
-             * public boolean mFilterMode
-             * public boolean mQuickStart
-             * private boolean mIconResized
-             * private int mIconResizeWidth
-             * private int mIconResizeHeight
-             * 
-             * All of these are "internal" working variables, not part of any contract
-             * private ActivityInfo mActivityInfo
-             * private Rect mTempRect
-             * private String mSuggestProviderPackage
-             * private String mCacheActivityContext
-             */
-        }
-    }
-    
-    /**
-     * Combo assert for "string not null and not empty"
-     */
-    private void assertNotEmpty(final String s) {
-        assertNotNull(s);
-        MoreAsserts.assertNotEqual(s, "");
-    }
-    
-    /**
-     * Combo assert for "string null or (not null and not empty)"
-     */
-    private void assertNullOrNotEmpty(final String s) {
-        if (s != null) {
-            MoreAsserts.assertNotEqual(s, "");
-        }
-    }    
-    
-    /**
-     * This is a mock for context.  Used to perform a true unit test on SearchableInfo.
-     * 
-     */
-    private class MyMockContext extends MockContext {
-        
-        protected Context mRealContext;
-        protected PackageManager mPackageManager;
-        
-        /**
-         * Constructor.
-         * 
-         * @param realContext Please pass in a real context for some pass-throughs to function.
-         */
-        MyMockContext(Context realContext, PackageManager packageManager) {
-            mRealContext = realContext;
-            mPackageManager = packageManager;
-        }
-        
-        /**
-         * Resources.  Pass through for now.
-         */
-        @Override
-        public Resources getResources() {
-            return mRealContext.getResources();
-        }
-
-        /**
-         * Package manager.  Pass through for now.
-         */
-        @Override
-        public PackageManager getPackageManager() {
-            return mPackageManager;
-        }
-
-        /**
-         * Package manager.  Pass through for now.
-         */
-        @Override
-        public Context createPackageContext(String packageName, int flags)
-                throws PackageManager.NameNotFoundException {
-            return mRealContext.createPackageContext(packageName, flags);
-        }
-    }
-
-/**
- * This is a mock for package manager.  Used to perform a true unit test on SearchableInfo.
- * 
- */
-    private class MyMockPackageManager extends MockPackageManager {
-        
-        public final static int SEARCHABLES_PASSTHROUGH = 0;
-        public final static int SEARCHABLES_MOCK_ZERO = 1;
-        public final static int SEARCHABLES_MOCK_ONEGOOD = 2;
-        public final static int SEARCHABLES_MOCK_ONEGOOD_ONEBAD = 3;
-        
-        protected PackageManager mRealPackageManager;
-        protected int mSearchablesMode;
-
-        public MyMockPackageManager(PackageManager realPM) {
-            mRealPackageManager = realPM;
-            mSearchablesMode = SEARCHABLES_PASSTHROUGH;
-        }
-
-        /**
-         * Set the mode for various tests.
-         */
-        public void setSearchablesMode(int newMode) {
-            switch (newMode) {
-            case SEARCHABLES_PASSTHROUGH:
-            case SEARCHABLES_MOCK_ZERO:
-                mSearchablesMode = newMode;
-                break;
-                
-            default:
-                throw new UnsupportedOperationException();       
-            }
-        }
-        
-        /**
-         * Find activities that support a given intent.
-         * 
-         * Retrieve all activities that can be performed for the given intent.
-         * 
-         * @param intent The desired intent as per resolveActivity().
-         * @param flags Additional option flags.  The most important is
-         *                    MATCH_DEFAULT_ONLY, to limit the resolution to only
-         *                    those activities that support the CATEGORY_DEFAULT.
-         * 
-         * @return A List<ResolveInfo> containing one entry for each matching
-         *         Activity. These are ordered from best to worst match -- that
-         *         is, the first item in the list is what is returned by
-         *         resolveActivity().  If there are no matching activities, an empty
-         *         list is returned.
-         */
-        @Override 
-        public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
-            assertNotNull(intent);
-            assertEquals(intent.getAction(), Intent.ACTION_SEARCH);
-            switch (mSearchablesMode) {
-            case SEARCHABLES_PASSTHROUGH:
-                return mRealPackageManager.queryIntentActivities(intent, flags);
-            case SEARCHABLES_MOCK_ZERO:
-                return null;
-            default:
-                throw new UnsupportedOperationException();
-            }
-        }
-        
-        /**
-         * Retrieve an XML file from a package.  This is a low-level API used to
-         * retrieve XML meta data.
-         * 
-         * @param packageName The name of the package that this xml is coming from.
-         * Can not be null.
-         * @param resid The resource identifier of the desired xml.  Can not be 0.
-         * @param appInfo Overall information about <var>packageName</var>.  This
-         * may be null, in which case the application information will be retrieved
-         * for you if needed; if you already have this information around, it can
-         * be much more efficient to supply it here.
-         * 
-         * @return Returns an XmlPullParser allowing you to parse out the XML
-         * data.  Returns null if the xml resource could not be found for any
-         * reason.
-         */
-        @Override 
-        public XmlResourceParser getXml(String packageName, int resid, ApplicationInfo appInfo) {
-            assertNotNull(packageName);
-            MoreAsserts.assertNotEqual(packageName, "");
-            MoreAsserts.assertNotEqual(resid, 0);
-            switch (mSearchablesMode) {
-            case SEARCHABLES_PASSTHROUGH:
-                return mRealPackageManager.getXml(packageName, resid, appInfo);
-            case SEARCHABLES_MOCK_ZERO:
-            default:
-                throw new UnsupportedOperationException();
-            }
-        }
-        
-        /**
-         * Find a single content provider by its base path name.
-         * 
-         * @param name The name of the provider to find.
-         * @param flags Additional option flags.  Currently should always be 0.
-         * 
-         * @return ContentProviderInfo Information about the provider, if found,
-         *         else null.
-         */
-        @Override 
-        public ProviderInfo resolveContentProvider(String name, int flags) {
-            assertNotNull(name);
-            MoreAsserts.assertNotEqual(name, "");
-            assertEquals(flags, 0);
-            switch (mSearchablesMode) {
-            case SEARCHABLES_PASSTHROUGH:
-                return mRealPackageManager.resolveContentProvider(name, flags);
-            case SEARCHABLES_MOCK_ZERO:
-            default:
-                throw new UnsupportedOperationException();
-            }
-        }
-    }
 }
 
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java
new file mode 100644
index 0000000..c299b10
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SearchablesTest.java
@@ -0,0 +1,411 @@
+/*
+ * 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.
+ */
+
+package com.android.unit_tests;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.server.search.SearchableInfo;
+import android.server.search.Searchables;
+import android.server.search.SearchableInfo.ActionKeyInfo;
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.test.mock.MockContext;
+import android.test.mock.MockPackageManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.KeyEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * To launch this test from the command line:
+ * 
+ * adb shell am instrument -w \
+ *   -e class com.android.unit_tests.SearchablesTest \
+ *   com.android.unit_tests/android.test.InstrumentationTestRunner
+ */
+@SmallTest
+public class SearchablesTest extends AndroidTestCase {
+    
+    /*
+     * SearchableInfo tests
+     *  Mock the context so I can provide very specific input data
+     *  Confirm OK with "zero" searchables
+     *  Confirm "good" metadata read properly
+     *  Confirm "bad" metadata skipped properly
+     *  Confirm ordering of searchables
+     *  Confirm "good" actionkeys
+     *  confirm "bad" actionkeys are rejected
+     *  confirm XML ordering enforced (will fail today - bug in SearchableInfo)
+     *  findActionKey works
+     *  getIcon works
+     */
+    
+    /**
+     * The goal of this test is to confirm proper operation of the 
+     * SearchableInfo helper class.
+     * 
+     * TODO:  The metadata source needs to be mocked out because adding
+     * searchability metadata via this test is causing it to leak into the
+     * real system.  So for now I'm just going to test for existence of the
+     * GoogleSearch app (which is searchable).
+     */
+    public void testSearchableGoogleSearch() {
+        // test basic array & hashmap
+        Searchables searchables = new Searchables(mContext);
+        searchables.buildSearchableList();
+
+        // test linkage from another activity
+        // TODO inject this via mocking into the package manager.
+        // TODO for now, just check for searchable GoogleSearch app (this isn't really a unit test)
+        ComponentName thisActivity = new ComponentName(
+                "com.android.googlesearch", 
+                "com.android.googlesearch.GoogleSearch");
+
+        SearchableInfo si = searchables.getSearchableInfo(thisActivity);
+        assertNotNull(si);
+        assertTrue(si.mSearchable);
+        assertEquals(thisActivity, si.mSearchActivity);
+        
+        Context appContext = si.getActivityContext(mContext);
+        assertNotNull(appContext);
+        MoreAsserts.assertNotEqual(appContext, mContext);
+        assertEquals("Google Search", appContext.getString(si.getHintId()));
+        assertEquals("Google", appContext.getString(si.getLabelId()));
+    }
+    
+    /**
+     * Test that non-searchable activities return no searchable info (this would typically
+     * trigger the use of the default searchable e.g. contacts)
+     */
+    public void testNonSearchable() {
+        // test basic array & hashmap
+        Searchables searchables = new Searchables(mContext);
+        searchables.buildSearchableList();
+
+        // confirm that we return null for non-searchy activities
+        ComponentName nonActivity = new ComponentName(
+                            "com.android.unit_tests",
+                            "com.android.unit_tests.NO_SEARCH_ACTIVITY");
+        SearchableInfo si = searchables.getSearchableInfo(nonActivity);
+        assertNull(si);
+    }
+    
+    /**
+     * This is an attempt to run the searchable info list with a mocked context.  Here are some
+     * things I'd like to test.
+     *
+     *  Confirm OK with "zero" searchables
+     *  Confirm "good" metadata read properly
+     *  Confirm "bad" metadata skipped properly
+     *  Confirm ordering of searchables
+     *  Confirm "good" actionkeys
+     *  confirm "bad" actionkeys are rejected
+     *  confirm XML ordering enforced (will fail today - bug in SearchableInfo)
+     *  findActionKey works
+     *  getIcon works
+
+     */
+    public void testSearchableMocked() {
+        MyMockPackageManager mockPM = new MyMockPackageManager(mContext.getPackageManager());
+        MyMockContext mockContext = new MyMockContext(mContext, mockPM);
+        Searchables searchables;
+        ArrayList<SearchableInfo> searchablesList;
+        int count;
+
+            
+        // build item list with real-world source data
+        mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_PASSTHROUGH);
+        searchables = new Searchables(mockContext);
+        searchables.buildSearchableList();
+        // tests with "real" searchables (deprecate, this should be a unit test)
+        searchablesList = searchables.getSearchablesList();
+        count = searchablesList.size();
+        assertTrue(count >= 1);         // this isn't really a unit test
+        checkSearchables(searchablesList);
+
+        // build item list with mocked search data
+        // this round of tests confirms good operations with "zero" searchables found
+        // This should return either a null pointer or an empty list
+        mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_MOCK_ZERO);
+        searchables = new Searchables(mockContext);
+        searchables.buildSearchableList();
+        searchablesList = searchables.getSearchablesList();
+        if (searchablesList != null) {
+            count = searchablesList.size();
+            assertTrue(count == 0);
+        }
+    }
+    
+    /**
+     * Generic health checker for an array of searchables.
+     * 
+     * This is designed to pass for any semi-legal searchable, without knowing much about
+     * the format of the underlying data.  It's fairly easy for a non-compliant application
+     * to provide meta-data that will pass here (e.g. a non-existent suggestions authority).
+     * 
+     * @param searchables The list of searchables to examine.
+     */
+    private void checkSearchables(ArrayList<SearchableInfo> searchablesList) {
+        assertNotNull(searchablesList);
+        int count = searchablesList.size();
+        for (int ii = 0; ii < count; ii++) {
+            SearchableInfo si = searchablesList.get(ii);
+            assertNotNull(si);
+            assertTrue(si.mSearchable);
+            assertTrue(si.getLabelId() != 0);        // This must be a useable string
+            assertNotEmpty(si.mSearchActivity.getClassName());
+            assertNotEmpty(si.mSearchActivity.getPackageName());
+            if (si.getSuggestAuthority() != null) {
+                // The suggestion fields are largely optional, so we'll just confirm basic health
+                assertNotEmpty(si.getSuggestAuthority());
+                assertNullOrNotEmpty(si.getSuggestPath());
+                assertNullOrNotEmpty(si.getSuggestSelection());
+                assertNullOrNotEmpty(si.getSuggestIntentAction());
+                assertNullOrNotEmpty(si.getSuggestIntentData());
+            }
+            /* Add a way to get the entire action key list, then explicitly test its elements */
+            /* For now, test the most common action key (CALL) */
+            ActionKeyInfo ai = si.findActionKey(KeyEvent.KEYCODE_CALL);
+            if (ai != null) {
+                assertEquals(ai.mKeyCode, KeyEvent.KEYCODE_CALL);
+                // one of these three fields must be non-null & non-empty
+                boolean m1 = (ai.mQueryActionMsg != null) && (ai.mQueryActionMsg.length() > 0);
+                boolean m2 = (ai.mSuggestActionMsg != null) && (ai.mSuggestActionMsg.length() > 0);
+                boolean m3 = (ai.mSuggestActionMsgColumn != null) && 
+                                (ai.mSuggestActionMsgColumn.length() > 0);
+                assertTrue(m1 || m2 || m3);
+            }
+            
+            /* 
+             * Find ways to test these:
+             * 
+             * private int mSearchMode
+             * private Drawable mIcon
+             */
+            
+            /*
+             * Explicitly not tested here:
+             * 
+             * Can be null, so not much to see:
+             * public String mSearchHint
+             * private String mZeroQueryBanner
+             * 
+             * To be deprecated/removed, so don't bother:
+             * public boolean mFilterMode
+             * public boolean mQuickStart
+             * private boolean mIconResized
+             * private int mIconResizeWidth
+             * private int mIconResizeHeight
+             * 
+             * All of these are "internal" working variables, not part of any contract
+             * private ActivityInfo mActivityInfo
+             * private Rect mTempRect
+             * private String mSuggestProviderPackage
+             * private String mCacheActivityContext
+             */
+        }
+    }
+    
+    /**
+     * Combo assert for "string not null and not empty"
+     */
+    private void assertNotEmpty(final String s) {
+        assertNotNull(s);
+        MoreAsserts.assertNotEqual(s, "");
+    }
+    
+    /**
+     * Combo assert for "string null or (not null and not empty)"
+     */
+    private void assertNullOrNotEmpty(final String s) {
+        if (s != null) {
+            MoreAsserts.assertNotEqual(s, "");
+        }
+    }    
+    
+    /**
+     * This is a mock for context.  Used to perform a true unit test on SearchableInfo.
+     * 
+     */
+    private class MyMockContext extends MockContext {
+        
+        protected Context mRealContext;
+        protected PackageManager mPackageManager;
+        
+        /**
+         * Constructor.
+         * 
+         * @param realContext Please pass in a real context for some pass-throughs to function.
+         */
+        MyMockContext(Context realContext, PackageManager packageManager) {
+            mRealContext = realContext;
+            mPackageManager = packageManager;
+        }
+        
+        /**
+         * Resources.  Pass through for now.
+         */
+        @Override
+        public Resources getResources() {
+            return mRealContext.getResources();
+        }
+
+        /**
+         * Package manager.  Pass through for now.
+         */
+        @Override
+        public PackageManager getPackageManager() {
+            return mPackageManager;
+        }
+
+        /**
+         * Package manager.  Pass through for now.
+         */
+        @Override
+        public Context createPackageContext(String packageName, int flags)
+                throws PackageManager.NameNotFoundException {
+            return mRealContext.createPackageContext(packageName, flags);
+        }
+    }
+
+/**
+ * This is a mock for package manager.  Used to perform a true unit test on SearchableInfo.
+ * 
+ */
+    private class MyMockPackageManager extends MockPackageManager {
+        
+        public final static int SEARCHABLES_PASSTHROUGH = 0;
+        public final static int SEARCHABLES_MOCK_ZERO = 1;
+        public final static int SEARCHABLES_MOCK_ONEGOOD = 2;
+        public final static int SEARCHABLES_MOCK_ONEGOOD_ONEBAD = 3;
+        
+        protected PackageManager mRealPackageManager;
+        protected int mSearchablesMode;
+
+        public MyMockPackageManager(PackageManager realPM) {
+            mRealPackageManager = realPM;
+            mSearchablesMode = SEARCHABLES_PASSTHROUGH;
+        }
+
+        /**
+         * Set the mode for various tests.
+         */
+        public void setSearchablesMode(int newMode) {
+            switch (newMode) {
+            case SEARCHABLES_PASSTHROUGH:
+            case SEARCHABLES_MOCK_ZERO:
+                mSearchablesMode = newMode;
+                break;
+                
+            default:
+                throw new UnsupportedOperationException();       
+            }
+        }
+        
+        /**
+         * Find activities that support a given intent.
+         * 
+         * Retrieve all activities that can be performed for the given intent.
+         * 
+         * @param intent The desired intent as per resolveActivity().
+         * @param flags Additional option flags.  The most important is
+         *                    MATCH_DEFAULT_ONLY, to limit the resolution to only
+         *                    those activities that support the CATEGORY_DEFAULT.
+         * 
+         * @return A List<ResolveInfo> containing one entry for each matching
+         *         Activity. These are ordered from best to worst match -- that
+         *         is, the first item in the list is what is returned by
+         *         resolveActivity().  If there are no matching activities, an empty
+         *         list is returned.
+         */
+        @Override 
+        public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
+            assertNotNull(intent);
+            assertEquals(intent.getAction(), Intent.ACTION_SEARCH);
+            switch (mSearchablesMode) {
+            case SEARCHABLES_PASSTHROUGH:
+                return mRealPackageManager.queryIntentActivities(intent, flags);
+            case SEARCHABLES_MOCK_ZERO:
+                return null;
+            default:
+                throw new UnsupportedOperationException();
+            }
+        }
+        
+        /**
+         * Retrieve an XML file from a package.  This is a low-level API used to
+         * retrieve XML meta data.
+         * 
+         * @param packageName The name of the package that this xml is coming from.
+         * Can not be null.
+         * @param resid The resource identifier of the desired xml.  Can not be 0.
+         * @param appInfo Overall information about <var>packageName</var>.  This
+         * may be null, in which case the application information will be retrieved
+         * for you if needed; if you already have this information around, it can
+         * be much more efficient to supply it here.
+         * 
+         * @return Returns an XmlPullParser allowing you to parse out the XML
+         * data.  Returns null if the xml resource could not be found for any
+         * reason.
+         */
+        @Override 
+        public XmlResourceParser getXml(String packageName, int resid, ApplicationInfo appInfo) {
+            assertNotNull(packageName);
+            MoreAsserts.assertNotEqual(packageName, "");
+            MoreAsserts.assertNotEqual(resid, 0);
+            switch (mSearchablesMode) {
+            case SEARCHABLES_PASSTHROUGH:
+                return mRealPackageManager.getXml(packageName, resid, appInfo);
+            case SEARCHABLES_MOCK_ZERO:
+            default:
+                throw new UnsupportedOperationException();
+            }
+        }
+        
+        /**
+         * Find a single content provider by its base path name.
+         * 
+         * @param name The name of the provider to find.
+         * @param flags Additional option flags.  Currently should always be 0.
+         * 
+         * @return ContentProviderInfo Information about the provider, if found,
+         *         else null.
+         */
+        @Override 
+        public ProviderInfo resolveContentProvider(String name, int flags) {
+            assertNotNull(name);
+            MoreAsserts.assertNotEqual(name, "");
+            assertEquals(flags, 0);
+            switch (mSearchablesMode) {
+            case SEARCHABLES_PASSTHROUGH:
+                return mRealPackageManager.resolveContentProvider(name, flags);
+            case SEARCHABLES_MOCK_ZERO:
+            default:
+                throw new UnsupportedOperationException();
+            }
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java
index 1ea83c3..e6639d3 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java
@@ -98,7 +98,7 @@
             mMetrics = new DisplayMetrics();
             mMetrics.widthPixels = 200;
             mMetrics.heightPixels = 320;
-            mMetrics.density = 120;
+            mMetrics.density = 1;
         }
 
         void setProperty(properties p, int value) {
@@ -131,7 +131,9 @@
                     mMetrics.heightPixels = value;
                     break;
                 case DENSITY:
-                    mMetrics.density = value;
+                    // this is the ratio from the standard
+
+                    mMetrics.density = (((float)value)/((float)DisplayMetrics.DEFAULT_DENSITY));
                     break;
                 default:
                     assert(false);
@@ -187,18 +189,16 @@
          */
         TotalConfig config = new TotalConfig();
         Resources res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple default");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag default"});
+        checkValue(res, R.configVarying.simple, "simple default");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag default"});
 
         config = new TotalConfig();
         config.setProperty(properties.LANGUAGE, "xx");
         res = config.getResources();
-// got simple xx 32dpi
-//        checkValue(res, R.configVarying.simple, "simple xx");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag xx"});
+        checkValue(res, R.configVarying.simple, "simple xx");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag xx"});
 
         config = new TotalConfig();
         config.setProperty(properties.LANGUAGE, "xx");
@@ -225,116 +225,66 @@
         config = new TotalConfig();
         config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_NOTOUCH);
         res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple notouch");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag notouch"});
-
-        config = new TotalConfig();
-        config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_FINGER);
-        res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple finger");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag finger"});
+        checkValue(res, R.configVarying.simple, "simple notouch");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag notouch"});
 
         config = new TotalConfig();
         config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS);
         res = config.getResources();
-// got simple 32dpi stylus
-//        checkValue(res, R.configVarying.simple, "simple stylus");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag stylus"});
+        checkValue(res, R.configVarying.simple, "simple stylus");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag stylus"});
 
         config = new TotalConfig();
         config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_NOKEYS);
         res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple nokeys");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag nokeys"});
-
-        config = new TotalConfig();
-        config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_QWERTY);
-        res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple qwerty");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag qwerty"});
+        checkValue(res, R.configVarying.simple, "simple nokeys");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag nokeys"});
 
         config = new TotalConfig();
         config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY);
         res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple 12key");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag 12key"});
-
-        config = new TotalConfig();
-        config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_YES);
-        res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple keyshidden");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag keyshidden"});
+        checkValue(res, R.configVarying.simple, "simple 12key");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag 12key"});
 
         config = new TotalConfig();
         config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO);
         res = config.getResources();
-// got simple 32dpi keysexposed
-//        checkValue(res, R.configVarying.simple, "simple keysexposed");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag keysexposed"});
+        checkValue(res, R.configVarying.simple, "simple keysexposed");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag keysexposed"});
 
         config = new TotalConfig();
         config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_NONAV);
         res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple nonav");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag nonav"});
+        checkValue(res, R.configVarying.simple, "simple nonav");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag nonav"});
 
         config = new TotalConfig();
         config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD);
         res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple dpad");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag dpad"});
-
-        config = new TotalConfig();
-        config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_TRACKBALL);
-        res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple trackball");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag trackball"});
+        checkValue(res, R.configVarying.simple, "simple dpad");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag dpad"});
 
         config = new TotalConfig();
         config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_WHEEL);
         res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple wheel");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag wheel"});
-
-        config = new TotalConfig();
-        config.setProperty(properties.HEIGHT, 320);
-        config.setProperty(properties.WIDTH, 200);
-        res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple 320x200");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag 320x200"});
+        checkValue(res, R.configVarying.simple, "simple wheel");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag wheel"});
 
         config = new TotalConfig();
         config.setProperty(properties.HEIGHT, 480);
         config.setProperty(properties.WIDTH, 320);
         res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple 480x320");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag 480x320"});
+        checkValue(res, R.configVarying.simple, "simple 480x320");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag 480x320"});
 
         config = new TotalConfig();
         config.setProperty(properties.DENSITY, 240);
@@ -344,36 +294,91 @@
                 R.styleable.TestConfig, new String[]{"bag 240dpi"});
 
         config = new TotalConfig();
-        config.setProperty(properties.DENSITY, 120);
-        res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple 120dpi");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag 120dpi"});
-
-        config = new TotalConfig();
         config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_LANDSCAPE);
         res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple landscape");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag landscape"});
-
-        config = new TotalConfig();
-        config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_PORTRAIT);
-        res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple portrait");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag portrait"});
+        checkValue(res, R.configVarying.simple, "simple landscape");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag landscape"});
 
         config = new TotalConfig();
         config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE);
         res = config.getResources();
-// got simple square 32dpi
-//        checkValue(res, R.configVarying.simple, "simple square");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag square"});
+        checkValue(res, R.configVarying.simple, "simple square");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag square"});
+    }
+
+    @MediumTest
+    public void testDensity() throws Exception {
+        // have 32, 240 and the default 160 content.
+        // rule is that closest wins, with down scaling (larger content)
+        // being twice as nice as upscaling.
+        // transition at H/2 * (-1 +/- sqrt(1+8L/H))
+        // SO, X < 49 goes to 32
+        // 49 >= X < 182 goes to 160
+        // X >= 182 goes to 240
+        TotalConfig config = new TotalConfig();
+        config.setProperty(properties.DENSITY, 2);
+        Resources res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple 32dpi");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag 32dpi"});
+
+        config = new TotalConfig();
+        config.setProperty(properties.DENSITY, 32);
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple 32dpi");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag 32dpi"});
+
+        config = new TotalConfig();
+        config.setProperty(properties.DENSITY, 48);
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple 32dpi");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag 32dpi"});
+
+        config = new TotalConfig();
+        config.setProperty(properties.DENSITY, 49);
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple default");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag default"});
+
+        config = new TotalConfig();
+        config.setProperty(properties.DENSITY, 150);
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple default");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag default"});
+
+        config = new TotalConfig();
+        config.setProperty(properties.DENSITY, 181);
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple default");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag default"});
+
+        config = new TotalConfig();
+        config.setProperty(properties.DENSITY, 182);
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple 240dpi");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag 240dpi"});
+
+        config = new TotalConfig();
+        config.setProperty(properties.DENSITY, 239);
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple 240dpi");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag 240dpi"});
+
+        config = new TotalConfig();
+        config.setProperty(properties.DENSITY, 490);
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple 240dpi");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag 240dpi"});
     }
 
 // TODO - add tests for special cases - ie, other key params seem ignored if 
@@ -407,10 +412,9 @@
         config = new TotalConfig();
         config.setProperty(properties.MNC, 333);
         res = config.getResources();
-// got simple 24dpi
-//        checkValue(res, R.configVarying.simple, "simple default");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag default"});
+        checkValue(res, R.configVarying.simple, "simple default");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag default"});
     }
 
     @MediumTest
@@ -419,13 +423,31 @@
          * Verify that in cases of ties, the specific ordering is followed
          */
 
-        /* full A + B + C doesn't exist.  Do we get A + C or B + C? 
+        /**
+         * Precidence order: mcc, mnc, locale, orientation, density,
+         * touchscreen, hidden, keyboard, navigation, width-height
+         */
+
+        /**
+         * verify mcc trumps mnc.  Have 110-xx, 220-xx but no 110-220
+         * so with is selected?  Should be mcc110-xx. 
          */
         TotalConfig config = new TotalConfig();
+        config.setProperty(properties.MCC, 110);
+        config.setProperty(properties.MNC, 220);
+        config.setProperty(properties.LANGUAGE, "xx");
+        Resources res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple mcc110 xx");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag mcc110 xx"});
+
+        /* full A + B + C doesn't exist.  Do we get A + C or B + C? 
+         */
+        config = new TotalConfig();
         config.setProperty(properties.MCC, 111);
         config.setProperty(properties.MNC, 222);
         config.setProperty(properties.LANGUAGE, "xx");
-        Resources res = config.getResources();
+        res = config.getResources();
         checkValue(res, R.configVarying.simple, "simple mcc111 mnc222");
         checkValue(res, R.configVarying.bag,
                 R.styleable.TestConfig, new String[]{"bag mcc111 mnc222"});
@@ -433,7 +455,8 @@
         config = new TotalConfig();
         config.setProperty(properties.MNC, 222);
         config.setProperty(properties.LANGUAGE, "xx");
-        config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE);
+        config.setProperty(properties.ORIENTATION, 
+                Configuration.ORIENTATION_SQUARE);
         res = config.getResources();
         checkValue(res, R.configVarying.simple, "simple mnc222 xx");
         checkValue(res, R.configVarying.bag,
@@ -441,60 +464,77 @@
 
         config = new TotalConfig();
         config.setProperty(properties.LANGUAGE, "xx");
-        config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE);
+        config.setProperty(properties.ORIENTATION, 
+                Configuration.ORIENTATION_SQUARE);
         config.setProperty(properties.DENSITY, 32);
         res = config.getResources();
-        checkValue(res, R.configVarying.simple, "simple xx 32dpi");
+        checkValue(res, R.configVarying.simple, "simple xx square");
         checkValue(res, R.configVarying.bag,
-                R.styleable.TestConfig, new String[]{"bag xx 32dpi"});
+                R.styleable.TestConfig, new String[]{"bag xx square"});
 
         config = new TotalConfig();
-        config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE);
+        config.setProperty(properties.ORIENTATION, 
+                Configuration.ORIENTATION_SQUARE);
         config.setProperty(properties.DENSITY, 32);
-        config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS);
+        config.setProperty(properties.TOUCHSCREEN, 
+                Configuration.TOUCHSCREEN_STYLUS);
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple square 32dpi");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag square 32dpi"});
+
+        config = new TotalConfig();
+        config.setProperty(properties.DENSITY, 32);
+        config.setProperty(properties.TOUCHSCREEN, 
+                Configuration.TOUCHSCREEN_STYLUS);
+        config.setProperty(properties.KEYBOARDHIDDEN, 
+                Configuration.KEYBOARDHIDDEN_NO);
         res = config.getResources();
         checkValue(res, R.configVarying.simple, "simple 32dpi stylus");
         checkValue(res, R.configVarying.bag,
                 R.styleable.TestConfig, new String[]{"bag 32dpi stylus"});
 
         config = new TotalConfig();
-        config.setProperty(properties.DENSITY, 32);
-        config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS);
-        config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO);
+        config.setProperty(properties.TOUCHSCREEN, 
+                Configuration.TOUCHSCREEN_STYLUS);
+        config.setProperty(properties.KEYBOARDHIDDEN, 
+                Configuration.KEYBOARDHIDDEN_NO);
+        config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY);
         res = config.getResources();
-        checkValue(res, R.configVarying.simple, "simple 32dpi stylus");
+        checkValue(res, R.configVarying.simple, "simple stylus keysexposed");
         checkValue(res, R.configVarying.bag,
-                R.styleable.TestConfig, new String[]{"bag 32dpi stylus"});
+                R.styleable.TestConfig, new String[]{"bag stylus keysexposed"});
 
         config = new TotalConfig();
-        config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS);
-        config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO);
+        config.setProperty(properties.KEYBOARDHIDDEN, 
+                Configuration.KEYBOARDHIDDEN_NO);
         config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY);
+        config.setProperty(properties.NAVIGATION, 
+                Configuration.NAVIGATION_DPAD);
         res = config.getResources();
-// got simple 32dpi stylus
-//        checkValue(res, R.configVarying.simple, "simple stylus 12key");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag stylus 12key"});
-
-        config = new TotalConfig();
-        config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO);
-        config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY);
-        config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD);
-        res = config.getResources();
-// got simple 32dpi exposed
-//        checkValue(res, R.configVarying.simple, "simple stylus keysexposed");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag stylus keysexposed"});
+        checkValue(res, R.configVarying.simple, "simple keysexposed 12key");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag keysexposed 12key"});
 
         config = new TotalConfig();
         config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY);
-        config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD);
+        config.setProperty(properties.NAVIGATION, 
+                Configuration.NAVIGATION_DPAD);
         config.setProperty(properties.HEIGHT, 63);
         config.setProperty(properties.WIDTH, 57);
         res = config.getResources();
-// got simple 240dpi
-//        checkValue(res, R.configVarying.simple, "simple 12key dpad");
-//        checkValue(res, R.configVarying.bag,
-//                R.styleable.TestConfig, new String[]{"bag 12key dpad"});
+        checkValue(res, R.configVarying.simple, "simple 12key dpad");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag 12key dpad"});
+
+        config = new TotalConfig();
+        config.setProperty(properties.NAVIGATION, 
+                Configuration.NAVIGATION_DPAD);
+        config.setProperty(properties.HEIGHT, 640);
+        config.setProperty(properties.WIDTH, 400);
+        res = config.getResources();
+        checkValue(res, R.configVarying.simple, "simple dpad");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag dpad"});
     }
 }
diff --git a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java
index 663b7a4..6f89fce 100644
--- a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java
+++ b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java
@@ -147,4 +147,56 @@
         // now try moving "down" - nothing should happen since there's no longer an adapter
         sendKeys("DPAD_DOWN");
     }
+    
+    /** Test the show/hide behavior of the drop-down. */
+    @MediumTest
+    public void testPopupShow() throws Throwable {
+        AutoCompleteTextViewSimple theActivity = getActivity();
+        final AutoCompleteTextView textView = theActivity.getTextView();
+        final Instrumentation instrumentation = getInstrumentation();
+        
+        // Drop-down should not be showing when no text has been entered
+        assertFalse("isPopupShowing() on start", textView.isPopupShowing());
+        
+        // focus and type
+        textView.requestFocus();
+        instrumentation.waitForIdleSync();
+        sendKeys("A");
+        
+        // Drop-down should now be visible
+        assertTrue("isPopupShowing() after typing", textView.isPopupShowing());
+        
+        // Clear the text
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                textView.setText("");
+            }
+        });
+        instrumentation.waitForIdleSync();
+        
+        // Drop-down should be hidden when text is cleared
+        assertFalse("isPopupShowing() after text cleared", textView.isPopupShowing());
+        
+        // Set the text, without filtering
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                textView.setText("a", false);
+            }
+        });
+        instrumentation.waitForIdleSync();
+        
+        // Drop-down should still be hidden
+        assertFalse("isPopupShowing() after setText(\"a\", false)", textView.isPopupShowing());
+        
+        // Set the text, now with filtering
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                textView.setText("a");
+            }
+        });
+        instrumentation.waitForIdleSync();
+        
+        // Drop-down should show up after setText() with filtering 
+        assertTrue("isPopupShowing() after text set", textView.isPopupShowing());
+    }
 }