├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── .travis.yml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── RootTools.jar ├── proguard-rules.pro ├── src │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── imczy │ │ │ └── googlehost │ │ │ └── ApplicationTest.java │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── imczy │ │ │ │ └── googlehost │ │ │ │ ├── AboutActivity.java │ │ │ │ ├── Constants.java │ │ │ │ ├── HostDetailActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ └── util │ │ │ │ ├── CloseUtil.java │ │ │ │ ├── DownloadUtil.java │ │ │ │ └── IOUtil.java │ │ └── res │ │ │ ├── layout │ │ │ ├── activity_about.xml │ │ │ ├── activity_detail.xml │ │ │ └── activity_main.xml │ │ │ ├── menu │ │ │ └── menu_main.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ └── test │ │ └── java │ │ └── com │ │ └── imczy │ │ └── googlehost │ │ └── ExampleUnitTest.java └── travis.keystore ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local.properties.travis ├── settings.gradle └── travis.keystore /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | *.apk 10 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | GoogleHost -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | jdk: 3 | - oraclejdk8 4 | sudo: false 5 | addons: 6 | apt: 7 | packages: 8 | - gcc-multilib 9 | - g++-multilib 10 | - libstdc++6:i386 11 | - libgcc1:i386 12 | - zlib1g:i386 13 | - libncurses5:i386 14 | android: 15 | components: 16 | - tools 17 | - build-tools-23.0.3 18 | - android-23 19 | - extra-android-m2repository 20 | - extra-android-support 21 | install: 22 | - cp local.properties.travis local.properties 23 | script: 24 | - "./gradlew assembleRelease" 25 | deploy: 26 | provider: releases 27 | skip_cleanup: true 28 | api_key: 29 | secure: GSkw9yxdZF5+rcbSbgfbQljC9Qqj8vJUdRu+XOdzpjmTnhPFCQKXh+TG0DWvgfX7T8D7/Q2ohvO+T7kKy9+6Vf7vcOeJnwGIuVl60QdRcR84ME1sRvDoL9kGXU2SA/DYPxi6l66/BJbnItDbU63mYXYoYds4uLSuoILd95YDedtnIaMJUIVIipTtVUp/z0ZM3rc1BEByOXx5Q2nXcp/Y9sVnnTDopyU6e6xKBdfglLA+41nbZhiZOFfhjjY8s00Rr2o0afBKk+oRpk8a5ky/y74YRTI5dBypoN0jYq1coJ0SQJKu/xCo2q/0UOSPNfhQXQuzcSVw3LAyxsru2Jf/HlzWwG+5uv1E99jtJWy/dnODQNy48e241dtd72tkBRDEggmVCeePm5s38kY/UdNcygK0xfFhXtplnq2vGiZcT9F44g6KTIeRXr6XHPqiTsW7SYQPeu+p1lF5IgNTOj7E/7UlsHs9l0tB+KGcSKh2fP43JhCEqV1MizyGDLuC/SqkT2Jq/ObXj8/4Drsvf/ZjjTGjDD8e7ZJuFRwzli3u0HkQf/3Xw9t7CC+P3tZiIgrI441xxT+a2An3whWrNFpGb0+nCyuacdXDyidQSKRq1et8IshabzUfspoH1tKVp9AVod5Zbw3uJJUus8n0HzWmAFKTynRvXGUDiD0Aj71WDfc= 30 | file: /home/travis/build/HostsTools/Android/app/build/outputs/apk/app-release.apk 31 | on: 32 | tags: true 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AndroidGoogleHost 2 | 方便Root了的Android手机 随时获取更新最新的GoogleHost 3 | 4 | [下载科学HostApk](https://github.com/HostsTools/Android/releases/download/1.0/app-release.apk) 5 | 6 | # Host来源 7 | Host来自于:[racaljk/hosts](https://github.com/racaljk/hosts) 8 | 9 | [host下载地址](https://coding.net/u/scaffrey/p/hosts/git/raw/master/hosts) 10 | 11 | 12 | # 注意: 13 | 由于Android的安全机制原因, 只有Root了的手机才能修改 Host文件 14 | 15 | #其他: 16 | 修改Host root相关的操作使用的是[RootTool](https://github.com/Stericson/RootTools) 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | applicationId "com.imczy.googlehost" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | signingConfigs { 15 | debug { 16 | 17 | } 18 | 19 | release { 20 | storeFile 21 | storePassword 22 | keyAlias 23 | keyPassword 24 | } 25 | 26 | } 27 | 28 | getSigningProperties() 29 | 30 | buildTypes { 31 | release { 32 | minifyEnabled false 33 | zipAlignEnabled true 34 | shrinkResources true // 移除无用的resource文件 35 | signingConfig signingConfigs.release 36 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 37 | } 38 | } 39 | } 40 | 41 | dependencies { 42 | compile fileTree(dir: 'libs', include: ['*.jar']) 43 | testCompile 'junit:junit:4.12' 44 | compile 'com.android.support:appcompat-v7:23.2.1' 45 | compile 'com.loopj.android:android-async-http:1.4.9' 46 | 47 | } 48 | 49 | def getSigningProperties(){ 50 | def propFile = file('../local.properties') 51 | if (propFile.canRead()){ 52 | def Properties props = new Properties() 53 | props.load(new FileInputStream(propFile)) 54 | if (props!=null && props.containsKey('key.store') && props.containsKey('key.store.password') && 55 | props.containsKey('key.alias')) { 56 | android.signingConfigs.release.storeFile = file(props['key.store']) 57 | android.signingConfigs.release.storePassword = props['key.store.password'] 58 | android.signingConfigs.release.keyAlias = props['key.alias'] 59 | android.signingConfigs.release.keyPassword = props['key.store.password'] 60 | } else { 61 | println 'local.properties found but some entries are missing' 62 | android.buildTypes.release.signingConfig = null 63 | } 64 | }else { 65 | println 'local.properties not found' 66 | android.buildTypes.release.signingConfig = null 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/libs/RootTools.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HostsTools/Android/7af61078cc7cf80ad163f4f068af16abaa7e9159/app/libs/RootTools.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/chenzhiyong/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/imczy/googlehost/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.imczy.googlehost; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/imczy/googlehost/AboutActivity.java: -------------------------------------------------------------------------------- 1 | package com.imczy.googlehost; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.text.Html; 6 | import android.text.method.LinkMovementMethod; 7 | import android.widget.TextView; 8 | 9 | /** 10 | * Created by chenzhiyong on 16/4/17. 11 | */ 12 | public class AboutActivity extends AppCompatActivity { 13 | 14 | 15 | TextView mAboutTxt, mHostGithubTxt, mAppGithubTxt; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_about); 21 | mAboutTxt = (TextView) findViewById(R.id.tips); 22 | mHostGithubTxt = (TextView) findViewById(R.id.host_github_txt); 23 | mAppGithubTxt = (TextView) findViewById(R.id.app_github_txt); 24 | 25 | String aboutText = getString(R.string.about_detail); 26 | String hostGithub = getString(R.string.host_github); 27 | String appGithub = getString(R.string.app_github); 28 | 29 | mAboutTxt.setText(Html.fromHtml(aboutText)); 30 | mHostGithubTxt.setText(Html.fromHtml(hostGithub)); 31 | mAppGithubTxt.setText(Html.fromHtml(appGithub)); 32 | 33 | mAboutTxt.setMovementMethod(LinkMovementMethod.getInstance()); 34 | mAppGithubTxt.setMovementMethod(LinkMovementMethod.getInstance()); 35 | mAppGithubTxt.setMovementMethod(LinkMovementMethod.getInstance()); 36 | 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/imczy/googlehost/Constants.java: -------------------------------------------------------------------------------- 1 | package com.imczy.googlehost; 2 | 3 | /** 4 | * Created by chenzhiyong on 16/4/17. 5 | */ 6 | public interface Constants { 7 | 8 | String SYSTEM_HOST_FILE_PATH = "/system/etc/hosts"; 9 | String VOID_HOST_NAME = "void_host"; 10 | String DOWNLOAD_HOST_NAME = "download_host"; 11 | String VOID_HOST_VALUE = "127.0.0.1 localhost"; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/imczy/googlehost/HostDetailActivity.java: -------------------------------------------------------------------------------- 1 | package com.imczy.googlehost; 2 | 3 | import android.app.ProgressDialog; 4 | import android.os.AsyncTask; 5 | import android.os.Bundle; 6 | import android.os.Handler; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.View; 9 | import android.widget.ProgressBar; 10 | import android.widget.TextView; 11 | 12 | import com.imczy.googlehost.util.CloseUtil; 13 | 14 | import java.io.BufferedReader; 15 | import java.io.File; 16 | import java.io.FileReader; 17 | 18 | /** 19 | * Created by chenzhiyong on 16/4/17. 20 | */ 21 | public class HostDetailActivity extends AppCompatActivity { 22 | private static final String TAG = "HostDetailActivity"; 23 | 24 | TextView mTextView; 25 | ProgressDialog mProgressDialog; 26 | StringBuffer hostString = new StringBuffer(); 27 | 28 | Handler mHandler = new Handler(); 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_detail); 34 | mTextView = (TextView) findViewById(R.id.detail_txt); 35 | 36 | 37 | showProgressDialog(); 38 | AsyncTask.execute(new Runnable() { 39 | @Override 40 | public void run() { 41 | File host = new File(Constants.SYSTEM_HOST_FILE_PATH); 42 | BufferedReader bre = null; 43 | try { 44 | bre = new BufferedReader(new FileReader(host));//此时获取到的bre就是整个文件的缓存流 45 | String str; 46 | while ((str = bre.readLine()) != null) { // 判断最后一行不存在,为空结束循环 47 | hostString.append(str).append("\n"); 48 | } 49 | 50 | mHandler.postDelayed(new Runnable() { 51 | @Override 52 | public void run() { 53 | // 延迟显示 mTextView 不然会卡在 启动 Activity 页面 54 | mTextView.setText(hostString); 55 | 56 | mHandler.postDelayed(new Runnable() { 57 | @Override 58 | public void run() { 59 | // 延迟 dialog 消失 显示 大量的Host 需要时间 60 | dismissDialog(); 61 | } 62 | }, 300); 63 | } 64 | }, 300); 65 | } catch (Exception e) { 66 | showProgressDialog(); 67 | e.printStackTrace(); 68 | } finally { 69 | CloseUtil.close(bre); 70 | } 71 | } 72 | }); 73 | 74 | } 75 | 76 | private void showProgressDialog() { 77 | if (mProgressDialog == null) { 78 | mProgressDialog = new ProgressDialog(this); 79 | } 80 | mProgressDialog.setTitle(""); 81 | mProgressDialog.setMessage(getString(R.string.loading)); 82 | mProgressDialog.show(); 83 | } 84 | 85 | private void dismissDialog() { 86 | if (mProgressDialog == null) { 87 | return; 88 | } 89 | mProgressDialog.dismiss(); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/imczy/googlehost/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.imczy.googlehost; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.AsyncTask; 7 | import android.os.Bundle; 8 | import android.os.Handler; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.util.Log; 11 | import android.view.Menu; 12 | import android.view.MenuItem; 13 | import android.view.View; 14 | import android.widget.Button; 15 | import android.widget.TextView; 16 | import android.widget.Toast; 17 | 18 | import com.imczy.googlehost.util.CloseUtil; 19 | import com.imczy.googlehost.util.DownloadUtil; 20 | import com.stericson.RootShell.RootShell; 21 | import com.stericson.RootTools.RootTools; 22 | 23 | import java.io.File; 24 | import java.io.FileWriter; 25 | 26 | public class MainActivity extends AppCompatActivity { 27 | private static final String TAG = "MainActivity"; 28 | 29 | Button mProxyHostBtn, cleanHostBtn, readHostBtn; 30 | TextView tipsView; 31 | 32 | ProgressDialog mProgressDialog; 33 | Handler mHandler = new Handler(); 34 | 35 | private boolean isMobileRoot = false; 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | setContentView(R.layout.activity_main); 41 | 42 | mProxyHostBtn = (Button) findViewById(R.id.proxy_btn); 43 | cleanHostBtn = (Button) findViewById(R.id.clean_host); 44 | readHostBtn = (Button) findViewById(R.id.read_host); 45 | tipsView = (TextView) findViewById(R.id.tips); 46 | 47 | mProxyHostBtn.setOnClickListener(new View.OnClickListener() { 48 | @Override 49 | public void onClick(View v) { 50 | if (!isMobileRoot) { 51 | Toast.makeText(getContext(), R.string.get_root_fail, Toast.LENGTH_SHORT).show(); 52 | return; 53 | } 54 | 55 | showProgressDialog(); 56 | DownloadUtil.downloadHostFile(MainActivity.this, new DownloadUtil.DownloadListener() { 57 | @Override 58 | public void success(final File file) { 59 | Log.e(TAG, "success: Thread = " + Thread.currentThread()); 60 | // 需要host 61 | AsyncTask.execute(new Runnable() { 62 | @Override 63 | public void run() { 64 | try { 65 | RootShell.getShell(true); 66 | } catch (Exception e) { 67 | mHandler.post(new Runnable() { 68 | @Override 69 | public void run() { 70 | dismissDialog(); 71 | } 72 | }); 73 | e.printStackTrace(); 74 | } 75 | 76 | try { 77 | RootTools.copyFile(file.getAbsolutePath(), "/system/etc/hosts", true, false); 78 | } catch (Exception e) { 79 | e.printStackTrace(); 80 | } 81 | mHandler.post(new Runnable() { 82 | @Override 83 | public void run() { 84 | Toast.makeText(getContext(), R.string.get_last_host_tips, Toast.LENGTH_SHORT).show(); 85 | dismissDialog(); 86 | } 87 | }); 88 | } 89 | }); 90 | } 91 | 92 | @Override 93 | public void error() { 94 | mHandler.post(new Runnable() { 95 | @Override 96 | public void run() { 97 | Toast.makeText(getContext(), R.string.network_error, Toast.LENGTH_SHORT).show(); 98 | dismissDialog(); 99 | } 100 | }); 101 | } 102 | }); 103 | } 104 | }); 105 | 106 | cleanHostBtn.setOnClickListener(new View.OnClickListener() { 107 | @Override 108 | public void onClick(View v) { 109 | if (!isMobileRoot) { 110 | Toast.makeText(getContext(), R.string.get_root_fail, Toast.LENGTH_SHORT).show(); 111 | return; 112 | } 113 | 114 | AsyncTask.execute(new Runnable() { 115 | @Override 116 | public void run() { 117 | try { 118 | RootShell.getShell(true); 119 | } catch (Exception e) { 120 | mHandler.post(new Runnable() { 121 | @Override 122 | public void run() { 123 | dismissDialog(); 124 | } 125 | }); 126 | e.printStackTrace(); 127 | } 128 | RootTools.copyFile(getVoidHostPath(), "/system/etc/hosts", true, false); 129 | mHandler.post(new Runnable() { 130 | @Override 131 | public void run() { 132 | Toast.makeText(getContext(), R.string.huifu_host_tips, Toast.LENGTH_SHORT).show(); 133 | } 134 | }); 135 | 136 | } 137 | }); 138 | } 139 | }); 140 | 141 | readHostBtn.setOnClickListener(new View.OnClickListener() { 142 | @Override 143 | public void onClick(View v) { 144 | Intent intent = new Intent(getContext(), HostDetailActivity.class); 145 | startActivity(intent); 146 | } 147 | }); 148 | 149 | initVoidHost(); 150 | checkMobileIsRoot(); 151 | 152 | } 153 | 154 | private void checkMobileIsRoot() { 155 | AsyncTask.execute(new Runnable() { 156 | @Override 157 | public void run() { 158 | isMobileRoot = RootShell.isRootAvailable(); 159 | if (!isMobileRoot) { 160 | mHandler.post(new Runnable() { 161 | @Override 162 | public void run() { 163 | tipsView.setText(getString(R.string.your_mobile_have_no_root)); 164 | mProxyHostBtn.setEnabled(false); 165 | cleanHostBtn.setEnabled(false); 166 | } 167 | }); 168 | } 169 | } 170 | }); 171 | } 172 | 173 | 174 | private void showProgressDialog() { 175 | if (mProgressDialog == null) { 176 | mProgressDialog = new ProgressDialog(getContext()); 177 | } 178 | mProgressDialog.setTitle(""); 179 | mProgressDialog.setMessage(getString(R.string.loading)); 180 | mProgressDialog.show(); 181 | } 182 | 183 | private void dismissDialog() { 184 | if (mProgressDialog == null) { 185 | return; 186 | } 187 | mProgressDialog.dismiss(); 188 | } 189 | 190 | 191 | public String getRealFileDirPath() { 192 | File dir = getFilesDir(); 193 | if (!dir.exists()) { 194 | dir.mkdirs(); 195 | } 196 | return dir.getAbsolutePath(); 197 | } 198 | 199 | private String getVoidHostPath() { 200 | return getRealFileDirPath() + File.separator + Constants.VOID_HOST_NAME; 201 | } 202 | 203 | private Context getContext() { 204 | return this; 205 | } 206 | 207 | private void initVoidHost() { 208 | File voidHostFile = new File(getVoidHostPath()); 209 | if (voidHostFile.exists()) { 210 | return; 211 | } 212 | AsyncTask.execute(new Runnable() { 213 | @Override 214 | public void run() { 215 | File file = new File(getRealFileDirPath() + File.separator + Constants.VOID_HOST_NAME); 216 | FileWriter fileWriter = null; 217 | try { 218 | fileWriter = new FileWriter(file); 219 | fileWriter.write(Constants.VOID_HOST_VALUE); 220 | fileWriter.flush(); 221 | } catch (Exception e) { 222 | e.printStackTrace(); 223 | } finally { 224 | CloseUtil.close(fileWriter); 225 | } 226 | } 227 | }); 228 | } 229 | 230 | @Override 231 | public boolean onCreateOptionsMenu(Menu menu) { 232 | getMenuInflater().inflate(R.menu.menu_main, menu); 233 | return true; 234 | } 235 | 236 | @Override 237 | public boolean onOptionsItemSelected(MenuItem item) { 238 | int id = item.getItemId(); 239 | 240 | if (id == R.id.action_about) { 241 | startActivity(new Intent(this, AboutActivity.class)); 242 | return true; 243 | } 244 | 245 | return super.onOptionsItemSelected(item); 246 | } 247 | 248 | 249 | } 250 | -------------------------------------------------------------------------------- /app/src/main/java/com/imczy/googlehost/util/CloseUtil.java: -------------------------------------------------------------------------------- 1 | package com.imczy.googlehost.util; 2 | 3 | import java.io.Closeable; 4 | import java.io.IOException; 5 | 6 | /** 7 | * Created by chenzhiyong on 16/4/17. 8 | */ 9 | public class CloseUtil { 10 | 11 | public static void close(Closeable closeable) { 12 | if (closeable != null) { 13 | try { 14 | closeable.close(); 15 | } catch (IOException e) { 16 | e.printStackTrace(); 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/imczy/googlehost/util/DownloadUtil.java: -------------------------------------------------------------------------------- 1 | package com.imczy.googlehost.util; 2 | 3 | import android.content.Context; 4 | import android.os.AsyncTask; 5 | 6 | import com.imczy.googlehost.Constants; 7 | import com.loopj.android.http.AsyncHttpClient; 8 | import com.loopj.android.http.AsyncHttpResponseHandler; 9 | 10 | import java.io.File; 11 | import java.io.FileOutputStream; 12 | import java.io.IOException; 13 | import java.io.OutputStream; 14 | 15 | import cz.msebera.android.httpclient.Header; 16 | 17 | /** 18 | * Created by chenzhiyong on 16/4/17. 19 | */ 20 | public class DownloadUtil { 21 | private static final String TAG = "DownloadUtil"; 22 | 23 | public static void downloadHostFile(final Context context, final DownloadListener downloadListener) { 24 | AsyncHttpClient mClient = new AsyncHttpClient(); 25 | //TODO umeng配置下载链接 26 | String url = "https://raw.githubusercontent.com/googlehosts/hosts/master/hosts-files/hosts"; 27 | mClient.get(context, url, new AsyncHttpResponseHandler() { 28 | @Override 29 | public void onSuccess(int statusCode, final Header[] headers, final byte[] bytes) { 30 | AsyncTask.execute(new Runnable() { 31 | @Override 32 | public void run() { 33 | OutputStream os = null; 34 | try { 35 | long totalLength = 0; 36 | for (int i = 0; i < headers.length; i++) { 37 | Header header = headers[i]; 38 | if ("Content-Length".equals(header.getName())) { 39 | try { 40 | totalLength = Long.parseLong(header.getValue()); 41 | } catch (Exception e) { 42 | e.printStackTrace(); 43 | } 44 | } 45 | } 46 | 47 | if (bytes == null || bytes.length < totalLength) { 48 | downloadListener.error(); 49 | return; 50 | } 51 | 52 | File saveDir = context.getFilesDir(); 53 | if (!saveDir.exists()) { 54 | saveDir.mkdirs(); 55 | } 56 | 57 | File hostFile = new File(saveDir.getAbsolutePath() + File.separator + Constants.DOWNLOAD_HOST_NAME); 58 | os = new FileOutputStream(hostFile); 59 | os.write(bytes); 60 | downloadListener.success(hostFile); 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | downloadListener.error(); 64 | } finally { 65 | if (os != null) { 66 | try { 67 | os.close(); 68 | } catch (IOException e) { 69 | e.printStackTrace(); 70 | } 71 | } 72 | } 73 | } 74 | }); 75 | } 76 | 77 | @Override 78 | public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { 79 | downloadListener.error(); 80 | } 81 | }).setTag(url); 82 | } 83 | 84 | 85 | public interface DownloadListener { 86 | void success(File file); 87 | 88 | void error(); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/imczy/googlehost/util/IOUtil.java: -------------------------------------------------------------------------------- 1 | package com.imczy.googlehost.util; 2 | 3 | import android.content.Context; 4 | import android.os.Environment; 5 | 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | 12 | /** 13 | * Created by chenzhiyong on 16/4/15. 14 | */ 15 | public class IOUtil { 16 | public static String getBaseLocalLocation(Context context) { 17 | boolean isSDCanRead = IOUtil.getExternalStorageState(); 18 | String baseLocation = ""; 19 | if (isSDCanRead) { 20 | baseLocation = IOUtil.getSDCardPath(); 21 | } else { 22 | baseLocation = context.getFilesDir().getAbsolutePath(); 23 | } 24 | return baseLocation; 25 | } 26 | 27 | public static boolean getExternalStorageState() { 28 | String state = Environment.getExternalStorageState(); 29 | if (Environment.MEDIA_MOUNTED.equals(state)) { 30 | return true; 31 | } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 32 | return false; 33 | } else { 34 | return false; 35 | } 36 | } 37 | 38 | public static String getSDCardPath() { 39 | return Environment.getExternalStorageDirectory().toString(); 40 | } 41 | 42 | public static boolean copyFile(File srcFile, File destFile) { 43 | boolean result = false; 44 | try { 45 | InputStream in = new FileInputStream(srcFile); 46 | try { 47 | result = copyToFile(in, destFile); 48 | } finally { 49 | in.close(); 50 | } 51 | } catch (IOException e) { 52 | e.printStackTrace(); 53 | result = false; 54 | } 55 | return result; 56 | } 57 | 58 | /** 59 | * Copy data from a source stream to destFile. Return true if succeed, return false if failed. 60 | */ 61 | public static boolean copyToFile(InputStream inputStream, File destFile) { 62 | try { 63 | if (destFile.exists()) { 64 | destFile.delete(); 65 | } 66 | FileOutputStream out = new FileOutputStream(destFile); 67 | try { 68 | byte[] buffer = new byte[4096]; 69 | int bytesRead; 70 | while ((bytesRead = inputStream.read(buffer)) >= 0) { 71 | out.write(buffer, 0, bytesRead); 72 | } 73 | } finally { 74 | out.flush(); 75 | try { 76 | out.getFD().sync(); 77 | } catch (IOException e) { 78 | } 79 | out.close(); 80 | } 81 | return true; 82 | } catch (IOException e) { 83 | e.printStackTrace(); 84 | return false; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 19 | 20 | 26 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 |