├── settings.gradle
├── play
├── assets
│ ├── screen1.png
│ ├── screen2.png
│ ├── screen3.png
│ ├── screen4.png
│ ├── screen5.png
│ ├── screen6.png
│ ├── ic_launcher-hdpi.png
│ ├── ic_launcher-hires.png
│ ├── ic_launcher-mdpi.png
│ ├── ic_launcher-xhdpi.png
│ ├── ic_launcher-feature.png
│ └── ic_launcher-xxhdpi.png
└── releases
│ ├── PortKnocker-release-1.0.1.apk
│ ├── PortKnocker-release-1.0.2.apk
│ ├── PortKnocker-release-1.0.3.apk
│ ├── PortKnocker-release-1.0.4.apk
│ ├── PortKnocker-release-1.0.5.apk
│ ├── PortKnocker-release-1.0.6.apk
│ ├── PortKnocker-release-1.0.7.apk
│ └── PortKnocker-release-1.0.apk
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── app
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── ic_alert.png
│ │ │ │ ├── fab_ic_add.png
│ │ │ │ ├── ic_delete.png
│ │ │ │ ├── ic_pencil.png
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_content_save.png
│ │ │ │ ├── ic_sort_variant.png
│ │ │ │ ├── ic_divider_dashed.png
│ │ │ │ └── appwidget_dark_bg.9.png
│ │ │ ├── drawable-mdpi
│ │ │ │ ├── ic_alert.png
│ │ │ │ ├── fab_ic_add.png
│ │ │ │ ├── ic_delete.png
│ │ │ │ ├── ic_pencil.png
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_content_save.png
│ │ │ │ ├── ic_sort_variant.png
│ │ │ │ └── appwidget_dark_bg.9.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ ├── ic_alert.png
│ │ │ │ ├── ic_delete.png
│ │ │ │ ├── ic_pencil.png
│ │ │ │ ├── fab_ic_add.png
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_content_save.png
│ │ │ │ ├── ic_sort_variant.png
│ │ │ │ └── appwidget_dark_bg.9.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ ├── ic_alert.png
│ │ │ │ ├── fab_ic_add.png
│ │ │ │ ├── ic_delete.png
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_pencil.png
│ │ │ │ ├── ic_content_save.png
│ │ │ │ └── ic_sort_variant.png
│ │ │ ├── drawable
│ │ │ │ ├── widget_preview_1x1.png
│ │ │ │ ├── widget_preview_2x1.png
│ │ │ │ ├── widget_preview_3x1.png
│ │ │ │ ├── widget_preview_4x1.png
│ │ │ │ └── selectable_item_background.xml
│ │ │ ├── xml
│ │ │ │ ├── file_provider_paths.xml
│ │ │ │ ├── widget1x1.xml
│ │ │ │ ├── widget2x1.xml
│ │ │ │ ├── widget3x1.xml
│ │ │ │ ├── widget4x1.xml
│ │ │ │ └── preferences.xml
│ │ │ ├── values
│ │ │ │ ├── colors.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── strings.xml
│ │ │ ├── layout
│ │ │ │ ├── toolbar.xml
│ │ │ │ ├── host_list.xml
│ │ │ │ ├── settings.xml
│ │ │ │ ├── icon_text_item.xml
│ │ │ │ ├── host_edit.xml
│ │ │ │ ├── ports_header.xml
│ │ │ │ ├── widget.xml
│ │ │ │ ├── host_fragment.xml
│ │ │ │ ├── port_row.xml
│ │ │ │ ├── list_view.xml
│ │ │ │ ├── host_row.xml
│ │ │ │ └── misc_fragment.xml
│ │ │ ├── menu
│ │ │ │ └── host_list.xml
│ │ │ ├── values-ja
│ │ │ │ └── strings.xml
│ │ │ └── values-de
│ │ │ │ └── strings.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── xargsgrep
│ │ │ │ └── portknocker
│ │ │ │ ├── widget
│ │ │ │ ├── HostWidget1x1.java
│ │ │ │ ├── HostWidget2x1.java
│ │ │ │ ├── HostWidget3x1.java
│ │ │ │ ├── HostWidget4x1.java
│ │ │ │ ├── ConfigureWidgetActivity.java
│ │ │ │ ├── ConfigureWidgetHostArrayAdapter.java
│ │ │ │ └── HostWidget.java
│ │ │ │ ├── utils
│ │ │ │ ├── BundleUtils.java
│ │ │ │ ├── SocketUtils.java
│ │ │ │ ├── StringUtils.java
│ │ │ │ └── SerializationUtils.java
│ │ │ │ ├── filter
│ │ │ │ ├── FilenameInputFilter.java
│ │ │ │ └── HostnameInputFilter.java
│ │ │ │ ├── model
│ │ │ │ ├── Application.java
│ │ │ │ ├── Port.java
│ │ │ │ └── Host.java
│ │ │ │ ├── fragment
│ │ │ │ ├── SettingsFragment.java
│ │ │ │ ├── ProgressDialogFragment.java
│ │ │ │ ├── PortsFragment.java
│ │ │ │ ├── HostFragment.java
│ │ │ │ └── HostListFragment.java
│ │ │ │ ├── activity
│ │ │ │ ├── SettingsActivity.java
│ │ │ │ └── SettingsActivityCompat.java
│ │ │ │ ├── adapter
│ │ │ │ ├── EditHostFragmentPagerAdapter.java
│ │ │ │ ├── ApplicationArrayAdapter.java
│ │ │ │ ├── HostArrayAdapter.java
│ │ │ │ └── PortArrayAdapter.java
│ │ │ │ ├── asynctask
│ │ │ │ ├── RetrieveApplicationsAsyncTask.java
│ │ │ │ ├── KnockerAsyncTask.java
│ │ │ │ └── Knocker.java
│ │ │ │ └── db
│ │ │ │ └── DatabaseHelper.java
│ │ └── AndroidManifest.xml
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── xargsgrep
│ │ └── portknocker
│ │ └── ApplicationTest.java
├── proguard-rules.pro
└── build.gradle
├── FileChooser
├── src
│ └── main
│ │ ├── res
│ │ ├── drawable-hdpi
│ │ │ ├── ic_file.png
│ │ │ ├── ic_chooser.png
│ │ │ ├── ic_folder.png
│ │ │ └── ic_provider.png
│ │ ├── drawable-mdpi
│ │ │ ├── ic_file.png
│ │ │ ├── ic_chooser.png
│ │ │ ├── ic_folder.png
│ │ │ └── ic_provider.png
│ │ ├── drawable-xhdpi
│ │ │ ├── ic_file.png
│ │ │ ├── ic_folder.png
│ │ │ ├── ic_chooser.png
│ │ │ └── ic_provider.png
│ │ ├── drawable-xxhdpi
│ │ │ ├── ic_file.png
│ │ │ ├── ic_chooser.png
│ │ │ ├── ic_folder.png
│ │ │ └── ic_provider.png
│ │ ├── values-v19
│ │ │ └── bool.xml
│ │ ├── values
│ │ │ ├── bool.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── values-ko
│ │ │ └── strings.xml
│ │ ├── values-de
│ │ │ └── strings.xml
│ │ ├── values-ru
│ │ │ └── strings.xml
│ │ ├── values-pl
│ │ │ └── strings.xml
│ │ ├── values-ca
│ │ │ └── strings.xml
│ │ ├── values-pt-rBR
│ │ │ └── strings.xml
│ │ ├── values-fr
│ │ │ └── strings.xml
│ │ ├── values-es
│ │ │ └── strings.xml
│ │ ├── values-it
│ │ │ └── strings.xml
│ │ ├── values-ga
│ │ │ └── strings.xml
│ │ ├── values-v11
│ │ │ └── strings.xml
│ │ ├── layout
│ │ │ └── file.xml
│ │ ├── values-ja
│ │ │ └── strings.xml
│ │ └── xml
│ │ │ └── mimetypes.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── ipaulpro
│ │ └── afilechooser
│ │ ├── FileListAdapter.java
│ │ ├── FileLoader.java
│ │ ├── FileListFragment.java
│ │ └── FileChooserActivity.java
└── build.gradle
├── .gitignore
├── gradle.properties
├── README.md
├── gradlew.bat
└── gradlew
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':FileChooser'
2 |
--------------------------------------------------------------------------------
/play/assets/screen1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/assets/screen1.png
--------------------------------------------------------------------------------
/play/assets/screen2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/assets/screen2.png
--------------------------------------------------------------------------------
/play/assets/screen3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/assets/screen3.png
--------------------------------------------------------------------------------
/play/assets/screen4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/assets/screen4.png
--------------------------------------------------------------------------------
/play/assets/screen5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/assets/screen5.png
--------------------------------------------------------------------------------
/play/assets/screen6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/assets/screen6.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/play/assets/ic_launcher-hdpi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/assets/ic_launcher-hdpi.png
--------------------------------------------------------------------------------
/play/assets/ic_launcher-hires.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/assets/ic_launcher-hires.png
--------------------------------------------------------------------------------
/play/assets/ic_launcher-mdpi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/assets/ic_launcher-mdpi.png
--------------------------------------------------------------------------------
/play/assets/ic_launcher-xhdpi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/assets/ic_launcher-xhdpi.png
--------------------------------------------------------------------------------
/play/assets/ic_launcher-feature.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/assets/ic_launcher-feature.png
--------------------------------------------------------------------------------
/play/assets/ic_launcher-xxhdpi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/assets/ic_launcher-xxhdpi.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_alert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-hdpi/ic_alert.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_alert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-mdpi/ic_alert.png
--------------------------------------------------------------------------------
/play/releases/PortKnocker-release-1.0.1.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/releases/PortKnocker-release-1.0.1.apk
--------------------------------------------------------------------------------
/play/releases/PortKnocker-release-1.0.2.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/releases/PortKnocker-release-1.0.2.apk
--------------------------------------------------------------------------------
/play/releases/PortKnocker-release-1.0.3.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/releases/PortKnocker-release-1.0.3.apk
--------------------------------------------------------------------------------
/play/releases/PortKnocker-release-1.0.4.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/releases/PortKnocker-release-1.0.4.apk
--------------------------------------------------------------------------------
/play/releases/PortKnocker-release-1.0.5.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/releases/PortKnocker-release-1.0.5.apk
--------------------------------------------------------------------------------
/play/releases/PortKnocker-release-1.0.6.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/releases/PortKnocker-release-1.0.6.apk
--------------------------------------------------------------------------------
/play/releases/PortKnocker-release-1.0.7.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/releases/PortKnocker-release-1.0.7.apk
--------------------------------------------------------------------------------
/play/releases/PortKnocker-release-1.0.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/play/releases/PortKnocker-release-1.0.apk
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/fab_ic_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-hdpi/fab_ic_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-hdpi/ic_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-hdpi/ic_pencil.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/fab_ic_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-mdpi/fab_ic_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-mdpi/ic_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-mdpi/ic_pencil.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_alert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xhdpi/ic_alert.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xhdpi/ic_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xhdpi/ic_pencil.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_alert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xxhdpi/ic_alert.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/fab_ic_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xhdpi/fab_ic_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/fab_ic_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xxhdpi/fab_ic_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xxhdpi/ic_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xxhdpi/ic_pencil.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/widget_preview_1x1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable/widget_preview_1x1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/widget_preview_2x1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable/widget_preview_2x1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/widget_preview_3x1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable/widget_preview_3x1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/widget_preview_4x1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable/widget_preview_4x1.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-hdpi/ic_file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-hdpi/ic_file.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-mdpi/ic_file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-mdpi/ic_file.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_content_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-hdpi/ic_content_save.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_sort_variant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-hdpi/ic_sort_variant.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_content_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-mdpi/ic_content_save.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_sort_variant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-mdpi/ic_sort_variant.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-hdpi/ic_chooser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-hdpi/ic_chooser.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-hdpi/ic_folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-hdpi/ic_folder.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-mdpi/ic_chooser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-mdpi/ic_chooser.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-mdpi/ic_folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-mdpi/ic_folder.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-xhdpi/ic_file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-xhdpi/ic_file.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-xhdpi/ic_folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-xhdpi/ic_folder.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-xxhdpi/ic_file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-xxhdpi/ic_file.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_divider_dashed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-hdpi/ic_divider_dashed.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_content_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xhdpi/ic_content_save.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_sort_variant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xhdpi/ic_sort_variant.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_content_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xxhdpi/ic_content_save.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_sort_variant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xxhdpi/ic_sort_variant.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | .idea
3 | *.iml
4 | local.properties
5 | build
6 | app/app-release.apk
7 | app/manifest-merger-release-report.txt
8 | app/release
9 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-hdpi/ic_provider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-hdpi/ic_provider.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-mdpi/ic_provider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-mdpi/ic_provider.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-xhdpi/ic_chooser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-xhdpi/ic_chooser.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-xhdpi/ic_provider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-xhdpi/ic_provider.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-xxhdpi/ic_chooser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-xxhdpi/ic_chooser.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-xxhdpi/ic_folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-xxhdpi/ic_folder.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/appwidget_dark_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-hdpi/appwidget_dark_bg.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/appwidget_dark_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-mdpi/appwidget_dark_bg.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/appwidget_dark_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/app/src/main/res/drawable-xhdpi/appwidget_dark_bg.9.png
--------------------------------------------------------------------------------
/FileChooser/src/main/res/drawable-xxhdpi/ic_provider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xargsgrep/PortKnocker/HEAD/FileChooser/src/main/res/drawable-xxhdpi/ic_provider.png
--------------------------------------------------------------------------------
/app/src/main/res/xml/file_provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-v19/bool.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 | true
6 |
7 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values/bool.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 | false
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #37474F
5 |
6 | #263238
7 |
8 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Mar 30 14:55:40 CEST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-ko/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 빈 디렉토리
5 | 저장소가 제거되었습니다.
6 | 파일 선택
7 | 파일 선택 오류
8 |
9 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Leerer Ordner
4 | Speicher wurde entferntet.
5 | Wähle eine Datei
6 | Fehler beim Öffnen der Datei
7 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Пустая папка
5 | Storage was removed or unmounted.
6 | Выберите файл
7 | Ошибка при выборе файла
8 |
9 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-pl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Pusty katalog
5 | Pamięć została usunięta lub odmontowana.
6 | Wybierz plik
7 | Błąd, podczas wybierania pliku
8 |
9 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-ca/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Carpeta buida
5 | S\'ha tret o desmuntat l\'emmagatzematge.
6 | Seleccioneu un fitxer
7 | Error en seleccionar el fitxer
8 |
9 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-pt-rBR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Pasta Vazia
5 | Unidade externa removida ou não preparada.
6 | Selecione um Arquivo
7 | Erro ao selecionar o Arquivo
8 |
9 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Dossier vide
5 | Le stockage a été enlevé ou démonté.
6 | Sélectionnez un fichier
7 | Erreur lors de la sélection du fichier
8 |
9 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Directorio vacío
5 | Se ha retirado o desmontado el almacenamiento.
6 | Seleccione un archivo
7 | Error al seleccionar el archivo
8 |
9 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-it/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Directory vuota
5 | Lo spazio di archiviazione è stato rimosso o smontato.
6 | Selezionare un file
7 | Errore nel selezionare il File
8 |
9 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-ga/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Comhadlann fholamh
5 | Baineadh amach an gléas stórála nó dínascadh é.
6 | Roghnaigh comhad
7 | Tharla botún fad is a bhí comhad á roghnú
8 |
9 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/xargsgrep/portknocker/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.xargsgrep.portknocker;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase
10 | {
11 | public ApplicationTest()
12 | {
13 | super(Application.class);
14 | }
15 | }
--------------------------------------------------------------------------------
/FileChooser/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 |
6 | defaultConfig {
7 | minSdkVersion 19
8 | targetSdkVersion 25
9 | }
10 |
11 | buildTypes {
12 | release {
13 | minifyEnabled false
14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
15 | }
16 | }
17 | }
18 |
19 | dependencies {
20 | implementation 'com.android.support:support-v4:25.4.0'
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 | 56dp
7 | 16dp
8 | 16dp
9 | 1dp
10 | 8dp
11 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/widget1x1.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/widget2x1.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/widget3x1.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/widget4x1.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/selectable_item_background.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
12 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/host_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/icon_text_item.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
14 |
15 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
18 |
19 |
--------------------------------------------------------------------------------
/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 /home/arabbani/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 |
19 | -dontwarn com.fasterxml.jackson.databind.ext.DOMSerializer
20 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-v11/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | Choose a file
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/widget/HostWidget1x1.java:
--------------------------------------------------------------------------------
1 | package com.xargsgrep.portknocker.widget;
2 |
3 | /*
4 | * Copyright 2016 TDFKAOlli
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | public class HostWidget1x1 extends HostWidget {
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/widget/HostWidget2x1.java:
--------------------------------------------------------------------------------
1 | package com.xargsgrep.portknocker.widget;
2 |
3 | /*
4 | * Copyright 2016 TDFKAOlli
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | public class HostWidget2x1 extends HostWidget {
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/widget/HostWidget3x1.java:
--------------------------------------------------------------------------------
1 | package com.xargsgrep.portknocker.widget;
2 |
3 | /*
4 | * Copyright 2016 TDFKAOlli
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | public class HostWidget3x1 extends HostWidget {
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/widget/HostWidget4x1.java:
--------------------------------------------------------------------------------
1 | package com.xargsgrep.portknocker.widget;
2 |
3 | /*
4 | * Copyright 2016 TDFKAOlli
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | public class HostWidget4x1 extends HostWidget {
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | 0dp
19 | 16dp
20 |
--------------------------------------------------------------------------------
/FileChooser/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/FileChooser/src/main/res/layout/file.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/utils/BundleUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.utils;
17 |
18 | import android.os.Bundle;
19 |
20 | public class BundleUtils
21 | {
22 | public static boolean contains(Bundle bundle, String key)
23 | {
24 | return (bundle != null && bundle.containsKey(key));
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values-ja/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | 空のディレクトリ
19 | ストレージが取り外されたか、マウント解除されました。
20 | ファイルを選択
21 | ファイルの選択時にエラー
22 | 内部ストレージ
23 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | Empty Directory
19 | Storage was removed or unmounted.
20 | Select a file
21 | Error selecting File
22 | Internal storage
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/host_edit.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
19 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 |
6 | defaultConfig {
7 | applicationId "com.xargsgrep.portknocker"
8 | minSdkVersion 19
9 | targetSdkVersion 25
10 | versionCode 14
11 | versionName "1.0.13"
12 | }
13 | signingConfigs {
14 | release {
15 | storeFile file("~/.android/android-release.keystore")
16 | keyAlias "android"
17 | storePassword System.getenv("KSTOREPWD")
18 | keyPassword System.getenv("KEYPWD")
19 | }
20 | }
21 | buildTypes {
22 | release {
23 | minifyEnabled false
24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
25 | }
26 | }
27 | packagingOptions {
28 | exclude 'META-INF/LICENSE'
29 | exclude 'META-INF/NOTICE'
30 | }
31 | }
32 |
33 | dependencies {
34 | implementation project(':FileChooser')
35 |
36 | implementation fileTree(dir: 'libs', include: ['*.jar'])
37 | implementation 'com.android.support:appcompat-v7:25.4.0'
38 | implementation 'com.fasterxml.jackson.core:jackson-databind:2.5.1'
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/utils/SocketUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.utils;
17 |
18 | import java.io.IOException;
19 | import java.net.DatagramSocket;
20 | import java.net.Socket;
21 |
22 | public class SocketUtils
23 | {
24 | public static void closeQuietly(Socket socket)
25 | {
26 | try
27 | {
28 | if (socket != null && socket.isConnected()) socket.close();
29 | }
30 | catch (IOException e) { }
31 | }
32 |
33 | public static void closeQuietly(DatagramSocket socket)
34 | {
35 | if (socket != null && socket.isConnected()) socket.close();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/filter/FilenameInputFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.filter;
17 |
18 | import android.text.InputFilter;
19 | import android.text.Spanned;
20 |
21 | public class FilenameInputFilter implements InputFilter
22 | {
23 | @Override
24 | public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
25 | {
26 | for (int i = start; i < end; i++)
27 | {
28 | char c = source.charAt(i);
29 | if (!Character.isLetterOrDigit(c) && c != '.' && c != '-' && c != '_') return "";
30 | }
31 | return null;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/filter/HostnameInputFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.filter;
17 |
18 | import android.text.InputFilter;
19 | import android.text.Spanned;
20 |
21 | public class HostnameInputFilter implements InputFilter
22 | {
23 | @Override
24 | public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
25 | {
26 | for (int i = start; i < end; i++)
27 | {
28 | char c = source.charAt(i);
29 | if (!Character.isLetterOrDigit(c) && c != '.' && c != '-' && c != ':') return "";
30 | }
31 | return null;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/utils/StringUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.utils;
17 |
18 | public class StringUtils
19 | {
20 | public static boolean contains(String stringToCheck, String str)
21 | {
22 | return (stringToCheck == null) ? false : stringToCheck.contains(str);
23 | }
24 |
25 | // String.isEmpty only available starting API 9
26 | public static boolean isEmpty(String str)
27 | {
28 | return (str == null || str.length() == 0);
29 | }
30 |
31 | public static boolean isBlank(String str)
32 | {
33 | return (str == null || isEmpty(str.trim()));
34 | }
35 |
36 | public static boolean isNotBlank(String str)
37 | {
38 | return !isBlank(str);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/ports_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
19 |
20 |
29 |
30 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Port Knocker
2 |
3 | ## Description
4 | A basic port knocker client for Android. Similar to the other port knocker apps but with a nicer interface. Also includes a widget and the ability to choose an application to launch after knocking.
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Usage
12 | First create a host. You must specify a label, hostname and at least one port. The delay (in ms) is the amount of time it will wait in between sending packets. The default value of 1000ms is recommended to prevent the host from receiving the packets out of sequence. You can optionally choose an app to launch after the knock is complete. Once the host has been created you can initiate the knock sequence by simply clicking on the host. The same thing applies to the widget.
13 |
14 | ## Privacy
15 | This app does not track, collect, or share any data it comes across with anyone or anything. There are no ads or analytics trackers in this software. It does not access, store, nor transmit any user data. Only data entered into the application is stored within the application on this device and is not stored outside of this device.
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/widget.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
24 |
25 |
32 |
33 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/model/Application.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.model;
17 |
18 | import android.graphics.drawable.Drawable;
19 |
20 | public class Application
21 | {
22 | private String label;
23 | private Drawable icon;
24 | private String intent;
25 |
26 | public Application(String label, Drawable icon, String intent)
27 | {
28 | this.label = label;
29 | this.icon = icon;
30 | this.intent = intent;
31 | }
32 |
33 | public Drawable getIcon()
34 | {
35 | return icon;
36 | }
37 |
38 | public void setIcon(Drawable icon)
39 | {
40 | this.icon = icon;
41 | }
42 |
43 | public String getLabel()
44 | {
45 | return label;
46 | }
47 |
48 | public void setLabel(String label)
49 | {
50 | this.label = label;
51 | }
52 |
53 | public String getIntent()
54 | {
55 | return intent;
56 | }
57 |
58 | public void setIntent(String intent)
59 | {
60 | this.intent = intent;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/host_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/fragment/SettingsFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.fragment;
17 |
18 | import android.content.SharedPreferences;
19 | import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
20 | import android.os.Bundle;
21 | import android.preference.PreferenceFragment;
22 |
23 | import com.xargsgrep.portknocker.R;
24 | import com.xargsgrep.portknocker.widget.HostWidget;
25 |
26 | public class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener
27 | {
28 | @Override
29 | public void onCreate(Bundle savedInstanceState)
30 | {
31 | super.onCreate(savedInstanceState);
32 | addPreferencesFromResource(R.xml.preferences);
33 | getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
34 | }
35 |
36 | @Override
37 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
38 | {
39 | if (isAdded() && getString(R.string.pref_key_hide_ports_widget).equals(key))
40 | {
41 | HostWidget.updateAllAppWidgets(getActivity());
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/host_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
20 |
21 |
31 |
32 |
40 |
41 |
51 |
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/model/Port.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.model;
17 |
18 | import com.fasterxml.jackson.annotation.JsonIgnore;
19 |
20 | public class Port
21 | {
22 | private long hostId;
23 | private int index;
24 | private int port = -1;
25 | private Protocol protocol = Protocol.TCP;
26 |
27 | public static enum Protocol {TCP, UDP}
28 |
29 | public Port() { }
30 |
31 | @JsonIgnore
32 | public long getHostId()
33 | {
34 | return hostId;
35 | }
36 |
37 | public void setHostId(long hostId)
38 | {
39 | this.hostId = hostId;
40 | }
41 |
42 | @JsonIgnore
43 | public int getIndex()
44 | {
45 | return index;
46 | }
47 |
48 | public void setIndex(int index)
49 | {
50 | this.index = index;
51 | }
52 |
53 | public int getPort()
54 | {
55 | return port;
56 | }
57 |
58 | public void setPort(int port)
59 | {
60 | this.port = port;
61 | }
62 |
63 | public Protocol getProtocol()
64 | {
65 | return protocol;
66 | }
67 |
68 | public void setProtocol(Protocol protocol)
69 | {
70 | this.protocol = protocol;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/port_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
21 |
22 |
31 |
32 |
37 |
38 |
39 |
45 |
46 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
26 |
27 |
40 |
41 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/activity/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.activity;
17 |
18 | import android.content.Intent;
19 | import android.os.Bundle;
20 | import android.support.v7.app.ActionBarActivity;
21 | import android.support.v7.widget.Toolbar;
22 | import android.view.MenuItem;
23 |
24 | import com.xargsgrep.portknocker.R;
25 | import com.xargsgrep.portknocker.fragment.SettingsFragment;
26 |
27 | public class SettingsActivity extends ActionBarActivity
28 | {
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState)
31 | {
32 | super.onCreate(savedInstanceState);
33 | setContentView(R.layout.settings);
34 |
35 | getFragmentManager()
36 | .beginTransaction()
37 | .replace(R.id.fragment_content, new SettingsFragment())
38 | .commit();
39 |
40 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
41 | setSupportActionBar(toolbar);
42 |
43 | getSupportActionBar().setSubtitle(getResources().getString(R.string.settings_subtitle));
44 | getSupportActionBar().setHomeButtonEnabled(true);
45 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
46 | }
47 |
48 | @Override
49 | public boolean onOptionsItemSelected(MenuItem item)
50 | {
51 | switch (item.getItemId())
52 | {
53 | case android.R.id.home:
54 | Intent hostListIntent = new Intent(this, HostListActivity.class);
55 | hostListIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
56 | startActivity(hostListIntent);
57 | return true;
58 | default:
59 | return super.onOptionsItemSelected(item);
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/activity/SettingsActivityCompat.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.activity;
17 |
18 | import android.content.Intent;
19 | import android.content.SharedPreferences;
20 | import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
21 | import android.os.Bundle;
22 | import android.preference.PreferenceActivity;
23 | import android.view.MenuItem;
24 |
25 | import com.xargsgrep.portknocker.R;
26 | import com.xargsgrep.portknocker.widget.HostWidget;
27 |
28 | public class SettingsActivityCompat extends PreferenceActivity implements OnSharedPreferenceChangeListener
29 | {
30 | @Override
31 | @SuppressWarnings("deprecation")
32 | public void onCreate(Bundle savedInstanceState)
33 | {
34 | super.onCreate(savedInstanceState);
35 |
36 | addPreferencesFromResource(R.xml.preferences);
37 | getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
38 | }
39 |
40 | @Override
41 | public boolean onOptionsItemSelected(MenuItem item)
42 | {
43 | switch (item.getItemId())
44 | {
45 | case android.R.id.home:
46 | Intent hostListIntent = new Intent(this, HostListActivity.class);
47 | hostListIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
48 | startActivity(hostListIntent);
49 | return true;
50 | default:
51 | return super.onOptionsItemSelected(item);
52 | }
53 | }
54 |
55 | @Override
56 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
57 | {
58 | if (getString(R.string.pref_key_hide_ports_widget).equals(key))
59 | {
60 | HostWidget.updateAllAppWidgets(this);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/utils/SerializationUtils.java:
--------------------------------------------------------------------------------
1 | package com.xargsgrep.portknocker.utils;
2 |
3 | import android.content.ContentResolver;
4 | import android.content.Context;
5 | import android.net.Uri;
6 | import android.os.Environment;
7 | import android.support.annotation.NonNull;
8 |
9 | import com.fasterxml.jackson.core.type.TypeReference;
10 | import com.fasterxml.jackson.databind.ObjectMapper;
11 | import com.fasterxml.jackson.databind.SerializationFeature;
12 | import com.xargsgrep.portknocker.model.Host;
13 |
14 | import java.io.File;
15 | import java.io.FileWriter;
16 | import java.io.InputStream;
17 | import java.util.List;
18 |
19 | public class SerializationUtils
20 | {
21 | public static String serializeHosts(String fileName, List hosts) throws Exception
22 | {
23 | if (!isExternalStorageAccessible())
24 | {
25 | throw new Exception("External storage is not currently accessible");
26 | }
27 |
28 | ObjectMapper mapper = new ObjectMapper();
29 | mapper.enable(SerializationFeature.INDENT_OUTPUT);
30 |
31 | File storageDir = createPortKnockerFolderIfNotExists();
32 |
33 | File file = new File(storageDir, fileName);
34 | FileWriter fileWriter = new FileWriter(file);
35 |
36 | mapper.writeValue(fileWriter, hosts);
37 |
38 | return file.getAbsolutePath();
39 | }
40 |
41 | @NonNull
42 | public static File createPortKnockerFolderIfNotExists() {
43 | File storageDir = new File(Environment.getExternalStorageDirectory(), "PortKnocker");
44 | if (!storageDir.exists())
45 | {
46 | storageDir.mkdirs();
47 | }
48 | return storageDir;
49 | }
50 |
51 | public static List deserializeHosts(Context context, Uri fileUri) throws Exception
52 | {
53 | if (!isExternalStorageAccessible())
54 | {
55 | throw new Exception("External storage is not currently accessible");
56 | }
57 |
58 | ObjectMapper objectMapper = new ObjectMapper();
59 | ContentResolver resolver = context.getContentResolver();
60 | InputStream input = resolver.openInputStream(fileUri);
61 |
62 | return objectMapper.readValue(input, new TypeReference>() {});
63 | }
64 |
65 | private static boolean isExternalStorageAccessible()
66 | {
67 | String state = Environment.getExternalStorageState();
68 | return Environment.MEDIA_MOUNTED.equals(state);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/adapter/EditHostFragmentPagerAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.adapter;
17 |
18 | import android.content.Context;
19 | import android.support.v4.app.Fragment;
20 | import android.support.v4.app.FragmentManager;
21 | import android.support.v4.app.FragmentPagerAdapter;
22 |
23 | import com.xargsgrep.portknocker.R;
24 | import com.xargsgrep.portknocker.activity.EditHostActivity;
25 | import com.xargsgrep.portknocker.fragment.HostFragment;
26 | import com.xargsgrep.portknocker.fragment.MiscFragment;
27 | import com.xargsgrep.portknocker.fragment.PortsFragment;
28 |
29 | public class EditHostFragmentPagerAdapter extends FragmentPagerAdapter
30 | {
31 | private Context context;
32 | private Long hostId;
33 |
34 | public EditHostFragmentPagerAdapter(FragmentManager fm, Context context, Long hostId)
35 | {
36 | super(fm);
37 | this.context = context;
38 | this.hostId = hostId;
39 | }
40 |
41 | @Override
42 | public Fragment getItem(int position)
43 | {
44 | switch (position)
45 | {
46 | case EditHostActivity.TAB_INDEX_HOST:
47 | return HostFragment.newInstance(hostId);
48 | case EditHostActivity.TAB_INDEX_PORTS:
49 | return PortsFragment.newInstance(hostId);
50 | case EditHostActivity.TAB_INDEX_MISC:
51 | return MiscFragment.newInstance(hostId);
52 | }
53 | throw new IllegalArgumentException("Invalid item position in ViewPager: " + position);
54 | }
55 |
56 | @Override
57 | public CharSequence getPageTitle(int position)
58 | {
59 | switch (position)
60 | {
61 | case EditHostActivity.TAB_INDEX_HOST:
62 | return context.getString(R.string.host_tab_name);
63 | case EditHostActivity.TAB_INDEX_PORTS:
64 | return context.getString(R.string.ports_tab_name);
65 | case EditHostActivity.TAB_INDEX_MISC:
66 | return context.getString(R.string.misc_tab_name);
67 | }
68 | throw new IllegalArgumentException("Invalid item position in ViewPager: " + position);
69 | }
70 |
71 | @Override
72 | public int getCount()
73 | {
74 | return 3;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/adapter/ApplicationArrayAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.adapter;
17 |
18 | import android.content.Context;
19 | import android.view.LayoutInflater;
20 | import android.view.View;
21 | import android.view.ViewGroup;
22 | import android.widget.ArrayAdapter;
23 | import android.widget.ImageView;
24 | import android.widget.TextView;
25 |
26 | import com.xargsgrep.portknocker.R;
27 | import com.xargsgrep.portknocker.model.Application;
28 |
29 | import java.util.List;
30 |
31 | public class ApplicationArrayAdapter extends ArrayAdapter
32 | {
33 | private Context context;
34 | private List applications;
35 |
36 | public ApplicationArrayAdapter(Context context, List applications)
37 | {
38 | super(context, -1, applications);
39 | this.context = context;
40 | this.applications = applications;
41 | }
42 |
43 | @Override
44 | public int getCount()
45 | {
46 | return applications.size();
47 | }
48 |
49 | @Override
50 | public Application getItem(int position)
51 | {
52 | return applications.get(position);
53 | }
54 |
55 | @Override
56 | public View getView(int position, View convertView, ViewGroup parent)
57 | {
58 | return getView(position, convertView);
59 | }
60 |
61 | @Override
62 | public View getDropDownView(int position, View convertView, ViewGroup parent)
63 | {
64 | return getView(position, convertView);
65 | }
66 |
67 | private View getView(int position, View convertView)
68 | {
69 | View view = convertView;
70 | if (view == null)
71 | {
72 | view = LayoutInflater.from(getContext()).inflate(R.layout.icon_text_item, null);
73 | }
74 |
75 | ImageView imageView = (ImageView) view.findViewById(R.id.icon);
76 | TextView textView = (TextView) view.findViewById(R.id.text);
77 |
78 | Application application = applications.get(position);
79 | // imageView.setImageDrawable(application.getIcon() == null ? context.getResources().getDrawable(R.drawable.ic_launcher) : application.getIcon());
80 | imageView.setImageDrawable(application.getIcon() == null ? null : application.getIcon());
81 | textView.setText(application.getLabel());
82 |
83 | return view;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/host_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
25 |
26 |
33 |
34 |
41 |
42 |
50 |
51 |
52 |
59 |
60 |
72 |
73 |
80 |
81 |
93 |
94 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/model/Host.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.model;
17 |
18 | import com.fasterxml.jackson.annotation.JsonIgnore;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | public class Host
24 | {
25 | public static final int DEFAULT_DELAY = 1000;
26 | public static final int DEFAULT_TCP_CONNECT_TIMEOUT = 100;
27 |
28 | private long id;
29 | private String label;
30 | private String hostname;
31 | private int delay = DEFAULT_DELAY;
32 | private int tcpConnectTimeout = DEFAULT_TCP_CONNECT_TIMEOUT;
33 | private String launchIntentPackage;
34 | private List ports = new ArrayList<>();
35 |
36 | @JsonIgnore
37 | public long getId()
38 | {
39 | return id;
40 | }
41 |
42 | public void setId(long id)
43 | {
44 | this.id = id;
45 | }
46 |
47 | public String getLabel()
48 | {
49 | return label;
50 | }
51 |
52 | public void setLabel(String label)
53 | {
54 | this.label = label;
55 | }
56 |
57 | public String getHostname()
58 | {
59 | return hostname;
60 | }
61 |
62 | public void setHostname(String hostname)
63 | {
64 | this.hostname = hostname;
65 | }
66 |
67 | public int getDelay()
68 | {
69 | return delay;
70 | }
71 |
72 | public void setDelay(int delay)
73 | {
74 | this.delay = delay;
75 | }
76 |
77 | public String getLaunchIntentPackage()
78 | {
79 | return launchIntentPackage;
80 | }
81 |
82 | public int getTcpConnectTimeout()
83 | {
84 | return tcpConnectTimeout;
85 | }
86 |
87 | public void setTcpConnectTimeout(int tcpConnectTimeout)
88 | {
89 | this.tcpConnectTimeout = tcpConnectTimeout;
90 | }
91 |
92 | public void setLaunchIntentPackage(String launchIntentPackage)
93 | {
94 | this.launchIntentPackage = launchIntentPackage;
95 | }
96 |
97 | public List getPorts()
98 | {
99 | return ports;
100 | }
101 |
102 | public void setPorts(List ports)
103 | {
104 | this.ports = ports;
105 | }
106 |
107 | @JsonIgnore
108 | public String getPortsString()
109 | {
110 | StringBuilder portsString = new StringBuilder();
111 |
112 | if (ports.size() > 0)
113 | {
114 | for (Port port : ports)
115 | {
116 | portsString.append(port.getPort());
117 | portsString.append(":");
118 | portsString.append(port.getProtocol());
119 | portsString.append(", ");
120 | }
121 | portsString.replace(portsString.length() - 2, portsString.length(), "");
122 | }
123 |
124 | return portsString.toString();
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/FileChooser/src/main/java/com/ipaulpro/afilechooser/FileListAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Paul Burke
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ipaulpro.afilechooser;
18 |
19 | import android.content.Context;
20 | import android.view.LayoutInflater;
21 | import android.view.View;
22 | import android.view.ViewGroup;
23 | import android.widget.BaseAdapter;
24 | import android.widget.TextView;
25 |
26 | import java.io.File;
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | /**
31 | * List adapter for Files.
32 | *
33 | * @version 2013-12-11
34 | * @author paulburke (ipaulpro)
35 | */
36 | public class FileListAdapter extends BaseAdapter {
37 |
38 | private final static int ICON_FOLDER = R.drawable.ic_folder;
39 | private final static int ICON_FILE = R.drawable.ic_file;
40 |
41 | private final LayoutInflater mInflater;
42 |
43 | private List mData = new ArrayList();
44 |
45 | public FileListAdapter(Context context) {
46 | mInflater = LayoutInflater.from(context);
47 | }
48 |
49 | public void add(File file) {
50 | mData.add(file);
51 | notifyDataSetChanged();
52 | }
53 |
54 | public void remove(File file) {
55 | mData.remove(file);
56 | notifyDataSetChanged();
57 | }
58 |
59 | public void insert(File file, int index) {
60 | mData.add(index, file);
61 | notifyDataSetChanged();
62 | }
63 |
64 | public void clear() {
65 | mData.clear();
66 | notifyDataSetChanged();
67 | }
68 |
69 | @Override
70 | public File getItem(int position) {
71 | return mData.get(position);
72 | }
73 |
74 | @Override
75 | public long getItemId(int position) {
76 | return position;
77 | }
78 |
79 | @Override
80 | public int getCount() {
81 | return mData.size();
82 | }
83 |
84 | public List getListItems() {
85 | return mData;
86 | }
87 |
88 | /**
89 | * Set the list items without notifying on the clear. This prevents loss of
90 | * scroll position.
91 | *
92 | * @param data
93 | */
94 | public void setListItems(List data) {
95 | mData = data;
96 | notifyDataSetChanged();
97 | }
98 |
99 | @Override
100 | public View getView(int position, View convertView, ViewGroup parent) {
101 | View row = convertView;
102 |
103 | if (row == null)
104 | row = mInflater.inflate(R.layout.file, parent, false);
105 |
106 | TextView view = (TextView) row;
107 |
108 | // Get the file at the current position
109 | final File file = getItem(position);
110 |
111 | // Set the TextView as the file name
112 | view.setText(file.getName());
113 |
114 | // If the item is not a directory, use the file icon
115 | int icon = file.isDirectory() ? ICON_FOLDER : ICON_FILE;
116 | view.setCompoundDrawablesWithIntrinsicBounds(icon, 0, 0, 0);
117 |
118 | return row;
119 | }
120 |
121 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/misc_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
20 |
29 |
35 |
36 |
45 |
53 |
60 |
68 |
69 |
70 |
79 |
87 |
94 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/widget/ConfigureWidgetActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.widget;
17 |
18 | import android.app.ListActivity;
19 | import android.appwidget.AppWidgetManager;
20 | import android.content.Context;
21 | import android.content.SharedPreferences;
22 | import android.os.Bundle;
23 |
24 | import com.xargsgrep.portknocker.R;
25 | import com.xargsgrep.portknocker.db.DatabaseManager;
26 | import com.xargsgrep.portknocker.model.Host;
27 |
28 | import java.util.List;
29 |
30 | public class ConfigureWidgetActivity extends ListActivity
31 | {
32 | private static final String PREFS_NAME = "com.xargsgrep.portknocker.widget";
33 | private static final String PREF_HOST_ID_KEY = "hostid_";
34 | private static final String PREF_CONFIGURED_KEY = "configured_";
35 |
36 | private DatabaseManager databaseManager;
37 |
38 | @Override
39 | protected void onCreate(Bundle savedInstanceState)
40 | {
41 | super.onCreate(savedInstanceState);
42 | setResult(RESULT_CANCELED);
43 | setContentView(R.layout.list_view);
44 |
45 | Bundle extras = getIntent().getExtras();
46 | int appWidgetId = (extras == null)
47 | ? AppWidgetManager.INVALID_APPWIDGET_ID
48 | : extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
49 | if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) finish();
50 |
51 | databaseManager = new DatabaseManager(this);
52 | List hosts = databaseManager.getAllHosts();
53 | ConfigureWidgetHostArrayAdapter hostAdapter = new ConfigureWidgetHostArrayAdapter(this, hosts, appWidgetId);
54 | setListAdapter(hostAdapter);
55 | }
56 |
57 | public static void saveHostIdPreference(Context context, int appWidgetId, long hostId)
58 | {
59 | SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
60 | prefs.putLong(getAppWidgetHostIdKey(appWidgetId), hostId);
61 | prefs.commit();
62 | }
63 |
64 | public static long getHostIdPreference(Context context, int appWidgetId)
65 | {
66 | SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
67 | return prefs.getLong(getAppWidgetHostIdKey(appWidgetId), -1);
68 | }
69 |
70 | public static void deleteHostIdPreference(Context context, int appWidgetId)
71 | {
72 | SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
73 | prefs.remove(getAppWidgetHostIdKey(appWidgetId));
74 | prefs.commit();
75 | }
76 |
77 | public static void saveConfiguredPreference(Context context, int appWidgetId)
78 | {
79 | SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
80 | prefs.putBoolean(getAppWidgetConfiguredKey(appWidgetId), true);
81 | prefs.commit();
82 | }
83 |
84 | public static boolean getConfiguredPreference(Context context, int appWidgetId)
85 | {
86 | SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
87 | return prefs.getBoolean(getAppWidgetConfiguredKey(appWidgetId), false);
88 | }
89 |
90 | private static String getAppWidgetHostIdKey(int appWidgetId)
91 | {
92 | return PREF_HOST_ID_KEY + appWidgetId;
93 | }
94 |
95 | private static String getAppWidgetConfiguredKey(int appWidgetId)
96 | {
97 | return PREF_CONFIGURED_KEY + appWidgetId;
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/FileChooser/src/main/res/xml/mimetypes.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ja/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Port Knocker
4 | Port Knocker 1x1
5 | Port Knocker 2x1
6 | Port Knocker 3x1
7 | Port Knocker 4x1
8 | ホスト
9 | ポート
10 | その他
11 | ラベル
12 | ラベル
13 | ホスト名/IP
14 | domain.com/192.168.10.1
15 | ポート
16 | 1234
17 | プロトコル
18 | パケット間の待機 (ms)
19 | 1000
20 | アプリケーションの起動
21 | なし
22 | TCP 接続タイムアウト (ms)
23 | はい
24 | いいえ
25 | ホストを削除しますか?
26 | 変更を破棄しますか?
27 | アプリケーションの取得中…
28 | パケットの送信中…
29 | hide_ports
30 | ホストリストでポートを非表示
31 | ホストリストにポートシーケンスを表示しません
32 | hide_ports_widget
33 | ウィジェットでポートを非表示
34 | ウィジェットにポートシーケンスを表示しません
35 | その他
36 | 設定
37 | アイテムはありません
38 | "すべてのポートを削除できません"
39 | ラベルを入力してください
40 | ホスト名を入力してください
41 | ホスト名/IPが正しくありません
42 | ポートを 1 つ以上入力してください
43 | "これ以上待機できません "
44 | "無効なポート: "
45 | 保存しました
46 | 保存に失敗しました
47 | ノックが完了しました
48 | ノックをキャンセルしました
49 | "ノックに失敗しました: "
50 | "ファイルからホストをインポートしました: "
51 | "ホストのインポートに失敗しました: "
52 | 外部メモリへのアクセス許可がありません。
53 | 設定
54 | ホストのエクスポート
55 | ホストのインポート
56 | ホストを送信
57 | ホストを並び替え
58 | ホスト名順
59 | ラベル順
60 | 最新順
61 | ホストのエクスポート
62 | ファイル名を入力してください
63 | OK
64 | キャンセル
65 | "ホストをファイルにエクスポートしました: "
66 | "ホストのエクスポートに失敗しました: "
67 | "共有... "
68 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/fragment/ProgressDialogFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.fragment;
17 |
18 | import android.app.Dialog;
19 | import android.app.ProgressDialog;
20 | import android.content.DialogInterface;
21 | import android.os.AsyncTask;
22 | import android.os.Bundle;
23 | import android.support.v4.app.DialogFragment;
24 |
25 | public class ProgressDialogFragment extends DialogFragment
26 | {
27 | public static final String TAG = "ProgressDialogFragment";
28 |
29 | private static final String KEY_MESSAGE = "message";
30 | private static final String KEY_INDETERMINATE = "indeterminate";
31 | private static final String KEY_STYLE = "style";
32 | private static final String KEY_MAX = "max";
33 |
34 | private ProgressDialog mDialog;
35 | private AsyncTask, ?, ?> mAsyncTask;
36 | private int mDialogProgress = 0;
37 |
38 | public static ProgressDialogFragment newInstance(AsyncTask, ?, ?> asyncTask, String message, boolean indeterminate, int style, int max)
39 | {
40 | ProgressDialogFragment fragment = new ProgressDialogFragment();
41 | fragment.mAsyncTask = asyncTask;
42 |
43 | Bundle args = new Bundle();
44 | args.putString(KEY_MESSAGE, message);
45 | args.putBoolean(KEY_INDETERMINATE, indeterminate);
46 | args.putInt(KEY_STYLE, style);
47 | args.putInt(KEY_MAX, max);
48 | fragment.setArguments(args);
49 |
50 | return fragment;
51 | }
52 |
53 | public static ProgressDialogFragment newInstance(String message, boolean indeterminate, int style)
54 | {
55 | return newInstance(null, message, indeterminate, style, 100);
56 | }
57 |
58 | @Override
59 | public Dialog getDialog()
60 | {
61 | return mDialog;
62 | }
63 |
64 | @Override
65 | public void onCreate(Bundle savedInstanceState)
66 | {
67 | super.onCreate(savedInstanceState);
68 | setRetainInstance(true);
69 | }
70 |
71 | @Override
72 | public Dialog onCreateDialog(Bundle savedInstanceState)
73 | {
74 | mDialog = new ProgressDialog(getActivity());
75 | mDialog.setMessage(getArguments().getString(KEY_MESSAGE));
76 | mDialog.setIndeterminate(getArguments().getBoolean(KEY_INDETERMINATE));
77 | mDialog.setProgressStyle(getArguments().getInt(KEY_STYLE));
78 | mDialog.setMax(getArguments().getInt(KEY_MAX));
79 | return mDialog;
80 | }
81 |
82 | @Override
83 | public void onStart()
84 | {
85 | super.onStart();
86 | mDialog.setProgress(mDialogProgress);
87 | }
88 |
89 | @Override
90 | public void onSaveInstanceState(Bundle outState)
91 | {
92 | super.onSaveInstanceState(outState);
93 | mDialogProgress = mDialog.getProgress();
94 | }
95 |
96 | @Override
97 | public void onCancel(DialogInterface dialog)
98 | {
99 | super.onCancel(dialog);
100 | if (isCancelable() && mAsyncTask != null) mAsyncTask.cancel(true);
101 | }
102 |
103 | @Override
104 | public void onDestroyView()
105 | {
106 | // NOTE: without this the dialog doesn't seem to get recreated on screen rotation
107 | if (mDialog != null && getRetainInstance())
108 | {
109 | mDialog.setOnDismissListener(null);
110 | }
111 | super.onDestroyView();
112 | }
113 |
114 | @Override
115 | public void onDestroy()
116 | {
117 | super.onDestroy();
118 | mDialog = null;
119 | mAsyncTask = null;
120 | }
121 |
122 | public void setProgress(int progress)
123 | {
124 | if (mDialog != null) mDialog.setProgress(progress);
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/FileChooser/src/main/java/com/ipaulpro/afilechooser/FileLoader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Paul Burke
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ipaulpro.afilechooser;
18 |
19 | import android.content.Context;
20 | import android.os.FileObserver;
21 | import android.support.v4.content.AsyncTaskLoader;
22 |
23 | import com.ipaulpro.afilechooser.utils.FileUtils;
24 |
25 | import java.io.File;
26 | import java.util.ArrayList;
27 | import java.util.Arrays;
28 | import java.util.List;
29 |
30 | /**
31 | * Loader that returns a list of Files in a given file path.
32 | *
33 | * @version 2013-12-11
34 | * @author paulburke (ipaulpro)
35 | */
36 | public class FileLoader extends AsyncTaskLoader> {
37 |
38 | private static final int FILE_OBSERVER_MASK = FileObserver.CREATE
39 | | FileObserver.DELETE | FileObserver.DELETE_SELF
40 | | FileObserver.MOVED_FROM | FileObserver.MOVED_TO
41 | | FileObserver.MODIFY | FileObserver.MOVE_SELF;
42 |
43 | private FileObserver mFileObserver;
44 |
45 | private List mData;
46 | private String mPath;
47 |
48 | public FileLoader(Context context, String path) {
49 | super(context);
50 | this.mPath = path;
51 | }
52 |
53 | @Override
54 | public List loadInBackground() {
55 |
56 | ArrayList list = new ArrayList();
57 |
58 | // Current directory File instance
59 | final File pathDir = new File(mPath);
60 |
61 | // List file in this directory with the directory filter
62 | final File[] dirs = pathDir.listFiles(FileUtils.sDirFilter);
63 | if (dirs != null) {
64 | // Sort the folders alphabetically
65 | Arrays.sort(dirs, FileUtils.sComparator);
66 | // Add each folder to the File list for the list adapter
67 | for (File dir : dirs)
68 | list.add(dir);
69 | }
70 |
71 | // List file in this directory with the file filter
72 | final File[] files = pathDir.listFiles(FileUtils.sFileFilter);
73 | if (files != null) {
74 | // Sort the files alphabetically
75 | Arrays.sort(files, FileUtils.sComparator);
76 | // Add each file to the File list for the list adapter
77 | for (File file : files)
78 | list.add(file);
79 | }
80 |
81 | return list;
82 | }
83 |
84 | @Override
85 | public void deliverResult(List data) {
86 | if (isReset()) {
87 | onReleaseResources(data);
88 | return;
89 | }
90 |
91 | List oldData = mData;
92 | mData = data;
93 |
94 | if (isStarted())
95 | super.deliverResult(data);
96 |
97 | if (oldData != null && oldData != data)
98 | onReleaseResources(oldData);
99 | }
100 |
101 | @Override
102 | protected void onStartLoading() {
103 | if (mData != null)
104 | deliverResult(mData);
105 |
106 | if (mFileObserver == null) {
107 | mFileObserver = new FileObserver(mPath, FILE_OBSERVER_MASK) {
108 | @Override
109 | public void onEvent(int event, String path) {
110 | onContentChanged();
111 | }
112 | };
113 | }
114 | mFileObserver.startWatching();
115 |
116 | if (takeContentChanged() || mData == null)
117 | forceLoad();
118 | }
119 |
120 | @Override
121 | protected void onStopLoading() {
122 | cancelLoad();
123 | }
124 |
125 | @Override
126 | protected void onReset() {
127 | onStopLoading();
128 |
129 | if (mData != null) {
130 | onReleaseResources(mData);
131 | mData = null;
132 | }
133 | }
134 |
135 | @Override
136 | public void onCanceled(List data) {
137 | super.onCanceled(data);
138 |
139 | onReleaseResources(data);
140 | }
141 |
142 | protected void onReleaseResources(List data) {
143 |
144 | if (mFileObserver != null) {
145 | mFileObserver.stopWatching();
146 | mFileObserver = null;
147 | }
148 | }
149 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/adapter/HostArrayAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.adapter;
17 |
18 | import android.content.Intent;
19 | import android.content.SharedPreferences;
20 | import android.preference.PreferenceManager;
21 | import android.support.v4.app.Fragment;
22 | import android.view.LayoutInflater;
23 | import android.view.View;
24 | import android.view.View.OnClickListener;
25 | import android.view.ViewGroup;
26 | import android.widget.ArrayAdapter;
27 | import android.widget.ImageButton;
28 | import android.widget.TextView;
29 |
30 | import com.xargsgrep.portknocker.R;
31 | import com.xargsgrep.portknocker.activity.EditHostActivity;
32 | import com.xargsgrep.portknocker.asynctask.KnockerAsyncTask;
33 | import com.xargsgrep.portknocker.fragment.HostListFragment;
34 | import com.xargsgrep.portknocker.model.Host;
35 |
36 | import java.util.List;
37 |
38 | public class HostArrayAdapter extends ArrayAdapter
39 | {
40 | private Fragment fragment;
41 |
42 | public HostArrayAdapter(Fragment fragment, List hosts)
43 | {
44 | super(fragment.getActivity(), -1, hosts);
45 | this.fragment = fragment;
46 | }
47 |
48 | @Override
49 | public View getView(int position, View convertView, ViewGroup parent)
50 | {
51 | View view = convertView;
52 | if (view == null) view = LayoutInflater.from(getContext()).inflate(R.layout.host_row, null);
53 |
54 | TextView labelView = (TextView) view.findViewById(R.id.host_row_label);
55 | TextView hostnameView = (TextView) view.findViewById(R.id.host_row_hostname);
56 | TextView portsView = (TextView) view.findViewById(R.id.host_row_ports);
57 |
58 | Host host = getItem(position);
59 |
60 | labelView.setText(host.getLabel());
61 | hostnameView.setText(host.getHostname());
62 | portsView.setText(host.getPortsString());
63 |
64 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(fragment.getActivity());
65 | if (sharedPreferences.getBoolean(fragment.getActivity().getString(R.string.pref_key_hide_ports), false))
66 | {
67 | portsView.setVisibility(View.GONE);
68 | }
69 |
70 | final int fPosition = position;
71 | view.setOnClickListener(new OnClickListener()
72 | {
73 | @Override
74 | public void onClick(View v)
75 | {
76 | Host host = getItem(fPosition);
77 | KnockerAsyncTask knockerAsyncTask = new KnockerAsyncTask(fragment.getActivity(), host.getPorts().size());
78 | knockerAsyncTask.execute(host);
79 | }
80 | });
81 |
82 | ImageButton deleteButton = (ImageButton) view.findViewById(R.id.host_row_delete);
83 | deleteButton.setOnClickListener(new OnClickListener()
84 | {
85 | @Override
86 | public void onClick(View v)
87 | {
88 | ((HostListFragment) fragment).setDeleteHostPosition(fPosition);
89 | ((HostListFragment) fragment).showDeleteDialog();
90 | }
91 | });
92 |
93 | ImageButton editButton = (ImageButton) view.findViewById(R.id.host_row_edit);
94 | editButton.setOnClickListener(new OnClickListener()
95 | {
96 | @Override
97 | public void onClick(View v)
98 | {
99 | Host host = getItem(fPosition);
100 | Intent editHostIntent = new Intent(fragment.getActivity(), EditHostActivity.class);
101 | editHostIntent.putExtra(EditHostActivity.KEY_HOST_ID, host.getId());
102 | fragment.getActivity().startActivity(editHostIntent);
103 | }
104 | });
105 |
106 | return view;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/asynctask/RetrieveApplicationsAsyncTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.asynctask;
17 |
18 | import android.content.pm.ApplicationInfo;
19 | import android.content.pm.PackageManager;
20 | import android.os.AsyncTask;
21 | import android.support.v4.app.Fragment;
22 | import android.support.v4.app.FragmentActivity;
23 | import android.support.v4.app.FragmentManager;
24 | import android.support.v4.app.FragmentTransaction;
25 |
26 | import com.xargsgrep.portknocker.R;
27 | import com.xargsgrep.portknocker.fragment.MiscFragment;
28 | import com.xargsgrep.portknocker.fragment.ProgressDialogFragment;
29 | import com.xargsgrep.portknocker.model.Application;
30 |
31 | import java.util.ArrayList;
32 | import java.util.Collections;
33 | import java.util.Comparator;
34 | import java.util.List;
35 |
36 | public class RetrieveApplicationsAsyncTask extends AsyncTask>
37 | {
38 | private FragmentActivity activity;
39 | private Fragment fragment;
40 |
41 | public RetrieveApplicationsAsyncTask(FragmentActivity activity, Fragment fragment)
42 | {
43 | this.activity = activity;
44 | this.fragment = fragment;
45 | }
46 |
47 | @Override
48 | protected void onPreExecute()
49 | {
50 | FragmentManager fragmentManager = activity.getSupportFragmentManager();
51 |
52 | FragmentTransaction ft = fragmentManager.beginTransaction();
53 | Fragment prev = fragmentManager.findFragmentByTag(ProgressDialogFragment.TAG);
54 | if (prev != null) ft.remove(prev);
55 | ft.addToBackStack(null);
56 | ft.commit();
57 |
58 | // ProgressDialogFragment dialogFragment = ProgressDialogFragment.newInstance(activity.getString(R.string.progress_dialog_retrieving_applications), true, ProgressDialog.STYLE_SPINNER);
59 | // dialogFragment.setCancelable(false);
60 | // dialogFragment.show(ft, ProgressDialogFragment.TAG);
61 | }
62 |
63 | @Override
64 | protected List doInBackground(Void... params)
65 | {
66 | PackageManager packageManager = activity.getPackageManager();
67 | List installedApplications = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
68 |
69 | List applications = new ArrayList<>();
70 | for (ApplicationInfo applicationInfo : installedApplications)
71 | {
72 | if (isSystemPackage(applicationInfo) || packageManager.getLaunchIntentForPackage(applicationInfo.packageName) == null)
73 | continue;
74 | applications.add(new Application(packageManager.getApplicationLabel(applicationInfo).toString(), applicationInfo.loadIcon(packageManager), applicationInfo.packageName));
75 | }
76 |
77 | Collections.sort(applications, new Comparator()
78 | {
79 | @Override
80 | public int compare(Application app1, Application app2)
81 | {
82 | return app1.getLabel().compareTo(app2.getLabel());
83 | }
84 | });
85 | applications.add(0, new Application(activity.getString(R.string.launch_app_list_default), null, ""));
86 |
87 | return applications;
88 | }
89 |
90 | @Override
91 | protected void onPostExecute(List applications)
92 | {
93 | // FragmentManager fragmentManager = activity.getSupportFragmentManager();
94 |
95 | ((MiscFragment) fragment).initializeApplicationAdapter(applications);
96 | // Fragment dialog = fragmentManager.findFragmentByTag(ProgressDialogFragment.TAG);
97 | // if (dialog != null) ((ProgressDialogFragment) dialog).dismiss();
98 | }
99 |
100 | private boolean isSystemPackage(ApplicationInfo applicationInfo)
101 | {
102 | return ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Port Knocker
4 | Port Knocker 1x1
5 | Port Knocker 2x1
6 | Port Knocker 3x1
7 | Port Knocker 4x1
8 | Host
9 | Ports
10 | Other
11 | Label
12 | Label
13 | Hostname/IP
14 | domain.com/192.168.10.1
15 | Port
16 | 1234
17 | Protocol
18 | Delay Between Packets (ms)
19 | 1000
20 | Launch Application
21 | None
22 | TCP Connect Timeout (ms)
23 | Yes
24 | No
25 | Delete host?
26 | Discard changes?
27 | Retrieving applications…
28 | Sending packets…
29 | hide_ports
30 | Hide ports in host list
31 | Port sequence will not be displayed in the host list
32 | hide_ports_widget
33 | Hide ports in widget
34 | Port sequence will not be displayed in widgets
35 | Miscellaneous
36 | Settings
37 | There are no items
38 | "Can't delete all ports"
39 | Please enter a label
40 | Please enter a hostname
41 | Invalid hostname/IP
42 | Please enter at least one port
43 | "Delay can't be more than "
44 | "Invalid port: "
45 | Saved
46 | Save failed
47 | Knocking complete
48 | Knocking canceled
49 | "Knocking failed: "
50 | "Imported hosts from file: "
51 | "Importing hosts failed: "
52 | No permission to access external memory.
53 | Settings
54 | Export Hosts
55 | Import Hosts
56 | Send Hosts
57 | Sort Hosts
58 | By hostname
59 | By label
60 | By newest
61 | Export Hosts
62 | Enter filename
63 | OK
64 | Cancel
65 | "Exported hosts to file: "
66 | "Exporting hosts failed: "
67 | "Share with... "
68 |
--------------------------------------------------------------------------------
/FileChooser/src/main/java/com/ipaulpro/afilechooser/FileListFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Paul Burke
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ipaulpro.afilechooser;
18 |
19 | import android.app.Activity;
20 | import android.os.Bundle;
21 | import android.os.Environment;
22 | import android.support.v4.app.ListFragment;
23 | import android.support.v4.app.LoaderManager;
24 | import android.support.v4.content.Loader;
25 | import android.view.View;
26 | import android.widget.ListView;
27 |
28 | import java.io.File;
29 | import java.util.List;
30 |
31 | /**
32 | * Fragment that displays a list of Files in a given path.
33 | *
34 | * @version 2013-12-11
35 | * @author paulburke (ipaulpro)
36 | */
37 | public class FileListFragment extends ListFragment implements
38 | LoaderManager.LoaderCallbacks> {
39 |
40 | /**
41 | * Interface to listen for events.
42 | */
43 | public interface Callbacks {
44 | /**
45 | * Called when a file is selected from the list.
46 | *
47 | * @param file The file selected
48 | */
49 | public void onFileSelected(File file);
50 | }
51 |
52 | private static final int LOADER_ID = 0;
53 |
54 | private FileListAdapter mAdapter;
55 | private String mPath;
56 |
57 | private Callbacks mListener;
58 |
59 | /**
60 | * Create a new instance with the given file path.
61 | *
62 | * @param path The absolute path of the file (directory) to display.
63 | * @return A new Fragment with the given file path.
64 | */
65 | public static FileListFragment newInstance(String path) {
66 | FileListFragment fragment = new FileListFragment();
67 | Bundle args = new Bundle();
68 | args.putString(FileChooserActivity.PATH, path);
69 | fragment.setArguments(args);
70 |
71 | return fragment;
72 | }
73 |
74 | @Override
75 | public void onAttach(Activity activity) {
76 | super.onAttach(activity);
77 |
78 | try {
79 | mListener = (Callbacks) activity;
80 | } catch (ClassCastException e) {
81 | throw new ClassCastException(activity.toString()
82 | + " must implement FileListFragment.Callbacks");
83 | }
84 | }
85 |
86 | @Override
87 | public void onCreate(Bundle savedInstanceState) {
88 | super.onCreate(savedInstanceState);
89 |
90 | mAdapter = new FileListAdapter(getActivity());
91 | mPath = getArguments() != null ? getArguments().getString(
92 | FileChooserActivity.PATH) : Environment
93 | .getExternalStorageDirectory().getAbsolutePath();
94 | }
95 |
96 | @Override
97 | public void onActivityCreated(Bundle savedInstanceState) {
98 | setEmptyText(getString(R.string.empty_directory));
99 | setListAdapter(mAdapter);
100 | setListShown(false);
101 |
102 | getLoaderManager().initLoader(LOADER_ID, null, this);
103 |
104 | super.onActivityCreated(savedInstanceState);
105 | }
106 |
107 | @Override
108 | public void onListItemClick(ListView l, View v, int position, long id) {
109 | FileListAdapter adapter = (FileListAdapter) l.getAdapter();
110 | if (adapter != null) {
111 | File file = (File) adapter.getItem(position);
112 | mPath = file.getAbsolutePath();
113 | mListener.onFileSelected(file);
114 | }
115 | }
116 |
117 | @Override
118 | public Loader> onCreateLoader(int id, Bundle args) {
119 | return new FileLoader(getActivity(), mPath);
120 | }
121 |
122 | @Override
123 | public void onLoadFinished(Loader> loader, List data) {
124 | mAdapter.setListItems(data);
125 |
126 | if (isResumed())
127 | setListShown(true);
128 | else
129 | setListShownNoAnimation(true);
130 | }
131 |
132 | @Override
133 | public void onLoaderReset(Loader> loader) {
134 | mAdapter.clear();
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/widget/ConfigureWidgetHostArrayAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.widget;
17 |
18 | import android.app.Activity;
19 | import android.appwidget.AppWidgetManager;
20 | import android.content.Context;
21 | import android.content.Intent;
22 | import android.content.SharedPreferences;
23 | import android.preference.PreferenceManager;
24 | import android.view.LayoutInflater;
25 | import android.view.View;
26 | import android.view.View.OnClickListener;
27 | import android.view.ViewGroup;
28 | import android.widget.ArrayAdapter;
29 | import android.widget.TextView;
30 |
31 | import com.xargsgrep.portknocker.R;
32 | import com.xargsgrep.portknocker.db.DatabaseManager;
33 | import com.xargsgrep.portknocker.model.Host;
34 |
35 | import java.util.List;
36 |
37 | public class ConfigureWidgetHostArrayAdapter extends ArrayAdapter
38 | {
39 | private DatabaseManager databaseManager;
40 | private Context context;
41 | private List hosts;
42 | private int appWidgetId;
43 |
44 | public ConfigureWidgetHostArrayAdapter(Context context, List hosts, int appWidgetId)
45 | {
46 | super(context, -1, hosts);
47 | databaseManager = new DatabaseManager(context);
48 | this.context = context;
49 | this.hosts = hosts;
50 | this.appWidgetId = appWidgetId;
51 | }
52 |
53 | @Override
54 | public int getCount()
55 | {
56 | return hosts.size();
57 | }
58 |
59 | @Override
60 | public Host getItem(int position)
61 | {
62 | return hosts.get(position);
63 | }
64 |
65 | @Override
66 | public View getView(int position, View convertView, ViewGroup parent)
67 | {
68 | View view = convertView;
69 | if (view == null) view = LayoutInflater.from(getContext()).inflate(R.layout.host_row, null);
70 |
71 | TextView labelView = (TextView) view.findViewById(R.id.host_row_label);
72 | TextView hostnameView = (TextView) view.findViewById(R.id.host_row_hostname);
73 | TextView portsView = (TextView) view.findViewById(R.id.host_row_ports);
74 |
75 | Host host = hosts.get(position);
76 |
77 | labelView.setText(host.getLabel());
78 | hostnameView.setText(host.getHostname());
79 | portsView.setText(host.getPortsString());
80 |
81 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
82 | if (sharedPreferences.getBoolean(context.getString(R.string.pref_key_hide_ports), false))
83 | {
84 | portsView.setVisibility(View.GONE);
85 | }
86 |
87 | final int fPosition = position;
88 | view.setOnClickListener(new OnClickListener()
89 | {
90 | @Override
91 | public void onClick(View v)
92 | {
93 | long hostId = getItem(fPosition).getId();
94 | ConfigureWidgetActivity.saveHostIdPreference(context, appWidgetId, hostId);
95 | // workaround for phantom widgets
96 | ConfigureWidgetActivity.saveConfiguredPreference(context, appWidgetId);
97 |
98 | AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
99 | HostWidget.updateAppWidget(context, appWidgetManager, appWidgetId, hostId);
100 |
101 | Intent resultValue = new Intent();
102 | resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
103 | ((Activity) context).setResult(Activity.RESULT_OK, resultValue);
104 | ((Activity) context).finish();
105 | }
106 | });
107 |
108 | view.findViewById(R.id.host_row_delete).setVisibility(View.GONE);
109 | view.findViewById(R.id.host_row_edit).setVisibility(View.GONE);
110 | view.findViewById(R.id.host_row_divider1).setVisibility(View.GONE);
111 | view.findViewById(R.id.host_row_divider2).setVisibility(View.GONE);
112 |
113 | return view;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/app/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Port Knocker
4 | Port Knocker 1x1
5 | Port Knocker 2x1
6 | Port Knocker 3x1
7 | Port Knocker 4x1
8 | Host
9 | Ports
10 | Weitere Einstellungen
11 | Titel
12 | Titel
13 | Hostname/IP
14 | domain.com/192.168.10.1
15 | Port
16 | 1234
17 | Protokoll
18 | Verzögerung zwischen Paketen (ms)
19 | 1000
20 | Starte Applikation
21 | Keine
22 | TCP Verbindungs-Timeout (ms)
23 | Ja
24 | Nein
25 | Host löschen?
26 | Änderungen verwerfen?
27 | Empfange Applikation…
28 | Sende Pakete…
29 | hide_ports
30 | Ports in Hostliste verstecken
31 | Portsequenz nicht in der Hostliste anzeigen
32 | hide_ports_widget
33 | Ports im Widget verstecken
34 | Portsequenz nicht im Widget anzeigen
35 | Weitere Einstellungen
36 | Einstellungen
37 | Liste ist leer
38 | \"Es können nicht alle Ports gelöscht werden\"
39 | Bitte Titel eingeben
40 | Hostnamen eingeben
41 | Ungültiger hostname/IP
42 | Es muss mindestens ein Port angegeben werden
43 | "Verzögerung kann nicht größer sein als "
44 | "Ungültiger Port: "
45 | Gespeichert
46 | Speichern fehlgeschlagen
47 | Anklopfen komplett
48 | Anklopfen abgebrochen
49 | \"Anklopfen fehlgeschlagen: \"
50 | "Importiert aus: "
51 | "Import fehlgeschlagen: "
52 | Keine Rechte um auf externen Speicher zuzugreifen.
53 | Einstellungen
54 | Exportiere Hostliste
55 | Importiere Hostliste
56 | Sende Hostliste
57 | Sortiere Hostliste
58 | Nach Hostname
59 | Nach Titel
60 | Nach Datum
61 | Exportiere Hosts
62 | Dateiname für Export
63 | Ok
64 | Abbrechen
65 | "Hostliste exportiert in file: "
66 | "Exportieren von Hostliste fehlgeschlagen: "
67 | "Teile mit... "
68 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/fragment/PortsFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.fragment;
17 |
18 | import android.os.Bundle;
19 | import android.support.v4.app.ListFragment;
20 | import android.view.LayoutInflater;
21 | import android.view.View;
22 | import android.view.ViewGroup;
23 | import android.widget.ImageButton;
24 | import android.widget.LinearLayout;
25 | import android.widget.ListView;
26 |
27 | import com.xargsgrep.portknocker.R;
28 | import com.xargsgrep.portknocker.activity.EditHostActivity;
29 | import com.xargsgrep.portknocker.adapter.PortArrayAdapter;
30 | import com.xargsgrep.portknocker.db.DatabaseManager;
31 | import com.xargsgrep.portknocker.model.Host;
32 | import com.xargsgrep.portknocker.model.Port;
33 |
34 | import java.util.ArrayList;
35 | import java.util.List;
36 |
37 | public class PortsFragment extends ListFragment
38 | {
39 | public static final String TAG = "PortsFragment";
40 |
41 | private DatabaseManager databaseManager;
42 | private PortArrayAdapter portAdapter;
43 | private boolean savedInstanceState = false;
44 |
45 | public static PortsFragment newInstance(Long hostId)
46 | {
47 | PortsFragment fragment = new PortsFragment();
48 | if (hostId != null)
49 | {
50 | Bundle args = new Bundle();
51 | args.putLong(EditHostActivity.KEY_HOST_ID, hostId);
52 | fragment.setArguments(args);
53 | }
54 | return fragment;
55 | }
56 |
57 | @Override
58 | public void onCreate(Bundle savedInstanceState)
59 | {
60 | super.onCreate(savedInstanceState);
61 | setRetainInstance(true);
62 | setHasOptionsMenu(true);
63 | databaseManager = new DatabaseManager(getActivity());
64 | }
65 |
66 | @Override
67 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
68 | {
69 | super.onCreateView(inflater, container, savedInstanceState);
70 | View view = inflater.inflate(R.layout.list_view, container, false);
71 | View header = inflater.inflate(R.layout.ports_header, null);
72 | ((LinearLayout) view.findViewById(R.id.list_header)).addView(header);
73 | return view;
74 | }
75 |
76 | @Override
77 | public void onViewCreated(View view, Bundle savedInstanceState)
78 | {
79 | super.onViewCreated(view, savedInstanceState);
80 |
81 | ImageButton addButton = (ImageButton) view.findViewById(R.id.fab_image_button);
82 | addButton.setOnClickListener(new View.OnClickListener()
83 | {
84 | @Override
85 | public void onClick(View v)
86 | {
87 | addPort();
88 | }
89 | });
90 |
91 | Bundle args = getArguments();
92 |
93 | List defaultPorts = new ArrayList<>();
94 | defaultPorts.add(new Port());
95 | defaultPorts.add(new Port());
96 | defaultPorts.add(new Port());
97 |
98 | if (args != null && !this.savedInstanceState)
99 | {
100 | // only restore state from args if onSaveInstanceState hasn't been invoked
101 | Long hostId = args.getLong(EditHostActivity.KEY_HOST_ID);
102 | Host host = databaseManager.getHost(hostId);
103 | List ports = (host.getPorts().size() > 0) ? host.getPorts() : defaultPorts;
104 | portAdapter = new PortArrayAdapter(getActivity(), ports);
105 | setListAdapter(portAdapter);
106 | }
107 | else if (portAdapter == null)
108 | {
109 | portAdapter = new PortArrayAdapter(getActivity(), defaultPorts);
110 | setListAdapter(portAdapter);
111 | }
112 | }
113 |
114 | @Override
115 | public void onSaveInstanceState(Bundle outState)
116 | {
117 | super.onSaveInstanceState(outState);
118 | savedInstanceState = true;
119 | }
120 |
121 | public void clearFoci()
122 | {
123 | ListView view = getListView();
124 | for (int i = 0; i < view.getChildCount(); i++)
125 | {
126 | View row = view.getChildAt(i);
127 | row.findViewById(R.id.port_row_port).clearFocus();
128 | }
129 | }
130 |
131 | private void addPort()
132 | {
133 | PortArrayAdapter adapter = (PortArrayAdapter) getListAdapter();
134 | adapter.add(new Port());
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/asynctask/KnockerAsyncTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.asynctask;
17 |
18 | import android.app.ProgressDialog;
19 | import android.content.Intent;
20 | import android.os.AsyncTask;
21 | import android.support.v4.app.Fragment;
22 | import android.support.v4.app.FragmentActivity;
23 | import android.support.v4.app.FragmentManager;
24 | import android.support.v4.app.FragmentTransaction;
25 | import android.view.Gravity;
26 | import android.widget.Toast;
27 |
28 | import com.xargsgrep.portknocker.R;
29 | import com.xargsgrep.portknocker.asynctask.Knocker.KnockResult;
30 | import com.xargsgrep.portknocker.fragment.ProgressDialogFragment;
31 | import com.xargsgrep.portknocker.model.Host;
32 | import com.xargsgrep.portknocker.utils.StringUtils;
33 |
34 | public class KnockerAsyncTask extends AsyncTask
35 | {
36 | private FragmentActivity activity;
37 | private int progressMax;
38 |
39 | public KnockerAsyncTask(FragmentActivity activity, int progressMax)
40 | {
41 | this.activity = activity;
42 | this.progressMax = progressMax;
43 | }
44 |
45 | @Override
46 | protected void onPreExecute()
47 | {
48 | FragmentManager fragmentManager = activity.getSupportFragmentManager();
49 |
50 | FragmentTransaction ft = fragmentManager.beginTransaction();
51 | Fragment prev = fragmentManager.findFragmentByTag(ProgressDialogFragment.TAG);
52 | if (prev != null) ft.remove(prev);
53 | ft.addToBackStack(null);
54 |
55 | ProgressDialogFragment dialogFragment = ProgressDialogFragment.newInstance(this, activity.getString(R.string.progress_dialog_sending_packets), false, ProgressDialog.STYLE_HORIZONTAL, progressMax);
56 | dialogFragment.setCancelable(true);
57 | dialogFragment.show(ft, ProgressDialogFragment.TAG);
58 | }
59 |
60 | @Override
61 | protected KnockResult doInBackground(Host... params)
62 | {
63 | Host host = params[0];
64 | // pass in 'this' so the progress dialog can be updated
65 | return Knocker.doKnock(host, this);
66 | }
67 |
68 | @Override
69 | protected void onPostExecute(KnockResult result)
70 | {
71 | FragmentManager fragmentManager = activity.getSupportFragmentManager();
72 |
73 | Fragment dialog = fragmentManager.findFragmentByTag(ProgressDialogFragment.TAG);
74 | if (dialog != null) ((ProgressDialogFragment) dialog).dismiss();
75 |
76 | if (result.isSuccess())
77 | {
78 | if (StringUtils.isNotBlank(result.getLaunchIntentPackage()))
79 | {
80 | Intent launchIntent = activity.getPackageManager().getLaunchIntentForPackage(result.getLaunchIntentPackage());
81 | if (launchIntent == null)
82 | {
83 | showToast("Unable to launch intent " + result.getLaunchIntentPackage());
84 | }
85 | else
86 | {
87 | activity.startActivity(launchIntent);
88 | }
89 | }
90 | else
91 | {
92 | showToast(activity.getString(R.string.toast_msg_knocking_complete));
93 | }
94 | }
95 | else
96 | {
97 | showToast(activity.getString(R.string.toast_msg_knocking_failed) + result.getError());
98 | }
99 | }
100 |
101 | @Override
102 | protected void onCancelled()
103 | {
104 | super.onCancelled();
105 | showToast(activity.getString(R.string.toast_msg_knocking_canceled));
106 | }
107 |
108 | @Override
109 | protected void onProgressUpdate(Integer... values)
110 | {
111 | FragmentManager fragmentManager = activity.getSupportFragmentManager();
112 | Fragment dialogFragment = fragmentManager.findFragmentByTag(ProgressDialogFragment.TAG);
113 | if (dialogFragment != null)
114 | ((ProgressDialogFragment) dialogFragment).setProgress(values[0]);
115 | }
116 |
117 | public void doPublishProgress(Integer value)
118 | {
119 | publishProgress(value);
120 | }
121 |
122 | private void showToast(String text)
123 | {
124 | Toast toast = Toast.makeText(activity, text, Toast.LENGTH_LONG);
125 | toast.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 0, 0);
126 | toast.show();
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/fragment/HostFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.fragment;
17 |
18 | import android.os.Bundle;
19 | import android.support.v4.app.Fragment;
20 | import android.text.Editable;
21 | import android.text.InputFilter;
22 | import android.text.TextWatcher;
23 | import android.view.LayoutInflater;
24 | import android.view.View;
25 | import android.view.ViewGroup;
26 | import android.widget.EditText;
27 |
28 | import com.xargsgrep.portknocker.R;
29 | import com.xargsgrep.portknocker.activity.EditHostActivity;
30 | import com.xargsgrep.portknocker.db.DatabaseManager;
31 | import com.xargsgrep.portknocker.filter.HostnameInputFilter;
32 | import com.xargsgrep.portknocker.model.Host;
33 |
34 | public class HostFragment extends Fragment
35 | {
36 | public static final String TAG = "HostFragment";
37 |
38 | private static final InputFilter HOSTNAME_INPUT_FILTER = new HostnameInputFilter();
39 |
40 | private DatabaseManager databaseManager;
41 | private String hostLabel;
42 | private String hostname;
43 |
44 | public static HostFragment newInstance(Long hostId)
45 | {
46 | HostFragment fragment = new HostFragment();
47 | if (hostId != null)
48 | {
49 | Bundle args = new Bundle();
50 | args.putLong(EditHostActivity.KEY_HOST_ID, hostId);
51 | fragment.setArguments(args);
52 | }
53 | return fragment;
54 | }
55 |
56 | @Override
57 | public void onCreate(Bundle savedInstanceState)
58 | {
59 | super.onCreate(savedInstanceState);
60 | setRetainInstance(true);
61 | databaseManager = new DatabaseManager(getActivity());
62 | }
63 |
64 | @Override
65 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
66 | {
67 | super.onCreateView(inflater, container, savedInstanceState);
68 | return inflater.inflate(R.layout.host_fragment, container, false);
69 | }
70 |
71 | @Override
72 | public void onViewCreated(View view, Bundle savedInstanceState)
73 | {
74 | super.onViewCreated(view, savedInstanceState);
75 |
76 | EditText hostLabelEdit = getHostLabelEditText();
77 | EditText hostnameEdit = getHostnameEditText();
78 |
79 | hostLabelEdit.addTextChangedListener(new FieldSettingTextWatcher("hostLabel"));
80 | hostnameEdit.addTextChangedListener(new FieldSettingTextWatcher("hostname"));
81 |
82 | Bundle args = getArguments();
83 |
84 | if (savedInstanceState != null)
85 | {
86 | hostLabelEdit.setText(savedInstanceState.getString("hostLabel"));
87 | hostnameEdit.setText(savedInstanceState.getString("hostname"));
88 | }
89 | else if (args != null)
90 | {
91 | Long hostId = args.getLong(EditHostActivity.KEY_HOST_ID);
92 | Host host = databaseManager.getHost(hostId);
93 | hostLabelEdit.setText(host.getLabel());
94 | hostnameEdit.setText(host.getHostname());
95 | }
96 |
97 | hostnameEdit.setFilters(new InputFilter[] {HOSTNAME_INPUT_FILTER});
98 | }
99 |
100 | @Override
101 | public void onSaveInstanceState(Bundle outState)
102 | {
103 | super.onSaveInstanceState(outState);
104 | outState.putString("hostLabel", hostLabel);
105 | outState.putString("hostname", hostname);
106 | }
107 |
108 | public String getHostLabel()
109 | {
110 | return hostLabel;
111 | }
112 |
113 | public String getHostname()
114 | {
115 | return hostname;
116 | }
117 |
118 | private EditText getHostLabelEditText()
119 | {
120 | return (EditText) getView().findViewById(R.id.host_label_edit);
121 | }
122 |
123 | private EditText getHostnameEditText()
124 | {
125 | return (EditText) getView().findViewById(R.id.host_name_edit);
126 | }
127 |
128 | private class FieldSettingTextWatcher implements TextWatcher
129 | {
130 | private String field;
131 |
132 | private FieldSettingTextWatcher(String field)
133 | {
134 | this.field = field;
135 | }
136 |
137 | @Override
138 | public void afterTextChanged(Editable s)
139 | {
140 | if (field.equals("hostLabel"))
141 | {
142 | hostLabel = s.toString();
143 | }
144 | else if (field.equals("hostname"))
145 | {
146 | hostname = s.toString();
147 | }
148 | }
149 |
150 | @Override
151 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
152 |
153 | @Override
154 | public void onTextChanged(CharSequence s, int start, int before, int count) { }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/adapter/PortArrayAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.adapter;
17 |
18 | import android.content.Context;
19 | import android.view.Gravity;
20 | import android.view.LayoutInflater;
21 | import android.view.View;
22 | import android.view.View.OnClickListener;
23 | import android.view.View.OnFocusChangeListener;
24 | import android.view.ViewGroup;
25 | import android.widget.AdapterView;
26 | import android.widget.AdapterView.OnItemSelectedListener;
27 | import android.widget.ArrayAdapter;
28 | import android.widget.EditText;
29 | import android.widget.ImageButton;
30 | import android.widget.LinearLayout;
31 | import android.widget.Spinner;
32 | import android.widget.Toast;
33 |
34 | import com.xargsgrep.portknocker.R;
35 | import com.xargsgrep.portknocker.model.Port;
36 | import com.xargsgrep.portknocker.model.Port.Protocol;
37 | import com.xargsgrep.portknocker.utils.StringUtils;
38 |
39 | import java.util.List;
40 |
41 | public class PortArrayAdapter extends ArrayAdapter
42 | {
43 | private Context context;
44 | private List ports;
45 |
46 | public PortArrayAdapter(Context context, List ports)
47 | {
48 | super(context, -1, ports);
49 | this.context = context;
50 | this.ports = ports;
51 | }
52 |
53 | @Override
54 | public int getCount()
55 | {
56 | return ports.size();
57 | }
58 |
59 | @Override
60 | public Port getItem(int position)
61 | {
62 | return ports.get(position);
63 | }
64 |
65 | public List getPorts()
66 | {
67 | return ports;
68 | }
69 |
70 | @Override
71 | public View getView(int position, View convertView, ViewGroup parent)
72 | {
73 | View view = convertView;
74 | if (view == null) view = LayoutInflater.from(getContext()).inflate(R.layout.port_row, null);
75 |
76 | EditText portView = (EditText) view.findViewById(R.id.port_row_port);
77 | Spinner protocolSpinner = (Spinner) view.findViewById(R.id.port_row_protocol);
78 | ImageButton deleteButton = (ImageButton) view.findViewById(R.id.port_row_delete);
79 |
80 | ArrayAdapter protocolAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, Protocol.values());
81 | protocolAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
82 | protocolSpinner.setAdapter(protocolAdapter);
83 |
84 | Port port = ports.get(position);
85 | portView.setText((port.getPort() > -1) ? Integer.valueOf(port.getPort()).toString() : "");
86 | protocolSpinner.setSelection(port.getProtocol().ordinal());
87 |
88 | final int fPosition = position;
89 | portView.setOnFocusChangeListener(new OnFocusChangeListener()
90 | {
91 | @Override
92 | public void onFocusChange(View view, boolean hasFocus)
93 | {
94 | if (!hasFocus)
95 | {
96 | String portStr = ((EditText) view).getText().toString();
97 | // if fPosition is out of bounds, it means the last row was focused and a row before it was deleted
98 | ports.get((fPosition >= getCount())
99 | ? fPosition - 1
100 | : fPosition).setPort((StringUtils.isNotBlank(portStr)) ? Integer.parseInt(portStr) : -1);
101 | }
102 | }
103 | });
104 |
105 | protocolSpinner.setOnItemSelectedListener(new OnItemSelectedListener()
106 | {
107 | @Override
108 | public void onItemSelected(AdapterView> parent, View view, int position, long id)
109 | {
110 | ports.get(fPosition).setProtocol(Protocol.values()[position]);
111 | }
112 |
113 | @Override
114 | public void onNothingSelected(AdapterView> parent) { }
115 | });
116 |
117 | deleteButton.setOnClickListener(new OnClickListener()
118 | {
119 | @Override
120 | public void onClick(View v)
121 | {
122 | if (getCount() == 1)
123 | {
124 | Toast toast = Toast.makeText(getContext(), context.getString(R.string.toast_msg_delete_all_ports), Toast.LENGTH_SHORT);
125 | toast.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 0, 0);
126 | toast.show();
127 | }
128 | else
129 | {
130 | LinearLayout parent = (LinearLayout) v.getParent();
131 | EditText dPortView = (EditText) parent.findViewById(R.id.port_row_port);
132 | dPortView.setOnFocusChangeListener(null);
133 | remove(getItem(fPosition));
134 | }
135 | }
136 | });
137 |
138 | return view;
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/widget/HostWidget.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.widget;
17 |
18 | import android.app.PendingIntent;
19 | import android.appwidget.AppWidgetManager;
20 | import android.appwidget.AppWidgetProvider;
21 | import android.content.ComponentName;
22 | import android.content.Context;
23 | import android.content.Intent;
24 | import android.content.SharedPreferences;
25 | import android.preference.PreferenceManager;
26 | import android.view.View;
27 | import android.widget.RemoteViews;
28 |
29 | import com.xargsgrep.portknocker.R;
30 | import com.xargsgrep.portknocker.activity.HostListActivity;
31 | import com.xargsgrep.portknocker.db.DatabaseManager;
32 | import com.xargsgrep.portknocker.model.Host;
33 |
34 | public class HostWidget extends AppWidgetProvider
35 | {
36 | @Override
37 | public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
38 | {
39 | for (int appWidgetId : appWidgetIds)
40 | {
41 | long hostId = ConfigureWidgetActivity.getHostIdPreference(context, appWidgetId);
42 | updateAppWidget(context, appWidgetManager, appWidgetId, hostId);
43 | }
44 | }
45 |
46 | @Override
47 | public void onDeleted(Context context, int[] appWidgetIds)
48 | {
49 | for (int i = 0; i < appWidgetIds.length; i++)
50 | {
51 | ConfigureWidgetActivity.deleteHostIdPreference(context, appWidgetIds[i]);
52 | }
53 | }
54 |
55 | public static void updateAllAppWidgets(Context context)
56 | {
57 | AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
58 | int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, HostWidget.class));
59 | for (int appWidgetId : appWidgetIds)
60 | {
61 | updateAppWidget(context, appWidgetManager, appWidgetId, null);
62 | }
63 | }
64 |
65 | public static void updateAllAppWidgetsForHost(Context context, long hostId)
66 | {
67 | AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
68 | int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, HostWidget.class));
69 | for (int appWidgetId : appWidgetIds)
70 | {
71 | updateAppWidget(context, appWidgetManager, appWidgetId, hostId);
72 | }
73 | }
74 |
75 | public static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Long hostId)
76 | {
77 | // workaround for phantom widgets
78 | boolean configured = ConfigureWidgetActivity.getConfiguredPreference(context, appWidgetId);
79 | if (!configured) return;
80 |
81 | Long widgetHostId = ConfigureWidgetActivity.getHostIdPreference(context, appWidgetId);
82 | if (hostId != null && !hostId.equals(widgetHostId)) return;
83 |
84 | DatabaseManager hostDataManager = new DatabaseManager(context);
85 | RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
86 |
87 |
88 | boolean hostExists = hostDataManager.hostExists(widgetHostId);
89 | if (hostExists)
90 | {
91 | Host host = hostDataManager.getHost(widgetHostId);
92 |
93 | Intent intent = new Intent(context, HostListActivity.class);
94 | intent.putExtra("hostId", widgetHostId);
95 | PendingIntent pendingIntent = PendingIntent.getActivity(context, appWidgetId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
96 | views.setOnClickPendingIntent(R.id.widget, pendingIntent);
97 |
98 | views.setTextViewText(R.id.widget_host_label, host.getLabel());
99 | views.setTextViewText(R.id.widget_host_hostname, host.getHostname());
100 | views.setTextViewText(R.id.widget_host_ports, host.getPortsString());
101 |
102 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
103 | if (sharedPreferences.getBoolean(context.getString(R.string.pref_key_hide_ports_widget), false))
104 | {
105 | views.setViewVisibility(R.id.widget_host_ports, View.GONE);
106 | }
107 | else
108 | {
109 | views.setViewVisibility(R.id.widget_host_ports, View.VISIBLE);
110 | }
111 | }
112 | else
113 | {
114 | views.setTextViewText(R.id.widget_host_label, "Invalid Host");
115 | views.setViewVisibility(R.id.widget_host_hostname, View.GONE);
116 | views.setViewVisibility(R.id.widget_host_ports, View.GONE);
117 |
118 | Intent intent = new Intent(context, HostListActivity.class);
119 | PendingIntent pendingIntent = PendingIntent.getActivity(context, appWidgetId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
120 | views.setOnClickPendingIntent(R.id.widget, pendingIntent);
121 | }
122 |
123 | appWidgetManager.updateAppWidget(appWidgetId, views);
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/db/DatabaseHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.db;
17 |
18 | import android.content.Context;
19 | import android.database.sqlite.SQLiteDatabase;
20 | import android.database.sqlite.SQLiteOpenHelper;
21 | import android.provider.BaseColumns;
22 | import android.util.Log;
23 |
24 | import com.xargsgrep.portknocker.model.Host;
25 |
26 | public class DatabaseHelper extends SQLiteOpenHelper
27 | {
28 | private static final String TAG = "DatabaseHelper";
29 | private static final int DATABASE_VERSION = 2;
30 |
31 | private static final String DATABASE_FILENAME = "hosts.db";
32 |
33 | public static final String HOST_TABLE_NAME = "host";
34 | public static final String HOST_ID_COLUMN = BaseColumns._ID;
35 | public static final String HOST_LABEL_COLUMN = "label";
36 | public static final String HOST_HOSTNAME_COLUMN = "hostname";
37 | public static final String HOST_DELAY_COLUMN = "delay";
38 | public static final String HOST_TCP_CONNECT_TIMEOUT_COLUMN = "tcp_connect_timeout";
39 | public static final String HOST_LAUNCH_INTENT_PACKAGE_COLUMN = "launch_intent_package";
40 | public static final String HOST_USERNAME_COLUMN = "username";
41 | public static final String HOST_TARGET_PORT_COLUMN = "target_port";
42 |
43 | public static final String PORT_TABLE_NAME = "port";
44 | public static final String PORT_HOST_ID_COLUMN = "host_id";
45 | public static final String PORT_INDEX_COLUMN = "idx";
46 | public static final String PORT_PORT_COLUMN = "port";
47 | public static final String PORT_PROTOCOL_COLUMN = "protocol";
48 |
49 | public static final String[] HOST_TABLE_COLUMNS = new String[]
50 | {
51 | HOST_ID_COLUMN,
52 | HOST_LABEL_COLUMN,
53 | HOST_HOSTNAME_COLUMN,
54 | HOST_DELAY_COLUMN,
55 | HOST_LAUNCH_INTENT_PACKAGE_COLUMN,
56 | HOST_USERNAME_COLUMN,
57 | HOST_TARGET_PORT_COLUMN,
58 | HOST_TCP_CONNECT_TIMEOUT_COLUMN
59 | };
60 | public static final String[] PORT_TABLE_COLUMNS = new String[]
61 | {
62 | PORT_HOST_ID_COLUMN,
63 | PORT_INDEX_COLUMN,
64 | PORT_PORT_COLUMN,
65 | PORT_PROTOCOL_COLUMN
66 | };
67 |
68 | public DatabaseHelper(Context context)
69 | {
70 | super(context, DATABASE_FILENAME, null, DATABASE_VERSION);
71 | }
72 |
73 | @Override
74 | public void onCreate(SQLiteDatabase db)
75 | {
76 | String createHostTableSQL =
77 | "create table %s (" +
78 | " %s integer primary key autoincrement," +
79 | " %s string not null," +
80 | " %s string not null," +
81 | " %s integer not null default %d," +
82 | " %s string," +
83 | " %s string," +
84 | " %s integer," +
85 | " %s integer not null default %d" +
86 | ");";
87 | createHostTableSQL = String.format(
88 | createHostTableSQL,
89 | HOST_TABLE_NAME,
90 | HOST_ID_COLUMN,
91 | HOST_LABEL_COLUMN,
92 | HOST_HOSTNAME_COLUMN,
93 | HOST_DELAY_COLUMN, Host.DEFAULT_DELAY,
94 | HOST_LAUNCH_INTENT_PACKAGE_COLUMN,
95 | HOST_USERNAME_COLUMN,
96 | HOST_TARGET_PORT_COLUMN,
97 | HOST_TCP_CONNECT_TIMEOUT_COLUMN, Host.DEFAULT_TCP_CONNECT_TIMEOUT
98 | );
99 |
100 | String createPortTableSQL =
101 | "create table %s (" +
102 | " %s integer not null," +
103 | " %s integer not null," +
104 | " %s integer not null," +
105 | " %s integer not null" +
106 | ");";
107 | createPortTableSQL = String.format(
108 | createPortTableSQL,
109 | PORT_TABLE_NAME,
110 | PORT_HOST_ID_COLUMN,
111 | PORT_INDEX_COLUMN,
112 | PORT_PORT_COLUMN,
113 | PORT_PROTOCOL_COLUMN
114 | );
115 |
116 | db.execSQL(createHostTableSQL);
117 | db.execSQL(createPortTableSQL);
118 | }
119 |
120 | @Override
121 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
122 | {
123 | Log.d(TAG, "Upgrading database from version " + oldVersion + " to version " + newVersion);
124 | switch (newVersion)
125 | {
126 | case DATABASE_VERSION:
127 | db.execSQL(String.format(
128 | "alter table %s add column %s integer not null default %d;",
129 | HOST_TABLE_NAME,
130 | HOST_TCP_CONNECT_TIMEOUT_COLUMN,
131 | Host.DEFAULT_TCP_CONNECT_TIMEOUT
132 | ));
133 | return;
134 | default:
135 | throw new IllegalStateException("Invalid newVersion: " + newVersion);
136 | }
137 | }
138 | }
139 | /*
140 | Version 1:
141 | create table host(
142 | _id integer primary key autoincrement,
143 | label string not null,
144 | hostname string not null,
145 | delay integer not null default 0,
146 | launch_intent_package string,
147 | username string,
148 | target_port integer
149 | );
150 |
151 | Version 2:
152 | create table host(
153 | _id integer primary key autoincrement,
154 | label string not null,
155 | hostname string not null,
156 | delay integer not null default 1000,
157 | launch_intent_package string,
158 | username string,
159 | target_port integer,
160 | tcp_connect_timeout integer not null default 100,
161 | );
162 | */
163 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
47 |
48 |
52 |
53 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
68 |
69 |
70 |
71 |
72 |
76 |
77 |
81 |
82 |
83 |
84 |
85 |
89 |
90 |
94 |
95 |
96 |
97 |
98 |
102 |
103 |
107 |
108 |
109 |
110 |
111 |
115 |
116 |
117 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
142 |
143 |
144 |
145 |
146 |
147 |
152 |
155 |
156 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/fragment/HostListFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.fragment;
17 |
18 | import android.app.AlertDialog;
19 | import android.content.DialogInterface;
20 | import android.content.Intent;
21 | import android.os.Bundle;
22 | import android.support.v4.app.ListFragment;
23 | import android.view.LayoutInflater;
24 | import android.view.View;
25 | import android.view.ViewGroup;
26 | import android.widget.ArrayAdapter;
27 | import android.widget.ImageButton;
28 |
29 | import com.xargsgrep.portknocker.R;
30 | import com.xargsgrep.portknocker.activity.EditHostActivity;
31 | import com.xargsgrep.portknocker.activity.HostListActivity;
32 | import com.xargsgrep.portknocker.adapter.HostArrayAdapter;
33 | import com.xargsgrep.portknocker.db.DatabaseManager;
34 | import com.xargsgrep.portknocker.model.Host;
35 | import com.xargsgrep.portknocker.widget.HostWidget;
36 |
37 | import java.util.Collections;
38 | import java.util.Comparator;
39 | import java.util.List;
40 |
41 | public class HostListFragment extends ListFragment
42 | {
43 | public static final String TAG = "HostListFragment";
44 |
45 | private DatabaseManager databaseManager;
46 | private int deleteHostPosition;
47 |
48 | public static HostListFragment newInstance()
49 | {
50 | return new HostListFragment();
51 | }
52 |
53 | @Override
54 | public void onCreate(Bundle savedInstanceState)
55 | {
56 | super.onCreate(savedInstanceState);
57 | setRetainInstance(true);
58 | databaseManager = new DatabaseManager(getActivity());
59 | }
60 |
61 | @Override
62 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
63 | {
64 | super.onCreateView(inflater, container, savedInstanceState);
65 | return inflater.inflate(R.layout.list_view, container, false);
66 | }
67 |
68 | @Override
69 | public void onViewCreated(View view, Bundle savedInstanceState)
70 | {
71 | super.onViewCreated(view, savedInstanceState);
72 |
73 | ImageButton addButton = (ImageButton) view.findViewById(R.id.fab_image_button);
74 | addButton.setOnClickListener(new View.OnClickListener()
75 | {
76 | @Override
77 | public void onClick(View v)
78 | {
79 | Intent editHostIntent = new Intent(getActivity(), EditHostActivity.class);
80 | startActivity(editHostIntent);
81 | }
82 | });
83 |
84 | List hosts = databaseManager.getAllHosts();
85 | HostArrayAdapter hostAdapter = new HostArrayAdapter(this, hosts);
86 | setListAdapter(hostAdapter);
87 | }
88 |
89 | public void showDeleteDialog()
90 | {
91 | AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity());
92 | dialogBuilder.setTitle(R.string.confirm_dialog_delete_host_title);
93 | dialogBuilder.setIcon(R.drawable.ic_alert);
94 |
95 | final int position = deleteHostPosition;
96 | dialogBuilder.setPositiveButton(R.string.confirm_dialog_confirm,
97 | new DialogInterface.OnClickListener()
98 | {
99 | @SuppressWarnings("unchecked")
100 | public void onClick(DialogInterface dialog, int which)
101 | {
102 | Host host = (Host) getListAdapter().getItem(position);
103 | databaseManager.deleteHost(host);
104 | ((ArrayAdapter) getListAdapter()).remove(host);
105 | HostWidget.updateAllAppWidgetsForHost(getActivity(), host.getId());
106 | }
107 | }
108 | );
109 | dialogBuilder.setNegativeButton(R.string.confirm_dialog_cancel,
110 | new DialogInterface.OnClickListener()
111 | {
112 | public void onClick(DialogInterface dialog, int which) { }
113 | }
114 | );
115 |
116 | AlertDialog deleteDialog = dialogBuilder.create();
117 | ((HostListActivity) getActivity()).setDeleteDialog(deleteDialog);
118 | deleteDialog.show();
119 | }
120 |
121 | public void setDeleteHostPosition(int position)
122 | {
123 | this.deleteHostPosition = position;
124 | }
125 |
126 | public void refreshHosts()
127 | {
128 | List hosts = databaseManager.getAllHosts();
129 | setHosts(hosts);
130 | }
131 |
132 | public void sortByHostname()
133 | {
134 | sortHosts(new Comparator()
135 | {
136 | @Override
137 | public int compare(Host lhs, Host rhs)
138 | {
139 | return lhs.getHostname().compareTo(rhs.getHostname());
140 | }
141 | });
142 | }
143 |
144 | public void sortByLabel()
145 | {
146 | sortHosts(new Comparator()
147 | {
148 | @Override
149 | public int compare(Host lhs, Host rhs)
150 | {
151 | return lhs.getLabel().compareTo(rhs.getLabel());
152 | }
153 | });
154 | }
155 |
156 | public void sortByNewest()
157 | {
158 | sortHosts(new Comparator()
159 | {
160 | @Override
161 | public int compare(Host lhs, Host rhs)
162 | {
163 | return Long.valueOf(rhs.getId()).compareTo(lhs.getId());
164 | }
165 | });
166 | }
167 |
168 | private void sortHosts(Comparator comparator)
169 | {
170 | List hosts = databaseManager.getAllHosts();
171 | Collections.sort(hosts, comparator);
172 | setHosts(hosts);
173 | }
174 |
175 | private void setHosts(List hosts)
176 | {
177 | ((ArrayAdapter) getListAdapter()).clear();
178 |
179 | for (Host host : hosts)
180 | {
181 | ((ArrayAdapter) getListAdapter()).add(host);
182 | }
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xargsgrep/portknocker/asynctask/Knocker.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Ahsan Rabbani
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.xargsgrep.portknocker.asynctask;
17 |
18 | import com.xargsgrep.portknocker.model.Host;
19 | import com.xargsgrep.portknocker.model.Port;
20 | import com.xargsgrep.portknocker.model.Port.Protocol;
21 | import com.xargsgrep.portknocker.utils.SocketUtils;
22 | import com.xargsgrep.portknocker.utils.StringUtils;
23 |
24 | import java.io.IOException;
25 | import java.net.ConnectException;
26 | import java.net.DatagramPacket;
27 | import java.net.DatagramSocket;
28 | import java.net.InetSocketAddress;
29 | import java.net.Socket;
30 | import java.net.SocketAddress;
31 | import java.net.SocketException;
32 | import java.net.SocketTimeoutException;
33 | import java.net.UnknownHostException;
34 |
35 | public class Knocker
36 | {
37 | private static final String ENETUNREACH = "ENETUNREACH";
38 |
39 | public static KnockResult doKnock(Host host, KnockerAsyncTask asyncTask)
40 | {
41 | KnockResult result = new KnockResult(false, null);
42 | for (int i = 0; i < host.getPorts().size(); i++)
43 | {
44 | Port port = host.getPorts().get(i);
45 | result = doKnock(host, port);
46 |
47 | if (result.isSuccess())
48 | {
49 | result.setLaunchIntentPackage(host.getLaunchIntentPackage());
50 | asyncTask.doPublishProgress(i + 1);
51 |
52 | if (i < host.getPorts().size() - 1)
53 | {
54 | // no need to sleep after last knock
55 | try
56 | {
57 | Thread.sleep(host.getDelay());
58 | }
59 | catch (InterruptedException e)
60 | {
61 | if (asyncTask.isCancelled()) break;
62 | }
63 | }
64 | }
65 | else
66 | {
67 | break;
68 | }
69 | }
70 |
71 | return result;
72 | }
73 |
74 | /*
75 | * no network/TCP --> java.net.ConnectException: failed to connect to /1.1.1.1 (port 1234) after 3000ms: connect failed: ENETUNREACH (Network is unreachable)
76 | * no network/UDP --> java.net.SocketException: sendto failed: ENETUNREACH (Network is unreachable)
77 | *
78 | * unable to resolve host/TCP --> java.net.UnknownHostException: Host is unresolved: fakedomain.com
79 | * unable to resolve host/UDP --> java.lang.IllegalArgumentException: Socket address unresolved: fakedomain.com:1234
80 | *
81 | * TCP:
82 | * router/firewall port closed --> java.net.SocketTimeoutException: failed to connect to fakedomain.com/1.1.1.1 (port 1234) after 3000ms
83 | * router/firewall port open, socket closed & REJECT packet --> java.net.ConnectException: failed to connect to fakedomain.com/1.1.1.1 (port 1234) after 3000ms: isConnected failed: ECONNREFUSED (Connection refused)
84 | * router/firewall port open, socket closed & DROP packet --> java.net.SocketTimeoutException: failed to connect to fakedomain.com/1.1.1.1 (port 1234) after 3000ms
85 | *
86 | * UDP:
87 | * router/firewall port closed --> no exception
88 | * router/firewall port open, socket closed & REJECT packet --> no exception
89 | * router/firewall port open, socket closed & DROP packet --> no exception
90 | *
91 | */
92 | private static KnockResult doKnock(Host host, Port port)
93 | {
94 | SocketAddress socketAddress = new InetSocketAddress(host.getHostname(), port.getPort());
95 |
96 | Socket socket = null;
97 | DatagramSocket datagramSocket = null;
98 | try
99 | {
100 | if (port.getProtocol() == Protocol.TCP)
101 | {
102 | socket = new Socket();
103 | // set timeout to the lowest possible value since we just want to transmit a packet, we don't care about receiving a syn-ack.
104 | // this also prevents multiple syn packets being sent (invalidating knock sequence) while waiting for the timeout (if it's high enough)
105 | socket.connect(socketAddress, host.getTcpConnectTimeout());
106 | }
107 | else
108 | { // PROTOCOL.UDP
109 | datagramSocket = new DatagramSocket();
110 | byte[] data = new byte[] {0};
111 | datagramSocket.send(new DatagramPacket(data, data.length, socketAddress));
112 | }
113 | }
114 | catch (SocketTimeoutException e)
115 | {
116 | // this is ok since the timeout is as low as can be and the remote socket isn't expected to be open anyway
117 | }
118 | catch (ConnectException e)
119 | {
120 | if (StringUtils.contains(e.getMessage(), ENETUNREACH))
121 | {
122 | // TCP: host unreachable
123 | return new KnockResult(false, e.getMessage());
124 | }
125 | // ok otherwise
126 | }
127 | catch (UnknownHostException e)
128 | {
129 | // TCP: unable to resolve hostname
130 | return new KnockResult(false, e.getMessage());
131 | }
132 | catch (IllegalArgumentException e)
133 | {
134 | // UDP: unable to resolve hostname
135 | return new KnockResult(false, e.getMessage());
136 | }
137 | catch (SocketException e)
138 | {
139 | // UDP: host unreachable
140 | return new KnockResult(false, e.getMessage());
141 | }
142 | catch (IOException e)
143 | {
144 | return new KnockResult(false, e.getMessage());
145 | }
146 | finally
147 | {
148 | SocketUtils.closeQuietly(socket);
149 | SocketUtils.closeQuietly(datagramSocket);
150 | }
151 |
152 | return new KnockResult(true, null);
153 | }
154 |
155 | public static class KnockResult
156 | {
157 | private final boolean success;
158 | private final String error;
159 | private String launchIntentPackage;
160 |
161 | public KnockResult(boolean success, String error)
162 | {
163 | this.success = success;
164 | this.error = error;
165 | }
166 |
167 | public boolean isSuccess()
168 | {
169 | return success;
170 | }
171 |
172 | public String getError()
173 | {
174 | return error;
175 | }
176 |
177 | public String getLaunchIntentPackage()
178 | {
179 | return launchIntentPackage;
180 | }
181 |
182 | public void setLaunchIntentPackage(String launchIntentPackage)
183 | {
184 | this.launchIntentPackage = launchIntentPackage;
185 | }
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/FileChooser/src/main/java/com/ipaulpro/afilechooser/FileChooserActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Paul Burke
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ipaulpro.afilechooser;
18 |
19 | import android.app.ActionBar;
20 | import android.content.BroadcastReceiver;
21 | import android.content.Context;
22 | import android.content.Intent;
23 | import android.content.IntentFilter;
24 | import android.net.Uri;
25 | import android.os.Build;
26 | import android.os.Bundle;
27 | import android.os.Environment;
28 | import android.support.v4.app.FragmentActivity;
29 | import android.support.v4.app.FragmentManager;
30 | import android.support.v4.app.FragmentManager.BackStackEntry;
31 | import android.support.v4.app.FragmentManager.OnBackStackChangedListener;
32 | import android.support.v4.app.FragmentTransaction;
33 | import android.support.v4.content.FileProvider;
34 | import android.view.Menu;
35 | import android.view.MenuItem;
36 | import android.widget.Toast;
37 |
38 | import java.io.File;
39 |
40 | /**
41 | * Main Activity that handles the FileListFragments
42 | *
43 | * @version 2013-06-25
44 | * @author paulburke (ipaulpro)
45 | */
46 | public class FileChooserActivity extends FragmentActivity implements
47 | OnBackStackChangedListener, FileListFragment.Callbacks {
48 |
49 | public static final String PATH = "path";
50 | public static final String EXTERNAL_BASE_PATH = Environment
51 | .getExternalStorageDirectory().getAbsolutePath();
52 |
53 | private static final boolean HAS_ACTIONBAR = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
54 |
55 | private FragmentManager mFragmentManager;
56 | private BroadcastReceiver mStorageListener = new BroadcastReceiver() {
57 | @Override
58 | public void onReceive(Context context, Intent intent) {
59 | Toast.makeText(context, R.string.storage_removed, Toast.LENGTH_LONG).show();
60 | finishWithResult(null);
61 | }
62 | };
63 |
64 | private String mPath;
65 |
66 | @Override
67 | protected void onCreate(Bundle savedInstanceState) {
68 | super.onCreate(savedInstanceState);
69 |
70 | mFragmentManager = getSupportFragmentManager();
71 | mFragmentManager.addOnBackStackChangedListener(this);
72 |
73 | if (savedInstanceState == null) {
74 | mPath = EXTERNAL_BASE_PATH;
75 | addFragment();
76 | } else {
77 | mPath = savedInstanceState.getString(PATH);
78 | }
79 |
80 | setTitle(mPath);
81 | }
82 |
83 | @Override
84 | protected void onPause() {
85 | super.onPause();
86 |
87 | unregisterStorageListener();
88 | }
89 |
90 | @Override
91 | protected void onResume() {
92 | super.onResume();
93 |
94 | registerStorageListener();
95 | }
96 |
97 | @Override
98 | protected void onSaveInstanceState(Bundle outState) {
99 | super.onSaveInstanceState(outState);
100 |
101 | outState.putString(PATH, mPath);
102 | }
103 |
104 | @Override
105 | public void onBackStackChanged() {
106 |
107 | int count = mFragmentManager.getBackStackEntryCount();
108 | if (count > 0) {
109 | BackStackEntry fragment = mFragmentManager.getBackStackEntryAt(count - 1);
110 | mPath = fragment.getName();
111 | } else {
112 | mPath = EXTERNAL_BASE_PATH;
113 | }
114 |
115 | setTitle(mPath);
116 | if (HAS_ACTIONBAR)
117 | invalidateOptionsMenu();
118 | }
119 |
120 | @Override
121 | public boolean onCreateOptionsMenu(Menu menu) {
122 | if (HAS_ACTIONBAR) {
123 | boolean hasBackStack = mFragmentManager.getBackStackEntryCount() > 0;
124 |
125 | ActionBar actionBar = getActionBar();
126 | actionBar.setDisplayHomeAsUpEnabled(hasBackStack);
127 | actionBar.setHomeButtonEnabled(hasBackStack);
128 | }
129 |
130 | return true;
131 | }
132 |
133 | @Override
134 | public boolean onOptionsItemSelected(MenuItem item) {
135 | switch (item.getItemId()) {
136 | case android.R.id.home:
137 | mFragmentManager.popBackStack();
138 | return true;
139 | }
140 |
141 | return super.onOptionsItemSelected(item);
142 | }
143 |
144 | /**
145 | * Add the initial Fragment with given path.
146 | */
147 | private void addFragment() {
148 | FileListFragment fragment = FileListFragment.newInstance(mPath);
149 | mFragmentManager.beginTransaction()
150 | .add(android.R.id.content, fragment).commit();
151 | }
152 |
153 | /**
154 | * "Replace" the existing Fragment with a new one using given path. We're
155 | * really adding a Fragment to the back stack.
156 | *
157 | * @param file The file (directory) to display.
158 | */
159 | private void replaceFragment(File file) {
160 | mPath = file.getAbsolutePath();
161 |
162 | FileListFragment fragment = FileListFragment.newInstance(mPath);
163 | mFragmentManager.beginTransaction()
164 | .replace(android.R.id.content, fragment)
165 | .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
166 | .addToBackStack(mPath).commit();
167 | }
168 |
169 | /**
170 | * Finish this Activity with a result code and URI of the selected file.
171 | *
172 | * @param file The file selected.
173 | */
174 | private void finishWithResult(File file) {
175 | if (file != null) {
176 | Uri uri = FileProvider.getUriForFile(this.getBaseContext(), "com.ipaulpro.afilechooser", file);
177 | setResult(RESULT_OK, new Intent().setData(uri));
178 | finish();
179 | } else {
180 | setResult(RESULT_CANCELED);
181 | finish();
182 | }
183 | }
184 |
185 | /**
186 | * Called when the user selects a File
187 | *
188 | * @param file The file that was selected
189 | */
190 | @Override
191 | public void onFileSelected(File file) {
192 | if (file != null) {
193 | if (file.isDirectory()) {
194 | replaceFragment(file);
195 | } else {
196 | finishWithResult(file);
197 | }
198 | } else {
199 | Toast.makeText(FileChooserActivity.this, R.string.error_selecting_file,
200 | Toast.LENGTH_SHORT).show();
201 | }
202 | }
203 |
204 | /**
205 | * Register the external storage BroadcastReceiver.
206 | */
207 | private void registerStorageListener() {
208 | IntentFilter filter = new IntentFilter();
209 | filter.addAction(Intent.ACTION_MEDIA_REMOVED);
210 | registerReceiver(mStorageListener, filter);
211 | }
212 |
213 | /**
214 | * Unregister the external storage BroadcastReceiver.
215 | */
216 | private void unregisterStorageListener() {
217 | unregisterReceiver(mStorageListener);
218 | }
219 | }
220 |
--------------------------------------------------------------------------------