package cn.jkdev.host.activity; import android.Manifest; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.Color; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.google.gson.Gson; import com.stericson.RootTools.RootTools; import org.xutils.common.Callback; import org.xutils.common.task.PriorityExecutor; import org.xutils.http.RequestParams; import org.xutils.x; import java.io.File; import cn.jkdev.host.BuildConfig; import cn.jkdev.host.R; import cn.jkdev.host.bean.AppUpdateInfo; import cn.jkdev.host.bean.HostsUpdateInfo; import cn.jkdev.host.utils.ConstantValues; import cn.jkdev.host.utils.SPUtils; public class HomeActivity extends AppCompatActivity implements View.OnClickListener { /* * 对操作内容进行标志 * */ private static final int UPDATE_HOSTS = 101;//更新hosts private static final int RECOVERY_HOSTS = 102;//恢复hosts private int OPERATE = UPDATE_HOSTS;//默认标记操作内容为更新hosts /* * 对操作状态进行标志 * */ private static final int UPLOAD_FINISHED = 201;//下载成功 private static final int UPLOAD_ERROR = 202;//下载失败 private static final int COPY_ERROR = 203;//复制失败 private static final int COPY_FINISHED = 204;//复制成功 private LinearLayout mStateDes;//安装过程的描述控件集合 private TextView mUpdateContent;//用于显示更新内容 private TextView mHostsState, mCheckRoot, mDownloadFile, mCopyFile;//状态显示文本 private ProgressBar mProgress;//进度条 private Button mUpdateButton;//更新按钮 private ProgressDialog progressDialog;//更新进度条 /** * 可取消的任务 */ private Callback.Cancelable cancelable; private HostsUpdateInfo updateInfo;//更新内容对象 Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case UPLOAD_FINISHED: //下载hosts文件成功 mDownloadFile.setVisibility(View.VISIBLE); //复制hosts文件 copyHostsToSystemEtcDir(); break; case UPLOAD_ERROR: //下载失败 mDownloadFile.setVisibility(View.VISIBLE); //更改文字 mDownloadFile.setTextColor(Color.RED); mDownloadFile.setText("失败"); Toast.makeText(getApplicationContext(), "请检查网络连接", Toast.LENGTH_LONG).show(); //使进度条消失 mProgress.setVisibility(View.INVISIBLE); //结束程序 return; case COPY_ERROR: //复制失败 mCopyFile.setVisibility(View.VISIBLE); mCopyFile.setTextColor(Color.RED); mCopyFile.setText("失败"); //使进度条消失 mProgress.setVisibility(View.INVISIBLE); break; case COPY_FINISHED: //复制成功 mCopyFile.setVisibility(View.VISIBLE); //使进度条消失 mProgress.setVisibility(View.INVISIBLE); //保存状态 switch (OPERATE) { case UPDATE_HOSTS: //更新hosts SPUtils.putBoolean(getApplicationContext(), ConstantValues.HAVE_HOSTS, true); //保存最后一次更新的版本(以日期代替) if (updateInfo != null) { SPUtils.putString(getApplicationContext(), ConstantValues.UPDATED_DATE, updateInfo.date); } //回显hosts状态 showHostStateInfo(); //提示是否访问谷歌 showDialogIfVisitGoogle(); break; case RECOVERY_HOSTS: //恢复hosts SPUtils.putBoolean(getApplicationContext(), ConstantValues.HAVE_HOSTS, false); //保存空字符串 SPUtils.putString(getApplicationContext(), ConstantValues.UPDATED_DATE, ""); //回显hosts状态 showHostStateInfo(); break; } break; default: break; } } }; private void showDialogIfVisitGoogle() { AlertDialog.Builder builder = new AlertDialog.Builder(this); //builder.setPositiveButton() final AlertDialog alertDialog = builder.create(); alertDialog.setIcon(R.mipmap.ic_launcher); alertDialog.setTitle("恭喜你!"); alertDialog.setMessage("成功安装科学上网hosts,请使用https加密访问,是否立即访问Google?"); alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { //访问谷歌 Uri uri = Uri.parse("https://www.google.com/ncr"); startActivity(new Intent(Intent.ACTION_VIEW, uri)); alertDialog.dismiss(); } }); alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { alertDialog.dismiss(); } }); alertDialog.show(); } //复制hosts文件 private void copyHostsToSystemEtcDir() { new Thread(new Runnable() { @Override public void run() { boolean isCopy = RootTools.copyFile("/sdcard/hosts", "/system/etc", true, true); Log.i("tag", "文件复制是否完成:" + isCopy); Message message = Message.obtain(); if (isCopy) { //复制成功 message.what = COPY_FINISHED; } else { //复制失败 message.what = COPY_ERROR; } //复制操作后删除下载的hosts文件 File file = new File("sdcard/hosts"); if (file.exists()) { boolean delete = file.delete(); if (delete) { Log.i("tag", "删除成功"); } else { Log.i("tag", "删除成功"); } } mHandler.sendMessage(message); } }).start(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); //初始化控件 initView(); //初始化数据 initData(); } //初始化数据 private void initData() { //初始化xUtils3工具 x.Ext.init(getApplication()); x.Ext.setDebug(BuildConfig.DEBUG); // 是否输出debug日志, 开启debug会影响性能. //请求权限 requestPermission(); //获取服务器更新数据 getJsonFromServer(); //回显Hosts状态 showHostStateInfo(); //准备更新 if (SPUtils.getBoolean(getApplicationContext(), ConstantValues.AUTO_UPDATE, true)) { //获取服务器更新信息 getUpdateInfoFromServer(); } } private void requestPermission() { int REQUEST_EXTERNAL_STORAGE = 1;//请求状态码 //请求权限集合 String[] PERMISSIONS_STORAGE = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; int permission = ActivityCompat.checkSelfPermission(HomeActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE); if (permission != PackageManager.PERMISSION_GRANTED) { // We don't have permission so prompt the user ActivityCompat.requestPermissions( HomeActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE ); } } //初始化控件 private void initView() { //设置toolbar的支持 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); //获取安装过程状态的描述信息 mStateDes = (LinearLayout) findViewById(R.id.ll_state_des); //获取文本控件 mHostsState = (TextView) findViewById(R.id.tv_hosts_state); mUpdateContent = (TextView) findViewById(R.id.tv_content); mCheckRoot = (TextView) findViewById(R.id.tv_check_root); mDownloadFile = (TextView) findViewById(R.id.tv_download_file); mCopyFile = (TextView) findViewById(R.id.tv_copy_file); //获取按钮 mUpdateButton = (Button) findViewById(R.id.bt_get_host); mUpdateButton.setOnClickListener(this); findViewById(R.id.tv_bt_recovery).setOnClickListener(this); //获取原型滚动空间 mProgress = (ProgressBar) findViewById(R.id.pb_progress); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_about: //关于 startActivity(new Intent(getApplicationContext(), AboutActivity.class)); break; case R.id.menu_feedback: //反馈 startActivity(new Intent(getApplicationContext(), FeedBackActivity.class)); break; case R.id.menu_setting: //设置界面 startActivity(new Intent(getApplicationContext(),SettingActivity.class)); break; default: break; } return super.onOptionsItemSelected(item); } @Override public void onClick(View view) { //1.点击按钮后让圆形滚动空间滚动 mProgress.setVisibility(View.VISIBLE); //初始化文字显示内容 initTextHintShow(); //2.判断权限 if (RootTools.isRootAvailable()) { //已经获取root权限 mCheckRoot.setVisibility(View.VISIBLE); } else { //未获取root权限 mCheckRoot.setVisibility(View.VISIBLE); //更改提示文字 mCheckRoot.setTextColor(Color.RED); mCheckRoot.setText("失败"); Toast.makeText(getApplicationContext(), "请检查root权限", Toast.LENGTH_LONG).show(); //使进度条消逝 mProgress.setVisibility(View.INVISIBLE); //退出逻辑 return; } //3.判断按钮,并作出相应的逻辑 switch (view.getId()) { case R.id.bt_get_host: //安装hosts updateHostsFile(); break; case R.id.tv_bt_recovery: //提示是否恢复默认hosts showDialogIfRecoveryHosts(); break; default: break; } } private void showDialogIfRecoveryHosts() { AlertDialog.Builder builder = new AlertDialog.Builder(this); final AlertDialog alertDialog = builder.create(); alertDialog.setIcon(R.mipmap.ic_launcher); alertDialog.setTitle("提示!"); alertDialog.setMessage("恢复默认hosts后,将不能顺利访问谷歌等网站,是否确定?"); alertDialog.setCancelable(false); alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { //恢复hosts recoveryHostsFile(); alertDialog.dismiss(); } }); alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { //初始化状态文本的默认状态 initTextHintShow(); //设置进度条不可见 mProgress.setVisibility(View.INVISIBLE); alertDialog.dismiss(); } }); alertDialog.show(); } private void initTextHintShow() { //描述文本集合设置可见 mStateDes.setVisibility(View.VISIBLE); //使描述安装状态的TextView对应的状态TextView设置为不可见 mCheckRoot.setText("已完成"); mCheckRoot.setTextColor(Color.BLUE); mCheckRoot.setVisibility(View.INVISIBLE); mDownloadFile.setText("已完成"); mDownloadFile.setTextColor(Color.BLUE); mDownloadFile.setVisibility(View.INVISIBLE); mCopyFile.setText("已完成"); mCopyFile.setTextColor(Color.BLUE); mCopyFile.setVisibility(View.INVISIBLE); } /** * 恢复默认文件 */ private void recoveryHostsFile() { //下载默认的hosts文件 downloadHostsFile(ConstantValues.URL_NORMAL_HOSTS); //标记操作内容 OPERATE = RECOVERY_HOSTS; } /** * 复制hosts文件 */ private void updateHostsFile() { //下载科学上网的hosts文件 downloadHostsFile(ConstantValues.URL_GET_GOOGLE_HOSTS); //标记操作内容 OPERATE = UPDATE_HOSTS; } private void downloadHostsFile(String downloadURL) { //设置请求参数 final RequestParams params = new RequestParams(downloadURL); params.setAutoResume(true);//设置是否在下载是自动断点续传 params.setAutoRename(false);//设置是否根据头信息自动命名文件 params.setSaveFilePath("/sdcard/hosts"); params.setExecutor(new PriorityExecutor(2, true));//自定义线程池,有效的值范围[1, 3], 设置为3时, 可能阻塞图片加载. params.setCancelFast(true);//是否可以被立即停止. //开启主线程进行下载 Log.i("tag", "未下载时的线程" + Thread.currentThread().getName()); cancelable = x.http().get(params, new Callback.ProgressCallback<File>() { @Override public void onCancelled(Callback.CancelledException arg0) { Log.i("tag", "取消" + Thread.currentThread().getName()); } @Override public void onError(Throwable arg0, boolean arg1) { Log.i("tag", "onError: 失败" + Thread.currentThread().getName()); //progressDialog.dismiss(); Message message = Message.obtain(); message.what = UPLOAD_ERROR; mHandler.sendMessage(message); } @Override public void onFinished() { Log.i("tag", "完成,每次取消下载也会执行该方法" + Thread.currentThread().getName()); //progressDialog.dismiss(); } @Override public void onSuccess(File arg0) { Log.i("tag", "下载成功的时候执行" + Thread.currentThread().getName()); //下载成功之后更新文件 Message message = Message.obtain(); message.what = UPLOAD_FINISHED; mHandler.sendMessage(message); } @Override public void onLoading(long total, long current, boolean isDownloading) { if (isDownloading) { //progressDialog.setProgress((int) (current*100/total)); Log.i("tag", "下载中,会不断的进行回调:" + Thread.currentThread().getName()); } } @Override public void onStarted() { Log.i("tag", "开始下载的时候执行" + Thread.currentThread().getName()); //progressDialog.show(); } @Override public void onWaiting() { Log.i("tag", "等待,在onStarted方法之前执行" + Thread.currentThread().getName()); } }); } //获取服务器更新数据 public void getJsonFromServer() { /* * 使用xUtils3开源框架 * */ //创建Request请求对象 RequestParams params = new RequestParams(ConstantValues.URL_GET_UPDATE_MESSAGE); //发送request请求 x.http().post(params, new Callback.CommonCallback<String>() { @Override public void onSuccess(String result) { //请求成功 Log.d("请求服务器的结果", result); //解析数据 processData(result); } @Override public void onError(Throwable ex, boolean isOnCallback) { //请求失败 ex.printStackTrace(); Log.i("请求失败的息:", ex.toString()); //提示失败信息 Toast.makeText(getApplicationContext(), "服务器连接失败\n请检查您的网络连接", Toast.LENGTH_LONG).show(); } @Override public void onCancelled(CancelledException cex) { } @Override public void onFinished() { } }); } /* * 解析数据 * */ protected void processData(String json) { Gson gson = new Gson(); //将json字段转化为UpdateInfo类泛型 updateInfo = gson.fromJson(json, HostsUpdateInfo.class); Log.i("json解析结果", updateInfo.toString()); //将解析更新内容保存到数据库并显示出来 showHostStateInfo(); } private void showHostStateInfo() { boolean haveHosts = SPUtils.getBoolean(getApplicationContext(), ConstantValues.HAVE_HOSTS, false); Log.i("tag", "是否含有hosts:" + haveHosts); if (haveHosts) { //设置hosts状态字体为绿色 mHostsState.setTextColor(Color.GREEN); mHostsState.setText("hosts状态:已安装" + SPUtils.getString(getApplicationContext(), ConstantValues.UPDATED_DATE, "")); if (updateInfo != null) { mUpdateContent.setText("最新hosts:" + updateInfo.date + "\n" + updateInfo.content); } } else { //设置hosts状态字体为黄色 mHostsState.setTextColor(Color.parseColor("#e4e430")); mHostsState.setText("hosts状态:未安装"); if (updateInfo != null) { mUpdateContent.setText("最新hosts:" + updateInfo.date + "\n" + updateInfo.content); } } if (updateInfo != null) { if (SPUtils.getString(getApplicationContext(), ConstantValues.UPDATED_DATE, "").equals(updateInfo.date)) { mUpdateButton.setBackgroundResource(R.color.colorPrimary); } else { mUpdateButton.setBackgroundResource(R.color.colorYellow); } } } public void getUpdateInfoFromServer() { RequestParams params = new RequestParams(ConstantValues.URL_GET_NEW_APP_MESSAGE); //发送request请求 x.http().post(params, new Callback.CommonCallback<String>() { @Override public void onSuccess(String result) { //请求成功 Log.d("请求服务器的结果", result); //解析数据,获取更新对象 processAppUpdateInfo(result); } @Override public void onError(Throwable ex, boolean isOnCallback) { //请求失败 ex.printStackTrace(); Log.i("请求失败的息:", ex.toString()); //提示失败信息 Toast.makeText(getApplicationContext(), "服务器连接失败\n请检查您的网络连接", Toast.LENGTH_LONG).show(); } @Override public void onCancelled(CancelledException cex) { } @Override public void onFinished() { } }); } private void processAppUpdateInfo(String result) { Gson gson = new Gson(); AppUpdateInfo appUpdateInfo = gson.fromJson(result, AppUpdateInfo.class); Log.i("tag", "解析到的app更新信息如下:" + appUpdateInfo.toString()); //如果版本号不一致,则开始更新 if (!getVersionName().equals(appUpdateInfo.versionName)) { //版本不一样,提示更新 showUpdateAppDialog(appUpdateInfo); } } /** * 提示更新app版本 * * @param appUpdateInfo */ private void showUpdateAppDialog(final AppUpdateInfo appUpdateInfo) { AlertDialog.Builder builder = new AlertDialog.Builder(this); final AlertDialog alertDialog = builder.create(); alertDialog.setIcon(R.mipmap.ic_launcher); alertDialog.setTitle("服务器有新版本了!"); alertDialog.setMessage("版本号:" + appUpdateInfo.versionName + "\n更新内容:" + appUpdateInfo.updateInfo); alertDialog.setCancelable(false); alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { //下载新版本 downloadNewAppFile(appUpdateInfo.updateUrl, appUpdateInfo.versionName); alertDialog.dismiss(); } }); alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { //初始化状态文本的默认状态 initTextHintShow(); //设置进度条不可见 alertDialog.dismiss(); } }); alertDialog.show(); } /** * 下载新版apk文件 * * @param updateUrl 下载地址 */ private void downloadNewAppFile(String updateUrl, String versionName) { //初始化进度条 initProgressDialog(); //设置请求参数 RequestParams params = new RequestParams(updateUrl); params.setAutoResume(true);//设置是否在下载是自动断点续传 params.setAutoRename(false);//设置是否根据头信息自动命名文件 params.setSaveFilePath(ConstantValues.SAVE_FILE_PATH); params.setExecutor(new PriorityExecutor(2, true));//自定义线程池,有效的值范围[1, 3], 设置为3时, 可能阻塞图片加载. params.setCancelFast(true);//是否可以被立即停止. //下面的回调都是在主线程中运行的,这里设置的带进度的回调 cancelable = x.http().get(params, new Callback.ProgressCallback<File>() { @Override public void onCancelled(CancelledException arg0) { Log.i("tag", "取消" + Thread.currentThread().getName()); } @Override public void onError(Throwable arg0, boolean arg1) { Log.i("tag", "onError: 失败" + Thread.currentThread().getName()); progressDialog.dismiss(); } @Override public void onFinished() { Log.i("tag", "完成,每次取消下载也会执行该方法" + Thread.currentThread().getName()); progressDialog.dismiss(); } @Override public void onSuccess(File arg0) { Log.i("tag", "下载成功的时候执行" + Thread.currentThread().getName()); //进行apk安装 File file = new File(ConstantValues.SAVE_FILE_PATH); if (file.exists()) { //进入应用安装界面 String fileName = file.getAbsolutePath(); Uri uri = Uri.fromFile(new File(fileName)); //开启intent Intent intent = new Intent(Intent.ACTION_VIEW); //设置安装数据和安装类型 intent.setDataAndType(uri, "application/vnd.android.package-archive"); startActivityForResult(intent, 0); } } @Override public void onLoading(long total, long current, boolean isDownloading) { if (isDownloading) { progressDialog.setProgress((int) (current * 100 / total)); Log.i("tag", "下载中,会不断的进行回调:" + Thread.currentThread().getName()); } } @Override public void onStarted() { Log.i("tag", "开始下载的时候执行" + Thread.currentThread().getName()); progressDialog.show(); } @Override public void onWaiting() { Log.i("tag", "等待,在onStarted方法之前执行" + Thread.currentThread().getName()); } }); } /*初始化对话框*/ private void initProgressDialog() { //创建进度条对话框 progressDialog = new ProgressDialog(this); //设置标题 progressDialog.setTitle("下载文件"); //设置信息 progressDialog.setMessage("下载中..."); progressDialog.setCancelable(false); //设置显示的格式 progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); //设置按钮 progressDialog.setButton(ProgressDialog.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //点击取消正在下载的操作 cancelable.cancel(); } }); } public String getVersionName() { //1.获取包管理对象 PackageManager packageManager = getPackageManager(); //2.获取版本信息,参数0代表获取基本信息 try { PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0); //返回版本名称 return packageInfo.versionName; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return ""; } }