Android XMPP Service (Google Talk) + Google Map == Follow Me

本文介绍了一个基于Android平台的应用程序“FollowMe”,该程序利用Android的XMPP服务(Google Talk)和Google Map实现了对联系人位置的实时跟踪,并允许用户之间通过Google Talk进行通讯。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android XMPP Service (Google Talk) + Google Map == Follow Me

分類: Mobile
2007/11/27 10:22

我在 Android SDK 上寫了一個簡單的程式 (姑且把她叫 Follow Me),來測試 Android 的 XMPP Services (Google Talk) & Google Map 整合,我希望可以透過 Google Talk,來追蹤 Contact Lists 現在的位置及互相通訊。例如可以透過 FollowMe ,我就可以很順利的開車跟在領導車的朋友後面,因為 FollwMe 會在地圖上追蹤及顯示共同出遊的車子(包含領導車及自己)的位置,一路順暢的共同到達目的地。畫面如下圖,我 (soccercheng) 在追蹤 sting.cheng@gmail.com 的行蹤。



要寫這個程式,必須要對下圖中,Application Framework 的一些項目進行了解,如:

  • XMPP Service
  • Google Map
  • Notification Manager
  • Location Manager
  • Content Providers

 

 

如果只看 Android 提供的 Google APIs & Services 文件,很難看的懂他在寫甚麼,MapView 還好,XMPP 就不好懂,所以我把在測試 XMPP 的經驗和大家分享一下:

 

 

首先,我們必須讓 GPhone 的 XMPP 掛載上 Google Talk (This means U have to apply an Google Talk account),在 Dev Tools --> XMPP Settings (如上圖),用你的帳號讓登入 Google Talk。

接下來,介紹一下 Android XMPP Programming 的基本概念:

 

Listen to XMPP Notifications

 

(建議你先看一下 Anatomy of an Android Application,不然你會看不懂)

 XMPP Services 是透過 Notification 的方式,來發佈消息,所已入你的程式想知道 XMPP Services 的訊息,就必須掛載 IntentReceiver & IntentFilter,文件中並未記載 XMPP Services 到底發布了哪些 Notifications,相關的定義在 com.google.android.xmppService.XmppConstants 中,不過文件上並沒有這個 class 的說明,我是直接在 eclipse 看這個 XmppConstants 的說明,XmppConstants  最主要定義了三個:

  • XmppConstants.ACTION_XMPP_CONNECTION_STATE,當你程式 bind 到 XMPP Services 時,XMPP Service 會透過這個 Action 告知你現在的  state。
  • XmppConstants.ACTION_ROSTER_OR_PRESENCE_CHANGED,我測試的結果是當你的聯絡人在  Google Talk 上的狀態有變化時 (忙碌、線上、下線、...),XMPP Service 會透過這個 Action 告知你。
  • XmppConstants.ACTION_NEW_CHAT

 

另外,我有定義了兩個 Action,讓我的程式透過 XMPP Service ,來告知我是否有人跟我要我現在位置,會是跟我回報他的位置:

  • ACTION_REQUEST_LOCATION
  • ACTION_REPORT_LOCATION

 

註冊 &  掛載 IntentReceiver & IntentFilter

 

註冊方式基本上有兩種,一種是在 AndroidManifest.xml 中定義,或是寫程式向系統註冊,兩者最主要的差異是:

  • 如果你是在 AndroidManifest.xml 中定義,則你的 IntentReceiver 是由系統來 instantiate ,當系統呼叫完你的 IntentReceiver  的 onReceiveIntent(...) 之後,這個物件 IntentReceiver  Object 隨時可能被 Garbage Collector 收回。
  • 由程式註冊,比較有彈性,我可以在 Activity's  onStart() 註冊,onStop() 時取消註冊。

 

public class FollowMe extends MapActivity
                      implements View.OnClickListener   {

    ....

    /** Called when the activity is becoming visible to the user. */
    /* For example, you can register an IntentReceiver in onStart()
      * to monitor for changes that impact your UI, and unregister it in onStop()
      * when the user an no longer see what you are displaying.
      * The onStart() and onStop() methods can be called multiple times,
      * as the activity becomes visible and hidden to the user.
      */
    @Override
    protected void onStart()    {
        super.onStart();
     
        // Register XMPP Data MessageReciver
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(XmppDataMessageReceiver.ACTION_REQUEST_LOCATION);
        intentFilter.addAction(XmppDataMessageReceiver.ACTION_REPORT_LOCATION);
        intentFilter.addAction(XmppDataMessageReceiver.ACTION_NEW_CHAT);
        intentFilter.addAction(...ACTION_XMPP_CONNECTION_STATE...);
        intentFilter.addAction(...ACTION_ROSTER_OR_PRESENCE_CHANGED...);

        ....

        this.registerReceiver(xmppDataMessageReceiver, intentFilter);
    }

 

    @Override
    protected void onStop() {
         super.onStop();
  
          // unregister XMPP Data MessageReciver
         this.unregisterReceiver(xmppDataMessageReceiver);
    }

    ....

}

 

在 IntentReceiver 中接收 Notification

 

public class XmppDataMessageReceiver extends IntentReceiver {

 ....

 @Override
 public void onReceiveIntent(Context context, Intent intent) {
  
  String action = intent.getAction();
  
  if(action.equals(ACTION_REQUEST_LOCATION)) {
   Bundle bundle = intent.getExtras();
            if(bundle != null) {
             String requester = bundle.getString("requester");
             //showMessage(context, requester);
                if(requester != null)
                 activity.reportLocation(requester);
            }
        }else if(action.equals(ACTION_REPORT_LOCATION))    {
         Bundle bundle = intent.getExtras();
            if(bundle != null) {
             String reporter = bundle.getString("reporter");
             int latitude = Integer.parseInt(bundle.getString("latitude"));
             int longitude =  Integer.parseInt(bundle.getString("longitude"));
             activity.setUserLocation(reporter, latitude, longitude);
            }
        }else if(action.equals(ACTION_XMPP_CONNECTION_STATE))    {
             Bundle bundle = intent.getExtras();
             int state = bundle.getInteger("state").intValue();
          if(state == com.google.android.xmppService.ConnectionState.REQUESTED_ROSTER)    {
          // Get the base URI for IM contacts.
              try {
                  ContentURI myPerson = new ContentURI("content://im/contacts");
     
                   // Query for this record.
                   Cursor cur = activity.managedQuery(myPerson, null, null, null);
                   String[] names = cur.getColumnNames();
                   // TODO There is no document for IM Contact operation,
                   //      2 hard for me to hacking it
              } catch (URISyntaxException e) {
                   // TODO Auto-generated catch block
                   e.printStackTrace();
              }
            }
        } else if(action.equals(ACTION_ROSTER_OR_PRESENCE_CHANGED)) {
             //showMessage(context, ACTION_ROSTER_OR_PRESENCE_CHANGED);
        } else if(action.equals(ACTION_NEW_CHAT)) {
             //showMessage(context, ACTION_NEW_CHAT);
        }
 }

 ....

}

 

Reporting Location

 

public class XmppDataMessageReceiver extends IntentReceiver {

 ....

    private Intent getRequestIntentToSend() {
        Intent intent = new Intent(XmppDataMessageReceiver.ACTION_REQUEST_LOCATION);
        intent.putExtra("requester", userName);

        return intent;
    }
   
    private Intent getResponseIntentToSend() {
        Intent intent = new Intent(XmppDataMessageReceiver.ACTION_REPORT_LOCATION);
        intent.putExtra("reporter", userName);
       
        //Bundle bundle = intent.getExtras();
       
        int i = locationIndex++ % 19;
        intent.putExtra("latitude", Integer.toString(locations[i][0]));
        intent.putExtra("longitude", Integer.toString(locations[i][1]));
        //intent.putExtra("location", new Point(locations[i][0], locations[i][1]));
       
        return intent;
    }

  public void reportLocation(String requester)    {
        Intent intent = getResponseIntentToSend();
  
        if (mXmppSession == null) {
            showMessage(getText(R.string.xmpp_service_not_connected));
            return;
        }

        try {
            mXmppSession.sendDataMessage(requester, intent);
        } catch (DeadObjectException ex) {
            showMessage(getText(R.string.found_stale_xmpp_service));
            mXmppSession = null;
            bindXmppService();
        }
 }

 ....

}

 

Binding to XMPP Service

 

如何 bind to XMPP Service,在現在接露的 document 中找不到,還好在  SDK 的 sample 中,有兩個應用 (XmppDataMessageReceiver.java & XmppDataMessageSender.java),有用到一些 undocumented classes,其中接露了不少秘密。

 

public class XmppDataMessageReceiver extends IntentReceiver {

 ....

    private void bindXmppService() {
        bindService((new Intent()).setComponent(
            com.google.android.xmppService.XmppConstants.XMPP_SERVICE_COMPONENT),
            null, mConnection, 0);
    }
   
    private IXmppSession mXmppSession = null;
   
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the XmppService has been
            // established, giving us the service object we can use to
            // interact with the service.  We are communicating with our
            // service through an IDL interface, so get a client-side
            // representation of that from the raw service object.
            IXmppService xmppService = IXmppService.Stub.asInterface(service);
           
            // Increment the event monitor reference count. When application UI
            // is alive and listening for the various XMPP event intent
            // broadcast (i.e. incoming chat, muc invitation, subscription invitation),
            // call this so XmppService will send the appropriate intent broadcast
            // instead of posting a titlebar notification.
            try {
                xmppService.incrementEventMonitorRef();
            } catch (DeadObjectException e1) {
                     // TODO Auto-generated catch block
                    e1.printStackTrace();
    
                   return;
            }

            try {
                  mXmppSession = xmppService.getDefaultSession();

                  if (mXmppSession == null) {
                      // this should not happen.
                      showMessage(getText(R.string.xmpp_session_not_found));
                   
                      return;
                  }
               
                  //if()
                  mXmppSession.requestRosterAndSendInitialPresence();
                  userName = mXmppSession.getUsername();
              } catch (DeadObjectException ex) {
                    //Log.e(LOG_TAG, "caught " + ex);
                    showMessage(getText(R.string.found_stale_xmpp_service));
               
                    return;
              }
           
              okButton.setEnabled(true);
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mXmppSession = null;
            okButton.setEnabled(false);
        }
    };

....

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值