├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── cn │ │ └── demo │ │ └── appq │ │ ├── App.java │ │ ├── Interceptor │ │ └── NetHttpInject.java │ │ ├── activity │ │ ├── DescriptionActivity.java │ │ └── VPNActivity.java │ │ ├── adapter │ │ ├── UrlAdapter.java │ │ └── UrlViewHolder.java │ │ ├── entity │ │ └── ReqEntity.java │ │ ├── greendao │ │ ├── DaoMaster.java │ │ ├── DaoSession.java │ │ └── ReqEntityDao.java │ │ ├── presenter │ │ ├── BasePresenter.java │ │ └── NetBarePresenter.java │ │ ├── service │ │ └── AppService.java │ │ ├── utils │ │ ├── Base64Utils.java │ │ ├── CustomizeDecoder.java │ │ ├── DBManager.java │ │ ├── DecoderHandler.java │ │ ├── IDecoder.java │ │ ├── IOUtils.java │ │ └── ZLibUtils.java │ │ └── view │ │ ├── FastScrollView.java │ │ └── NetBareView.java │ └── res │ ├── drawable-hdpi │ ├── ic_action_name.png │ ├── ic_delete_name.png │ ├── ic_info_name.png │ ├── ic_menu_name.png │ ├── ic_restore.png │ ├── ic_serch.png │ ├── ic_setting_name.png │ └── ic_start_name.png │ ├── drawable-mdpi │ ├── ic_action_name.png │ ├── ic_delete_name.png │ ├── ic_info_name.png │ ├── ic_menu_name.png │ ├── ic_restore.png │ ├── ic_serch.png │ ├── ic_setting_name.png │ └── ic_start_name.png │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable-xhdpi │ ├── ic_action_name.png │ ├── ic_delete_name.png │ ├── ic_info_name.png │ ├── ic_menu_name.png │ ├── ic_restore.png │ ├── ic_serch.png │ ├── ic_setting_name.png │ ├── ic_start_name.png │ └── netbare_notification.png │ ├── drawable-xxhdpi │ ├── ic_action_name.png │ ├── ic_delete_name.png │ ├── ic_info_name.png │ ├── ic_menu_name.png │ ├── ic_restore.png │ ├── ic_serch.png │ ├── ic_setting_name.png │ ├── ic_start_name.png │ └── netbare_notification.png │ ├── drawable-xxxhdpi │ ├── ic_action_name.png │ ├── ic_delete_name.png │ ├── ic_info_name.png │ ├── ic_menu_name.png │ ├── ic_restore.png │ ├── ic_serch.png │ ├── ic_setting_name.png │ ├── ic_start_name.png │ └── netbare_notification.png │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_description.xml │ ├── activity_main.xml │ ├── activity_v_p_n.xml │ └── item_url_logs.xml │ ├── menu │ ├── bottom_nav_menu.xml │ └── desc_activity_menu.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ ├── ic_launcher_unknow.png │ └── ic_send_white_18dp.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ ├── ic_launcher_unknow.png │ └── ic_send_white_18dp.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ ├── ic_launcher_unknow.png │ └── ic_send_white_18dp.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_unknow.png │ └── ic_send_white_18dp.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_unknow.png │ └── ic_send_white_18dp.png │ ├── navigation │ └── nav_graph.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── netbare-core ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── github │ │ └── megatronking │ │ └── netbare │ │ ├── NetBare.java │ │ ├── NetBareConfig.java │ │ ├── NetBareListener.java │ │ ├── NetBareLog.java │ │ ├── NetBareService.java │ │ ├── NetBareThread.java │ │ ├── NetBareUtils.java │ │ ├── NetBareVirtualGateway.java │ │ ├── NetBareXLog.java │ │ ├── gateway │ │ ├── AbstractRequestChain.java │ │ ├── AbstractResponseChain.java │ │ ├── DefaultVirtualGateway.java │ │ ├── DefaultVirtualGatewayFactory.java │ │ ├── IndexedInterceptor.java │ │ ├── Interceptor.java │ │ ├── InterceptorChain.java │ │ ├── InterceptorFactory.java │ │ ├── PendingIndexedInterceptor.java │ │ ├── Request.java │ │ ├── RequestChain.java │ │ ├── Response.java │ │ ├── ResponseChain.java │ │ ├── SSLCodecInterceptor.java │ │ ├── SSLRefluxInterceptor.java │ │ ├── SessionTunnelFlow.java │ │ ├── SpecVirtualGateway.java │ │ ├── TunnelFlow.java │ │ ├── VirtualGateway.java │ │ └── VirtualGatewayFactory.java │ │ ├── http │ │ ├── ContainerHttpInterceptor.java │ │ ├── Http2SniffInterceptor.java │ │ ├── HttpHeaderParseInterceptor.java │ │ ├── HttpHeaderSeparateInterceptor.java │ │ ├── HttpHeaderSniffInterceptor.java │ │ ├── HttpId.java │ │ ├── HttpIndexedInterceptor.java │ │ ├── HttpInterceptor.java │ │ ├── HttpInterceptorFactory.java │ │ ├── HttpInterceptorsFactory.java │ │ ├── HttpMethod.java │ │ ├── HttpMultiplexInterceptor.java │ │ ├── HttpPendingIndexedInterceptor.java │ │ ├── HttpProtocol.java │ │ ├── HttpRequest.java │ │ ├── HttpRequestChain.java │ │ ├── HttpResponse.java │ │ ├── HttpResponseChain.java │ │ ├── HttpSSLCodecInterceptor.java │ │ ├── HttpSSLRefluxInterceptor.java │ │ ├── HttpSSLRequestCodec.java │ │ ├── HttpSSLResponseCodec.java │ │ ├── HttpSession.java │ │ ├── HttpSessionFactory.java │ │ ├── HttpSniffInterceptor.java │ │ ├── HttpVirtualGateway.java │ │ ├── HttpVirtualGatewayFactory.java │ │ ├── HttpZygoteRequest.java │ │ └── HttpZygoteResponse.java │ │ ├── http2 │ │ ├── DecodeCallback.java │ │ ├── EncodeCallback.java │ │ ├── ErrorCode.java │ │ ├── FrameType.java │ │ ├── Hpack.java │ │ ├── Http2.java │ │ ├── Http2DecodeInterceptor.java │ │ ├── Http2EncodeInterceptor.java │ │ ├── Http2Settings.java │ │ ├── Http2Stream.java │ │ ├── Http2Updater.java │ │ └── Huffman.java │ │ ├── ip │ │ ├── Header.java │ │ ├── IcmpHeader.java │ │ ├── IpAddress.java │ │ ├── IpHeader.java │ │ ├── Protocol.java │ │ ├── TcpHeader.java │ │ └── UdpHeader.java │ │ ├── net │ │ ├── DumpCallback.java │ │ ├── Net.java │ │ ├── Session.java │ │ ├── SessionProvider.java │ │ ├── UidDumper.java │ │ └── UidProvider.java │ │ ├── proxy │ │ ├── BaseProxyServer.java │ │ ├── IcmpProxyServerForwarder.java │ │ ├── ProxyServer.java │ │ ├── ProxyServerForwarder.java │ │ ├── TcpProxyServer.java │ │ ├── TcpProxyServerForwarder.java │ │ ├── UdpProxyServer.java │ │ └── UdpProxyServerForwarder.java │ │ ├── ssl │ │ ├── CertificateGenerator.java │ │ ├── CertificateInstallActivity.java │ │ ├── JKS.java │ │ ├── SSLCodec.java │ │ ├── SSLEngineFactory.java │ │ ├── SSLKeyManagerProvider.java │ │ ├── SSLRefluxCallback.java │ │ ├── SSLRequestCodec.java │ │ ├── SSLResponseCodec.java │ │ ├── SSLTrustManagerProvider.java │ │ ├── SSLUtils.java │ │ └── SSLWhiteList.java │ │ ├── tcp │ │ └── TcpVirtualGateway.java │ │ ├── tunnel │ │ ├── ConnectionShutdownException.java │ │ ├── NioCallback.java │ │ ├── NioTunnel.java │ │ ├── TcpProxyTunnel.java │ │ ├── TcpRemoteTunnel.java │ │ ├── TcpTunnel.java │ │ ├── TcpVATunnel.java │ │ ├── Tunnel.java │ │ ├── UdpRemoteTunnel.java │ │ ├── UdpTunnel.java │ │ ├── UdpVATunnel.java │ │ └── VirtualGatewayTunnel.java │ │ ├── udp │ │ └── UdpVirtualGateway.java │ │ └── ws │ │ ├── WebSocketCallback.java │ │ ├── WebSocketProtocol.java │ │ └── WebSocketReader.java │ └── res │ └── values │ └── styles.xml ├── netbare-injector ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── github │ └── megatronking │ └── netbare │ ├── http │ ├── Cookie.java │ ├── HttpBody.java │ ├── HttpHeaderPart.java │ ├── HttpInjectInterceptor.java │ ├── HttpRawBody.java │ ├── HttpRequestHeaderPart.java │ ├── HttpRequestInjectorCallback.java │ ├── HttpResponseHeaderPart.java │ └── HttpResponseInjectorCallback.java │ ├── injector │ ├── BlockedHttpInjector.java │ ├── HttpInjector.java │ ├── InjectorCallback.java │ └── SimpleHttpInjector.java │ ├── io │ ├── ByteBufferInputStream.java │ └── HttpBodyInputStream.java │ ├── stream │ ├── BufferStream.java │ ├── ByteStream.java │ ├── Stream.java │ ├── StringStream.java │ └── TinyFileStream.java │ └── utils │ └── CaseInsensitiveLinkedMap.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | gradle.properties 9 | gradlew 10 | gradlew.bat 11 | .externalNativeBuild 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2019 Megatron King 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aether 2 | 3 | ## About 4 | 5 | 依赖于 [NetBare](https://github.com/MegatronKing/NetBare) 之上的抓包工具,启动抓包后,电脑可访问 http://手机ip:8080 查看抓包结果。 6 | 7 | ## 目前实现的功能 8 | 9 | 1. 手机app流量消耗排行。 10 | 2. 实时手机请求抓取。 11 | 3. 网络访问host流量消耗排行。 12 | 4. 直接在手机端展示请求列表。 13 | 5. 自定义过滤功能。 14 | 6. Gzip识别自动解码。 15 | 16 | ## 后续计划 17 | 18 | 1. 图片、音视频相关支持。 19 | 2. 界面优化。 20 | 3. 抓包能力提升。 21 | 4. 模拟信息相关。 22 | 23 | 24 | > android 11 自动安装证书被禁止,需要手动安装证书 25 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'org.greenrobot.greendao' // 应用插件 3 | greendao { 4 | // 指定数据库schema版本号,迁移等操作会用到 5 | schemaVersion 2 6 | // 设置生成数据库文件的目录,默认是在build中,可以将生成的文件放到我们的java目录中 7 | targetGenDir 'src/main/java' 8 | // 设置生成的数据库相关文件的包名,默认为entity所在的包名 9 | daoPackage 'cn.demo.appq.greendao' 10 | } 11 | 12 | android { 13 | compileSdkVersion 29 14 | buildToolsVersion "29.0.3" 15 | defaultConfig { 16 | applicationId "com.good.vpn" 17 | minSdkVersion 21 18 | targetSdkVersion 29 19 | versionCode 1 20 | versionName "1.0" 21 | } 22 | buildTypes { 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | compileOptions { 29 | sourceCompatibility JavaVersion.VERSION_1_7 30 | targetCompatibility JavaVersion.VERSION_1_7 31 | } 32 | aaptOptions { 33 | cruncherEnabled = false 34 | useNewCruncher = false 35 | } 36 | lintOptions { 37 | checkReleaseBuilds false 38 | abortOnError false 39 | warningsAsErrors false 40 | disable "UnusedResources" 41 | textOutput "stdout" 42 | textReport false 43 | disable 'RestrictedApi' 44 | } 45 | } 46 | 47 | tasks.withType(Javadoc) { 48 | options.addStringOption('Xdoclint:none', '-quiet') 49 | options.addStringOption('encoding', 'UTF-8') 50 | options.addStringOption('charSet', 'UTF-8') 51 | } 52 | 53 | 54 | dependencies { 55 | implementation fileTree(dir: 'libs', include: ['*.jar']) 56 | implementation 'me.weishu:free_reflection:1.2.0' 57 | implementation 'com.amitshekhar.android:debug-db:1.0.6' 58 | // NetBare libraries 59 | implementation project(':netbare-core') 60 | implementation project(':netbare-injector') 61 | implementation 'com.android.support:appcompat-v7:28.0.0' 62 | implementation 'org.greenrobot:greendao:3.2.2' 63 | implementation 'com.blankj:utilcode:1.29.0' 64 | implementation 'com.android.support:design:28.0.0' 65 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 66 | implementation 'android.arch.navigation:navigation-fragment:1.0.0' 67 | implementation 'android.arch.navigation:navigation-ui:1.0.0' 68 | implementation 'com.github.clans:fab:1.6.4' 69 | } 70 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/App.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import com.github.megatronking.netbare.NetBare; 7 | import com.github.megatronking.netbare.NetBareUtils; 8 | import com.github.megatronking.netbare.ssl.JKS; 9 | 10 | import me.weishu.reflection.Reflection; 11 | 12 | public class App extends Application { 13 | 14 | public static final String JSK_ALIAS = "MyVPNSample"; 15 | 16 | 17 | private static JKS mJKS = null; 18 | 19 | private static Context mContext; 20 | 21 | 22 | @Override 23 | public void onCreate() { 24 | super.onCreate(); 25 | mContext = this; 26 | // 创建自签证书 27 | mJKS = new JKS(this, JSK_ALIAS, JSK_ALIAS.toCharArray(), JSK_ALIAS, JSK_ALIAS, 28 | JSK_ALIAS, JSK_ALIAS, JSK_ALIAS); 29 | // 初始化NetBare 30 | NetBare.get().attachApplication(this, true); 31 | } 32 | 33 | public static JKS getJKS() { 34 | return mJKS; 35 | } 36 | 37 | @Override 38 | protected void attachBaseContext(Context base) { 39 | super.attachBaseContext(base); 40 | // On android Q, we can't access Java8EngineWrapper with reflect. 41 | if (NetBareUtils.isAndroidQ()) { 42 | Reflection.unseal(base); 43 | } 44 | } 45 | 46 | public static String getProcessNameByUid(int uid) { 47 | return mContext.getPackageManager().getNameForUid(uid); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/adapter/UrlAdapter.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq.adapter; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v7.recyclerview.extensions.ListAdapter; 5 | import android.support.v7.util.DiffUtil; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import cn.demo.appq.R; 11 | import cn.demo.appq.entity.ReqEntity; 12 | 13 | public class UrlAdapter extends ListAdapter { 14 | 15 | public UrlAdapter() { 16 | this(new DiffUtil.ItemCallback() { 17 | @Override 18 | public boolean areItemsTheSame(@NonNull ReqEntity reqEntity, @NonNull ReqEntity t1) { 19 | return reqEntity.getId().equals(t1.getId()); 20 | } 21 | 22 | @Override 23 | public boolean areContentsTheSame(@NonNull ReqEntity reqEntity, @NonNull ReqEntity t1) { 24 | if (reqEntity.getId() != null && !reqEntity.getId().equals(t1.getId())) { 25 | return false; 26 | } 27 | if (reqEntity.getTime() != null && !reqEntity.getTime().equals(t1.getTime())) { 28 | return false; 29 | } 30 | if (reqEntity.getLength() != null && !reqEntity.getLength().equals(t1.getLength())) { 31 | return false; 32 | } 33 | if (reqEntity.getRespCode() != null && !reqEntity.getRespCode().equals(t1.getRespCode())) { 34 | return false; 35 | } 36 | return true; 37 | } 38 | }); 39 | } 40 | 41 | public UrlAdapter(@NonNull DiffUtil.ItemCallback diffCallback) { 42 | super(diffCallback); 43 | } 44 | 45 | @NonNull 46 | @Override 47 | public UrlViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { 48 | View view = LayoutInflater.from(viewGroup.getContext()) 49 | .inflate(R.layout.item_url_logs, 50 | null, false); 51 | return new UrlViewHolder(view); 52 | } 53 | 54 | @Override 55 | public void onBindViewHolder(@NonNull UrlViewHolder urlViewHolder, int i) { 56 | urlViewHolder.setData(getItem(i)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/adapter/UrlViewHolder.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq.adapter; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.drawable.Drawable; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.blankj.utilcode.util.ActivityUtils; 13 | import com.blankj.utilcode.util.AppUtils; 14 | import com.blankj.utilcode.util.TimeUtils; 15 | 16 | import java.util.Date; 17 | 18 | import cn.demo.appq.R; 19 | import cn.demo.appq.activity.DescriptionActivity; 20 | import cn.demo.appq.entity.ReqEntity; 21 | 22 | public class UrlViewHolder extends RecyclerView.ViewHolder { 23 | private final ImageView iv_icon; 24 | private final TextView tv_status; 25 | private final TextView tv_url; 26 | 27 | public UrlViewHolder(@NonNull View itemView) { 28 | super(itemView); 29 | iv_icon = itemView.findViewById(R.id.iv_icon); 30 | tv_status = itemView.findViewById(R.id.tv_status); 31 | tv_url = itemView.findViewById(R.id.tv_url); 32 | } 33 | 34 | public void setData(final ReqEntity data) { 35 | if (data == null) { 36 | return; 37 | } 38 | Drawable drawable = AppUtils.getAppIcon(data.getAppPackage()); 39 | if (drawable != null) { 40 | iv_icon.setImageDrawable(drawable); 41 | } 42 | tv_status.setText(data.getMethod() + " Status:" + data.getRespCode() + 43 | " Size:" + String.format("%.2f", (data.getLength() / 1024f)) + "KB" + 44 | " Time:" + TimeUtils.date2String(new Date(data.getTime()), "yyyy-MM-dd HH:mm:ss")); 45 | tv_url.setText(data.getUrl()); 46 | 47 | itemView.setOnClickListener(new View.OnClickListener() { 48 | @Override 49 | public void onClick(View v) { 50 | Bundle options = new Bundle(); 51 | options.putLong("id", data.getId()); 52 | ActivityUtils.startActivity(options, DescriptionActivity.class); 53 | } 54 | }); 55 | if (data.getRespCode() != null) { 56 | if (data.getRespCode() == 200) { 57 | itemView.setBackgroundColor(Color.parseColor("#99FF99")); 58 | } else { 59 | itemView.setBackgroundColor(Color.parseColor("#FF9999")); 60 | } 61 | } else { 62 | itemView.setBackgroundColor(Color.parseColor("#FFFFFF")); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/greendao/DaoSession.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq.greendao; 2 | 3 | import java.util.Map; 4 | 5 | import org.greenrobot.greendao.AbstractDao; 6 | import org.greenrobot.greendao.AbstractDaoSession; 7 | import org.greenrobot.greendao.database.Database; 8 | import org.greenrobot.greendao.identityscope.IdentityScopeType; 9 | import org.greenrobot.greendao.internal.DaoConfig; 10 | 11 | import cn.demo.appq.entity.ReqEntity; 12 | 13 | import cn.demo.appq.greendao.ReqEntityDao; 14 | 15 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. 16 | 17 | /** 18 | * {@inheritDoc} 19 | * 20 | * @see org.greenrobot.greendao.AbstractDaoSession 21 | */ 22 | public class DaoSession extends AbstractDaoSession { 23 | 24 | private final DaoConfig reqEntityDaoConfig; 25 | 26 | private final ReqEntityDao reqEntityDao; 27 | 28 | public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> 29 | daoConfigMap) { 30 | super(db); 31 | 32 | reqEntityDaoConfig = daoConfigMap.get(ReqEntityDao.class).clone(); 33 | reqEntityDaoConfig.initIdentityScope(type); 34 | 35 | reqEntityDao = new ReqEntityDao(reqEntityDaoConfig, this); 36 | 37 | registerDao(ReqEntity.class, reqEntityDao); 38 | } 39 | 40 | public void clear() { 41 | reqEntityDaoConfig.clearIdentityScope(); 42 | } 43 | 44 | public ReqEntityDao getReqEntityDao() { 45 | return reqEntityDao; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/presenter/BasePresenter.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq.presenter; 2 | 3 | public interface BasePresenter { 4 | void start(); 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/service/AppService.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq.service; 2 | 3 | import android.app.Notification; 4 | import android.app.NotificationChannel; 5 | import android.app.NotificationManager; 6 | import android.app.PendingIntent; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.graphics.BitmapFactory; 10 | import android.os.Build; 11 | import android.support.v4.app.NotificationCompat; 12 | 13 | import com.github.megatronking.netbare.NetBareService; 14 | 15 | import cn.demo.appq.R; 16 | import cn.demo.appq.activity.VPNActivity; 17 | 18 | public class AppService extends NetBareService { 19 | 20 | 21 | private String CHANNEL_ID = "cn.demo.appq.NOTIFICATION_CHANNEL_ID"; 22 | 23 | 24 | @Override 25 | public void onCreate() { 26 | super.onCreate(); 27 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 28 | NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 29 | if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) { 30 | notificationManager.createNotificationChannel( 31 | new NotificationChannel(CHANNEL_ID, getString(R.string.app_name), NotificationManager.IMPORTANCE_LOW)); 32 | } 33 | } 34 | } 35 | 36 | @Override 37 | protected int notificationId() { 38 | return 200; 39 | } 40 | 41 | @Override 42 | protected Notification createNotification() { 43 | 44 | Intent intent = new Intent(this, VPNActivity.class); 45 | intent.addCategory(Intent.CATEGORY_LAUNCHER); 46 | intent.setAction(Intent.ACTION_MAIN); 47 | PendingIntent pendingIntent = PendingIntent.getActivity( 48 | this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); 49 | 50 | 51 | return new NotificationCompat.Builder(this, CHANNEL_ID) 52 | .setSmallIcon(R.drawable.netbare_notification) 53 | .setContentTitle(getString(R.string.app_name)) 54 | .setContentText(getString(R.string.app_name)) 55 | .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)) 56 | .setOngoing(true) 57 | .setContentIntent(pendingIntent) 58 | .build(); 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/utils/CustomizeDecoder.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq.utils; 2 | 3 | import com.blankj.utilcode.util.EncodeUtils; 4 | import com.blankj.utilcode.util.GsonUtils; 5 | import com.blankj.utilcode.util.JsonUtils; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import cn.demo.appq.entity.ReqEntity; 11 | 12 | public class CustomizeDecoder implements IDecoder { 13 | @Override 14 | public ReqEntity decode(ReqEntity entity) { 15 | try { 16 | entity.setReqContent(JsonUtils.formatJson( 17 | EncodeUtils.urlDecode(new String(Base64Utils.decode(entity.getReqContent()))) 18 | , 2)); 19 | byte[] respData = Base64Utils.decode(entity.getRespContent()); 20 | 21 | Map> map = GsonUtils.fromJson(entity.getResponseHeaders(), Map.class); 22 | if (map.containsKey("Content-Encoding")) { 23 | String encodeType = map.get("Content-Encoding").get(0); 24 | if (encodeType.toLowerCase().equals("gzip")) { 25 | String s = ZLibUtils.uncompress(respData); 26 | entity.setRespContent( 27 | JsonUtils.formatJson( 28 | EncodeUtils.urlDecode(s), 2)); 29 | } else { 30 | entity.setRespContent( 31 | EncodeUtils.urlDecode( 32 | JsonUtils.formatJson(new String(respData), 2))); 33 | } 34 | } else { 35 | entity.setRespContent( 36 | EncodeUtils.urlDecode( 37 | JsonUtils.formatJson(new String(respData), 2))); 38 | } 39 | } catch (Exception e) { 40 | e.printStackTrace(); 41 | } 42 | return entity; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/utils/DBManager.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq.utils; 2 | 3 | 4 | import com.blankj.utilcode.util.Utils; 5 | 6 | import org.greenrobot.greendao.database.Database; 7 | 8 | import cn.demo.appq.greendao.DaoMaster; 9 | import cn.demo.appq.greendao.DaoSession; 10 | 11 | public class DBManager { 12 | private static volatile DaoSession instance = null; 13 | 14 | private DBManager() { 15 | } 16 | 17 | public static DaoSession getInstance() { 18 | if (instance == null) { 19 | synchronized (DBManager.class) { 20 | if (instance == null) { 21 | Database db = new DaoMaster.DevOpenHelper(Utils.getApp(), "log_db").getWritableDb(); 22 | DaoMaster daoMaster = new DaoMaster(db); 23 | //汇总APP使用流量排行 24 | daoMaster.getDatabase().execSQL( 25 | "CREATE VIEW IF NOT EXISTS APP_USAGE_TRAFFIC_RANK \n" + 26 | "AS\n" + 27 | "SELECT APP_NAME AS app_name," + 28 | "COUNT(*) AS req_count, " + 29 | "SUM(LENGTH) AS usage_net," + 30 | "MIN(TIME) AS begin_time\n" + 31 | "FROM NETWORK_REQUEST_DETAILED \n" + 32 | "GROUP BY APP_NAME \n" + 33 | "ORDER BY SUM(LENGTH) DESC;"); 34 | daoMaster.getDatabase().execSQL( 35 | "CREATE VIEW IF NOT EXISTS [HOST_USAGE_TRAFFIC_RANK]\n" + 36 | "AS\n" + 37 | "SELECT \n" + 38 | " APP_NAME AS app_name, \n" + 39 | " HOST AS host, \n" + 40 | " COUNT(*) AS req_count, \n" + 41 | " SUM(LENGTH) AS usage_net, \n" + 42 | " MIN(TIME) AS begin_time\n" + 43 | "FROM NETWORK_REQUEST_DETAILED\n" + 44 | "GROUP BY HOST\n" + 45 | "ORDER BY SUM(LENGTH) DESC;"); 46 | instance = daoMaster.newSession(); 47 | } 48 | } 49 | } 50 | return instance; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/utils/DecoderHandler.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq.utils; 2 | 3 | import cn.demo.appq.entity.ReqEntity; 4 | 5 | public class DecoderHandler { 6 | public static final IDecoder DEFAULT =new CustomizeDecoder(); 7 | private static volatile IDecoder instance = null; 8 | 9 | private DecoderHandler() { 10 | } 11 | 12 | public static IDecoder getDecoder() { 13 | if (instance == null) { 14 | synchronized (IDecoder.class) { 15 | if (instance == null) { 16 | instance = DEFAULT; 17 | } 18 | } 19 | } 20 | return instance; 21 | } 22 | 23 | public static void focusDecoder(IDecoder iDecoder) { 24 | if (iDecoder == null) { 25 | return; 26 | } 27 | instance = iDecoder; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/utils/IDecoder.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq.utils; 2 | 3 | import cn.demo.appq.entity.ReqEntity; 4 | 5 | public interface IDecoder { 6 | ReqEntity decode(ReqEntity entity) ; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/utils/IOUtils.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq.utils; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | public class IOUtils { 6 | public static String byteBuffer2String(ByteBuffer buffer) { 7 | if (buffer == null) { 8 | return null; 9 | } 10 | buffer.rewind(); 11 | byte[] bytes = new byte[buffer.limit() - buffer.position()]; 12 | buffer.get(bytes); 13 | return Base64Utils.encode(bytes); 14 | } 15 | 16 | public static ByteBuffer string2ByteBuffer(String value) { 17 | if (value == null) { 18 | return null; 19 | } 20 | byte[] data = Base64Utils.decode(value); 21 | if (data == null) { 22 | return ByteBuffer.allocate(0); 23 | } 24 | return ByteBuffer.wrap(data); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/view/FastScrollView.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ScrollView; 6 | 7 | import com.blankj.utilcode.util.ScreenUtils; 8 | 9 | public class FastScrollView extends ScrollView { 10 | 11 | public FastScrollView(Context context) { 12 | super(context); 13 | } 14 | 15 | public FastScrollView(Context context, AttributeSet attrs) { 16 | super(context, attrs); 17 | } 18 | 19 | public FastScrollView(Context context, AttributeSet attrs, int defStyleAttr) { 20 | super(context, attrs, defStyleAttr); 21 | } 22 | 23 | public FastScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 24 | super(context, attrs, defStyleAttr, defStyleRes); 25 | } 26 | 27 | @Override 28 | public void fling(int velocityY) { 29 | int viewHeight = getChildAt(0).getHeight(); 30 | int screenHeight = ScreenUtils.getScreenHeight(); 31 | if (viewHeight * 1.0f / screenHeight > 8) { 32 | super.fling((int) (velocityY * (viewHeight * 0.05f / screenHeight))); 33 | } else { 34 | super.fling(velocityY); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/cn/demo/appq/view/NetBareView.java: -------------------------------------------------------------------------------- 1 | package cn.demo.appq.view; 2 | 3 | import java.util.List; 4 | 5 | import cn.demo.appq.entity.ReqEntity; 6 | 7 | public interface NetBareView { 8 | void onQueryReqlogResult(List reqEntities); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-hdpi/ic_action_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_delete_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-hdpi/ic_delete_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_info_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-hdpi/ic_info_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-hdpi/ic_menu_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_restore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-hdpi/ic_restore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_serch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-hdpi/ic_serch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_setting_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-hdpi/ic_setting_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_start_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-hdpi/ic_start_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-mdpi/ic_action_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_delete_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-mdpi/ic_delete_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_info_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-mdpi/ic_info_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_menu_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-mdpi/ic_menu_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_restore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-mdpi/ic_restore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_serch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-mdpi/ic_serch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_setting_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-mdpi/ic_setting_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_start_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-mdpi/ic_start_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xhdpi/ic_action_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_delete_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xhdpi/ic_delete_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_info_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xhdpi/ic_info_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_menu_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xhdpi/ic_menu_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_restore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xhdpi/ic_restore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_serch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xhdpi/ic_serch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_setting_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xhdpi/ic_setting_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_start_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xhdpi/ic_start_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/netbare_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xhdpi/netbare_notification.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxhdpi/ic_action_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_delete_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxhdpi/ic_delete_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_info_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxhdpi/ic_info_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_menu_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxhdpi/ic_menu_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_restore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxhdpi/ic_restore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_serch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxhdpi/ic_serch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_setting_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxhdpi/ic_setting_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_start_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxhdpi/ic_start_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/netbare_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxhdpi/netbare_notification.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_action_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxxhdpi/ic_action_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_delete_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxxhdpi/ic_delete_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_info_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxxhdpi/ic_info_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_menu_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxxhdpi/ic_menu_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_restore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxxhdpi/ic_restore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_serch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxxhdpi/ic_serch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_setting_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxxhdpi/ic_setting_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_start_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxxhdpi/ic_start_name.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/netbare_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NetCapture/Aether/3726dcdb22f930f541fabd7b4ff1f31a45ff656d/app/src/main/res/drawable-xxxhdpi/netbare_notification.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 |