复制代码 代码如下: public class Search extends LinearLayout implements OnClickListener, OnKeyListener, OnLongClickListener, OnItemClickListener { // Speed at which the widget slides up/down, in pixels/ms. private static final float ANIMATION_VELOCITY = 1.0f; /** The distance in dips between the optical top of the widget and the top if its bounds */ private static final float WIDGET_TOP_OFFSET = 9; private final String TAG = "SearchWidget"; private Launcher mLauncher; private EditText mSearchText; private ImageButton mVoiceButton; private ImageButton mClearButton; /** The animation that morphs the search widget to the search dialog. */ private Animation mMorphAnimation; /** The animation that morphs the search widget back to its normal position. */ private Animation mUnmorphAnimation; // These four are passed to Launcher.startSearch() when the search widget // has finished morphing. They are instance variables to make it possible to update // them while the widget is morphing. private String mInitialQuery; private boolean mSelectInitialQuery; private Bundle mAppSearchData; private boolean mGlobalSearch; ListView mSearchResultList=null; LinearLayout mSearchResult=null; // For voice searching private Intent mVoiceSearchIntent;
private int mWidgetTopOffset;
private int mAlpha = 0xff;//2011-01-12 add for draw alpha private ArrayList<Map<String, Object>> mData; private LockScreenAdapter mAdapter; private List<Info> dataList; private Context mContext; private static final String[] ALL_THREADS_PROJECTION = { Threads._ID, Threads.DATE, Threads.MESSAGE_COUNT, Threads.RECIPIENT_IDS, Threads.SNIPPET, Threads.SNIPPET_CHARSET, Threads.READ, Threads.ERROR, Threads.HAS_ATTACHMENT }; private static final Uri sAllThreadsUri = Threads.CONTENT_URI.buildUpon().appendQueryParameter("simple", "true").build();
/** * Used to inflate the Workspace from XML. * * @param context The application"s context. * @param attrs The attributes set containing the Workspace"s customization values. */ public Search(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; final float scale = context.getResources().getDisplayMetrics().density; mWidgetTopOffset = Math.round(WIDGET_TOP_OFFSET * scale);
Interpolator interpolator = new AccelerateDecelerateInterpolator(); mMorphAnimation = new ToParentOriginAnimation(); // no need to apply transformation before the animation starts, // since the gadget is already in its normal place. mMorphAnimation.setFillBefore(false); // stay in the top position after the animation finishes mMorphAnimation.setFillAfter(true); mMorphAnimation.setInterpolator(interpolator); mMorphAnimation.setAnimationListener(new Animation.AnimationListener() { // The amount of time before the animation ends to show the search dialog. private static final long TIME_BEFORE_ANIMATION_END = 80;
// The runnable which we"ll pass to our handler to show the search dialog. private final Runnable mShowSearchDialogRunnable = new Runnable() { public void run() { showSearchDialog(); } };
public void onAnimationEnd(Animation animation) { } public void onAnimationRepeat(Animation animation) { } public void onAnimationStart(Animation animation) { // Make the search dialog show up ideally *just* as the animation reaches // the top, to aid the illusion that the widget becomes the search dialog. // Otherwise, there is a short delay when the widget reaches the top before // the search dialog shows. We do this roughly 80ms before the animation ends. getHandler().postDelayed( mShowSearchDialogRunnable, Math.max(mMorphAnimation.getDuration() - TIME_BEFORE_ANIMATION_END, 0)); } }); mUnmorphAnimation = new FromParentOriginAnimation(); // stay in the top position until the animation starts mUnmorphAnimation.setFillBefore(true); // no need to apply transformation after the animation finishes, // since the gadget is now back in its normal place. mUnmorphAnimation.setFillAfter(false); mUnmorphAnimation.setInterpolator(interpolator); mUnmorphAnimation.setAnimationListener(new Animation.AnimationListener(){ public void onAnimationEnd(Animation animation) { clearAnimation(); } public void onAnimationRepeat(Animation animation) { } public void onAnimationStart(Animation animation) { } });
mVoiceSearchIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH); mVoiceSearchIntent.putExtra(android.speech.RecognizerIntent.EXTRA_LANGUAGE_MODEL, android.speech.RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH); } /** * Implements OnClickListener. */ public void onVoiceClick(View v) { /*if (v == mVoiceButton) { startVoiceSearch(); } else { mLauncher.onSearchRequested(); }*/ } public void onClick(View v) {//sxyang modified. mSearchText.setText(""); mSearchResult.setVisibility(View.INVISIBLE); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { /** Log.w(TAG, "view="+view+"position="+position+"id="+id);
Map map = (Map)mAdapter.getItem(position); Log.w(TAG, "onItemClick title="+map.get("title")+" intent="+map.get("intent")); Intent intent = (Intent) map.get("intent"); getContext().startActivity(intent); */ } private void startVoiceSearch() { try { getContext().startActivity(mVoiceSearchIntent); } catch (ActivityNotFoundException ex) { // Should not happen, since we check the availability of // voice search before showing the button. But just in case... Log.w(TAG, "Could not find voice search activity"); } } /** * Sets the query text. The query field is not editable, instead we forward * the key events to the launcher, which keeps track of the text, * calls setQuery() to show it, and gives it to the search dialog. */ public void setQuery(String query) { mSearchText.setText(query, TextView.BufferType.NORMAL); } /** * Morph the search gadget to the search dialog. * See {@link Activity#startSearch()} for the arguments. */ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData, boolean globalSearch) { mInitialQuery = initialQuery; mSelectInitialQuery = selectInitialQuery; mAppSearchData = appSearchData; mGlobalSearch = globalSearch;
showSearchDialog(); if (isAtTop()) { // showSearchDialog(); } else { // Call up the keyboard before we actually call the search dialog so that it // (hopefully) animates in at about the same time as the widget animation, and // so that it becomes available as soon as possible. Only do this if a hard // keyboard is not currently available. if (getContext().getResources().getConfiguration().hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { InputMethodManager inputManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); // inputManager.showSoftInputUnchecked(0, null); }
// Start the animation, unless it has already started. // if (getAnimation() != mMorphAnimation) { // mMorphAnimation.setDuration(getAnimationDuration()); // startAnimation(mMorphAnimation); // } } } /** * Shows the system search dialog immediately, without any animation. */ private void showSearchDialog() { Log.d(TAG, "showSearchDialog getText="+mSearchText.getText());
/*mLauncher.showSearchDialog( mInitialQuery, mSelectInitialQuery, mAppSearchData, mGlobalSearch);*/ } /** * Restore the search gadget to its normal position. * * @param animate Whether to animate the movement of the gadget. */ public void stopSearch(boolean animate) { setQuery("");
// Only restore if we are not already restored. if (getAnimation() == mMorphAnimation) { if (animate && !isAtTop()) { mUnmorphAnimation.setDuration(getAnimationDuration()); startAnimation(mUnmorphAnimation); } else { clearAnimation(); } } } private boolean isAtTop() { return getWidgetTop() == 0; } private int getAnimationDuration() { return (int) (getWidgetTop() / ANIMATION_VELOCITY); } /** * Modify clearAnimation() to invalidate the parent. This works around * an issue where the region where the end of the animation placed the view * was not redrawn after clearing the animation. */ @Override public void clearAnimation() { Animation animation = getAnimation(); if (animation != null) { super.clearAnimation(); if (animation.hasEnded() && animation.getFillAfter() && animation.willChangeBounds()) { ((View) getParent()).invalidate(); } else { invalidate(); } } }
public boolean onKey(View v, int keyCode, KeyEvent event) { 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)) { // Forward key events to Launcher, which will forward text // to search dialog switch (event.getAction()) { case KeyEvent.ACTION_DOWN: return mLauncher.onKeyDown(keyCode, event); case KeyEvent.ACTION_MULTIPLE: return mLauncher.onKeyMultiple(keyCode, event.getRepeatCount(), event); case KeyEvent.ACTION_UP: return mLauncher.onKeyUp(keyCode, event); } } return false; } /** * Implements OnLongClickListener to pass long clicks on child views * to the widget. This makes it possible to pick up the widget by long * clicking on the text field or a button. */ public boolean onLongClick(View v) { return performLongClick(); } @Override protected void onFinishInflate() { super.onFinishInflate(); mSearchText = (EditText) findViewById(R.id.search_src_text); /**Begin: add by liuzepeng **/ if(android.provider.Settings.System.getInt(mContext.getContentResolver(),android.provider.Settings.System.ISIPHONE,0) == 1) { mSearchText.setHint(R.string.search_hint_iphone); } /**End: add by liuzepeng **/ mVoiceButton = (ImageButton) findViewById(R.id.search_voice_btn);//sxyang modified. mClearButton = (ImageButton) findViewById(R.id.search_clear_btn);//sxyang modified.
mSearchText.setOnKeyListener(this); //mSearchText.setOnClickListener(this); mVoiceButton.setOnClickListener(this); mClearButton.setOnClickListener(this);//modified by liuzepeng
configureVoiceSearchButton(); configureClearSearchButton(); mSearchResultList.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(mSearchResultList.getWindowToken(), 0); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {} }); if(cachedNumbers == null) cachedNumbers = new HashMap<Long, String>(); dataList = new ArrayList<Info>(); mAdapter = new LockScreenAdapter(getContext(), dataList); mSearchResultList.setAdapter(mAdapter); mSearchText.addTextChangedListener(new TextWatcher(){ public void afterTextChanged(Editable s) {} public void beforeTextChanged(CharSequence s, int start, int count,int after) {} public void onTextChanged(CharSequence s, int start, int before,int count) {
}}); } private static Uri sAllCanonical = Uri.parse("content://mms-sms/canonical-addresses"); private static final int QUERY_FILTERED_SMS_TOKEN = 1000; private static final int QUERY_THREAD_ID_TOKEN = 1001; private static final int QUERY_FILTERED_CONTACTS_TOKEN = 1002; private static final int QUERY_FAVORITES_TOKEN = 1003; private static final int QUERY_PANEL_TOKEN = 1004;
private static final int CONTACTS_ID_INDEX = 0; private static final int CONTACTS_LOOKUP_KEY_INDEX = 1; private static final int CONTACTS_DISPLAY_NAME_INDEX = 2;
private static final int THREAD_ID_INDEX = 0; private static final int RECIPIENT_IDS_INDEX = 3; private static final int SNIPPET_INDEX = 4; private static final int TYPE_MMS = 100; private static final int TYPE_CONTACTS = 101; private static final int TYPE_FAVORITES = 102; private static final int TYPE_PANEL = 103; private static final int TYPE_WEB = 104;
private SearchQueryHandler mQueryHandler; private Map<Long, String> cachedNumbers; private String[] CONTACTS_FILTER_PROJECTION = new String[] { Contacts._ID, // 0 Contacts.LOOKUP_KEY, // 1 Contacts.DISPLAY_NAME, // 2 }; /** * the query order is:favorites->panel->mms->contacts. At last, add web search * cancel all querying process and start a new */ public void startQuery(AsyncQueryHandler handler, String filter) { handler.cancelOperation(QUERY_FAVORITES_TOKEN); handler.cancelOperation(QUERY_PANEL_TOKEN); handler.cancelOperation(QUERY_THREAD_ID_TOKEN); handler.cancelOperation(QUERY_FILTERED_SMS_TOKEN); handler.cancelOperation(QUERY_FILTERED_CONTACTS_TOKEN); startQueryFavorites(mQueryHandler, QUERY_FAVORITES_TOKEN, " title like "%"+filter+"%"", null , filter);//query favorites } public void startQueryFavorites(AsyncQueryHandler handler, int token,String selection,String[] selectionArgs, String filter) { //handler.cancelOperation(token); handler.startQuery(token, filter, LauncherSettings.Favorites.CONTENT_URI, null, selection, selectionArgs, null); } public void startQueryPanel(AsyncQueryHandler handler, int token,String selection,String[] selectionArgs, String filter) { //handler.cancelOperation(token); handler.startQuery(token, filter, LauncherSettings.Panel.CONTENT_URI, null, selection, selectionArgs, null); } public void startQueryThreadIdFromMms(AsyncQueryHandler handler, int token,String selection,String[] selectionArgs, String filter) { //handler.cancelOperation(token); handler.startQuery(token, filter, Threads.CONTENT_URI, new String[]{Conversations.THREAD_ID}, selection, selectionArgs, Conversations.IPHONE_DEFAULT_SORT_ORDER); }
private Info mFootInfo = null; private void addWebSearch(String filter) { /**Begin: add by liuzepeng **/ String editText = mSearchText.getText().toString().trim(); //Log.v("liuzepeng","filter:"+filter+"/mSearchText.getText():"+mSearchText.getText()); if(!editText.equals(filter)) { filter = editText; if(filter.equals("")) { mSearchResult.setVisibility(View.INVISIBLE); return; } } /**Begin: add by liuzepeng **/ List<ItemInfo> itemInfoList = new ArrayList<ItemInfo>(); ItemInfo itemInfo = new ItemInfo();
Drawable icon = getAppIcon("com.android.browser"); Uri uri = Uri.parse("http://m.baidu.com/s?ie=utf-8&word="+filter); Resources re = getContext().getResources(); String title = re.getString(R.string.web_search); Intent intent = new Intent(Intent.ACTION_VIEW,uri);
@Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); } /** * If appropriate & available, configure voice search * * Note: Because the home screen search widget is always web search, we only check for * getVoiceSearchLaunchWebSearch() modes. We don"t support the alternate form of app-specific * voice search. */ private void configureVoiceSearchButton() { // Enable the voice search button if there is an activity that can handle it PackageManager pm = getContext().getPackageManager(); ResolveInfo ri = pm.resolveActivity(mVoiceSearchIntent, PackageManager.MATCH_DEFAULT_ONLY); boolean voiceSearchVisible = ri != null; // finally, set visible state of voice search button, as appropriate mVoiceButton.setVisibility(voiceSearchVisible ? View.VISIBLE : View.GONE); } private void configureClearSearchButton() { //sxyang modified. mSearchText.addTextChangedListener(new TextWatcher(){ public void afterTextChanged(Editable s) {} public void beforeTextChanged(CharSequence s, int start, int count,int after) {} public void onTextChanged(CharSequence s, int start, int before,int count) { if (s == null || s.toString().equals("")) { mClearButton.setVisibility(View.INVISIBLE); } else { mClearButton.setVisibility(View.VISIBLE); } }}); } /** * Sets the {@link Launcher} that this gadget will call on to display the search dialog. */ public void setLauncher(Launcher launcher) { mLauncher = launcher; }
/** * Moves the view to the top left corner of its parent. */ private class ToParentOriginAnimation extends Animation { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { float dx = -getLeft() * interpolatedTime; float dy = -getWidgetTop() * interpolatedTime; t.getMatrix().setTranslate(dx, dy); } } /** * Moves the view from the top left corner of its parent. */ private class FromParentOriginAnimation extends Animation { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { float dx = -getLeft() * (1.0f - interpolatedTime); float dy = -getWidgetTop() * (1.0f - interpolatedTime); t.getMatrix().setTranslate(dx, dy); } }
/** * The widget is centered vertically within it"s 4x1 slot. This is * accomplished by nesting the actual widget inside another view. For * animation purposes, we care about the top of the actual widget rather * than it"s container. This method return the top of the actual widget. */ private int getWidgetTop() { return getTop() + getChildAt(0).getTop() + mWidgetTopOffset; }