欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-11-29 22:34:40
复制代码 代码如下:public class search extends linearlayout     implements oncli...
复制代码 代码如下:

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>