我的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 ...
随机推荐
- [Tools] Support VS Code Navigation and Autocomplete Based on Webpack Aliases with jsconfig.json
It's common to setup Webpack aliases to make imports much more convenient, but then you lose the abi ...
- 为什么我获取不到这个css样式?js原生获取css样式总结
还是自己遇到的一个坑的总结吧!与其说是坑不如说自己学艺不精,让我先哭一会!! 需求 简单就是获取一个css的height (好吧 就是一个这么简单的需求) 实践 好吧 长时间的JQ 我已经对原生无能了 ...
- golang一些知识点
2.冒泡排序(二维数组使用): func main() { i := 1 MYLABEL: for { i++ if i > 3 { break MYLABEL } } fmt.Println( ...
- MVVM模式源码分析手写实现
1.demo1.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...
- js控制div内的滚动条的位置
通过div的scrollTop变动控制垂直滚动条位置. 通过div的scrollLeft变动控制水平滚动条位置. 示例: <body> //d1是外层div,带滚动条 <div id ...
- DNS主从服务器
一.目的: 我们知道,DNS服务器在网络服务中可能出现故障当机等状况,会导致DNS服务瘫痪,显然在实际的网络应用中我们不希望出现这种状况,所有我们就要配置从 服务器来在主DNS服务器出现故障时代替他来 ...
- AutoWare 使用
1.安装readme当中的要求,安装依赖库 52 sudo apt-get install ros-indigo-desktop-full ros-indigo-nmea-msgs ros-i ...
- ExtJs的Ext.grid.GridPanel不能选择复制表格中的内容解决方案
今天遇到grid复制的问题,在网上找到了一个解决办法,只需改下CSS和JS,给大家分享一下: 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dy_paradise/a ...
- android 多应用程序数据共享 ContentProvider和ContentResolver
android 没有一个可以将所有应用程序数据统一放置的地方,即两个应用程序间的数据不能共享.但ContentProvider与ContentResolver可以解决多应用程序数据共享. 我们都知 ...
- 两个页面相同js方法兼容
1. a.js页面 //Js获取Url参数 function request(paras) { var url = location.href; var paraString = url.substr ...