我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(三)Android客户端功能实现
我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(一)PC服务器端
(地址:http://blog.csdn.net/ouyang_peng/article/details/47004617)
我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(二)Android客户端功能展示
(地址:http://blog.csdn.net/ouyang_peng/article/details/47005739)
通过以上两篇文章,我们了解了Android实现用Android手机控制PC端的关机和重启的的大概功能,现在我们来实现Android客户端的代码。
首先来看看整个项目的结构,如下图所示:
第一步:扫描局域网内所有PC,看是否有PC端的服务器在运行并监听30000端口。
此界面的布局文件为:/res/layout/layout_scanip.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:id="@+id/ll"
android:layout_width="200dp"
android:layout_height="100dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/scaning" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="100dp"
android:layout_height="1dp" />
</LinearLayout>
</RelativeLayout> </RelativeLayout>
扫描IP的Activity为com.oyp.shutdown.ScanActivity,代码如下:
package com.oyp.shutdown; import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket; import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Window;
import android.widget.ProgressBar;
import android.widget.Toast; public class ScanActivity extends Activity {
private MyWifiManager myWifiManager = null;
private String serverIP = "", resultIP = "";
private ScanIPThread scanThread = null;
private ProgressBar progressBar; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
int height = getWindow().getWindowManager().getDefaultDisplay()
.getHeight();
int width = getWindow().getWindowManager().getDefaultDisplay()
.getWidth();
setContentView(R.layout.layout_scanip);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
myWifiManager = new MyWifiManager(ScanActivity.this);
scanThread = new ScanIPThread();
scanThread.start();
} private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1000:
Toast.makeText(ScanActivity.this, getString(R.string.find),
Toast.LENGTH_SHORT).show(); // 找到可连接PC
Intent controlIntent = new Intent(ScanActivity.this,
ControlActivity.class);
// 将可以连接的ip发过去
controlIntent.putExtra("ip", (String) msg.obj);
startActivity(controlIntent);
finish();
break;
case 2000:
Toast.makeText(ScanActivity.this, getString(R.string.notFind),
Toast.LENGTH_SHORT).show(); // 没有找到可连接PC
Intent reScanIntent = new Intent(ScanActivity.this,
ReScanActivity.class);
startActivity(reScanIntent);
finish();
break;
default:
progressBar.setMax(254);
progressBar.setProgress(msg.what);
break;
}
super.handleMessage(msg);
}
}; // 扫描连接的WiFi所在网段开启了30000端口的C类ip
// 例如,wifi的ip是192.168.1.1 则扫描 192.168.1.1-192.168.1.254
class ScanIPThread extends Thread {
@Override
public void run() {
serverIP = myWifiManager.getServerIp();
int t = serverIP.lastIndexOf(".") + 1;
resultIP = serverIP.substring(0, t);
boolean flag = false;
for (int i = 1; i < 255; i++) {
try {
Socket socket = new Socket();
InetSocketAddress s = new InetSocketAddress(resultIP + i,
30000);
socket.connect(s, 50);
Message message = new Message();
message.what = 1000;
message.obj = resultIP + i;
handler.sendMessage(message);
flag = true;
socket.close();
break;
} catch (IOException e) {
handler.sendEmptyMessage(i);
}
}
if (!flag) {
handler.sendEmptyMessage(2000);
}
super.run();
}
}
}
第二步:如果没有扫描到有PC端的服务器在运行并监听30000端口,则重新扫描或者退出。如上述代码中,当msg.what=2000时,重新进行扫描。
此界面的布局文件为:/res/layout/layout_rescan.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" > <Button
android:id="@id/btnReScan"
style="@style/StyleButton"
android:text="@string/rescan" /> <Button
android:id="@id/btnClose"
style="@style/StyleButtonClose"
android:text="@string/close" /> </LinearLayout>
重新扫描IP的Activity为com.oyp.shutdown.ReScanActivity,代码如下:
package com.oyp.shutdown; import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button; public class ReScanActivity extends Activity implements OnClickListener {
private Button btn_rescan, btn_close; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
setContentView(R.layout.layout_rescan);
getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
R.drawable.acticon); btn_rescan = (Button) findViewById(R.id.btnReScan);
btn_close = (Button) findViewById(R.id.btnClose); btn_rescan.setOnClickListener(this);
btn_close.setOnClickListener(this);
} @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnReScan:
Intent intent = new Intent(ReScanActivity.this,ScanActivity.class);
startActivity(intent);
finish();
break;
case R.id.btnClose:
finish();
break;
default:
break;
}
}
}
第二步:扫描到了有PC端的服务器在运行并监听30000端口,则控制PC端关机、重启或者取消关机。如上述代码中,当msg.what=1000时,则打开控制PC端界面。
此界面的布局文件为:/res/layout/layout_control.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" > <Button
android:id="@id/btnShutdown"
style="@style/StyleButton"
android:text="@string/shutdown" /> <Button
android:id="@id/btnReboot"
style="@style/StyleButton"
android:text="@string/reboot" /> <Button
android:id="@id/btnCancel"
style="@style/StyleButton"
android:text="@string/cancel" /> <Button
android:id="@id/btnClose"
style="@style/StyleButtonClose"
android:text="@string/close" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="6.0dip"
android:text=" "
android:textSize="12.0dip" /> </LinearLayout>
控制PC端的Activity为com.oyp.shutdown.ControlActivity,代码如下:
package com.oyp.shutdown; import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket; import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.Toast; public class ControlActivity extends Activity implements OnClickListener {
private Button btn_shutdown, btn_restart, btn_cancel, btn_close;
private Socket clientSocket;// 客户端socket
private DataOutputStream dataOutput = null;// 客户端发送数据
private DataInputStream dataInput = null;// 客户端接收数据
private String connIP = "";
private ConnThread connThread = null;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Toast.makeText(ControlActivity.this, (String) msg.obj,
Toast.LENGTH_SHORT).show();
break;
default:
break;
}
super.handleMessage(msg);
}
}; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
setContentView(R.layout.layout_control);
getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
R.drawable.acticon); btn_shutdown = (Button) findViewById(R.id.btnShutdown);
btn_restart = (Button) findViewById(R.id.btnReboot);
btn_cancel = (Button) findViewById(R.id.btnCancel);
btn_close = (Button) findViewById(R.id.btnClose); Intent intent = getIntent();
connIP = intent.getStringExtra("ip"); btn_shutdown.setOnClickListener(this);
btn_restart.setOnClickListener(this);
btn_cancel.setOnClickListener(this);
btn_close.setOnClickListener(this);
} @Override
public void onClick(View v) {
// 连接服务器
switch (v.getId()) {
case R.id.btnShutdown:
final String shutdown = "shutdown";
if (connThread != null) {
connThread.interrupt();
}
connThread = new ConnThread(connIP, 30000, shutdown);
connThread.start();
break;
case R.id.btnReboot:
final String reboot = "reboot";
if (connThread != null) {
connThread.interrupt();
}
connThread = new ConnThread(connIP, 30000, reboot);
connThread.start();
break;
case R.id.btnCancel:
final String cancel = "cancel";
if (connThread != null) {
connThread.interrupt();
}
connThread = new ConnThread(connIP, 30000, cancel);
connThread.start();
break;
case R.id.btnClose:
finish();
break;
default:
break;
}
} class ConnThread extends Thread {
private String ip;
private int port;
private String content; public ConnThread(String ip, int port, String content) {
this.ip = ip;
this.port = port;
this.content = content;
} @Override
public void run() {
try {
clientSocket = new Socket(ip, port);
while (true) {
dataOutput = new DataOutputStream(
clientSocket.getOutputStream());
dataInput = new DataInputStream(
clientSocket.getInputStream());
String msg = "";
if ((dataOutput != null) && (!content.equals(""))) {
dataOutput.writeUTF(content);
}
msg = dataInput.readUTF();
if (msg != null && !"".equals(msg)) {
Message message = new Message();
message.what = 1;
message.obj = msg;
handler.sendMessage(message);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (dataOutput != null) {
dataOutput.close();
}
if (dataInput != null) {
dataInput.close();
}
if (clientSocket != null) {
clientSocket = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
super.run();
}
}
}
其中MyWifiManager.java代码如下:
package com.oyp.shutdown; import android.content.Context;
import android.net.DhcpInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager; public class MyWifiManager { private WifiManager wifiManager;
private WifiInfo wifiInfo;
private DhcpInfo dhcpInfo;
public MyWifiManager(Context context){
wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
wifiInfo = wifiManager.getConnectionInfo();
dhcpInfo = wifiManager.getDhcpInfo();
}
//得到本机ip
public String getLocalIp(){
return FormatString(dhcpInfo.ipAddress);
}
//得到服务器ip(热点ip)
public String getServerIp(){
return FormatString(dhcpInfo.serverAddress);
}
//转换ip格式为*.*.*.*
public String FormatString(int value){
String strValue="";
byte[] ary = intToByteArray(value);
for(int i=ary.length-1;i>=0;i--){
strValue+=(ary[i]&0xFF);
if(i>0){
strValue+=".";
}
}
return strValue;
}
public byte[] intToByteArray(int value){
byte[] b=new byte[4];
for(int i=0;i<4;i++){
int offset = (b.length-1-i)*8;
b[i]=(byte) ((value>>>offset)&0xFF);
}
return b;
}
}
定义控件ID的文件为/res/values/id.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="btnAirplane">false</item>
<item type="id" name="btnShutdown">false</item>
<item type="id" name="btnReScan">false</item>
<item type="id" name="btnCancel">false</item>
<item type="id" name="btnReboot">false</item>
<item type="id" name="btnRecovery">false</item>
<item type="id" name="btnBootloader">false</item>
<item type="id" name="btnClose">false</item>
</resources>
/res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">控制PC</string>
<string name="shutdown">关机</string>
<string name="rescan">重新扫描</string>
<string name="reboot">重启</string>
<string name="cancel">取消</string>
<string name="please_wait">请稍等......</string>
<string name="warning">错误</string>
<string name="root">无法获得 Root 权限!</string>
<string name="close">退出</string>
<string name="ok">确定</string>
<string name="scaning">正在扫描......</string>
<string name="find">找到可连接PC.</string>
<string name="notFind">没有找到可连接PC</string>
</resources>
/res/values/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="StyleButton">
<item name="android:textSize">16.0dip</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">#ffffffff</item>
<item name="android:layout_gravity">center_horizontal</item>
<item name="android:background">@drawable/btn_selector</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginLeft">30.0dip</item>
<item name="android:layout_marginRight">30.0dip</item>
<item name="android:layout_marginBottom">8.0dip</item>
</style>
<style name="StyleButtonClose">
<item name="android:textSize">16.0dip</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">#ffffffff</item>
<item name="android:layout_gravity">center_horizontal</item>
<item name="android:background">@drawable/btn_close_selector</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginLeft">30.0dip</item>
<item name="android:layout_marginRight">30.0dip</item>
<item name="android:layout_marginBottom">8.0dip</item>
</style>
</resources>
项目描述文件:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.oyp.shutdown"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" /> <application
android:allowBackup="true"
android:icon="@drawable/icon"
android:label="@string/app_name" >
<activity
android:name=".ScanActivity"
android:theme="@android:style/Theme.Dialog" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ReScanActivity"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@android:style/Theme.Dialog" >
</activity>
<activity
android:name=".ControlActivity"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@android:style/Theme.Dialog" >
</activity>
</application>
</manifest>
代码可以在此处下载:Android实现用Android手机控制PC端的关机和重启的功能 地址:(http://download.csdn.net/detail/qq446282412/8923991)
====================================================================================
作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址:http://blog.csdn.net/ouyang_peng
====================================================================================
我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(三)Android客户端功能实现的更多相关文章
- 我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重新启动的功能(二)Androidclient功能展示
Androidclient的实现思路大致例如以下: 1.首先扫描局域网内全部PC,看是否有PC端的server在执行并监听30000port. watermark/2/text/aHR0cDovL2J ...
- [置顶] 我的Android进阶之旅------>介绍一款集录制与剪辑为一体的屏幕GIF 动画制作工具 GifCam
由于上一篇文章:我的Android进阶之旅------>Android之动画之Frame Animation实例 中展示的是Frame动画效果,但是之前我是将图片截取下来,不好说明确切的动画过程 ...
- 我的Android进阶之旅------> Android在TextView中显示图片方法
面试题:请说出Android SDK支持哪些方式显示富文本信息(不同颜色.大小.并包括图像的文本信息).并简要说明实现方法. 答案:Android SDK支持例如以下显示富文本信息的方式. 1.使用T ...
- 【我的Android进阶之旅】推荐一款视频转换GIF图片格式的转换工具(Video to GIF)
一.背景 最近想把一些Android Demo的运行效果图获取下来,但是一直使用真机进行调试,在电脑上不好截取一段gif动画.而之前使用模拟器的时候可以使用 GifCam 工具进行屏幕动画截取.Gif ...
- 我的Android进阶之旅------>Android字符串资源中的单引號问题error: Apostrophe not preceded by 的解决的方法
刚刚在string字符串资源文件里,写了一个单引號.报错了,错误代码例如以下 error: Apostrophe not preceded by \ (in OuyangPeng's blog ) 资 ...
- 我的Android进阶之旅------>Android颜色值(#AARRGGBB)透明度百分比和十六进制对应关系以及计算方法
我的Android进阶之旅-->Android颜色值(RGB)所支持的四种常见形式 透明度百分比和十六进制对应关系表格 透明度 十六进制 100% FF 99% FC 98% FA 97% F7 ...
- 我的Android进阶之旅------>解决Jackson等第三方转换Json的开发包在开启混淆后转换的实体类数据都是null的bug
1.错误描述 今天测试人员提了一个bug,说使用我们的app出现了闪退的bug,后来通过debug断点调试,发现我们的app转换服务器发送过来的json数据后,都是为null.而之前已经提测快一个月的 ...
- 我的Android进阶之旅------>关于android:layout_weight属性的详细解析
关于androidlayout_weight属性的详细解析 效果一 效果二 图3的布局代码 图4的布局代码 效果三 图7代码 图8代码 效果四 效果五 版权声明:本文为[欧阳鹏]原创文章,欢迎转载,转 ...
- 我的Android进阶之旅------>如何解决Android 5.0中出现的警告: Service Intent must be explicit:
我的Android进阶之旅-->如何解决Android 5.0中出现的警告: java.lang.IllegalArgumentException: Service Intent must be ...
随机推荐
- 仿苹果电脑任务栏菜单&&拼图小游戏&&模拟表单控件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Fragment简单用法
一.示意图 二.新建一个左侧碎片布局left_fragment.xml <LinearLayout xmlns:android="http://schemas.android.com/ ...
- react-native AsyncStorage 数据持久化方案
1,AsyncStorage介绍 AsyncStorage 是一个简单的.异步的.持久化的 Key-Value 存储系统,它对于 App 来说是全局性的.它用来代替 LocalStorage. 由于它 ...
- Unity3d修炼之路:游戏开发中,3d数学知识的练习【1】(不断更新.......)
#pragma strict public var m_pA : Vector3 = new Vector3(2.0f, 4.0f, 0.0f); public var m_pB : Vector3 ...
- python 存取xml方法
或者也可以参考http://www.cnblogs.com/xiaowuyi/archive/2012/10/17/2727912.html中内容 目前而言,Python 3.2存取XML有以下四种方 ...
- android tooggle button
1 http://stackoverflow.com/questions/9938315/toggle-button-in-iphone-style 2 http://blog.csdn.net/bi ...
- 用Scratch2.0源码定制一个自己的编辑器
用Scratch2.0源码定制一个自己的编辑器,换成自己的软件名称和图标,添加中文字体,修复汉化错误等等1.准备:下载Scratch2.0源码.安装开发工具Adobe Flash Builder4.7 ...
- Android_Fragment_Fragment详解
Android_Fragment_Fragment详解 分类: Android基础2013-10-03 08:23 92人阅读 评论(0) 收藏 举报 AndroidFragmentFragmen ...
- Windows 清除系统垃圾文件
@echo off echo 正在清除系统垃圾文件,请稍等...... del /f /s /q %systemdrive%\*.tmp del /f /s /q %systemdrive%\*._m ...
- 解决PHP显示Warning和Notice等问题
PHP在安装后,会在php.ini 文件中设置报错.提醒.警告等方式的出现,这样的方式可以使我们在调试PHP程序的时候能及时了解程序所存在的问题.然后,有时候我们并不需要提醒.警告 等内容,比如当我们 ...