From a22d334b5a956bc520557448e3d751dc6b8d9549 Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Mon, 30 May 2022 19:58:55 +0200 Subject: [PATCH] Add app on-boarding Closes #149 --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 2 + .../activities/AboutActivity.java | 13 +- .../activities/MainActivity.java | 13 +- .../activities/OnBoardingActivity.java | 164 ++++++++++++++++++ .../emanuelef/remote_capture/model/Prefs.java | 10 ++ app/src/main/res/drawable/ic_location_dot.xml | 5 + .../main/res/drawable/ic_rocket_launch.xml | 5 + .../menu/{unlock_menu.xml => about_menu.xml} | 5 + app/src/main/res/values-night-v8/colors.xml | 3 +- app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 14 ++ 12 files changed, 231 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/emanuelef/remote_capture/activities/OnBoardingActivity.java create mode 100644 app/src/main/res/drawable/ic_location_dot.xml create mode 100644 app/src/main/res/drawable/ic_rocket_launch.xml rename app/src/main/res/menu/{unlock_menu.xml => about_menu.xml} (66%) diff --git a/app/build.gradle b/app/build.gradle index 2eaa5dc5..b7cca1d2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,4 +85,5 @@ dependencies { // Third-party implementation 'cat.ereza:customactivityoncrash:2.3.0' implementation 'com.github.KaKaVip:Android-Flag-Kit:v0.1' + implementation 'com.github.AppIntro:AppIntro:6.2.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 81a1f8d3..c230db79 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -54,6 +54,8 @@ android:name=".activities.EditCtrlPermissions" android:parentActivityName=".activities.SettingsActivity" /> + { diff --git a/app/src/main/java/com/emanuelef/remote_capture/activities/OnBoardingActivity.java b/app/src/main/java/com/emanuelef/remote_capture/activities/OnBoardingActivity.java new file mode 100644 index 00000000..ba1e4513 --- /dev/null +++ b/app/src/main/java/com/emanuelef/remote_capture/activities/OnBoardingActivity.java @@ -0,0 +1,164 @@ +/* + * This file is part of PCAPdroid. + * + * PCAPdroid is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PCAPdroid is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PCAPdroid. If not, see . + * + * Copyright 2020-22 - Emanuele Faranda + */ + +package com.emanuelef.remote_capture.activities; + +import android.content.Intent; +import android.os.Bundle; +import android.text.method.LinkMovementMethod; +import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import androidx.preference.PreferenceManager; + +import com.emanuelef.remote_capture.R; +import com.emanuelef.remote_capture.Utils; +import com.emanuelef.remote_capture.model.Prefs; +import com.github.appintro.AppIntro; +import com.github.appintro.AppIntroBaseFragment; +import com.github.appintro.model.SliderPagerBuilder; + +import org.jetbrains.annotations.Nullable; + +public class OnBoardingActivity extends AppIntro { + private static final String TAG = "OnBoardingActivity"; + + public static class OnBoardingFragment extends AppIntroBaseFragment { + @Override + protected int getLayoutId() { + return R.layout.appintro_fragment_intro; + } + + public static OnBoardingFragment createInstance(CharSequence title, CharSequence description, int imageRes, int imageTint) { + OnBoardingFragment fragment = new OnBoardingFragment(); + Bundle args = new SliderPagerBuilder() + .title(title) + //.description(description) see below + .imageDrawable(imageRes) + .backgroundColorRes(R.color.backgroundColor) + .titleColorRes(R.color.colorAccent) + .descriptionColorRes(R.color.colorTabText) + .build().toBundle(); + + args.putCharSequence("pd_descr", description); + args.putInt("pd_image_tint", imageTint); + fragment.setArguments(args); + + return fragment; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + if(view == null) + return null; + + Bundle args = getArguments(); + assert args != null; + + // fixes links from Utils.getText not clickable + TextView tv = view.findViewById(R.id.description); + tv.setAutoLinkMask(0); + tv.setMovementMethod(LinkMovementMethod.getInstance()); + tv.setText(args.getCharSequence("pd_descr")); + tv.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); + + // fix drawable tint and size + ImageView image = view.findViewById(R.id.image); + int tint = args.getInt("pd_image_tint"); + if(tint > 0) + image.setColorFilter(ContextCompat.getColor(view.getContext(), tint)); + image.setAdjustViewBounds(true); + ViewGroup.LayoutParams params = image.getLayoutParams(); + params.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 120, getResources().getDisplayMetrics()); + + return view; + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + addSlide(OnBoardingFragment.createInstance(getString(R.string.welcome_to_pcapdroid), + getText(R.string.app_intro_welcome_msg), + R.drawable.ic_logo, R.color.colorAccent)); + + addSlide(OnBoardingFragment.createInstance(getString(R.string.privacy_first), + Utils.getText(this, R.string.app_intro_privacy_msg, MainActivity.PRIVACY_POLICY_URL, + MainActivity.GITHUB_PROJECT_URL), + R.drawable.ic_shield, R.color.colorAccent)); + + addSlide(OnBoardingFragment.createInstance(getString(R.string.country_and_asn), + getText(R.string.app_intro_geolocation_msg), + R.drawable.ic_location_dot, R.color.colorAccent)); + + addSlide(OnBoardingFragment.createInstance(getString(R.string.additional_features), + Utils.getText(this, R.string.app_intro_additional_features_msg, MainActivity.FIREWALL_DOCS_URL, + MainActivity.MALWARE_DETECTION_DOCS_URL, MainActivity.TLS_DECRYPTION_DOCS_URL), + R.drawable.ic_rocket_launch, R.color.colorAccent)); + + showStatusBar(true); + setSkipButtonEnabled(false); + setIndicatorEnabled(true); + setSystemBackButtonLocked(true); + + // Theme + int colorAccent = ContextCompat.getColor(this, R.color.colorAccent); + setIndicatorColor(colorAccent, ContextCompat.getColor(this, R.color.colorAccentLight)); + setBackArrowColor(colorAccent); + setColorSkipButton(colorAccent); + setNextArrowColor(colorAccent); + setBackArrowColor(colorAccent); + setColorDoneText(colorAccent); + } + + @Override + protected void onSkipPressed(@Nullable Fragment currentFragment) { + Log.d(TAG, "onSkipPressed"); + super.onSkipPressed(currentFragment); + runMainActivity(); + } + + @Override + protected void onDonePressed(@Nullable Fragment currentFragment) { + Log.d(TAG, "onDonePressed"); + super.onDonePressed(currentFragment); + runMainActivity(); + } + + private void runMainActivity() { + Prefs.refreshAppVersion(PreferenceManager.getDefaultSharedPreferences(this)); + + Intent intent = new Intent(this, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(intent); + finish(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java b/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java index 9f46596b..f1d3b4cb 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java +++ b/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.SharedPreferences; import com.emanuelef.remote_capture.Billing; +import com.emanuelef.remote_capture.BuildConfig; import com.emanuelef.remote_capture.Utils; public class Prefs { @@ -66,6 +67,7 @@ public class Prefs { public static final String PREF_FULL_PAYLOAD = "full_payload"; public static final String PREF_BLOCK_QUIC = "block_quic"; public static final String PREF_AUTO_BLOCK_PRIVATE_DNS = "auto_block_private_dns"; + public static final String PREF_APP_VERSION = "appver"; public enum DumpMode { NONE, @@ -97,6 +99,14 @@ public class Prefs { } } + public static int getAppVersion(SharedPreferences p) { + return p.getInt(PREF_APP_VERSION, 0); + } + + public static void refreshAppVersion(SharedPreferences p) { + p.edit().putInt(PREF_APP_VERSION, BuildConfig.VERSION_CODE).apply(); + } + /* Prefs with defaults */ public static String getCollectorIp(SharedPreferences p) { return(p.getString(PREF_COLLECTOR_IP_KEY, "127.0.0.1")); } public static int getCollectorPort(SharedPreferences p) { return(Integer.parseInt(p.getString(PREF_COLLECTOR_PORT_KEY, "1234"))); } diff --git a/app/src/main/res/drawable/ic_location_dot.xml b/app/src/main/res/drawable/ic_location_dot.xml new file mode 100644 index 00000000..c052a55b --- /dev/null +++ b/app/src/main/res/drawable/ic_location_dot.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_rocket_launch.xml b/app/src/main/res/drawable/ic_rocket_launch.xml new file mode 100644 index 00000000..5f6dc715 --- /dev/null +++ b/app/src/main/res/drawable/ic_rocket_launch.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/menu/unlock_menu.xml b/app/src/main/res/menu/about_menu.xml similarity index 66% rename from app/src/main/res/menu/unlock_menu.xml rename to app/src/main/res/menu/about_menu.xml index 92280350..215f5019 100644 --- a/app/src/main/res/menu/unlock_menu.xml +++ b/app/src/main/res/menu/about_menu.xml @@ -8,4 +8,9 @@ android:title="@string/paid_features" android:orderInCategory="10" app:showAsAction="never" /> + \ No newline at end of file diff --git a/app/src/main/res/values-night-v8/colors.xml b/app/src/main/res/values-night-v8/colors.xml index dd5f42ee..77948501 100644 --- a/app/src/main/res/values-night-v8/colors.xml +++ b/app/src/main/res/values-night-v8/colors.xml @@ -6,7 +6,8 @@ #6C52AB #24144D #121212 - @color/design_default_color_secondary + #03DAC6 + #BCEBE7 #1CFFFFFF #FF202020 @color/background_material_dark diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index cc7ce38e..4926f14a 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,6 +7,7 @@ #4D3294 #512da8 #D81B60 + #D8ADBD #2C000000 @color/design_default_color_surface @color/background_material_light diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 069f5d0c..be611d73 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -22,6 +22,7 @@ - MaxMind DB Reader: Apache-2.0\n\n - FlagKit: MIT\n\n - IP Geolocation by DB-IP\n\n + - AppIntro: Apache-2.0\n\n - Font Awesome: Licenses\n\n - App icon by Freepik from flaticon\n\n - SourceCodePro font: OFL-1.1\n\n @@ -346,4 +347,17 @@ Detect and possibly block private DNS to inspect DNS traffic. Disabling this can hinder detection This wizard will guide you through the installation of the PCAPdroid mitm addon and certification authority, which are needed to perform the TLS decryption PCAPdroid is now ready to decrypt TLS traffic\n\nCheck out the user guide to know more about the security measures which may prevent decryption and how to bypass them + Skip + Next + Back + Done + Welcome to PCAPdroid + PCAPdroid is a privacy-friendly app which lets you track and analyze the connections made by the apps in your device\n\nMoreover, it allows you to export a PCAP dump of the traffic, extract metadata and much more! + Privacy-first + The app does not embed any tracking, analytics or calling home\n\nHow can you be sure? Check out its privacy policy and its source code + Additional features + Monitoring is not enough? PCAPdroid gets you covered!\n\n• Firewall: block apps, domains or IP addresses*\n• Malware detection and blocking*\n• TLS decryption\n\n*paid feature, only available on Google Play + Country and ASN + PCAPdroid can query a local database to determine the country of a remote server\n\nYou must first download the database from the PCAPdroid settings + On-boarding