龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 移动开发 > Android开发 >

仿Iphone中搜索结果的布局详解

时间:2014-06-15 15:00来源:网络整理 作者:网络 点击:
分享到:
本篇文章是对仿Iphone中搜索结果的布局进行了详细的分析介绍,需要的朋友参考下
代码如下:

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    

        mSearchText.setOnLongClickListener(this);
        mVoiceButton.setOnLongClickListener(this);

  mSearchResultList = (ListView)findViewById(R.id.SearchResultView);
  mSearchResult = (LinearLayout)findViewById(R.id.search_result);
  mSearchResult.setVisibility(View.GONE);
/**
  mData = new  ArrayList<Map<String, Object>>();
  mAdapter = new SimpleAdapter(getContext(),
             mData,
             R.layout.searchitem,
             new String[]{"icon","title"},
             new int[]{R.id.searchappicon,R.id.searchapptitle}
            );
*/

     
/**
  mAdapter.setViewBinder(new ViewBinder(){
                  @Override
       public boolean setViewValue(View view ,Object data,String textRepresentation){
                          if(view instanceof ImageView && data instanceof Drawable){
                                ImageView iv=(ImageView)view;
     iv.setImageDrawable((Drawable)data);
     return true;
    }
    return false;
       }
    });
*/

 
        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) {

               dataList.clear();

   if (s == null  || s.toString().equals("")|| mSearchText.getText().toString().trim() == null) {
    mSearchResult.setVisibility(View.INVISIBLE);
    return;
   }  
   if(mQueryHandler == null)
    mQueryHandler = new SearchQueryHandler(mLauncher.getContentResolver());
                     String filter = s.toString().replace("'",".");
   startQuery(mQueryHandler, filter);

  }});
    }
 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);
    }

    public void startQueryFilteredContentFromMms(AsyncQueryHandler handler, int token,String selection,String[] selectionArgs, String filter) {
     //handler.cancelOperation(token);
       handler.startQuery(token, filter, sAllThreadsUri,
                ALL_THREADS_PROJECTION, selection, selectionArgs, Conversations.IPHONE_DEFAULT_SORT_ORDER);
    }
    public void startQueryFromContacts(AsyncQueryHandler handler, int token, String[] projection, String selection,String[] selectionArgs, String filter) {
        handler.cancelOperation(token);
        handler.startQuery(token, filter, Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI, filter),
                projection, selection, selectionArgs, "sort_key");
    }

    private final class SearchQueryHandler extends AsyncQueryHandler {
  Drawable mmsIcon = null, contactsIcon = null;
        public SearchQueryHandler(ContentResolver contentResolver) {
            super(contentResolver);
      if(mmsIcon == null)
    mmsIcon = getAppIcon("com.android.mms");
      if(contactsIcon == null)
    contactsIcon = getAppIcon("com.android.contacts");
        }
        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
         //if(cursor == null) return;
         //dataList.clear();
            switch (token) {
             case QUERY_FILTERED_SMS_TOKEN:
   List<ItemInfo> itemInfoList = new ArrayList<ItemInfo>();
   while(cursor.moveToNext()) {
    long threadId = cursor.getLong(THREAD_ID_INDEX);
    String snippet = cursor.getString(SNIPPET_INDEX);
    String recipientIds = cursor.getString(RECIPIENT_IDS_INDEX);

    String numbers = getAddresses(recipientIds);
    if(!TextUtils.isEmpty(snippet) && !TextUtils.isEmpty(numbers)) {
     ItemInfo itemInfo = new ItemInfo();
     String title = numbers;
     Intent intent = new Intent();
     intent.setData(ContentUris.withAppendedId(Threads.CONTENT_URI, threadId));
     intent.setAction("android.intent.action.VIEW");
     intent.addCategory("android.intent.category.DEFAULT");
     intent.putExtra("from", numbers);
     //intent.putExtra("inner", true);//deleted by sunjinbiao on 20120814 for bug[548]
     if (title!= null ) {
      mSearchResult.setVisibility(View.VISIBLE);
      itemInfo.title = title;
      itemInfo.intent = intent;
     }
     itemInfoList.add(itemInfo);
    }
   }
   //System.out.println("itemInfoList.size()="+itemInfoList.size());
   if(itemInfoList.size()>0) {
    Info info = new Info();
    info.type = TYPE_MMS;
    info.data = itemInfoList;
    synchronized (dataList) {
     dataList.add(info);
    }
   }
   mAdapter.notifyDataSetChanged();
   String filter = (String)cookie;
   if(isDigits(filter) && filter.length() > 3) {
    startQueryFromContacts(mQueryHandler, QUERY_FILTERED_CONTACTS_TOKEN, CONTACTS_FILTER_PROJECTION, null, null, filter);//query contacts
   } else if(!isDigits(filter)) {
    startQueryFromContacts(mQueryHandler, QUERY_FILTERED_CONTACTS_TOKEN, CONTACTS_FILTER_PROJECTION, null, null, filter);//query contacts
   }
              break;
             case QUERY_THREAD_ID_TOKEN:
              String id = null;
              while(cursor.moveToNext()) {
               if (id == null)
                id = " _id = " + cursor.getLong(0);
               else
                id += " or _id = " + cursor.getLong(0);
              }
              if (id == null)
               id = " _id = -1";
               startQueryFilteredContentFromMms(mQueryHandler, QUERY_FILTERED_SMS_TOKEN,id, null, (String)cookie);
             break;
             case QUERY_FILTERED_CONTACTS_TOKEN:
   itemInfoList = new ArrayList<ItemInfo>();
   if(cursor == null)   break;              
   while(cursor.moveToNext()) {
    long contactId = cursor.getLong(CONTACTS_ID_INDEX);
    String lookupKey = cursor.getString(CONTACTS_LOOKUP_KEY_INDEX);
    String name = cursor.getString(CONTACTS_DISPLAY_NAME_INDEX);
    Uri lookupUri = Contacts.getLookupUri(contactId, lookupKey);
    ItemInfo itemInfo = new ItemInfo();
    String title = name;
    Intent intent = intent = new Intent(Intent.ACTION_VIEW, lookupUri);
    if (title!= null ) {
     mSearchResult.setVisibility(View.VISIBLE);
     itemInfo.title = title;
     itemInfo.intent = intent;
     itemInfoList.add(itemInfo);
    }
   }
   if(itemInfoList.size()>0) {
    Info info = new Info();
    info.type = TYPE_CONTACTS;
    info.data = itemInfoList;
    synchronized (dataList) {
     dataList.add(info);
    }
   }
   addWebSearch((String)cookie);
             break;
             case QUERY_FAVORITES_TOKEN:
   int titleIndex = cursor.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
   int iconIndex = cursor.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
   int intentIndex = cursor.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
   Intent intent=null;
   PackageManager manager = getContext().getPackageManager();
   Drawable  icon=null;
   while (cursor.moveToNext()) {
    itemInfoList = new ArrayList<ItemInfo>();
    ItemInfo itemInfo = new ItemInfo();
                      final  String title = cursor.getString(titleIndex);
    final  String intentDescription = cursor.getString(intentIndex);

    if(intentDescription == null)
     continue;
    try {
                             intent = Intent.parseUri(intentDescription, 0);
                            } catch (java.net.URISyntaxException e) {

                            }
    icon = getApplicationsIcons(manager, getContext(), intent);

    if (title!= null ) {
     mSearchResult.setVisibility(View.VISIBLE);
     itemInfo.title = title;
     itemInfo.intent = intent;
     itemInfo.icon = icon;
     itemInfoList.add(itemInfo);
    }
    if(itemInfoList.size()>0) {
     Info info = new Info();
     info.type = TYPE_FAVORITES;
     info.data = itemInfoList;
     synchronized (dataList) {
      dataList.add(info);
      mAdapter.notifyDataSetChanged();
     }
    }
   }
   mAdapter.notifyDataSetChanged();
   startQueryPanel(mQueryHandler, QUERY_PANEL_TOKEN, " title like '%"+((String)cookie)+"%'", null , (String)cookie);//query panel
             break;
             case QUERY_PANEL_TOKEN:
   titleIndex = cursor.getColumnIndexOrThrow(LauncherSettings.Panel.TITLE);
   iconIndex = cursor.getColumnIndexOrThrow(LauncherSettings.Panel.ICON);
   intentIndex = cursor.getColumnIndexOrThrow(LauncherSettings.Panel.INTENT);
   intent=null;
   manager = getContext().getPackageManager();
   icon=null;
   while (cursor.moveToNext()) {
    itemInfoList = new ArrayList<ItemInfo>();
    ItemInfo itemInfo = new ItemInfo();
    final  String title = cursor.getString(titleIndex);
    final  String intentDescription = cursor.getString(intentIndex);

    if(intentDescription == null)
     continue;
    try {
                             intent = Intent.parseUri(intentDescription, 0);
                            } catch (java.net.URISyntaxException e) {
                             //intent = null;
                            }
    icon = getApplicationsIcons(manager, getContext(), intent);
    if (title!= null ) {
     mSearchResult.setVisibility(View.VISIBLE);
     itemInfo.title = title;
     itemInfo.intent = intent;
     itemInfo.icon = icon;
     itemInfoList.add(itemInfo);
    }
    if(itemInfoList.size()>0) {
     Info info = new Info();
     info.type = TYPE_PANEL;
     info.data = itemInfoList;
     synchronized (dataList) {
      dataList.add(info);
      mAdapter.notifyDataSetChanged();
     }
    }
   }
   mAdapter.notifyDataSetChanged();
   startQueryThreadIdFromMms(mQueryHandler, QUERY_THREAD_ID_TOKEN," body like '%"+((String)cookie)+"%'", null, ((String)cookie));//query mms
             break;
             default:
               Log.e(TAG, "onQueryComplete called with unknown token " + token);
            }
            cursor.close();
        }
        @Override
        protected void onDeleteComplete(int token, Object cookie, int result) {}
    }

 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);

  if (title!= null ) {
   mSearchResult.setVisibility(View.VISIBLE);
   itemInfo.title = title;
   itemInfo.intent = intent;
   itemInfo.icon = icon;
   itemInfoList.add(itemInfo);
  }
  if(mFootInfo == null){
   mFootInfo = new Info();
   mFootInfo.type = TYPE_WEB;
  }
  mFootInfo.data = itemInfoList;
  /**Begin: modified by liuzepeng **/
  if(!dataList.contains(mFootInfo)) {
   dataList.add(mFootInfo);
  } else {
   dataList.remove(mFootInfo);
   dataList.add(mFootInfo);
  }
  /**Begin: modified by liuzepeng **/
  mAdapter.notifyDataSetChanged();
    }
    private Drawable getAppIcon(String packageName) {
  List<PackageInfo> packages = getContext().getPackageManager().getInstalledPackages(0);
  Drawable appIcon = null;
  for (int i = 0; i < packages.size(); i++) {
   PackageInfo packageInfo = packages.get(i);
   if(packageInfo.packageName.equals(packageName)) {
    appIcon = packageInfo.applicationInfo.loadIcon(getContext().getPackageManager());
    break;
   }
  }
  return appIcon;
    }

    public String getAddresses(String spaceSepIds) {
  String numbers = "";
        synchronized (cachedNumbers) {
            String[] ids = spaceSepIds.split(" ");
            for (String id : ids) {
                long longId;
                try {
                    longId = Long.parseLong(id);
                } catch (NumberFormatException ex) {
                    // skip this id
                    continue;
                }
                String number = cachedNumbers.get(longId);
                if (number == null) {
                    getNumbers();
                    number = cachedNumbers.get(longId);
                }
                if (TextUtils.isEmpty(number)) {
                    Log.w(TAG, "RecipientId " + longId + " has empty number!");
                } else {
                    numbers += number;
                }
            }
            return numbers;
        }
    }

    public void getNumbers() {
  final ContentResolver contentResolver = mLauncher.getContentResolver();
  Cursor c = contentResolver.query(sAllCanonical, null, null, null, null);
        if (c == null) {
            Log.w(TAG, "null Cursor in fill()");
            return;
        }
        try {
            synchronized (cachedNumbers) {
                // Technically we don't have to clear this because the stupid
                // canonical_addresses table is never GC'ed.
                cachedNumbers.clear();
                while (c.moveToNext()) {
                    // TODO: don't hardcode the column indices
                    long id = c.getLong(0);
                    String number = c.getString(1);
                    cachedNumbers.put(id, number);
                }
            }
        } finally {
            c.close();
        }
    }
 private boolean isDigits(String str) {
  if(str == null || "".equals(str))
   return false;
  int len = str.length();
  for(int i=0;i<len;i++) {
   char c = str.charAt(i);
   if(!Character.isDigit(c))
    return false;
  }
  return true;
 }
 private class Info {
  public int type;
  public List<ItemInfo> data;
  public String toString() {
   return "type="+type;
  }
 }
 private class ItemInfo {
  public Drawable icon;
  public String title;
  public Intent intent;
  public String toString() {
   return "title="+title;
  }
 }
 class LockScreenAdapter extends BaseAdapter {
  private Context context;
  List<Info> data;
  LayoutInflater inflater;
  Drawable mmsIcon = null, contactsIcon = null;
  public LockScreenAdapter(Context aContext,List<Info> aData) {
   context = aContext;
   inflater = LayoutInflater.from(context);
   data = aData;
   if(mmsIcon == null)
     mmsIcon = getAppIcon("com.android.mms");
   if(contactsIcon == null)
     contactsIcon = getAppIcon("com.android.contacts");
  }
  public int getCount() {
   return data.size();
  }
  public Object getItem(int position) {
   return data.get(position);
  }
  public long getItemId(int position) {
   return position;
  }
  public View getView(int position, View convertView, ViewGroup parent) {
   convertView = inflater.inflate(R.layout.item_launcher_search, null);

   if((position+1)%2 == 0 ){
    convertView.setBackgroundDrawable(getResources().getDrawable(R.drawable.result0));
   }else{
           convertView.setBackgroundDrawable(getResources().getDrawable(R.drawable.result1));
   }

   int wrapContent = LinearLayout.LayoutParams.WRAP_CONTENT;
   int fillParent = LinearLayout.LayoutParams.FILL_PARENT;
   LinearLayout.LayoutParams contentsllp = new LinearLayout.LayoutParams(fillParent, wrapContent);
   LinearLayout contents = (LinearLayout) convertView.findViewById(R.id.contents);
   ImageView icon = (ImageView) convertView.findViewById(R.id.icon);

   Info info = data.get(position);
   int type = info.type;
   int size = info.data.size();
   for (int i = 0; i < size; i++) {
    ItemInfo itemInfo = info.data.get(i);
    contents.addView(createItemView(itemInfo), contentsllp);
    if(type == TYPE_MMS)
     icon.setBackgroundDrawable(mmsIcon);
    else if(type == TYPE_CONTACTS)
     icon.setBackgroundDrawable(contactsIcon);
    else
     icon.setBackgroundDrawable(itemInfo.icon);
    if(size>1 && i!=size -1){
    TextView hLine = new TextView(getContext());

    LinearLayout.LayoutParams hLinellp = new LinearLayout.LayoutParams(fillParent, wrapContent);
    hLinellp.height = 1;
    hLine.setBackgroundColor(Color.argb(255, 157, 157, 160));
    contents.addView(hLine, hLinellp);
    TextView bLine = new TextView(getContext());
    bLine.setBackgroundColor(Color.argb(255, 255, 255, 255));
    contents.addView(bLine, hLinellp);
     }
   }
   return convertView;
  }
 }
 LinearLayout createItemView(final ItemInfo itemInfo) {
  final Context cxt = getContext();
  LinearLayout contentLayout = new LinearLayout(cxt);
  TextView seperatorLine = new TextView(cxt);
  TextView content = new TextView(cxt);

  int wrapContent = LinearLayout.LayoutParams.WRAP_CONTENT;
  int fillParent = LinearLayout.LayoutParams.FILL_PARENT;
  LinearLayout.LayoutParams seperatorLinellp = new LinearLayout.LayoutParams(wrapContent, 45);
  seperatorLinellp.rightMargin = 50;
  seperatorLinellp.height = 70;
  LinearLayout.LayoutParams contentllp = new LinearLayout.LayoutParams(fillParent, 45);
  contentllp.gravity=Gravity.CENTER_VERTICAL;
  contentllp.leftMargin = 5;

  seperatorLine.setBackgroundResource(R.drawable.launcher_item_vertical_line);
  content.setText(itemInfo.title);
  content.setTextColor(Color.BLACK);
  content.setGravity(Gravity.CENTER_VERTICAL);

  contentLayout.setOrientation(LinearLayout.HORIZONTAL);

  contentLayout.addView(seperatorLine, seperatorLinellp);
  contentLayout.addView(content, contentllp);
  contentLayout.setBackgroundResource(R.drawable.search_item_press);
  contentLayout.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    cxt.startActivity(itemInfo.intent);
   }
  });

  return contentLayout;
 }

 
    @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;
    }

    /*
     * //2011-01-12 add for draw alpha
     */
 public boolean setAlpha(int alpha) {
  if (mAlpha != alpha) {
   mAlpha = alpha;

   Drawable background = findViewById(R.id.search_plate).getBackground();
   //Drawable background = findViewById(R.id.search_plate).getBackground();
         if (background != null) {
          background.setAlpha(alpha);
         } else {
          Log.d(TAG, "background  null");
         }
   background = findViewById(R.id.search_src_text).getBackground();
         if (background != null) {
          if (background instanceof StateListDrawable) {
           StateListDrawable stateDrawable = (StateListDrawable)background;
           int stateCount = stateDrawable.getStateCount();
           for (int i = 0; i < stateCount; i++) {
            Drawable d = stateDrawable.getStateDrawable(i);
            d.setAlpha(alpha);
           }
          } else {
           background.setAlpha(alpha);
          }
         } else {
          Log.d(TAG, "background  null");
         }
         this.invalidate();
         return true;
  }
  return false;
 }
 /**
     * Morph the search gadget to the search dialog.
     * See {@link Activity#startSearch()} for the arguments.
     */
    public void showstartSearch() {
     //mSearchText.setText("", TextView.BufferType.NORMAL);
     //mSearchResult.setVisibility(View.GONE);
     if(mSearchResult.getVisibility() != View.VISIBLE) {
         mSearchText.requestFocus();
         Log.d(TAG, "showstartSearch");
         if (getContext().getResources().getConfiguration().hardKeyboardHidden ==
                 Configuration.HARDKEYBOARDHIDDEN_YES) {
             InputMethodManager inputManager = (InputMethodManager)
                     getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
             inputManager.showSoftInputUnchecked(0, null);
         }
     }

    }
  private Drawable getApplicationsIcons(PackageManager manager,Context context, Intent intent){
         Drawable icon=null;
         final ResolveInfo resolveInfo = manager.resolveActivity(intent, 0);
   if(resolveInfo == null) return null;
         final ActivityInfo activityInfo = resolveInfo.activityInfo;
         Drawable customerIcon = Utilities.getCustomerIcon(context, intent);
         if(customerIcon != null){
           icon = Utilities.createIconThumbnail(customerIcon, context);
         } else {
          icon = Utilities.createIconThumbnail(activityInfo.loadIcon(manager), context);
          }
     Bitmap bitmap = Utilities.createMiddleIcon(icon,context);
     BitmapDrawable  bd = new BitmapDrawable(bitmap);
         return bd;
 }
}
<com.hskj.hometest.Search
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher2"
    android:id="@+id/widget_search" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:gravity="top">
    <LinearLayout
        android:id="@+id/search_plate"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:paddingLeft="14dip"
        android:paddingRight="4dip"
        android:paddingTop="5dip"
        android:layout_marginLeft="10dip"
        android:layout_marginRight="10dip"        
        android:background="@drawable/textfield_searchwidget" >
        <EditText
            android:id="@+id/search_src_text"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1.0"
            android:textSize="15sp"
            android:paddingLeft="16dip"
            android:hint="@string/search_hint"
            android:singleLine="true"
            android:background="@android:color/transparent"
            android:textAppearance="?android:attr/textAppearanceMediumInverse"
            android:textColor="@android:color/primary_text_light"
        />

        <ImageButton
            android:id="@+id/search_clear_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="0dip"        
            android:background="@drawable/iphone_clean_icon" 
        />
        <ImageButton
            android:id="@+id/search_voice_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="4dip"
            android:background="@*android:drawable/btn_search_dialog_voice"
            android:src="@*android:drawable/ic_btn_speak_now"
        />

    </LinearLayout>
 <LinearLayout android:id="@+id/search_result"
        android:layout_weight="1"
        android:layout_height="0dip"
        android:layout_width="fill_parent"
        android:layout_marginTop="5dip"
               android:layout_marginLeft="10dip" 
               android:layout_marginRight="11dip"  
        android:background="@drawable/search_list_bg">
  <ListView android:layout_width="fill_parent"
                          android:id="@+id/SearchResultView"
                          android:scrollbars="vertical"
                          android:listSelector="@android:color/transparent"
                          android:cacheColorHint="#00000000"
                          android:divider="#CCCCCC"
                          android:dividerHeight="1px"
     android:layout_height="fill_parent"
     android:fadingEdge="none"  >
                </ListView>
 </LinearLayout>

</com.hskj.hometest.Search>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent" android:layout_height="fill_parent"
 android:orientation="horizontal">
 <ImageView android:id="@+id/icon" android:layout_width="30dip"
  android:layout_height="30dip"
  android:layout_margin="5dip" />
 <LinearLayout android:id="@+id/contents"
  android:layout_width="fill_parent" android:layout_height="fill_parent"
  android:orientation="vertical"
  android:layout_gravity="center_vertical"
  android:layout_toRightOf="@id/icon">
 </LinearLayout>
</RelativeLayout>
精彩图集

赞助商链接