diff options
75 files changed, 4991 insertions, 3698 deletions
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=""android.permission.SDCARD_WRITE"" + 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=""android.permission-group.STORAGE"" + 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.AttributeSet; 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.view.inputmethod.InputMethodManager; 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 @@ import java.util.concurrent.atomic.AtomicLong; 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; - - // 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; + // 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; + // 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS /** * 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS // 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; - - // receive broadcasts - getContext().registerReceiver(mBroadcastReceiver, mCloseDialogsFilter); - getContext().registerReceiver(mBroadcastReceiver, mPackageFilter); + // 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()); - // 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 + // show the dialog. this will call onStart(). + if (!isShowing()) { + show(); } - // 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); - } + updateUI(); - 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; + protected void onStart() { + super.onStart(); + + // receive broadcasts + getContext().registerReceiver(mBroadcastReceiver, mCloseDialogsFilter); + getContext().registerReceiver(mBroadcastReceiver, mPackageFilter); } /** @@ -289,6 +290,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS // 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS /** * 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS inputType |= InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE; } } - mSearchTextField.setInputType(inputType); - mSearchTextField.setImeOptions(mSearchable.getImeOptions()); + mSearchAutoComplete.setInputType(inputType); + mSearchAutoComplete.setImeOptions(mSearchable.getImeOptions()); } } - + /** - * 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. + * Updates the auto-complete text view. */ - public void onPackageListChange() { - cancel(); + 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); + } } - + /** * Update the text in the search button. Note: This is deprecated functionality, for * 1.0 compatibility only. @@ -481,26 +495,40 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS hint = mActivityContext.getString(hintId); } } - mSearchTextField.setHint(hint); + mSearchAutoComplete.setHint(hint); } } @@ -548,63 +576,129 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS */ 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS */ 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS */ 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS */ View.OnKeyListener mTextKeyListener = new View.OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - cancel(); - return true; - } - // 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()"); - } - // 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); - 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; - } + // guard against possible race conditions + if (mSearchable == null) { + return false; } - 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); + if (DBG_LOG_TIMING) dbgLogTiming("doTextKey()"); + if (DBG) { + Log.d(LOG_TAG, "mTextListener.onKey(" + keyCode + "," + event + + "), selection: " + mSearchAutoComplete.getListSelection()); } - 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; + + // 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); } - // 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); + + // 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; + } + if (event.getAction() == KeyEvent.ACTION_DOWN) { + SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); + if ((actionKey != null) && (actionKey.mQueryActionMsg != null)) { + launchQuerySearch(keyCode, actionKey.mQueryActionMsg); + return true; } } } - + return false; } }; - */ - + /** - * 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } /** - * 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,158 +973,194 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS 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; - } + } + + /** + * Launch a search for the text in the query text field. + */ + protected void launchQuerySearch() { + launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null); + } /** - * Set or reset the user query to follow the selections in the suggestions + * Launch a search for the text in the query text field. + * + * @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. + */ + 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); + } + + /** + * Launches an intent based on a suggestion. * - * @param jamQuery True means to set the query, false means to reset it to the user's choice + * @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 void jamSuggestionQuery(boolean jamQuery, AdapterView<?> parent, int position) { - // quick check against race conditions - if (mSearchable == null) { + 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)) { + 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; } - - 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(); - } + if (handleSpecialIntent(intent)){ + return; + } + if (!mGlobalSearchMode) { + dismiss(); } - // 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); + getContext().startActivity(intent); } - + /** - * Assemble a search intent and send it. - * - * @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. + * Handles the special intent actions declared in {@link SearchManager}. + * + * @return <code>true</code> if the intent was handled. */ - 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); + 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; } - - if (data != null) { - launcher.setData(data); + 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; } - - if (appData != null) { - launcher.putExtra(SearchManager.APP_DATA, appData); + ComponentName componentName = ComponentName.unflattenFromString(dataUri.toString()); + if (componentName == null) { + Log.w(LOG_TAG, "Invalid ComponentName: " + dataUri); + return; } - - // add launch info (action key, etc.) - if (actionKey != KeyEvent.KEYCODE_UNKNOWN) { - launcher.putExtra(SearchManager.ACTION_KEY, actionKey); - launcher.putExtra(SearchManager.ACTION_MSG, actionMsg); + 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); - // attempt to enforce security requirement (no 3rd-party intents) - launcher.setComponent(si.mSearchActivity); - - getContext().startActivity(launcher); + String query = intent.getStringExtra(SearchManager.QUERY); + setUserQuery(query); } - + /** - * 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) + * Handles {@link SearchManager#INTENT_ACTION_CURSOR_RESPOND}. */ - private boolean launchSuggestion(CursorAdapter ca, int position) { - Cursor c = ca.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); - return true; + private void handleCursorRespondIntent(Intent intent) { + Cursor c = mSuggestionsAdapter.getCursor(); + if (c != null) { + c.respond(intent.getExtras()); } - return false; + } + + /** + * 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; } /** @@ -1159,62 +1169,43 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS * 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; - } - } - if (mSuggestionAction == null) { - mSuggestionAction = si.getSuggestIntentAction(); + String action = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_ACTION); + if (action == null) { + action = mSearchable.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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } 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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS * * @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 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } /** - * 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(); } - - /** - * 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. - */ - @Override - public void replaceText(CharSequence text) { + + private void setSearchDialog(SearchDialog searchDialog) { + mSearchDialog = searchDialog; } - /** - * 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". - */ @Override - public boolean enoughToFilter() { - return true; + public void setThreshold(int threshold) { + super.setThreshold(threshold); + mThreshold = threshold; } - } - - /** - * 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(); - } - /** - * Set this field (temporarily!) to disable suggestions updating. This allows us - * to change the string in the text view without changing the suggestions list. + * Returns true if the text field is empty, or contains only whitespace. */ - public void setNonUserQuery(boolean nonUserQuery) { - synchronized (this) { - mNonUserQuery = nonUserQuery; - } + private boolean isEmpty() { + return TextUtils.getTrimmedLength(getText()) == 0; } - 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. + * Clears the entered text. */ - @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; + private void clear() { + setText(""); } /** - * Overriding changeCursor() allows us to change not only the cursor, but by sampling - * the cursor's columns, the actual display characteristics of the list. + * We override this method to avoid replacing the query box text + * when a suggestion is clicked. */ @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."); - } + protected void replaceText(CharSequence text) { } /** - * 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. + * We override this method so that we can allow a threshold of zero, which ACTV does not. */ @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; + public boolean enoughToFilter() { + return mThreshold <= 0 || super.enoughToFilter(); } - + /** - * 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 + * {@link AutoCompleteTextView#onKeyPreIme(int, KeyEvent)}) dismisses the drop-down on BACK, + * so we must override this method to modify the BACK behavior. */ @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); + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + return mSearchDialog.handleBackKey(keyCode, event); } - - /** - * 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; + } + + 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; } - + 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 @@ import android.view.KeyEvent; * * <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 class SearchManager 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 class SearchManager 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 class SearchManager */ 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 class SearchManager */ 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 @@ public class SearchManager 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 @@ public class SearchManager 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.ComponentName; 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 @@ public class SearchManagerService extends ISearchManager.Stub // 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 @@ public class SearchManagerService extends ISearchManager.Stub 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 class SearchManagerService extends ISearchManager.Stub 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 @@ public class SearchManagerService extends ISearchManager.Stub 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 @@ public class SearchManagerService extends ISearchManager.Stub }; /** - * 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 @@ public class SearchManagerService extends ISearchManager.Stub } 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 org.xmlpull.v1.XmlPullParserException; 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.util.Xml; 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 @@ public final class SearchableInfo implements Parcelable { // 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 @@ public final class SearchableInfo implements Parcelable { 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 @@ public final class SearchableInfo implements Parcelable { 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 @@ public final class SearchableInfo implements Parcelable { * @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 @@ public final class SearchableInfo implements Parcelable { } /** - * 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 @@ public final class SearchableInfo implements Parcelable { /** * 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 @@ public final class SearchableInfo implements Parcelable { /** * 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 @@ public final class SearchableInfo implements Parcelable { 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 @@ public final class SearchableInfo implements Parcelable { 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 @@ public final class SearchableInfo implements Parcelable { 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 @@ public final class SearchableInfo implements Parcelable { } 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 @@ public final class SearchableInfo implements Parcelable { } catch (IOException e) { throw new RuntimeException(e); } + return result; } @@ -757,16 +563,6 @@ public final class SearchableInfo implements Parcelable { } /** - * 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 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te 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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe 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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * {@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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * {@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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * <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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * 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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe } 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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe } } - dismissDropDown(); + if (mDropDownDismissedOnCompletion) { + dismissDropDown(); + } } /** @@ -721,6 +883,42 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe } /** + * 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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe Selection.setSelection(spannable, spannable.length()); } + /** {@inheritDoc} */ public void onFilterComplete(int count) { if (mAttachCount <= 0) return; @@ -744,7 +943,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * to filter. */ - if (count > 0 && enoughToFilter()) { + if ((count > 0 || mDropDownAlwaysVisible) && enoughToFilter()) { if (hasFocus() && hasWindowFocus()) { showDropDown(); } @@ -809,22 +1008,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe } /** - * 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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe 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 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe 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 > 0 if an EOL token was seen, < 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: + * + * <property-name> <type> = <value> + * <property-name> 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. + * + * <property-name> is a valid fully-qualified class name + * (one or more valid identifiers separated by dot characters). + * + * <type> is one of {boolean, byte, short, int, long, + * float, double, string}, and is case-insensitive. + * + * <value> 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<TYPE>()} 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 Binary files differnew file mode 100644 index 0000000..9b7d3e5 --- /dev/null +++ b/core/res/res/drawable/btn_global_search_normal.9.png 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 Binary files differnew file mode 100644 index 0000000..ec39178 --- /dev/null +++ b/core/res/res/drawable/btn_search_dialog_default.9.png diff --git a/core/res/res/drawable/btn_search_dialog_pressed.9.png b/core/res/res/drawable/btn_search_dialog_pressed.9.png Binary files differnew file mode 100644 index 0000000..5f52fef --- /dev/null +++ b/core/res/res/drawable/btn_search_dialog_pressed.9.png diff --git a/core/res/res/drawable/btn_search_dialog_selected.9.png b/core/res/res/drawable/btn_search_dialog_selected.9.png Binary files differnew file mode 100644 index 0000000..9fc2fde --- /dev/null +++ b/core/res/res/drawable/btn_search_dialog_selected.9.png 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 Binary files differnew file mode 100644 index 0000000..2a3366c --- /dev/null +++ b/core/res/res/drawable/btn_search_dialog_voice_default.9.png 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 Binary files differnew file mode 100644 index 0000000..57d7a74 --- /dev/null +++ b/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png 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 Binary files differnew file mode 100644 index 0000000..db3187e --- /dev/null +++ b/core/res/res/drawable/btn_search_dialog_voice_selected.9.png diff --git a/core/res/res/drawable/search_dropdown_background.9.png b/core/res/res/drawable/search_dropdown_background.9.png Binary files differnew file mode 100755 index 0000000..a6923b7 --- /dev/null +++ b/core/res/res/drawable/search_dropdown_background.9.png diff --git a/core/res/res/drawable/search_plate_global.9.png b/core/res/res/drawable/search_plate_global.9.png Binary files differnew file mode 100644 index 0000000..126054b --- /dev/null +++ b/core/res/res/drawable/search_plate_global.9.png 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 Binary files differnew file mode 100755 index 0000000..7dc5b27 --- /dev/null +++ b/core/res/res/drawable/textfield_search_default.9.png diff --git a/core/res/res/drawable/textfield_search_pressed.9.png b/core/res/res/drawable/textfield_search_pressed.9.png Binary files differnew file mode 100644 index 0000000..da00c25 --- /dev/null +++ b/core/res/res/drawable/textfield_search_pressed.9.png diff --git a/core/res/res/drawable/textfield_search_selected.9.png b/core/res/res/drawable/textfield_search_selected.9.png Binary files differnew file mode 100755 index 0000000..a9fd3b2 --- /dev/null +++ b/core/res/res/drawable/textfield_search_selected.9.png 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 @@ class Camera : public BnCameraClient, public IBinder::DeathRecipient { 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 @@ struct ResTable_config 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; - } + + // 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 (touchscreen != 0 && (!requested || requested->touchscreen != 0)) { - if (o.touchscreen == 0) { - 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 != o.keyboard) { + if (!keyboard) return false; + if (!o.keyboard) return true; + } + + if (navigation != o.navigation) { + if (!navigation) return false; + if (!o.navigation) 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; + + if (screenSize || o.screenSize) { + if (screenWidth != o.screenWidth) { + if (!screenWidth) return false; + if (!o.screenWidth) return true; + } + + if (screenHeight != o.screenHeight) { + if (!screenHeight) return false; + if (!o.screenHeight) return true; + } + } + + if (version || o.version) { + if (sdkVersion != o.sdkVersion) { + if (!sdkVersion) return false; + if (!o.sdkVersion) 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); } - // 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 ((mnc != o.mnc) && requested->mnc) { + return (mnc); } } - if (keyboard != 0 && (!requested || requested->keyboard != 0)) { - if (o.keyboard == 0) { - return true; + + if (locale || o.locale) { + if ((language[0] != o.language[0]) && requested->language[0]) { + return (language[0]); } - } - if (navigation != 0 && (!requested || requested->navigation != 0)) { - if (o.navigation == 0) { - return true; + + if ((country[0] != o.country[0]) && requested->country[0]) { + return (country[0]); } } - } - if (screenSize != 0 && (!requested || requested->screenSize != 0)) { - if (screenWidth != 0 && (!requested || requested->screenWidth != 0)) { - if (o.screenWidth == 0) { - return true; + + 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 (screenHeight != 0 && (!requested || requested->screenHeight != 0)) { - if (o.screenHeight == 0) { - return true; + + 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 (version != 0 && (!requested || requested->version != 0)) { - if (sdkVersion != 0 && (!requested || requested->sdkVersion != 0)) { - if (o.sdkVersion == 0) { - return true; + + if (screenSize || o.screenSize) { + if ((screenWidth != o.screenWidth) && requested->screenWidth) { + return (screenWidth); + } + + if ((screenHeight != o.screenHeight) && + requested->screenHeight) { + return (screenHeight); } } - if (minorVersion != 0 && (!requested || requested->minorVersion != 0)) { - if (o.minorVersion == 0) { - return true; + + if (version || o.version) { + if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) { + return (sdkVersion); + } + + if ((minorVersion != o.minorVersion) && + requested->minorVersion) { + return (minorVersion); } } + + return false; } - 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 @@ struct ResTable_config && 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 @@ Camera::Camera(const sp<ICamera>& camera) } } + +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 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag } } - if (bestPackage != NULL && bestItem.isBetterThan(thisConfig)) { + if (bestPackage != NULL && bestItem.isMoreSpecificThan(thisConfig)) { continue; } diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 7d35814..096622a 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -45,7 +45,10 @@ interface ILocationManager boolean addGpsStatusListener(IGpsStatusListener listener); void removeGpsStatusListener(IGpsStatusListener listener); - + + // for reporting callback completion + void locationCallbackFinished(ILocationListener listener); + boolean sendExtraCommand(String provider, String command, inout Bundle extras); void addProximityAlert(double latitude, double longitude, float distance, diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 0c7254e..f587f96 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -194,6 +194,11 @@ public class LocationManager { mListener.onProviderDisabled((String) msg.obj); break; } + try { + mService.locationCallbackFinished(this); + } catch (RemoteException e) { + Log.e(TAG, "locationCallbackFinished: RemoteException", e); + } } } /** 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 @@ struct extention_map_t { }; 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 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, } } + // 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 2ecc776..d636d73 100644 --- a/opengl/libs/Android.mk +++ b/opengl/libs/Android.mk @@ -35,7 +35,6 @@ include $(CLEAR_VARS) 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 @@ private: 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 @@ struct egl_display_t : public egl_object_t<'_dpy'> 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 void gl_unimplemented() { static char const * const gl_names[] = { #include "gl_entries.in" + #include "glext_entries.in" NULL }; @@ -156,7 +157,7 @@ static char const * const egl_names[] = { // ---------------------------------------------------------------------------- -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 @@ void *load_driver(const char* driver, gl_hooks_t* hooks) 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 @@ egl_display_t* get_display(EGLDisplay dpy) return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index]; } +template<typename NATIVE, typename EGL> +static inline NATIVE* egl_to_native_cast(EGL arg) { + return reinterpret_cast<NATIVE*>(arg); +} + static inline -egl_surface_t* get_surface(EGLSurface surface) -{ - egl_surface_t* s = (egl_surface_t *)surface; - return s; +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) -{ - egl_context_t* c = (egl_context_t *)context; - return c; +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 @@ static egl_connection_t* validate_display_config( 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 @@ static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface) 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 eglGetDisplay(NativeDisplayType display) 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 @@ EGLDisplay eglGetDisplay(NativeDisplayType display) return dpy; } + +// ---------------------------------------------------------------------------- +}; // namespace android +// ---------------------------------------------------------------------------- + +using namespace android; + +EGLDisplay eglGetDisplay(NativeDisplayType display) +{ + return egl_init_displays(display); +} + // ---------------------------------------------------------------------------- // Initialization // ---------------------------------------------------------------------------- @@ -594,7 +625,7 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) // 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 eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) } 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 @@ EGLBoolean eglTerminate(EGLDisplay dpy) 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 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy, 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 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, 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 @@ EGLBoolean eglWaitNative(EGLint engine) 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 @@ EGLint eglGetError(void) 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 @@ void (*eglGetProcAddress(const char *procname))() 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 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) 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 @@ EGLBoolean eglBindAPI(EGLenum api) { // 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 @@ EGLBoolean eglBindAPI(EGLenum api) 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 @@ EGLenum eglQueryAPI(void) 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 @@ void glVertexPointerBounds(GLint size, GLenum type, // 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 @@ void glVertexPointerBounds(GLint size, GLenum type, #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,606 +1,435 @@ -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(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + CALL_GL_API(glClearColor, red, green, blue, alpha); +} +void API_ENTRY(glClearDepthf)(GLclampf depth) { + CALL_GL_API(glClearDepthf, depth); +} +void API_ENTRY(glClipPlanef)(GLenum plane, const GLfloat *equation) { + CALL_GL_API(glClipPlanef, 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(glDepthRangef)(GLclampf zNear, GLclampf zFar) { + CALL_GL_API(glDepthRangef, zNear, zFar); +} +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(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(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(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(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(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 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(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(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) { +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) { +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(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); } - -void API_ENTRY(glLightModelf)(GLenum pname, GLfloat param) { - CALL_GL_API(glLightModelf, pname, param); +GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) { + CALL_GL_API_RETURN(glIsBuffer, buffer); } - -void API_ENTRY(glLightModelfv)(GLenum pname, const GLfloat *params) { - CALL_GL_API(glLightModelfv, pname, params); +GLboolean API_ENTRY(glIsEnabled)(GLenum cap) { + CALL_GL_API_RETURN(glIsEnabled, cap); +} +GLboolean API_ENTRY(glIsTexture)(GLuint texture) { + CALL_GL_API_RETURN(glIsTexture, texture); } - 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) { +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(glPointParameterx)(GLenum pname, GLfixed param) { + CALL_GL_API(glPointParameterx, pname, param); +} +void API_ENTRY(glPointParameterxv)(GLenum pname, const GLfixed *params) { + CALL_GL_API(glPointParameterxv, pname, params); } - 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) { +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) { +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(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(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(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(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(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(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) { + CALL_GL_API(glTexParameteriv, target, pname, params); } - -void API_ENTRY(glTranslatef)(GLfloat x, GLfloat y, GLfloat z) { - CALL_GL_API(glTranslatef, x, y, z); +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) { +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(glBindBuffer)(GLenum target, GLuint buffer) { - CALL_GL_API(glBindBuffer, target, buffer); -} -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(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(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(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(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); -} -GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) { - CALL_GL_API_RETURN(glIsBuffer, buffer); -} -GLboolean API_ENTRY(glIsEnabled)(GLenum cap) { - CALL_GL_API_RETURN(glIsEnabled, cap); -} -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(glPointParameterfv)(GLenum pname, const GLfloat *params) { - CALL_GL_API(glPointParameterfv, pname, params); -} -void API_ENTRY(glPointParameterx)(GLenum pname, GLfixed param) { - CALL_GL_API(glPointParameterx, pname, param); -} -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(glTexEnvi)(GLenum target, GLenum pname, GLint param) { - CALL_GL_API(glTexEnvi, 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(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) { - CALL_GL_API(glTexParameteriv, target, pname, params); -} - -void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) { - CALL_GL_API(glTexParameteri, target, pname, param); -} -void API_ENTRY(glTexParameterxv)(GLenum target, GLenum pname, const GLfixed *params) { - CALL_GL_API(glTexParameterxv, target, pname, params); -} 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_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGL /* 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, glAlphaFunc, GLenum func, GLclampf ref) +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, glDepthRangex, GLclampx zNear, GLclampx 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, glPolygonOffsetx, GLfixed factor, GLfixed units) -GL_ENTRY(void, glLogicOp, GLenum opcode) +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, glAlphaFunc, GLenum func, GLclampf 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, glClearColor, GLclampf r, GLclampf g, GLclampf b, GLclampf a) -GL_ENTRY(void, glClearColorx, GLclampx r, GLclampx g, GLclampx b, GLclampx a) -GL_ENTRY(void, glClearDepthf, GLclampf depth) +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 @@ const unsigned int NUM_DISPLAYS = 1; 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 @@ enum { 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/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 5e079d4..2def877 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -93,10 +93,6 @@ public class LocationManagerService extends ILocationManager.Stub { // Max time to hold wake lock for, in milliseconds. private static final long MAX_TIME_FOR_WAKE_LOCK = 60 * 1000L; - // Time to wait after releasing a wake lock for clients to process location update, - // in milliseconds. - private static final long TIME_AFTER_WAKE_LOCK = 2 * 1000L; - // The last time a location was written, by provider name. private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>(); @@ -130,7 +126,6 @@ public class LocationManagerService extends ILocationManager.Stub { // Handler messages private static final int MESSAGE_LOCATION_CHANGED = 1; - private static final int MESSAGE_RELEASE_WAKE_LOCK = 2; // Alarm manager and wakelock variables private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT"; @@ -138,6 +133,7 @@ public class LocationManagerService extends ILocationManager.Stub { private AlarmManager mAlarmManager; private long mAlarmInterval = 0; private PowerManager.WakeLock mWakeLock = null; + private int mPendingBroadcasts; private long mWakeLockAcquireTime = 0; private boolean mWakeLockGpsReceived = true; private boolean mWakeLockNetworkReceived = true; @@ -159,7 +155,8 @@ public class LocationManagerService extends ILocationManager.Stub { new HashMap<String,ArrayList<UpdateRecord>>(); // Proximity listeners - private Receiver mProximityListener = null; + private Receiver mProximityReceiver = null; + private ILocationListener mProximityListener = null; private HashMap<PendingIntent,ProximityAlert> mProximityAlerts = new HashMap<PendingIntent,ProximityAlert>(); private HashSet<ProximityAlert> mProximitiesEntered = @@ -181,11 +178,12 @@ public class LocationManagerService extends ILocationManager.Stub { * A wrapper class holding either an ILocationListener or a PendingIntent to receive * location updates. */ - private final class Receiver implements IBinder.DeathRecipient { + private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished { final ILocationListener mListener; final PendingIntent mPendingIntent; final Object mKey; final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>(); + int mPendingBroadcasts; Receiver(ILocationListener listener) { mListener = listener; @@ -252,7 +250,16 @@ public class LocationManagerService extends ILocationManager.Stub { public boolean callStatusChangedLocked(String provider, int status, Bundle extras) { if (mListener != null) { try { - mListener.onStatusChanged(provider, status, extras); + synchronized (this) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + mListener.onStatusChanged(provider, status, extras); + if (mListener != mProximityListener) { + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } + } } catch (RemoteException e) { return false; } @@ -261,7 +268,14 @@ public class LocationManagerService extends ILocationManager.Stub { statusChanged.putExtras(extras); statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); try { - mPendingIntent.send(mContext, 0, statusChanged, null, null); + synchronized (this) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler); + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } } catch (PendingIntent.CanceledException e) { return false; } @@ -272,7 +286,16 @@ public class LocationManagerService extends ILocationManager.Stub { public boolean callLocationChangedLocked(Location location) { if (mListener != null) { try { - mListener.onLocationChanged(location); + synchronized (this) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + mListener.onLocationChanged(location); + if (mListener != mProximityListener) { + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } + } } catch (RemoteException e) { return false; } @@ -280,7 +303,53 @@ public class LocationManagerService extends ILocationManager.Stub { Intent locationChanged = new Intent(); locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); try { - mPendingIntent.send(mContext, 0, locationChanged, null, null); + synchronized (this) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler); + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } + } catch (PendingIntent.CanceledException e) { + return false; + } + } + return true; + } + + public boolean callProviderEnabledLocked(String provider, boolean enabled) { + if (mListener != null) { + try { + synchronized (this) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + if (enabled) { + mListener.onProviderEnabled(provider); + } else { + mListener.onProviderDisabled(provider); + } + if (mListener != mProximityListener) { + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } + } + } catch (RemoteException e) { + return false; + } + } else { + Intent providerIntent = new Intent(); + providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); + try { + synchronized (this) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler); + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } } catch (PendingIntent.CanceledException e) { return false; } @@ -295,6 +364,42 @@ public class LocationManagerService extends ILocationManager.Stub { synchronized (mLock) { removeUpdatesLocked(this); } + synchronized (this) { + if (mPendingBroadcasts > 0) { + LocationManagerService.this.decrementPendingBroadcasts(); + mPendingBroadcasts = 0; + } + } + } + + public void onSendFinished(PendingIntent pendingIntent, Intent intent, + int resultCode, String resultData, Bundle resultExtras) { + decrementPendingBroadcasts(); + } + + // this must be called while synchronized by callerin a synchronized block + // containing the sending of the broadcaset + private void incrementPendingBroadcastsLocked() { + if (mPendingBroadcasts++ == 0) { + synchronized (mLock) { + LocationManagerService.this.incrementPendingBroadcastsLocked(); + } + } + } + + private void decrementPendingBroadcasts() { + synchronized (this) { + if (--mPendingBroadcasts == 0) { + LocationManagerService.this.decrementPendingBroadcasts(); + } + } + } + } + + public void locationCallbackFinished(ILocationListener listener) { + Receiver receiver = getReceiver(listener); + if (receiver != null) { + receiver.decrementPendingBroadcasts(); } } @@ -722,29 +827,11 @@ public class LocationManagerService extends ILocationManager.Stub { for (int i=0; i<N; i++) { UpdateRecord record = records.get(i); // Sends a notification message to the receiver - try { - Receiver receiver = record.mReceiver; - if (receiver.isListener()) { - if (enabled) { - receiver.getListener().onProviderEnabled(provider); - } else { - receiver.getListener().onProviderDisabled(provider); - } - } else { - Intent providerIntent = new Intent(); - providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); - try { - receiver.getPendingIntent().send(mContext, 0, - providerIntent, null, null); - } catch (PendingIntent.CanceledException e) { - if (deadReceivers == null) { - deadReceivers = new ArrayList<Receiver>(); - deadReceivers.add(receiver); - } - } + if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) { + if (deadReceivers == null) { + deadReceivers = new ArrayList<Receiver>(); + deadReceivers.add(record.mReceiver); } - } catch (RemoteException e) { - // The death link will clean this up. } listeners++; } @@ -958,15 +1045,8 @@ public class LocationManagerService extends ILocationManager.Stub { impl.enableLocationTracking(true); updateWakelockStatusLocked(); } else { - try { - // Notify the listener that updates are currently disabled - if (receiver.isListener()) { - receiver.getListener().onProviderDisabled(provider); - } - } catch(RemoteException e) { - Log.w(TAG, "RemoteException calling onProviderDisabled on " + - receiver.getListener()); - } + // Notify the listener that updates are currently disabled + receiver.callProviderEnabledLocked(provider, false); } } finally { Binder.restoreCallingIdentity(identity); @@ -1161,7 +1241,7 @@ public class LocationManagerService extends ILocationManager.Stub { } // Listener for receiving locations to trigger proximity alerts - class ProximityListener extends ILocationListener.Stub { + class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished { boolean isGpsAvailable = false; @@ -1198,7 +1278,14 @@ public class LocationManagerService extends ILocationManager.Stub { Intent enteredIntent = new Intent(); enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true); try { - intent.send(mContext, 0, enteredIntent, null, null); + synchronized (mLock) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + intent.send(mContext, 0, enteredIntent, this, mLocationHandler); + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } } catch (PendingIntent.CanceledException e) { if (LOCAL_LOGV) { Log.v(TAG, "Canceled proximity alert: " + alert, e); @@ -1216,7 +1303,14 @@ public class LocationManagerService extends ILocationManager.Stub { Intent exitedIntent = new Intent(); exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false); try { - intent.send(mContext, 0, exitedIntent, null, null); + synchronized (mLock) { + // synchronize to ensure incrementPendingBroadcastsLocked() + // is called before decrementPendingBroadcasts() + intent.send(mContext, 0, exitedIntent, this, mLocationHandler); + // call this after broadcasting so we do not increment + // if we throw an exeption. + incrementPendingBroadcastsLocked(); + } } catch (PendingIntent.CanceledException e) { if (LOCAL_LOGV) { Log.v(TAG, "Canceled proximity alert: " + alert, e); @@ -1269,6 +1363,11 @@ public class LocationManagerService extends ILocationManager.Stub { isGpsAvailable = false; } } + + public void onSendFinished(PendingIntent pendingIntent, Intent intent, + int resultCode, String resultData, Bundle resultExtras) { + decrementPendingBroadcasts(); + } } public void addProximityAlert(double latitude, double longitude, @@ -1306,19 +1405,20 @@ public class LocationManagerService extends ILocationManager.Stub { latitude, longitude, radius, expiration, intent); mProximityAlerts.put(intent, alert); - if (mProximityListener == null) { - mProximityListener = new Receiver(new ProximityListener()); + if (mProximityReceiver == null) { + mProximityListener = new ProximityListener(); + mProximityReceiver = new Receiver(mProximityListener); LocationProvider provider = LocationProviderImpl.getProvider( LocationManager.GPS_PROVIDER); if (provider != null) { - requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener); + requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver); } provider = LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER); if (provider != null) { - requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener); + requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver); } } } @@ -1342,7 +1442,8 @@ public class LocationManagerService extends ILocationManager.Stub { mProximityAlerts.remove(intent); if (mProximityAlerts.size() == 0) { - removeUpdatesLocked(mProximityListener); + removeUpdatesLocked(mProximityReceiver); + mProximityReceiver = null; mProximityListener = null; } } @@ -1585,35 +1686,7 @@ public class LocationManagerService extends ILocationManager.Stub { } handleLocationChangedLocked(location); - - if ((mWakeLockAcquireTime != 0) && - (SystemClock.elapsedRealtime() - mWakeLockAcquireTime - > MAX_TIME_FOR_WAKE_LOCK)) { - - removeMessages(MESSAGE_RELEASE_WAKE_LOCK); - - log("LocationWorkerHandler: Exceeded max time for wake lock"); - Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK); - sendMessageAtFrontOfQueue(m); - - } else if (mWakeLockAcquireTime != 0 && - mWakeLockGpsReceived && mWakeLockNetworkReceived) { - - removeMessages(MESSAGE_RELEASE_WAKE_LOCK); - - log("LocationWorkerHandler: Locations received."); - mWakeLockAcquireTime = 0; - Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK); - sendMessageDelayed(m, TIME_AFTER_WAKE_LOCK); - } - } - } else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) { - log("LocationWorkerHandler: Release"); - - // Update wakelock status so the next alarm is set before releasing wakelock - synchronized (mLock) { updateWakelockStatusLocked(); - releaseWakeLockLocked(); } } } catch (Exception e) { @@ -1727,7 +1800,7 @@ public class LocationManagerService extends ILocationManager.Stub { long callerId = Binder.clearCallingIdentity(); - boolean needsLock = false; + boolean needsLock = (mPendingBroadcasts > 0); long minTime = Integer.MAX_VALUE; if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) { @@ -1757,8 +1830,6 @@ public class LocationManagerService extends ILocationManager.Stub { log("No need for alarm"); mAlarmInterval = -1; - // Clear out existing wakelocks - mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK); releaseWakeLockLocked(); } Binder.restoreCallingIdentity(callerId); @@ -1836,6 +1907,20 @@ public class LocationManagerService extends ILocationManager.Stub { } } + private void incrementPendingBroadcastsLocked() { + if (mPendingBroadcasts++ == 0) { + updateWakelockStatusLocked(); + } + } + + private void decrementPendingBroadcasts() { + synchronized (mLock) { + if (--mPendingBroadcasts == 0) { + updateWakelockStatusLocked(); + } + } + } + // Geocoder public String getFromLocation(double latitude, double longitude, int maxResults, @@ -2061,6 +2146,7 @@ public class LocationManagerService extends ILocationManager.Stub { i.dump(pw, " "); } } + pw.println(" mProximityReceiver=" + mProximityReceiver); pw.println(" mProximityListener=" + mProximityListener); if (mEnabledProviders.size() > 0) { pw.println(" Enabled Providers:"); diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java index 28a9968..7274e99 100644 --- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java @@ -98,7 +98,7 @@ public abstract class ServiceStateTracker extends Handler { protected static final int EVENT_RESET_PREFERRED_NETWORK_TYPE = 21; protected static final int EVENT_CHECK_REPORT_GPRS = 22; protected static final int EVENT_RESTRICTED_STATE_CHANGED = 23; - + //*****CDMA events: protected static final int EVENT_POLL_STATE_REGISTRATION_CDMA = 24; protected static final int EVENT_POLL_STATE_OPERATOR_CDMA = 25; @@ -112,9 +112,6 @@ public abstract class ServiceStateTracker extends Handler { protected static final int EVENT_SIGNAL_STRENGTH_UPDATE_CDMA = 33; protected static final int EVENT_NV_LOADED = 34; - // Event Log Tags - protected static final int EVENT_LOG_CGREG_FAIL = 50107; - //***** Time Zones protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; diff --git a/tests/AndroidTests/res/values-port/configVarying.xml b/tests/AndroidTests/res/values-32dpi/configVarying.xml index 0e1f247..f903f0f 100644 --- a/tests/AndroidTests/res/values-port/configVarying.xml +++ b/tests/AndroidTests/res/values-32dpi/configVarying.xml @@ -15,8 +15,8 @@ --> <resources> - <item type="configVarying" name="simple">simple portrait</item> + <item type="configVarying" name="simple">simple 32dpi</item> <bag type="configVarying" name="bag"> - <item name="testString">bag portrait</item> + <item name="testString">bag 32dpi</item> </bag> </resources> diff --git a/tests/AndroidTests/res/values-320x200/configVarying.xml b/tests/AndroidTests/res/values-640x400/configVarying.xml index ca2a286..30332c0 100644 --- a/tests/AndroidTests/res/values-320x200/configVarying.xml +++ b/tests/AndroidTests/res/values-640x400/configVarying.xml @@ -15,8 +15,8 @@ --> <resources> - <item type="configVarying" name="simple">simple 320x200</item> + <item type="configVarying" name="simple">simple 640x400</item> <bag type="configVarying" name="bag"> - <item name="testString">bag 320x200</item> + <item name="testString">bag 640x400</item> </bag> </resources> diff --git a/tests/AndroidTests/res/values-fr-rFR/configVarying.xml b/tests/AndroidTests/res/values-fr-rFR/configVarying.xml new file mode 100644 index 0000000..5ecac7c --- /dev/null +++ b/tests/AndroidTests/res/values-fr-rFR/configVarying.xml @@ -0,0 +1,22 @@ +<?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 fr FR</item> + <bag type="configVarying" name="bag"> + <item name="testString">bag fr FR</item> + </bag> +</resources> diff --git a/tests/AndroidTests/res/values-fr/configVarying.xml b/tests/AndroidTests/res/values-fr/configVarying.xml new file mode 100644 index 0000000..8413b5a --- /dev/null +++ b/tests/AndroidTests/res/values-fr/configVarying.xml @@ -0,0 +1,22 @@ +<?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 fr</item> + <bag type="configVarying" name="bag"> + <item name="testString">bag fr</item> + </bag> +</resources> diff --git a/tests/AndroidTests/res/values-trackball/configVarying.xml b/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-qwerty/configVarying.xml b/tests/AndroidTests/res/values-mcc112/configVarying.xml index 939f682..9c05d77 100644 --- a/tests/AndroidTests/res/values-qwerty/configVarying.xml +++ b/tests/AndroidTests/res/values-mcc112/configVarying.xml @@ -15,8 +15,8 @@ --> <resources> - <item type="configVarying" name="simple">simple qwerty</item> + <item type="configVarying" name="simple">simple mcc112</item> <bag type="configVarying" name="bag"> - <item name="testString">bag qwerty</item> + <item name="testString">bag mcc112</item> </bag> </resources> diff --git a/tests/AndroidTests/res/values-mnc220-xx/configVarying.xml b/tests/AndroidTests/res/values-mnc220-xx/configVarying.xml new file mode 100644 index 0000000..fbc7888 --- /dev/null +++ b/tests/AndroidTests/res/values-mnc220-xx/configVarying.xml @@ -0,0 +1,22 @@ +<?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 mnc220 xx</item> + <bag type="configVarying" name="bag"> + <item name="testString">bag mnc220 xx</item> + </bag> +</resources> diff --git a/tests/AndroidTests/res/values-keyshidden/configVarying.xml b/tests/AndroidTests/res/values-mnc222-32dpi/configVarying.xml index fdffc4d..03bea33 100644 --- a/tests/AndroidTests/res/values-keyshidden/configVarying.xml +++ b/tests/AndroidTests/res/values-mnc222-32dpi/configVarying.xml @@ -15,8 +15,8 @@ --> <resources> - <item type="configVarying" name="simple">simple keyshidden</item> + <item type="configVarying" name="simple">simple mnc222 32dpi</item> <bag type="configVarying" name="bag"> - <item name="testString">bag keyshidden</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 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/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.ISearchManager; 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 @@ import java.util.List; * -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 @@ public class SearchManagerTest extends ActivityInstrumentationTestCase<LocalActi * 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 @@ public class SearchManagerTest extends ActivityInstrumentationTestCase<LocalActi 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 @@ public class ConfigTest extends AndroidTestCase { 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 @@ public class ConfigTest extends AndroidTestCase { 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 @@ public class ConfigTest extends AndroidTestCase { */ 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,155 +225,160 @@ public class ConfigTest extends AndroidTestCase { 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"}); + 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); + config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); 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 stylus"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag stylus"}); config = new TotalConfig(); - config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); + config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_NOKEYS); 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 nokeys"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag nokeys"}); config = new TotalConfig(); - config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_NOKEYS); + config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); 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"}); + 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.KEYBOARD, Configuration.KEYBOARD_QWERTY); + config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); 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 keysexposed"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag keysexposed"}); config = new TotalConfig(); - config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); + config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_NONAV); 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"}); + 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.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_YES); + config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD); 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 dpad"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag dpad"}); config = new TotalConfig(); - config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); + config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_WHEEL); 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 wheel"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag wheel"}); config = new TotalConfig(); - config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_NONAV); + config.setProperty(properties.HEIGHT, 480); + config.setProperty(properties.WIDTH, 320); 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 480x320"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 480x320"}); config = new TotalConfig(); - config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD); + config.setProperty(properties.DENSITY, 240); 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"}); + 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.NAVIGATION, Configuration.NAVIGATION_TRACKBALL); + config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_LANDSCAPE); 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 landscape"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag landscape"}); config = new TotalConfig(); - config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_WHEEL); + config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); 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"}); + 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.HEIGHT, 320); - config.setProperty(properties.WIDTH, 200); + config.setProperty(properties.DENSITY, 32); 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 32dpi"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 32dpi"}); config = new TotalConfig(); - config.setProperty(properties.HEIGHT, 480); - config.setProperty(properties.WIDTH, 320); + config.setProperty(properties.DENSITY, 48); 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 32dpi"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 32dpi"}); config = new TotalConfig(); - config.setProperty(properties.DENSITY, 240); + config.setProperty(properties.DENSITY, 49); res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 240dpi"); + checkValue(res, R.configVarying.simple, "simple default"); checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 240dpi"}); + R.styleable.TestConfig, new String[]{"bag default"}); config = new TotalConfig(); - config.setProperty(properties.DENSITY, 120); + config.setProperty(properties.DENSITY, 150); 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"}); + 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.ORIENTATION, Configuration.ORIENTATION_LANDSCAPE); + config.setProperty(properties.DENSITY, 181); 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"}); + 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.ORIENTATION, Configuration.ORIENTATION_PORTRAIT); + config.setProperty(properties.DENSITY, 182); 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 240dpi"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag 240dpi"}); config = new TotalConfig(); - config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); + config.setProperty(properties.DENSITY, 239); 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 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 @@ public class ConfigTest extends AndroidTestCase { 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 @@ public class ConfigTest extends AndroidTestCase { * 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 @@ public class ConfigTest extends AndroidTestCase { 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 @@ public class ConfigTest extends AndroidTestCase { 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 32dpi stylus"); + checkValue(res, R.configVarying.simple, "simple square 32dpi"); checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 32dpi stylus"}); + 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); + 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.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(); -// 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"}); + checkValue(res, R.configVarying.simple, "simple stylus keysexposed"); + checkValue(res, R.configVarying.bag, + R.styleable.TestConfig, new String[]{"bag stylus keysexposed"}); config = new TotalConfig(); - 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); + 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 @@ public class AutoCompleteTextViewPopup // 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()); + } } |