免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1771 | 回复: 0
打印 上一主题 下一主题

android平台上的手机定位器 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-26 14:10 |只看该作者 |倒序浏览
android平台上的手机定位器  

Post By:2008-8-30 23:27:00
在本教程中,我们将创建一个叫做PhoneFinder的应用。本应用将演示如何发送和接收短信。当你的手机丢了或者被偷,你可以使用别人的手机,接收你
手机所处位置的GPS坐标,从而找到你的手机,这正是本应用的创意来源。
本应用需要一个Activity让用户输入密码,还需要一个IntentReceiver来过滤接收到的短信。
[color="#ee3d11"]这里下载全部源码
译者注:本文完全按照原文翻译,如果说明文字中的代码行号和实际显示的代码行号有出入,请按代码执行的功能理解
密码输入
如下所示,我们使用一个简单的对话框来帮助用户输入密码。一旦密码被正确输入,我们将把密码的MD5置入应用包的
SharedPreferences中。Preferences是一个存储少量持久数据的好地方,包中的其他类也可以访问Preferences。之所以
存储密码的MD5,是因为即使密码被读取,它也不会泄露密码的明文,除非这密码本身非常弱。



上图所示的对话框对应的layout文件,main.xml如下所示:


  • android:orientation=[color="#ff33ff"]"vertical"
  • android:layout_width=[color="#ff33ff"]"fill_parent"
  • android:layout_height=[color="#ff33ff"]"fill_parent"
  • >

  • android:layout_width=[color="#ff33ff"]"fill_parent"
  • android:layout_height=[color="#ff33ff"]"wrap_content"
  • android:text=[color="#ff33ff"]"@string/password_label"
  • />
  • android:maxLines=[color="#ff33ff"]"1"
  • android:layout_marginTop=[color="#ff33ff"]"2dip"
  • android:layout_width=[color="#ff33ff"]"wrap_content"
  • android:ems=[color="#ff33ff"]"25"
  • android:layout_height=[color="#ff33ff"]"wrap_content"
  • android:autoText=[color="#ff33ff"]"true"
  • android:scrollHorizontally=[color="#ff33ff"]"true"
  • android:password=[color="#ff33ff"]"true" />
  • android:layout_width=[color="#ff33ff"]"fill_parent"
  • android:layout_height=[color="#ff33ff"]"wrap_content"
  • android:text=[color="#ff33ff"]"@string/password_confirm_label"
  • />
  • android:maxLines=[color="#ff33ff"]"1"
  • android:layout_marginTop=[color="#ff33ff"]"2dip"
  • android:layout_width=[color="#ff33ff"]"wrap_content"
  • android:ems=[color="#ff33ff"]"25"
  • android:layout_height=[color="#ff33ff"]"wrap_content"
  • android:autoText=[color="#ff33ff"]"true"
  • android:scrollHorizontally=[color="#ff33ff"]"true"
  • android:password=[color="#ff33ff"]"true" />

  • android:layout_width=[color="#ff33ff"]"wrap_content"
  • android:layout_height=[color="#ff33ff"]"wrap_content"
  • android:layout_gravity=[color="#ff33ff"]"right"
  • android:text=[color="#ff33ff"]"@string/button_ok" />

  • android:layout_width=[color="#ff33ff"]"fill_parent"
  • android:layout_height=[color="#ff33ff"]"wrap_content"
  • />
  • 如你所见,这是一个相当简单的Layout,2个
    TextView,2个输入框,1个button,另外还有一个TextView用来显示提示信息。Layout中所涉及到的字符串在
    strings.xml中定义,以便提供更好的国际化支持。
    这个Activity对应的代码也是简单的。它所完成的任务就是确保输入的密码在6个字符以上并且密码的2次输入必须匹配。一旦所有条件满足,我们所要做
    的就是把用户输入的密码所对应的MD5保存在应用的SharedPreferences里。PhoneFinder Activity的代码如下所示:

  • [color="#0000ff"]public [color="#0000ff"]class PhoneFinder [color="#0000ff"]extends Activity {

  • [color="#0000ff"]public [color="#0000ff"]static [color="#0000ff"]final
    [color="#0000ff"]String
    PASSWORD_PREF_KEY = [color="#ff33ff"]"passwd";

  • [color="#0000ff"]private TextView messages;
  • [color="#0000ff"]private EditText pass1;
  • [color="#0000ff"]private EditText pass2;

  • @Override
  • [color="#0000ff"]public [color="#0000ff"]void onCreate(Bundle icicle) {
  • [color="#0000ff"]super.onCreate(icicle);
  • setContentView(R.layout.main);

  • messages = (TextView) findViewById(R.id.text1);
  • pass1 = (EditText) findViewById(R.id.password);
  • pass2 = (EditText) findViewById(R.id.password_confirm);

  • [color="#ff0000"]Button button = ([color="#ff0000"]Button) findViewById(R.id.ok);
  • button.setOnClickListener(clickListener);
  • }

  • [color="#0000ff"]private OnClickListener clickListener = [color="#0000ff"]new OnClickListener() {

  • [color="#0000ff"]public [color="#0000ff"]void onClick([color="#ff0000"]View v) {

  • [color="#0000ff"]String
    p1 = pass1.getText().toString();

  • [color="#0000ff"]String
    p2 = pass2.getText().toString();

  • [color="#0000ff"]if (p1.equals(p2)) {

  • [color="#0000ff"]if (p1.[color="#0000ff"]length() >= 6 || p2.[color="#0000ff"]length() >= 6) {

  • Editor passwdfile = getSharedPreferences(PhoneFinder.PASSWORD_PREF_KEY, 0).edit();

  • [color="#0000ff"]String
    md5hash = getMd5Hash(p1);
  • passwdfile.putString(PhoneFinder.PASSWORD_PREF_KEY,
  • md5hash);
  • passwdfile.commit();
  • messages.setText([color="#ff33ff"]"Password updated!");

  • } [color="#0000ff"]else
  • messages.setText([color="#ff33ff"]"Passwords must be at least 6 characters");

  • } [color="#0000ff"]else {
  • pass1.setText([color="#ff33ff"]"");
  • pass2.setText([color="#ff33ff"]"");
  • messages.setText([color="#ff33ff"]"Passwords do not match");
  • }

  • }

  • };
  • }

  • 在onCreate()方法中,我们初始化了将要在layout中使用的各种View,然后,我们创
    建了ok按钮的OnClickListener对象。当ok按钮被点击,位于第40行的onClick()方法将会被调用。
    在onClick()方法中,我们确保密码的最少长度要求被满足,而且2个输入框中输入的密码字串一致。如果所有的条件满足,我们在第48行创建一个
    SharedPreferences.Editor对象,通过该对象,我们可以编辑该应用的shared
    preferences。之所以把此类preferences称为“共享”(shared),因为它是一个应用程序范围内的参数。如果你想把数据的可见性
    局限在调用的Activity对象内,你可以使用Activity.getPreferences(int),这是Activity级别的数据存储方式。
    在第48行,我们调用成员函数getMd5Hash(String),它返回字符串形式的MD5,然后我们把它存储在preferences里面。以下就
    是getMd5Hash(String)函数:

  • [color="#0000ff"]public [color="#0000ff"]static
    [color="#0000ff"]String
    getMd5Hash(
    [color="#0000ff"]String
    input) {
  • [color="#0000ff"]try {
  • [color="#ff0000"]MessageDigest md = [color="#ff0000"]MessageDigest.getInstance([color="#ff33ff"]"MD5");
  • [color="#0000ff"]byte[] messageDigest = md.digest(input.getBytes());
  • [color="#ff0000"]BigInteger number = [color="#0000ff"]new [color="#ff0000"]BigInteger(1,messageDigest);

  • [color="#0000ff"]String
    md5 = number.toString(16);

  • [color="#0000ff"]while (md5.[color="#0000ff"]length()
  • md5 = [color="#ff33ff"]"0" + md5;

  • [color="#0000ff"]return md5;
  • } [color="#0000ff"]catch([color="#ff0000"]NoSuchAlgorithmException e) {
  • Log.e([color="#ff33ff"]"MD5", e.getMessage());
  • [color="#0000ff"]return [color="#0000ff"]null;
  • }
  • }

  • 我们使用android.security.MessageDigest对象来表达我们想要使用的算
    法。digest()函数的输入参数为字符串所对应的字节数组,输出参数也是一个字节数组。输出的字节数组可以转化成一个BigInteger对象,进而
    利用该对象的toString(16)方法转变成16进制的字符串。因为把字节数组转化成一个BigInteger的时候,前端的0会被删掉,所以我们在
    MD5字串前面补上足够的0,使它的长度达到32个字符。 处理短消息现在,用户可以在应用的preferences中保存输入的密码了,接下来,我们将要检查手机接收到的短信,并且对我们感兴趣的短信做出响应。这种短信的格式为:
  • SMSLOCATE: 因此,如果某条短信以“SMSLOCATE:”开头,
    并且紧跟‘:’字符后面的密码的MD5和我们先前存储的匹配,我们将回复一条包含手机当前位置信息的短信。为了实现这一目的,我们需要建立一个
    IntentReceiver,响应类型为“android.provider.Telephony.SMS_RECEIVED”的Action。该
    IntentReceiver必须在AndroidManifest.xml 文件中声明,以下是AndroidManifest.xml 文件:


  • [color="#0000ff"]package=[color="#ff33ff"]"com.helloandroid.android.phonefinder">
















  • 在第4行,通过标签,我们请求接收短信的权限。在第13行,我们指定我们的FinderReceiver作为一个receiver,同时声
    明了intent-filter,以此来过滤被广播的所有intent。你可以看到,我们只对
    “android.provider.Telephony.SMS_RECEIVED”这类action感兴趣。
    现在,系统知道了对于这类action,该调用何种receiver。接下来我们来创建名为FinderReceiver的
    IntentReceiver。

  • [color="#0000ff"]public [color="#0000ff"]class FinderReceiver [color="#0000ff"]extends IntentReceiver {

  • @Override
  • [color="#0000ff"]public [color="#0000ff"]void onReceiveIntent([color="#ff0000"]Context context, Intent intent) {

  • SharedPreferences passwdfile = context.getSharedPreferences(
  • PhoneFinder.PASSWORD_PREF_KEY, 0);


  • [color="#0000ff"]String
    correctMd5 = passwdfile.getString(PhoneFinder.PASSWORD_PREF_KEY,
  • [color="#0000ff"]null);

  • [color="#0000ff"]if (correctMd5 != [color="#0000ff"]null) {

  • SmsMessage[] messages = Telephony.Sms.Intents
  • .getMessagesFromIntent(intent);

  • [color="#0000ff"]for (SmsMessage msg : messages) {
  • [color="#0000ff"]if (msg.getMessageBody().contains([color="#ff33ff"]"SMSLOCATE:")) {

  • [color="#0000ff"]String
    [] tokens = msg.getMessageBody().split([color="#ff33ff"]":");
  • [color="#0000ff"]if (tokens.[color="#0000ff"]length >= 2) {

  • [color="#0000ff"]String
    md5hash = PhoneFinder.getMd5Hash(tokens[1]);

  • [color="#0000ff"]if (md5hash.equals(correctMd5)) {

  • [color="#0000ff"]String
    to = msg.getOriginatingAddress();
  • LocationManager lm =
  • (LocationManager) context.getSystemService([color="#ff0000"]Context.LOCATION_SERVICE);
  • SmsManager sm = SmsManager.getDefault();

  • sm.sendTextMessage(to, [color="#0000ff"]null, lm.getCurrentLocation([color="#ff33ff"]"gps").toString(),
  • [color="#0000ff"]null, [color="#0000ff"]null, [color="#0000ff"]null);

  • NotificationManager nm =
  • (NotificationManager) context.getSystemService([color="#ff0000"]Context.NOTIFICATION_SERVICE);
  • nm.notifyWithText(R.layout.main,
  • context.getText(R.string.notify_text) + [color="#ff33ff"]" " + msg.getDisplayOriginatingAddress(),
  • NotificationManager.LENGTH_LONG, [color="#0000ff"]null);
  • }
  • }
  • }
  • }
  • }
  • }
  • }
    首先,我们从SharedPreferences取出密码的MD5(18-21行),如果我们取到了,我们就用它来检查我们接收到的所有的短信。
    我们使用Telphony.Sms.Intents.getMessageFromInent(intent)来获取SmsMessages数组,我们将
    遍历该数组,查看每条短信消息体中是否包含“SMSLOCATE:”标记,如果找到符合条件的短消息,我们会获取‘:’字符后的密码,计算其MD5,和手
    机里存储的MD5进行比较。
    如果密码匹配,系统会执行第36行处的代码块。接下来我们将回复该短信,现在我们只需要一个代表短信目的地的字符串,以及代表手机位置信息的字符串。我们
    创建一个LocationManager,使用其getCurrentLocation("gps").toString()方法来获取位置信息。该信息
    由GPS位置服务提供者提供。然后,我们使用一个SmsManager对象发送短信。短信发送完毕后,我们还会显示一个通知。 注意:有一个可能更好做法是,在密码输入对话框中加入一个可选项来控制是否显示通知。如果手机被偷,最好把通知隐藏起来,否则小偷会意识到自己被跟踪,从而把手机关掉。
      
    测试
    现在,万事俱备。在新版的android
    SDK中,给模拟器打电话或者发短信都很容易。这些操作都可以通过Eclipse中的模拟器控制面板视图来完成。你可以通过“"Window
    -> Show View -> Other”,选择android部分的“Emulator Control”项来增加这个视图。 译者注:如果你的android Eclipse插件为ADT0.3.1,请务必升级到ADT0.3.3,升级步骤见
    http://code.google.com/android/intro/upgrading.html
    测试的第一步是激活主Activity,设置密码。例如,我使用“123456”作为密码,接下来,你可以发送一条内容为“SMSLOCATE:123456”的短信,如下图所示:


    好了,一切OK。我想,这是一个很好的例子。通过它,你会发现在android平台上开发一个有用的应用是多么的容易。我们通过2个基本的对象就完成了一件非常有用的任务。
                   
                   
                   

    本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/85193/showart_1667228.html
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP