From 7ebb82df44a7f38b4320363ce692839bbdd26c2a Mon Sep 17 00:00:00 2001 From: 75py Date: Sat, 30 Apr 2022 16:43:50 +0900 Subject: [PATCH 1/9] remove old files --- .travis.yml | 83 - CHANGELOG.md | 124 - README.md.template | 51 - app/.gitignore | 1 - app/aplin_beta.keystore | Bin 2140 -> 0 bytes app/build.gradle | 168 -- app/google-services.json | 105 - app/licenses.yml | 75 - app/proguard-rules.pro | 29 - .../nagopy/android/aplin/AplinTestRunner.kt | 76 - .../android/aplin/ApplicationMockComponent.kt | 32 - .../android/aplin/ApplicationMockModule.kt | 23 - .../android/aplin/NoAnimationTestRule.kt | 58 - .../com/nagopy/android/aplin/TestFunction.kt | 33 - .../com/nagopy/android/aplin/TestResources.kt | 15 - .../model/AplinDevicePolicyManagerTest.kt | 73 - .../aplin/model/converter/AppConverterTest.kt | 115 - .../presenter/MainScreenPresenterTest.kt | 108 - .../aplin/presenter/SettingsPresenterTest.kt | 92 - .../android/aplin/view/MainActivityTest.kt | 327 --- app/src/androidTest/res/values-ja/strings.xml | 21 - app/src/androidTest/res/values/strings.xml | 21 - app/src/main/AndroidManifest.xml | 88 - .../android/webkit/IWebViewUpdateService.aidl | 28 - app/src/main/assets/licenses.html | 2303 ----------------- app/src/main/ic_launcher-web.png | Bin 25536 -> 0 bytes .../kotlin/com/nagopy/android/aplin/Aplin.kt | 87 - .../android/aplin/ApplicationComponent.kt | 37 - .../nagopy/android/aplin/ApplicationModule.kt | 52 - .../android/aplin/constants/Constants.kt | 52 - .../com/nagopy/android/aplin/entity/App.kt | 65 - .../android/aplin/entity/PermissionGroup.kt | 19 - .../aplin/model/AplinDevicePolicyManager.kt | 235 -- .../android/aplin/model/Applications.kt | 222 -- .../nagopy/android/aplin/model/Category.kt | 88 - .../nagopy/android/aplin/model/DisplayItem.kt | 154 -- .../nagopy/android/aplin/model/IconHelper.kt | 88 - .../nagopy/android/aplin/model/MenuHandler.kt | 84 - .../android/aplin/model/PermissionGroups.kt | 69 - .../android/aplin/model/SharingMethod.kt | 98 - .../nagopy/android/aplin/model/ShellCmd.kt | 47 - .../com/nagopy/android/aplin/model/Sort.kt | 73 - .../android/aplin/model/UserSettings.kt | 58 - .../aplin/model/converter/AppConverter.kt | 126 - .../aplin/model/converter/AppParameters.kt | 160 -- .../android/aplin/presenter/AdPresenter.kt | 68 - .../aplin/presenter/AppListPresenter.kt | 185 -- .../aplin/presenter/MainScreenPresenter.kt | 170 -- .../android/aplin/presenter/Presenter.kt | 25 - .../aplin/presenter/SettingsPresenter.kt | 74 - .../android/aplin/view/AppListFragment.kt | 158 -- .../nagopy/android/aplin/view/AppListView.kt | 26 - .../android/aplin/view/AppListViewParent.kt | 34 - .../android/aplin/view/LicenseActivity.kt | 58 - .../nagopy/android/aplin/view/MainActivity.kt | 207 -- .../android/aplin/view/MainScreenView.kt | 46 - .../aplin/view/PackageChangedReceiver.kt | 57 - .../android/aplin/view/SettingsActivity.kt | 90 - .../nagopy/android/aplin/view/SettingsView.kt | 19 - .../aplin/view/adapter/AppCategoryAdapter.kt | 93 - .../aplin/view/adapter/AppListAdapter.kt | 38 - .../view/adapter/MainScreenPagerAdapter.kt | 40 - .../view/preference/DisplayItemPreference.kt | 57 - .../aplin/view/preference/SortPreference.kt | 80 - app/src/main/res/color/text_color.xml | 23 - app/src/main/res/drawable/ic_action_back.xml | 9 - app/src/main/res/drawable/ic_action_more.xml | 9 - .../main/res/drawable/ic_action_search.xml | 9 - .../main/res/drawable/ic_action_settings.xml | 9 - app/src/main/res/drawable/ic_action_share.xml | 9 - .../main/res/drawable/icon_transparent.xml | 24 - app/src/main/res/drawable/tab_indicator.xml | 50 - .../res/layout-w640dp/fragment_app_list.xml | 26 - app/src/main/res/layout/activity_license.xml | 37 - app/src/main/res/layout/activity_main.xml | 65 - app/src/main/res/layout/activity_settings.xml | 36 - app/src/main/res/layout/fragment_app_list.xml | 24 - app/src/main/res/layout/list_item.xml | 62 - .../preference_widget_checkbox_single.xml | 25 - .../layout/toolbar_spinner_item_actionbar.xml | 33 - .../layout/toolbar_spinner_item_dropdown.xml | 41 - app/src/main/res/menu/main.xml | 54 - app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 2058 -> 0 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 1362 -> 0 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 2801 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 4628 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 6513 -> 0 bytes app/src/main/res/values-ja/strings.xml | 86 - app/src/main/res/values-v21/styles.xml | 37 - app/src/main/res/values-w820dp/dimens.xml | 39 - app/src/main/res/values/colors.xml | 41 - .../main/res/values/colors_orange_green.xml | 28 - app/src/main/res/values/dimens.xml | 59 - app/src/main/res/values/strings.xml | 92 - app/src/main/res/values/styles.xml | 86 - app/src/main/res/xml/pref.xml | 44 - .../android/aplin/model/CategoryTest.kt | 315 --- .../android/aplin/model/DisplayItemTest.kt | 52 - .../model/converter/AppParametersTest.kt | 182 -- .../aplin/presenter/AdPresenterTest.kt | 127 - .../aplin/presenter/AppListPresenterTest.kt | 146 -- build.gradle | 113 - gradle.properties | 38 - gradle/wrapper/gradle-wrapper.jar | Bin 49896 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 6 - gradlew | 164 -- gradlew.bat | 90 - settings.gradle | 17 - version.properties | 22 - 109 files changed, 9717 deletions(-) delete mode 100644 .travis.yml delete mode 100644 CHANGELOG.md delete mode 100644 README.md.template delete mode 100644 app/.gitignore delete mode 100644 app/aplin_beta.keystore delete mode 100644 app/build.gradle delete mode 100644 app/google-services.json delete mode 100644 app/licenses.yml delete mode 100644 app/proguard-rules.pro delete mode 100644 app/src/androidTest/kotlin/com/nagopy/android/aplin/AplinTestRunner.kt delete mode 100644 app/src/androidTest/kotlin/com/nagopy/android/aplin/ApplicationMockComponent.kt delete mode 100644 app/src/androidTest/kotlin/com/nagopy/android/aplin/ApplicationMockModule.kt delete mode 100644 app/src/androidTest/kotlin/com/nagopy/android/aplin/NoAnimationTestRule.kt delete mode 100644 app/src/androidTest/kotlin/com/nagopy/android/aplin/TestFunction.kt delete mode 100644 app/src/androidTest/kotlin/com/nagopy/android/aplin/TestResources.kt delete mode 100644 app/src/androidTest/kotlin/com/nagopy/android/aplin/model/AplinDevicePolicyManagerTest.kt delete mode 100644 app/src/androidTest/kotlin/com/nagopy/android/aplin/model/converter/AppConverterTest.kt delete mode 100644 app/src/androidTest/kotlin/com/nagopy/android/aplin/presenter/MainScreenPresenterTest.kt delete mode 100644 app/src/androidTest/kotlin/com/nagopy/android/aplin/presenter/SettingsPresenterTest.kt delete mode 100644 app/src/androidTest/kotlin/com/nagopy/android/aplin/view/MainActivityTest.kt delete mode 100644 app/src/androidTest/res/values-ja/strings.xml delete mode 100644 app/src/androidTest/res/values/strings.xml delete mode 100644 app/src/main/AndroidManifest.xml delete mode 100644 app/src/main/aidl/android/webkit/IWebViewUpdateService.aidl delete mode 100644 app/src/main/assets/licenses.html delete mode 100644 app/src/main/ic_launcher-web.png delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/Aplin.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/ApplicationComponent.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/ApplicationModule.kt delete mode 100755 app/src/main/kotlin/com/nagopy/android/aplin/constants/Constants.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/entity/App.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/entity/PermissionGroup.kt delete mode 100755 app/src/main/kotlin/com/nagopy/android/aplin/model/AplinDevicePolicyManager.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/model/Applications.kt delete mode 100755 app/src/main/kotlin/com/nagopy/android/aplin/model/Category.kt delete mode 100755 app/src/main/kotlin/com/nagopy/android/aplin/model/DisplayItem.kt delete mode 100755 app/src/main/kotlin/com/nagopy/android/aplin/model/IconHelper.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/model/MenuHandler.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/model/PermissionGroups.kt delete mode 100755 app/src/main/kotlin/com/nagopy/android/aplin/model/SharingMethod.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/model/ShellCmd.kt delete mode 100755 app/src/main/kotlin/com/nagopy/android/aplin/model/Sort.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/model/UserSettings.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/model/converter/AppConverter.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/model/converter/AppParameters.kt delete mode 100755 app/src/main/kotlin/com/nagopy/android/aplin/presenter/AdPresenter.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/presenter/AppListPresenter.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/presenter/MainScreenPresenter.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/presenter/Presenter.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/presenter/SettingsPresenter.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/AppListFragment.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/AppListView.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/AppListViewParent.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/LicenseActivity.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/MainActivity.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/MainScreenView.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/PackageChangedReceiver.kt delete mode 100755 app/src/main/kotlin/com/nagopy/android/aplin/view/SettingsActivity.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/SettingsView.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/adapter/AppCategoryAdapter.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/adapter/AppListAdapter.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/adapter/MainScreenPagerAdapter.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/preference/DisplayItemPreference.kt delete mode 100644 app/src/main/kotlin/com/nagopy/android/aplin/view/preference/SortPreference.kt delete mode 100755 app/src/main/res/color/text_color.xml delete mode 100644 app/src/main/res/drawable/ic_action_back.xml delete mode 100644 app/src/main/res/drawable/ic_action_more.xml delete mode 100644 app/src/main/res/drawable/ic_action_search.xml delete mode 100644 app/src/main/res/drawable/ic_action_settings.xml delete mode 100644 app/src/main/res/drawable/ic_action_share.xml delete mode 100755 app/src/main/res/drawable/icon_transparent.xml delete mode 100755 app/src/main/res/drawable/tab_indicator.xml delete mode 100755 app/src/main/res/layout-w640dp/fragment_app_list.xml delete mode 100755 app/src/main/res/layout/activity_license.xml delete mode 100644 app/src/main/res/layout/activity_main.xml delete mode 100755 app/src/main/res/layout/activity_settings.xml delete mode 100755 app/src/main/res/layout/fragment_app_list.xml delete mode 100755 app/src/main/res/layout/list_item.xml delete mode 100644 app/src/main/res/layout/preference_widget_checkbox_single.xml delete mode 100644 app/src/main/res/layout/toolbar_spinner_item_actionbar.xml delete mode 100644 app/src/main/res/layout/toolbar_spinner_item_dropdown.xml delete mode 100755 app/src/main/res/menu/main.xml delete mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 app/src/main/res/values-ja/strings.xml delete mode 100644 app/src/main/res/values-v21/styles.xml delete mode 100755 app/src/main/res/values-w820dp/dimens.xml delete mode 100644 app/src/main/res/values/colors.xml delete mode 100644 app/src/main/res/values/colors_orange_green.xml delete mode 100755 app/src/main/res/values/dimens.xml delete mode 100644 app/src/main/res/values/strings.xml delete mode 100644 app/src/main/res/values/styles.xml delete mode 100755 app/src/main/res/xml/pref.xml delete mode 100644 app/src/test/kotlin/com/nagopy/android/aplin/model/CategoryTest.kt delete mode 100644 app/src/test/kotlin/com/nagopy/android/aplin/model/DisplayItemTest.kt delete mode 100644 app/src/test/kotlin/com/nagopy/android/aplin/model/converter/AppParametersTest.kt delete mode 100644 app/src/test/kotlin/com/nagopy/android/aplin/presenter/AdPresenterTest.kt delete mode 100644 app/src/test/kotlin/com/nagopy/android/aplin/presenter/AppListPresenterTest.kt delete mode 100644 build.gradle delete mode 100644 gradle.properties delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties delete mode 100755 gradlew delete mode 100644 gradlew.bat delete mode 100644 settings.gradle delete mode 100644 version.properties diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c64a137..0000000 --- a/.travis.yml +++ /dev/null @@ -1,83 +0,0 @@ -language: android - -sudo: false - -env: - global: - - ADB_INSTALL_TIMEOUT=10 - - MALLOC_ARENA_MAX=2 - -android: - components: - # Uncomment the lines below if you want to - # use the latest revision of Android SDK Tools - - tools - - platform-tools - - tools - - # The BuildTools version used by your project - - build-tools-30.0.3 - - # The SDK version used to compile your project - - android-30 - - # Additional components - #- extra-google-google_play_services - - extra-google-m2repository - - extra-android-m2repository - - # Emulator -# - sys-img-armeabi-v7a-android-21 - licenses: - - 'android-sdk-license-.+' - - 'google-gdk-license-.+' - -jdk: - - oraclejdk8 - -branches: - only: - - master - -before_install: - - yes | sdkmanager "platforms;android-30" - -before_script: - - chmod +x gradlew - - echo "sdk.dir=$ANDROID_HOME" > local.properties - - echo "travis.job=$TRAVIS_JOB_NUMBER" >> local.properties - - mkdir app/signingConfigs - - echo 'signingConfigs{ release {} }' > app/signingConfigs/release.gradle - # see https://github.com/travis-ci/travis-ci/issues/2496 - - ulimit -t 514029 - # Emulator -# - echo no | android create avd --force -n test -t android-21 --abi armeabi-v7a -# - emulator -avd test -no-skin -no-audio -no-window & -# - android-wait-for-emulator -# - adb shell settings put global window_animation_scale 0 & -# - adb shell settings put global transition_animation_scale 0 & -# - adb shell settings put global animator_duration_scale 0 & -# - adb shell input keyevent 82 & - -script: - - ./gradlew assembleDebug jacocoTestDebugUnitTestReport -PdisablePreDex ${BUILD_OPTIONS} -# - echo 'test' -# - ./gradlew testDebug -PdisablePreDex ${BUILD_OPTIONS} -# - echo 'connectedDebugAndroidTest small' -# - ./gradlew connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.size=small -PdisablePreDex ${BUILD_OPTIONS} -# - echo 'connectedDebugAndroidTest medium' -# - ./gradlew connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.size=medium -PdisablePreDex ${BUILD_OPTIONS} -# - echo 'connectedDebugAndroidTest large' -# - ./gradlew connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.size=large -PdisablePreDex ${BUILD_OPTIONS} - -after_success: - - bash <(curl -s https://codecov.io/bash) - -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - - $HOME/.android/build-cache diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index a38272b..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,124 +0,0 @@ -Change Log -========== - -Version 3.3.1 *(2018-09-26)* ----------------------------- - -* Disable Advertising ID collection -https://firebase.google.com/support/guides/disable-analytics#disable_advertising_id_collection - -* [Nougat or higher] #112 -If multi-window mode is enabled, open settings app in split-screen - -Version 3.3.0 *(2017-10-22)* ----------------------------- - -* [Nougat or higher] #112 -If multi-window mode is enabled, open settings app in split-screen - -Version 3.2.4 *(2017-09-17)* ----------------------------- - -* Fix #117 - -Version 3.2.3 *(2017-08-20)* ----------------------------- - -* Fix #116 - -Version 3.2.2 *(2017-08-20)* ----------------------------- - -* Fix #115 -* Support Android O -353fd519dcc85ee0bd3d64c6e0c17b6a9e9931a9 -* Update dependencies - - -Version 3.2.1 *(2017-02-26)* ----------------------------- - -* Add text filter feature - - -Version 3.1.3 *(2017-02-18)* ----------------------------- - -* Fix bugs -パーミッションの取得をPackageManager経由ではなくコマンド経由にした。 - - -Version 3.1.2 *(2017-02-05)* ----------------------------- - -* Fix bugs - - -Version 3.1.1 *(2017-02-04)* ----------------------------- - -* Fix bugs - - -Version 3.1.0 *(2017-01-29)* ----------------------------- - -* Support Nougat -* Fix bugs - -Version 3.0.1 *(2016-02-28)* ----------------------------- - -* Small bug fix - -Version 3.0.0 *(2016-02-13)* ----------------------------- - -* Support KitKat devices -* Implement fast scroll #76 -* Fix bugs - -Version 2.1.0 *(2016-02-04)* ----------------------------- - -* Add "First install time desc" sort #96 -* Small bug fix -* Remove Crashlytics, Add Google Analytics - -Version 1.2.2 *(2016-01-18)* ----------------------------- - -* Small bug fix - -Version 1.2.1 *(2016-01-17)* ----------------------------- - -* Add vector navigation icons - -Version 1.2.0 *(2016-01-16)* ----------------------------- - -* Design for tablets(list -> grid) #88 -* Fix #78 -* Fix #80 - -Version 1.1.1 *(2016-01-09)* ----------------------------- - -* Fix #68 -* Fix #69 -* Add debug log for #70 -* Update library - * Realm - 0.87.2, gradle plugin - -Version 1.1.0 *(2015-12-28)* ----------------------------- - -* Add a description of "Not installed" - - -Version 1.0.0 *(2015-12-23)* ----------------------------- - -Initial release on Google Play! diff --git a/README.md.template b/README.md.template deleted file mode 100644 index bf305e3..0000000 --- a/README.md.template +++ /dev/null @@ -1,51 +0,0 @@ -Aplin [![Build Status](https://travis-ci.org/75py/Aplin.svg?branch=master)](https://travis-ci.org/75py/Aplin) [![codecov](https://codecov.io/gh/75py/Aplin/branch/master/graph/badge.svg)](https://codecov.io/gh/75py/Aplin) -===== - -Application manager for Android! - - -Download --------- - -https://play.google.com/store/apps/details?id=com.nagopy.android.aplin - - -Latest version --------------- - -%%version%% - - -For Developers --------------- - -Unit test -========= - -* Command -``` -cd Aplin/app -../gradlew testDebug --info -``` - -* Android Studio -"VM Options -noverify" is required. - - -License -------- - - Copyright 2015 75py - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/app/.gitignore b/app/.gitignore deleted file mode 100644 index 796b96d..0000000 --- a/app/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/app/aplin_beta.keystore b/app/aplin_beta.keystore deleted file mode 100644 index edf9baa1daab709b523cfcee8d75eaa340697ef3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2140 zcmbVMX*3iJ8=WyTXr^IM#%o`)jcvvfgT|0zWXUjO$-Yb3vL^=F4rMD;$kJG{maQm^ zJ<1lPCXsy?GM3Eed%yR``}_NG&vWkm@to(m_ndpYcDx1v0GLhy{2MHeH(mU1dAgi% zQw3RCDF6Tgp~+wdnvEGM!wduiQA`{_AOrv=gIAv4jKkH>CnLEJJX}4w``58^L{jW( zVh(&Mi04>?mwrR1bYf&Vb!QQgoz0O^6kp~?oFg2zF&+sHboq|b+v7Y?iD!5ktS|in z!(?+kXuXIEm8kQ>^I}HBMC*#Uoiac;P8{PTFUR5z%zVUXwmQ6k6N{zk1#JF!i`?!*=t_%$tqUjpx6K=dmo#2HuGu*E2tB>nZ&dKRjJj?wO%cXP%4eHcG{K z+(B?mKAVkyMS()N75&G*LcN=i>$Qd+0qPRs7O%QY#$H>*`AWw_!>M1*m#^YQI1qM z!&e(hi#^KQM9c*1!6Yn8v%Qo-;@2x?pajbwjBy*~5jHF>=FvC74z|LpILOfI9Y?n* z7rDs1!=UuDqpna~{Lfgslrl?DYP#xUiO=% z8zFY<)pyxv6#ZQB{kbR;XzEVY{%w@t8J+I$X$S3<{;_kcXN~$K9Pg=lMnq$HR&uFV z8ghiVoxdwq?DMiR*7pa;xpqqE37Rqsh}5ggv|==bWtU_XCfIUAGX!R~E?-1$SglB`WTry z@*J}M%tRRB>zuxh%tU;KDJK#ASM;ekn=#$hQ2vPiDl>VMz3YjMHEFh0L-j4tWeRDw}$=v zSvI}HFiNazmM_%~|L`D&%f-&Ylu~0%?$BSGA&cm)NNE!*D&3Ay6H5hmG;6moM41M0 z5ifyJ(Rb859D=V?Ifzn5x3sQ|I@1G839_(TclFx$!~KR_dQLyw0VT zf~`g$c=Y^a}vi>#Hbs4PL1YQZ?YJ2``P+P>xW z7HU&7cmvNs_^`P4xOp)uZHep|vIzU)02H?371GQM3cu`W7DK7C1-QKpqt7_e9_A9! zTP2+_-oAHX70Ve*VQJf7Pq|9lr_UVB$*o?@q<=)dfFRRw#T9MfUZNe4CQZ$p8mZ(I1mVf0MM!!82S`5hy-TlVj`Jg5GMtCLZDnM z+W#w93^)4Be-#iH{2xVF*VXB^J6aG4$EaX1ii#LTCA6}tH4?6TGSS$7=>NZ%3>5wM zktZb%A_Lh0Cx1Yh$Uq<|HMiiLprJ2o7nvYW#OU{vn&Bzaoa5>e92`HjA8_9x09hY zGch`_kHz1{Pbp3}a$1X}jw2 z`xi}77Nw-{JPw%1_Cy!{N%(BI0kjDj(|IZp5Am=|Ya%*x2RnY`#F65k>C@CYSxl1%vhZw}~f7 zpO^>);Ogj43DedC)qYwfwZBB(!gT#X??PH-tKa&hs~Z&;zVM=#*zatpF|kPPS^8Xu zgbY|o+r6Yv7{e$;}620q^0h-&5Qqmu14%5YycT{Kq!z zk-gz7%oDU4Cmo4fu8XsxSb?w$8a*b1Q-ZcWwP@dq1+W+Kv)$aho4Gd_HpK**bxN3P Y?!`lEvsL{RDm`1J@H&xSO=Ri#KXN+0qyPW_ diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 0527621..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt' -apply plugin: 'com.cookpad.android.licensetools' -apply plugin: 'project-report' -apply plugin: 'com.hiya.jacoco-android' -apply plugin: 'com.google.firebase.crashlytics' - -apply from: 'signingConfigs/release.gradle', to: android - -def preDexLibs = !project.hasProperty('disablePreDex') -def gitSha = 'git rev-parse --short HEAD'.execute([], project.rootDir).text.trim() -def buildTime = new Date().format("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone("UTC")) - -android { - compileSdkVersion 30 - buildToolsVersion '30.0.3' - - defaultConfig { - applicationId "com.nagopy.android.aplin" - minSdkVersion 28 - targetSdkVersion "$target_sdk_version" - versionCode publish_version_code - versionName "$publish_version_name-$gitSha" - resValue "string", "version_name", "$publish_version_name ($publish_version_code, $gitSha, $buildTime)" - testInstrumentationRunner "com.nagopy.android.aplin.AplinTestRunner" - multiDexEnabled true - - buildConfigField "String", "AD_APP_ID", "\"ca-app-pub-2998260208076899~7954619765\"" - resValue "string", "ad_app_id", "ca-app-pub-2998260208076899~7954619765" - } - signingConfigs { - debug { - storeFile file('aplin_beta.keystore') - storePassword 'android' - keyAlias 'android' - keyPassword 'android' - } - } - buildTypes { - debug { - minifyEnabled false - shrinkResources false - // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - signingConfig signingConfigs.debug - testCoverageEnabled true - } - release { - minifyEnabled true - shrinkResources true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - signingConfig signingConfigs.release - } - } - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - test.java.srcDirs += 'src/test/kotlin' - androidTest.java.srcDirs += 'src/androidTest/kotlin' - } - packagingOptions { - exclude 'asm-license.txt' - exclude 'LICENSE' - exclude 'NOTICE' - exclude 'DEPENDENCIES' - exclude 'LICENSE.txt' - exclude 'NOTICE.txt' - exclude 'META-INF/NOTICE' - exclude 'META-INF/LICENSE' - exclude 'META-INF/LICENSE.txt' - exclude 'META-INF/DEPENDENCIES' - exclude 'META-INF/services/javax.annotation.processing.Processor' - } - lintOptions { - abortOnError false - disable 'PrivateResource' - } - dexOptions { - //javaMaxHeapSize "1024M" - preDexLibraries = preDexLibs - } - testOptions { - unitTests.returnDefaultValues = true - unitTests.includeAndroidResources = true - unitTests.all { - jvmArgs '-noverify' - } - } -} - -dependencies { - implementation 'androidx.multidex:multidex:2.0.1' - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.preference:preference-ktx:1.1.1' - implementation 'com.google.firebase:firebase-crashlytics:17.3.1' - implementation 'com.google.firebase:firebase-ads:19.7.0' - implementation 'io.reactivex.rxjava2:rxjava:2.1.5' - implementation ('io.reactivex.rxjava2:rxandroid:2.0.1') { - exclude module: 'rxjava' - } - implementation 'com.jakewharton.timber:timber:4.7.1' - implementation "com.google.dagger:dagger:$dagger_version" - kapt "com.google.dagger:dagger-compiler:$dagger_version" - compileOnly 'javax.annotation:jsr250-api:1.0' - - testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - testImplementation 'junit:junit:4.12' - testImplementation "org.mockito:mockito-core:2.28.2" - testImplementation "org.robolectric:robolectric:4.5.1" - - androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - androidTestImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' - androidTestImplementation 'androidx.test.espresso:espresso-intents:3.3.0' - androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.3.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test:rules:1.3.0' - androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' - androidTestImplementation 'org.mockito:mockito-core:2.28.2' - androidTestImplementation 'org.mockito:mockito-android:2.28.2' - //kapt "org.jetbrains.kotlin:kotlin-annotation-processing:${kotlin_version}" - kaptAndroidTest "com.google.dagger:dagger-compiler:$dagger_version" -} -buildscript { - ext.support_libs_version = '28.0.0' - ext.kotlin_version = '1.4.31' - ext.dagger_version = '2.28.1' - ext.target_sdk_version = 30 - Properties properties = new Properties() - properties.load(project.rootProject.file('local.properties').newDataInputStream()) - ext.sdk_dir = properties.getProperty("sdk.dir") - if(properties.containsKey("travis.job")) { - ext.publish_version_name = "$publish_version_name-${properties.getProperty("travis.job")}" - } - repositories { - mavenCentral() - jcenter() - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} -repositories { - mavenCentral() -} -kapt { - generateStubs = true - correctErrorTypes = true -} - -apply plugin: 'com.google.gms.google-services' diff --git a/app/google-services.json b/app/google-services.json deleted file mode 100644 index a214fbd..0000000 --- a/app/google-services.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "project_info": { - "project_number": "96118885052", - "firebase_url": "https://file-shortcut.firebaseio.com", - "project_id": "file-shortcut", - "storage_bucket": "file-shortcut.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:96118885052:android:1e67b2e6c66c6431", - "android_client_info": { - "package_name": "com.nagopy.android.fileshortcut" - } - }, - "oauth_client": [ - { - "client_id": "96118885052-u9drdhaffifu5d16u9ppvu5989mdtfop.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "com.nagopy.android.fileshortcut", - "certificate_hash": "936927F2236F4B4312549A56DF7C527A001F641C" - } - }, - { - "client_id": "96118885052-vopecqso5d7ibbbjk3an3ghddqkmn7e3.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "96118885052-ipcck68cujkkdgum44ls5qlhv05psv0v.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyB8RA2xZlCLmtuMRqjJtXXBBLfPODLxRW8" - } - ], - "services": { - "analytics_service": { - "status": 2, - "analytics_property": { - "tracking_id": "UA-9578951-21" - } - }, - "appinvite_service": { - "status": 1, - "other_platform_oauth_client": [] - }, - "ads_service": { - "status": 2 - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:96118885052:android:6abc9e8079e8ac28", - "android_client_info": { - "package_name": "com.nagopy.android.aplin" - } - }, - "oauth_client": [ - { - "client_id": "96118885052-iijjbm9oe31gm3hgekso30i8n74fuq7g.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "com.nagopy.android.aplin", - "certificate_hash": "14DC0368483C975C9B82FCF971CE2D644E6683F1" - } - }, - { - "client_id": "96118885052-vopecqso5d7ibbbjk3an3ghddqkmn7e3.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "96118885052-ipcck68cujkkdgum44ls5qlhv05psv0v.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyB8RA2xZlCLmtuMRqjJtXXBBLfPODLxRW8" - } - ], - "services": { - "analytics_service": { - "status": 1 - }, - "appinvite_service": { - "status": 2, - "other_platform_oauth_client": [ - { - "client_id": "96118885052-vopecqso5d7ibbbjk3an3ghddqkmn7e3.apps.googleusercontent.com", - "client_type": 3 - } - ] - }, - "ads_service": { - "status": 2 - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file diff --git a/app/licenses.yml b/app/licenses.yml deleted file mode 100644 index 120f3d7..0000000 --- a/app/licenses.yml +++ /dev/null @@ -1,75 +0,0 @@ -- artifact: com.android.support:+:+ - name: Android Support Libraries - copyrightHolder: The Android Open Source Project - license: apache2 - -- artifact: com.google.android.gms:+:+ - skip: true - -- artifact: com.google.firebase:+:+ - skip: true - -- artifact: com.google.dagger:dagger:+ - name: Dagger - copyrightHolder: The Dagger Authors - license: apache2 - -- artifact: com.jakewharton.timber:timber:+ - name: Timber - copyrightHolder: Jake Wharton - license: The Apache Software License, Version 2.0 - licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt - url: https://github.com/JakeWharton/timber - - -- artifact: io.reactivex.rxjava2:rxandroid:+ - name: RxAndroid - copyrightHolder: The RxAndroid authors - license: The Apache Software License, Version 2.0 - licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt - url: https://github.com/ReactiveX/RxAndroid - -- artifact: io.reactivex.rxjava2:rxjava:+ - name: rxjava - copyrightHolder: Netflix, Inc. - license: The Apache Software License, Version 2.0 - licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt - url: https://github.com/ReactiveX/RxJava - -- artifact: org.reactivestreams:reactive-streams:+ - name: reactive-streams - copyrightHolder: CC0 - license: CC0 - licenseUrl: http://creativecommons.org/publicdomain/zero/1.0/ - url: http://www.reactive-streams.org/ - skip: true - -- artifact: javax.inject:javax.inject:+ - name: javax.inject - copyrightHolder: The JSR-330 Expert Group - license: The Apache Software License, Version 2.0 - licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt - url: http://code.google.com/p/atinject/ - -- artifact: org.jetbrains.kotlin:kotlin-stdlib:+ - name: kotlin-stdlib - copyrightHolder: JetBrains - license: The Apache Software License, Version 2.0 -- artifact: org.jetbrains.kotlin:kotlin-reflect:+ - name: kotlin-reflect - copyrightHolder: JetBrains - license: The Apache Software License, Version 2.0 - -- artifact: org.jetbrains:annotations:+ - name: IntelliJ IDEA Annotations - copyrightHolder: JetBrains - license: The Apache Software License, Version 2.0 - licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt - url: http://www.jetbrains.org - -- artifact: android.arch.lifecycle:common:+ - skip: true -- artifact: android.arch.core:common:+ - skip: true -- artifact: android.arch.lifecycle:runtime:+ - skip: true diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro deleted file mode 100644 index 98eaffa..0000000 --- a/app/proguard-rules.pro +++ /dev/null @@ -1,29 +0,0 @@ --dontskipnonpubliclibraryclasses --optimizationpasses 3 --flattenpackagehierarchy --keepattributes SourceFile,LineNumberTable --printmapping map.txt - --keep public class com.google.android.gms.ads.** { - public *; -} - --keep public class com.google.ads.** { - public *; -} - --keep class android.support.v7.widget.SearchView { *; } - -# Kotlin --keep class kotlin.reflect.jvm.internal.impl.** { *; } --dontwarn kotlin.** - -# Timber --dontwarn org.jetbrains.annotations.** - -# Support libs --dontwarn android.support.** - -# Others --dontobfuscate --dontskipnonpubliclibraryclassmembers diff --git a/app/src/androidTest/kotlin/com/nagopy/android/aplin/AplinTestRunner.kt b/app/src/androidTest/kotlin/com/nagopy/android/aplin/AplinTestRunner.kt deleted file mode 100644 index a04df99..0000000 --- a/app/src/androidTest/kotlin/com/nagopy/android/aplin/AplinTestRunner.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin - -import android.content.Context -import android.graphics.PixelFormat -import android.os.Bundle -import android.os.Handler -import android.os.Looper -import android.util.Log -import android.view.View -import android.view.WindowManager -import androidx.multidex.MultiDex -import androidx.test.runner.AndroidJUnitRunner - -class AplinTestRunner : AndroidJUnitRunner() { - - override fun onCreate(arguments: Bundle) { - MultiDex.install(this.targetContext) - super.onCreate(arguments) - } - - val wm by lazy { - targetContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager - } - - val dummyView by lazy { - View(targetContext.applicationContext) - } - - val mainHandler = Handler(Looper.getMainLooper()) - - override fun onStart() { - val p = WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_TOAST, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_FULLSCREEN - or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR - or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD - or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, - PixelFormat.TRANSLUCENT) - p.width = 0 - p.height = 0 - mainHandler.post { - try { - wm.addView(dummyView, p) - } catch (e: Exception) { - Log.e(this.javaClass.simpleName, "Error", e) - } - } - super.onStart() - } - - override fun onDestroy() { - mainHandler.post { - wm.removeView(dummyView) - } - - super.onDestroy() - } - -} diff --git a/app/src/androidTest/kotlin/com/nagopy/android/aplin/ApplicationMockComponent.kt b/app/src/androidTest/kotlin/com/nagopy/android/aplin/ApplicationMockComponent.kt deleted file mode 100644 index f612182..0000000 --- a/app/src/androidTest/kotlin/com/nagopy/android/aplin/ApplicationMockComponent.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin - -import com.nagopy.android.aplin.model.AplinDevicePolicyManagerTest -import com.nagopy.android.aplin.model.converter.AppConverterTest -import com.nagopy.android.aplin.presenter.MainScreenPresenterTest -import dagger.Component -import javax.inject.Singleton - - -@Singleton -@Component(modules = arrayOf(ApplicationMockModule::class)) -interface ApplicationMockComponent : ApplicationComponent { - fun inject(appParametersTest: AppConverterTest) - fun inject(mainScreenPresenterTest: MainScreenPresenterTest) - fun inject(aplinDevicePolicyManagerTest: AplinDevicePolicyManagerTest) -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/nagopy/android/aplin/ApplicationMockModule.kt b/app/src/androidTest/kotlin/com/nagopy/android/aplin/ApplicationMockModule.kt deleted file mode 100644 index f1a1de2..0000000 --- a/app/src/androidTest/kotlin/com/nagopy/android/aplin/ApplicationMockModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin - -import android.app.Application -import dagger.Module - -@Module -open class ApplicationMockModule(val a: Application) : ApplicationModule(a) diff --git a/app/src/androidTest/kotlin/com/nagopy/android/aplin/NoAnimationTestRule.kt b/app/src/androidTest/kotlin/com/nagopy/android/aplin/NoAnimationTestRule.kt deleted file mode 100644 index c9bb1ee..0000000 --- a/app/src/androidTest/kotlin/com/nagopy/android/aplin/NoAnimationTestRule.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.nagopy.android.aplin - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.uiautomator.UiDevice -import org.junit.rules.TestRule -import org.junit.runner.Description -import org.junit.runners.model.Statement - -class NoAnimationTestRule : TestRule { - - override fun apply(base: Statement?, description: Description?): Statement { - return object : Statement() { - override fun evaluate() { - val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - val backupAnimationScale = getAnimationScale(uiDevice) - putAnimationScale(uiDevice, disableAnimationScale) - try { - base?.evaluate() - } finally { - putAnimationScale(uiDevice, backupAnimationScale) - } - } - } - } - - data class AnimationScale( - val windowAnimationScale: String - , val transitionAnimationScale: String - , val animatorDurationScale: String - ) - - val disableAnimationScale = AnimationScale("0.0", "0.0", "0.0") - - fun getAnimationScale(uiDevice: UiDevice): AnimationScale? { - return try { - val windowAnimationScale = uiDevice.executeShellCommand("settings get global window_animation_scale") - val transitionAnimationScale = uiDevice.executeShellCommand("settings get global transition_animation_scale") - val animatorDurationScale = uiDevice.executeShellCommand("settings get global animator_duration_scale") - AnimationScale(windowAnimationScale, transitionAnimationScale, animatorDurationScale) - } catch (e: Exception) { - e.printStackTrace() - null - } - } - - fun putAnimationScale(uiDevice: UiDevice, animationScale: AnimationScale?) { - if (animationScale != null) { - try { - uiDevice.executeShellCommand("settings put global window_animation_scale ${animationScale.windowAnimationScale}") - uiDevice.executeShellCommand("settings put global transition_animation_scale ${animationScale.transitionAnimationScale}") - uiDevice.executeShellCommand("settings put global animator_duration_scale ${animationScale.animatorDurationScale}") - } catch (e: Exception) { - e.printStackTrace() - } - } - } - -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/nagopy/android/aplin/TestFunction.kt b/app/src/androidTest/kotlin/com/nagopy/android/aplin/TestFunction.kt deleted file mode 100644 index 0979ade..0000000 --- a/app/src/androidTest/kotlin/com/nagopy/android/aplin/TestFunction.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin - -import androidx.test.espresso.intent.Intents - -object TestFunction { - - @JvmStatic - fun intentBlock(func: () -> Unit) { - try { - Intents.init() - func() - } finally { - Intents.release() - } - } - -} diff --git a/app/src/androidTest/kotlin/com/nagopy/android/aplin/TestResources.kt b/app/src/androidTest/kotlin/com/nagopy/android/aplin/TestResources.kt deleted file mode 100644 index 97e1994..0000000 --- a/app/src/androidTest/kotlin/com/nagopy/android/aplin/TestResources.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.nagopy.android.aplin - -import androidx.test.platform.app.InstrumentationRegistry -import com.nagopy.android.aplin.test.R - -object TestResources { - - object string { - val test_btn_disable = InstrumentationRegistry.getInstrumentation().context.getString(R.string.test_btn_disable) - - val test_btn_enable = InstrumentationRegistry.getInstrumentation().context.getString(R.string.test_btn_enable) - - val test_permissions = InstrumentationRegistry.getInstrumentation().context.getString(R.string.test_permissions) - } -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/nagopy/android/aplin/model/AplinDevicePolicyManagerTest.kt b/app/src/androidTest/kotlin/com/nagopy/android/aplin/model/AplinDevicePolicyManagerTest.kt deleted file mode 100644 index 0d40fc0..0000000 --- a/app/src/androidTest/kotlin/com/nagopy/android/aplin/model/AplinDevicePolicyManagerTest.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model - -import android.app.Application -import android.os.Build -import androidx.test.filters.SmallTest -import androidx.test.platform.app.InstrumentationRegistry -import com.nagopy.android.aplin.Aplin -import com.nagopy.android.aplin.ApplicationMockComponent -import com.nagopy.android.aplin.ApplicationMockModule -import com.nagopy.android.aplin.DaggerApplicationMockComponent -import org.junit.Before -import org.junit.Test -import javax.inject.Inject -import kotlin.test.assertNotNull - -class AplinDevicePolicyManagerTest { - - val application = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as Application - - @Inject - lateinit var aplinDevicePolicyManager: AplinDevicePolicyManager - - @Before - fun setup() { - Aplin.component = DaggerApplicationMockComponent.builder() - .applicationMockModule(ApplicationMockModule(application)) - .build() - - (Aplin.getApplicationComponent() as ApplicationMockComponent).inject(this) - } - - @SmallTest - @Test - fun reflectionEnabled() { - assertNotNull(aplinDevicePolicyManager) - assertNotNull(aplinDevicePolicyManager.devicePolicyManager) - assertNotNull(aplinDevicePolicyManager.packageManager) - assertNotNull(aplinDevicePolicyManager.packageHasActiveAdmins) - assertNotNull(aplinDevicePolicyManager.mSystemPackageInfo) - - if (Build.VERSION_CODES.N <= Build.VERSION.SDK_INT) { - assertNotNull(aplinDevicePolicyManager.permissionControllerPackageName) - } - if (Build.VERSION_CODES.N <= Build.VERSION.SDK_INT) { - assertNotNull(aplinDevicePolicyManager.servicesSystemSharedLibraryPackageName) - } - if (Build.VERSION_CODES.N <= Build.VERSION.SDK_INT) { - assertNotNull(aplinDevicePolicyManager.sharedSystemSharedLibraryPackageName) - } - if (Build.VERSION_CODES.N_MR1 <= Build.VERSION.SDK_INT) { - assertNotNull(aplinDevicePolicyManager.PRINT_SPOOLER_PACKAGE_NAME) - } - if (Build.VERSION_CODES.N <= Build.VERSION.SDK_INT && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - assertNotNull(aplinDevicePolicyManager.webviewUpdateService) - } - } -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/nagopy/android/aplin/model/converter/AppConverterTest.kt b/app/src/androidTest/kotlin/com/nagopy/android/aplin/model/converter/AppConverterTest.kt deleted file mode 100644 index 9a698e9..0000000 --- a/app/src/androidTest/kotlin/com/nagopy/android/aplin/model/converter/AppConverterTest.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model.converter - -import android.app.Application -import androidx.test.platform.app.InstrumentationRegistry -import com.nagopy.android.aplin.* -import com.nagopy.android.aplin.entity.App -import org.junit.After -import org.junit.Before -import org.junit.Test -import javax.inject.Inject -import kotlin.test.assertEquals - -class AppConverterTest { - - val application = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as Application - - @Inject - lateinit var appConverter: AppConverter - - lateinit var aplinApp: App - - @Before - fun setup() { - Aplin.component = DaggerApplicationMockComponent.builder() - .applicationMockModule(ApplicationMockModule(application)) - .build() - - (Aplin.getApplicationComponent() as ApplicationMockComponent).inject(this) - - aplinApp = App() - appConverter.prepare() - appConverter.setValues(aplinApp, application.packageName) - } - - @After - fun tearDown() { - } - - @Test - fun packageName() { - assertEquals(InstrumentationRegistry.getInstrumentation().targetContext.packageName, aplinApp.packageName) - } - - @Test - fun label() { - assertEquals(application.getString(R.string.app_name), aplinApp.label) - } - - @Test - fun isEnabled() { - assertEquals(true, aplinApp.isEnabled) - } - - @Test - fun isSystem() { - assertEquals(false, aplinApp.isSystem) - } - - @Test - fun isThisASystemPackage() { - assertEquals(false, aplinApp.isSystemPackage) - } - - @Test - fun firstInstallTime() { - assert(aplinApp.firstInstallTime > 0) - } - - @Test - fun lastUpdateTime() { - assert(aplinApp.lastUpdateTime > 0) - } - - @Test - fun hasActiveAdmins() { - assertEquals(false, aplinApp.hasActiveAdmins) - } - - @Test - fun isInstalled() { - assertEquals(true, aplinApp.isInstalled) - } - - @Test - fun isDefaultApp() { - assertEquals(false, aplinApp.hasActiveAdmins) - } - - @Test - fun versionName() { - assertEquals(BuildConfig.VERSION_NAME, aplinApp.versionName) - } - - @Test - fun permissions() { - assertEquals(true, aplinApp.requestedPermissions.isNotEmpty()) - assertEquals(true, aplinApp.requestedPermissions.contains(android.Manifest.permission.INTERNET)) - } -} diff --git a/app/src/androidTest/kotlin/com/nagopy/android/aplin/presenter/MainScreenPresenterTest.kt b/app/src/androidTest/kotlin/com/nagopy/android/aplin/presenter/MainScreenPresenterTest.kt deleted file mode 100644 index 27db374..0000000 --- a/app/src/androidTest/kotlin/com/nagopy/android/aplin/presenter/MainScreenPresenterTest.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.presenter - -import android.app.Activity -import android.app.Application -import android.os.Build -import android.provider.Settings -import androidx.test.espresso.intent.Intents -import androidx.test.espresso.intent.matcher.IntentMatchers -import androidx.test.filters.MediumTest -import androidx.test.filters.SdkSuppress -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.rule.ActivityTestRule -import androidx.test.uiautomator.UiDevice -import com.nagopy.android.aplin.Aplin -import com.nagopy.android.aplin.ApplicationMockComponent -import com.nagopy.android.aplin.ApplicationMockModule -import com.nagopy.android.aplin.DaggerApplicationMockComponent -import com.nagopy.android.aplin.TestFunction.intentBlock -import com.nagopy.android.aplin.entity.App -import com.nagopy.android.aplin.model.Category -import com.nagopy.android.aplin.view.MainActivity -import org.junit.After -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import javax.inject.Inject - -class MainScreenPresenterTest { - - val application = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as Application - - @Rule - @JvmField - val rule: ActivityTestRule = ActivityTestRule(MainActivity::class.java, true, false) - - @Inject - lateinit var mainScreenPresenter: MainScreenPresenter - - var activity: MainActivity? = null - - lateinit var uiDevice: UiDevice - - @Before - fun setup() { - uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - - Aplin.component = DaggerApplicationMockComponent.builder() - .applicationMockModule(ApplicationMockModule(application)) - .build() - - (Aplin.getApplicationComponent() as ApplicationMockComponent).inject(this) - } - - @After - fun tearDown() { - uiDevice.pressBack() - uiDevice.pressBack() - uiDevice.waitForIdle(1000) - } - - @MediumTest - @Test - fun listItemClicked_ALL() { - activity = rule.launchActivity(null) - - intentBlock { - val app = App() - app.packageName = "com.nagopy.android.aplin" - mainScreenPresenter.listItemClicked(activity as Activity, app, Category.ALL) - - Intents.intended(IntentMatchers.hasAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)) - Intents.intended(IntentMatchers.hasData("package:com.nagopy.android.aplin")) - } - } - - @MediumTest - @Test - @SdkSuppress(minSdkVersion = Build.VERSION_CODES.M) - fun listItemClicked_OVERLAY() { - val activity = rule.launchActivity(null) - - intentBlock { - val app = App() - app.packageName = "com.nagopy.android.aplin" - mainScreenPresenter.listItemClicked(activity, app, Category.SYSTEM_ALERT_WINDOW_PERMISSION) - - Intents.intended(IntentMatchers.hasAction(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)) - Intents.intended(IntentMatchers.hasData("package:com.nagopy.android.aplin")) - } - } - -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/nagopy/android/aplin/presenter/SettingsPresenterTest.kt b/app/src/androidTest/kotlin/com/nagopy/android/aplin/presenter/SettingsPresenterTest.kt deleted file mode 100644 index 1440e3d..0000000 --- a/app/src/androidTest/kotlin/com/nagopy/android/aplin/presenter/SettingsPresenterTest.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.nagopy.android.aplin.presenter - -import android.app.Application -import android.content.SharedPreferences -import androidx.test.filters.SmallTest -import com.nagopy.android.aplin.view.SettingsView -import org.junit.Before -import org.junit.Test -import org.mockito.ArgumentMatchers -import org.mockito.Mockito -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -class SettingsPresenterTest { - - lateinit var target: SettingsPresenter - - lateinit var application: Application - lateinit var sharedPreferences: SharedPreferences - lateinit var settingsView: SettingsView - - @Before - fun setup() { - target = SettingsPresenter() - application = Mockito.mock(Application::class.java) - sharedPreferences = Mockito.mock(SharedPreferences::class.java) - settingsView = Mockito.mock(SettingsView::class.java) - - target.application = application - target.sharedPreferences = sharedPreferences - } - - @SmallTest - @Test - fun initialize() { - target.settingChanged = true - target.initialize(settingsView) - assertFalse(target.settingChanged) - } - - @SmallTest - @Test - fun resume() { - Mockito.doNothing().`when`(sharedPreferences).registerOnSharedPreferenceChangeListener( - ArgumentMatchers.any(SharedPreferences.OnSharedPreferenceChangeListener::class.java)) - - target.initialize(settingsView) - target.resume() - - Mockito.verify(sharedPreferences, Mockito.times(1)).registerOnSharedPreferenceChangeListener(target) - } - - @SmallTest - @Test - fun pause() { - Mockito.doNothing().`when`(sharedPreferences).unregisterOnSharedPreferenceChangeListener( - ArgumentMatchers.any(SharedPreferences.OnSharedPreferenceChangeListener::class.java)) - - target.pause() - - Mockito.verify(sharedPreferences, Mockito.times(1)).unregisterOnSharedPreferenceChangeListener(target) - } - - @SmallTest - @Test - fun flag() { - assertFalse(target.settingChanged) - target.onSharedPreferenceChanged(sharedPreferences, "test") - assertTrue(target.settingChanged) - } - - - @SmallTest - @Test - fun destroy() { - target.destroy() - } - - @SmallTest - @Test - fun finish_1() { - target.settingChanged = false - assertFalse(target.finish()) - } - - @SmallTest - @Test - fun finish_2() { - target.settingChanged = true - assertTrue(target.finish()) - } -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/nagopy/android/aplin/view/MainActivityTest.kt b/app/src/androidTest/kotlin/com/nagopy/android/aplin/view/MainActivityTest.kt deleted file mode 100644 index c216e1e..0000000 --- a/app/src/androidTest/kotlin/com/nagopy/android/aplin/view/MainActivityTest.kt +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.view - -import android.content.SharedPreferences -import android.os.Build -import android.provider.Settings -import android.widget.Adapter -import android.widget.AdapterView -import android.widget.ProgressBar -import androidx.preference.PreferenceManager -import androidx.test.espresso.Espresso.onData -import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.action.AdapterViewProtocol -import androidx.test.espresso.action.AdapterViewProtocols -import androidx.test.espresso.action.ViewActions -import androidx.test.espresso.action.ViewActions.click -import androidx.test.espresso.intent.Intents -import androidx.test.espresso.intent.matcher.IntentMatchers -import androidx.test.espresso.matcher.ViewMatchers.isDisplayed -import androidx.test.espresso.matcher.ViewMatchers.withId -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.LargeTest -import androidx.test.filters.SdkSuppress -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.rule.ActivityTestRule -import androidx.test.uiautomator.By -import androidx.test.uiautomator.UiDevice -import androidx.test.uiautomator.UiSelector -import androidx.test.uiautomator.Until -import com.nagopy.android.aplin.BuildConfig -import com.nagopy.android.aplin.NoAnimationTestRule -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.TestFunction.intentBlock -import com.nagopy.android.aplin.TestResources -import com.nagopy.android.aplin.entity.App -import com.nagopy.android.aplin.model.Category -import org.hamcrest.CoreMatchers.allOf -import org.hamcrest.CoreMatchers.instanceOf -import org.junit.After -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import timber.log.Timber -import java.util.* -import kotlin.collections.ArrayList -import kotlin.test.assertFalse -import kotlin.test.assertNotNull -import kotlin.test.assertTrue -import kotlin.test.fail -import org.hamcrest.CoreMatchers.`is` as _is - -@RunWith(AndroidJUnit4::class) -class MainActivityTest { - - @Rule - @JvmField - val rule: ActivityTestRule = ActivityTestRule(MainActivity::class.java, false, false) - - @Rule - @JvmField - val noAnimationTestRule = NoAnimationTestRule() - - private val timeout = 500L - private val testPackageName = BuildConfig.APPLICATION_ID + ".test" - - lateinit var uiDevice: UiDevice - lateinit var sp: SharedPreferences - - @Before - fun setup() { - uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - sp = PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getInstrumentation().targetContext) - } - - @After - fun tearDown() { - uiDevice.pressBack() - rule.activity?.finish() - } - - private fun startActivity(): MainActivity = rule.launchActivity(null) - - @LargeTest - @Test - fun testLaunch() { - startActivity() - - val activity = rule.activity - assertNotNull(activity.presenter) - assertNotNull(activity.adPresenter) - assertNotNull(activity.adView) - assertNotNull(activity.toolbar) - assertNotNull(activity.viewPager) - assertNotNull(activity.progressBar) - } - - - @LargeTest - @Test - fun textFilter() { - start() - switchCategory(Category.ALL) - - onView(withId(R.id.action_search)) - .perform(click()) - - onView(withId(R.id.search_src_text)) - .perform(ViewActions.replaceText("nagopy")) - .perform(ViewActions.pressImeActionButton()) - - clickAll { app -> - assertTrue(app.packageName.contains("nagopy"), app.toString()) - } - } - - - @LargeTest - @Test - fun all() { - start() - switchCategory(Category.ALL) - clickAll { app -> - if (app.packageName != testPackageName) { - // アプリ名が表示されていることを確認 - assertTrue(uiDevice.findObject(UiSelector().text(app.label)).waitForExists(timeout), app.toString()) - } - } - } - - @LargeTest - @Test - fun SYSTEM_DISABLABLE() { - start() - switchCategory(Category.SYSTEM_DISABLABLE) - val errors = ArrayList() - clickAll { app -> - try { - // アプリ名が表示されていることを確認 - assertTrue(uiDevice.findObject(UiSelector().text(app.label)).waitForExists(timeout), app.toString()) - - val disableButtonLabel = - if (app.isEnabled && !app.isDisabledUntilUsed) { - TestResources.string.test_btn_disable - } else { - TestResources.string.test_btn_enable - } - assertTrue(uiDevice.findObject(UiSelector().textStartsWith(disableButtonLabel)).waitForExists(timeout), app.toString()) - assertTrue(uiDevice.findObject(UiSelector().textStartsWith(disableButtonLabel)).isEnabled, app.toString()) - } catch (t: Throwable) { - Timber.e(t, "Continue") - errors.add(t) - } - } - - errors.forEach { - Timber.e(it) - } - if (errors.isNotEmpty()) { - throw errors[0] - } - } - - @LargeTest - @Test - fun SYSTEM_UNDISABLABLE() { - start() - switchCategory(Category.SYSTEM_UNDISABLABLE) - clickAll { app -> - // アプリ名が表示されていることを確認 - assertTrue(uiDevice.findObject(UiSelector().text(app.label)).waitForExists(timeout), app.toString()) - - val disableButtonLabel = - if (app.isEnabled && !app.isDisabledUntilUsed) { - TestResources.string.test_btn_disable - } else { - TestResources.string.test_btn_enable - } - if (uiDevice.findObject(UiSelector().textStartsWith(disableButtonLabel)).waitForExists(timeout)) { - assertFalse(uiDevice.findObject(UiSelector().textStartsWith(disableButtonLabel)).isEnabled, app.toString()) - } - } - } - - @SdkSuppress(minSdkVersion = Build.VERSION_CODES.M) - @LargeTest - @Test - fun DENIABLE_PERMISSIONS() { - val errors = HashSet() - - start() - switchCategory(Category.DENIABLE_PERMISSIONS) - clickAll { app -> - // アプリ名が表示されていることを確認 - assertTrue(uiDevice.findObject(UiSelector().text(app.label)).waitForExists(timeout), app.toString()) - - // 「権限」が表示されている - assertTrue(uiDevice.findObject(UiSelector().text(TestResources.string.test_permissions)).waitForExists(timeout), app.toString()) - - if (uiDevice.findObject(UiSelector().text(TestResources.string.test_permissions)).isEnabled) { - // 「権限」がクリックできる - // クリックして次の画面へ - uiDevice.findObject(UiSelector().text(TestResources.string.test_permissions)).clickAndWaitForNewWindow(timeout) - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - // Android 10未満のみ - // Android 10では権限グループを知る手段がない - // https://developer.android.com/about/versions/10/privacy/changes#permission-groups-removed - app.permissionGroups.forEach { - val exists = uiDevice.findObject(UiSelector().text(it.label)).waitForExists(timeout) - if (!exists) { - Timber.w("pkg=%s cannot deny permission %s", app.packageName, it) - errors.add(app.packageName) - } - } - } - - uiDevice.pressBack() - } else { - // 「権限」がクリックできない - Timber.w("pkg=%s cannot deny any permissions.", app.packageName) - errors.add(app.packageName) - } - } - - assertTrue(errors.size < 10, "Too many errors. $errors") - assertTrue(errors.filter { !it.startsWith("com.android") }.count() < 3, "Too many errors. $errors") - } - - private fun start() { - startActivity() - - uiDevice.wait(Until.gone(By.clazz(ProgressBar::class.java)), timeout) - uiDevice.waitForIdle() - - Thread.sleep(5000) // Wait for loading - } - - private fun switchCategory(category: Category) { - onView(withId(R.id.spinner)).perform(click()) - onData(allOf(_is(instanceOf(Category::class.java)), _is(category))) - .atPosition(0) - .perform(click()) - uiDevice.waitForIdle() - } - - private fun clickAll(validator: (app: App) -> Unit) { - val appListViewProtocol = AppListViewProtocol() - val errors = ArrayList() - var i = 0 - do { - try { - var skipFlag = false - - intentBlock { - onData(instanceOf(App::class.java)) - .inAdapterView(allOf(withId(R.id.list), isDisplayed())) - .atPosition(i) - .usingAdapterViewProtocol(appListViewProtocol) - .perform(click()) - uiDevice.waitForIdle() - val packageName = appListViewProtocol.apps[i].packageName - Timber.i("packageName=%s", packageName) - - if (setOf("com.google.android.angle", - "com.google.android.captiveportallogin", - "com.google.android.modulemetadata", - "com.google.android.networkstack", - "com.google.android.networkstack.permissionconfig", - "com.google.android.documentsui", - "com.google.android.ims" - ).contains(packageName)) { - skipFlag = true - return@intentBlock - } - - Intents.intended(allOf( - IntentMatchers.hasAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS), IntentMatchers.hasData("package:$packageName") - )) - } - - if (!skipFlag) { - // validation - validator(appListViewProtocol.apps[i]) - } - - // Back to Aplin - uiDevice.pressBack() - uiDevice.waitForIdle() - } catch (e: Error) { - errors.add(appListViewProtocol.apps[i]) - } - i += (appListViewProtocol.apps.count() / 10 + 1) - } while (i < appListViewProtocol.apps.count()) - - if (errors.isNotEmpty()) { - fail(errors.toString()) - } - } - - class AppListViewProtocol : AdapterViewProtocol by AdapterViewProtocols.standardProtocol() { - - var apps: List = emptyList() - - override fun getDataInAdapterView(adapterView: AdapterView?): MutableIterable { - val result = AdapterViewProtocols.standardProtocol().getDataInAdapterView(adapterView) - apps = result.map { it.getData() as App }.toList() - return result - } - } - -} diff --git a/app/src/androidTest/res/values-ja/strings.xml b/app/src/androidTest/res/values-ja/strings.xml deleted file mode 100644 index 4ed1439..0000000 --- a/app/src/androidTest/res/values-ja/strings.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - 有効にする - 無効にする - 権限 - diff --git a/app/src/androidTest/res/values/strings.xml b/app/src/androidTest/res/values/strings.xml deleted file mode 100644 index 56d1fc5..0000000 --- a/app/src/androidTest/res/values/strings.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - Enable - Disable - Permissions - diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml deleted file mode 100644 index f7f09db..0000000 --- a/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/aidl/android/webkit/IWebViewUpdateService.aidl b/app/src/main/aidl/android/webkit/IWebViewUpdateService.aidl deleted file mode 100644 index db7b1b0..0000000 --- a/app/src/main/aidl/android/webkit/IWebViewUpdateService.aidl +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.webkit; -/** - * Private service to wait for the updatable WebView to be ready for use. - */ -interface IWebViewUpdateService { - - /** - * Used by Settings to determine whether a certain package can be enabled/disabled by the user - - * the package should not be modifiable in this way if it is a fallback package. - */ - boolean isFallbackPackage(String packageName); - -} diff --git a/app/src/main/assets/licenses.html b/app/src/main/assets/licenses.html deleted file mode 100644 index c0f967d..0000000 --- a/app/src/main/assets/licenses.html +++ /dev/null @@ -1,2303 +0,0 @@ - - - - - - - - -
- -

Android Support Libraries

-

Copyright © The Android Open Source Project. All rights reserved.

-

http://developer.android.com/tools/extras/support-library.html

- -
-

- Apache License -
- Version 2.0, January 2004 -
- http://www.apache.org/licenses/ -

-

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

-

1. Definitions.

-

- "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. -

-

- "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. -

-

- "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. -

-

- "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. -

-

- "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. -

-

- "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. -

-

- "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). -

-

- "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. -

-

- "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." -

-

- "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. -

-
-

2. Grant of Copyright License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. -

-
-
-

3. Grant of Patent License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. -

-
-
-

4. Redistribution.

-

- You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: -

-
-
    -
  • - You must give any other recipients of the Work or - Derivative Works a copy of this License; and -
  • -
  • - You must cause any modified files to carry prominent notices - stating that You changed the files; and -
  • -
  • - You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of | - the Derivative Works; and -
  • -
  • - If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. -
  • -
-

- You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. -

-
-

5. Submission of Contributions.

-

- Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. -

-
-
-

6. Trademarks.

-

- This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. -

-
-
-

7. Disclaimer of Warranty.

-

- Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. -

-
-
-

8. Limitation of Liability.

-

- In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. -

-
-
-

9. Accepting Warranty or Additional Liability.

-

- While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. -

-
-

END OF TERMS AND CONDITIONS

-

APPENDIX: How to apply the Apache License to your work.

-

- To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. -

-
Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
-
-
- -

Dagger

-

Copyright © The Dagger Authors. All rights reserved.

- - -
-

- Apache License -
- Version 2.0, January 2004 -
- http://www.apache.org/licenses/ -

-

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

-

1. Definitions.

-

- "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. -

-

- "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. -

-

- "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. -

-

- "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. -

-

- "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. -

-

- "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. -

-

- "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). -

-

- "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. -

-

- "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." -

-

- "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. -

-
-

2. Grant of Copyright License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. -

-
-
-

3. Grant of Patent License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. -

-
-
-

4. Redistribution.

-

- You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: -

-
-
    -
  • - You must give any other recipients of the Work or - Derivative Works a copy of this License; and -
  • -
  • - You must cause any modified files to carry prominent notices - stating that You changed the files; and -
  • -
  • - You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of | - the Derivative Works; and -
  • -
  • - If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. -
  • -
-

- You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. -

-
-

5. Submission of Contributions.

-

- Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. -

-
-
-

6. Trademarks.

-

- This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. -

-
-
-

7. Disclaimer of Warranty.

-

- Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. -

-
-
-

8. Limitation of Liability.

-

- In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. -

-
-
-

9. Accepting Warranty or Additional Liability.

-

- While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. -

-
-

END OF TERMS AND CONDITIONS

-

APPENDIX: How to apply the Apache License to your work.

-

- To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. -

-
Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
-
-
- -

Timber

-

Copyright © Jake Wharton. All rights reserved.

-

https://github.com/JakeWharton/timber

- -
-

- Apache License -
- Version 2.0, January 2004 -
- http://www.apache.org/licenses/ -

-

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

-

1. Definitions.

-

- "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. -

-

- "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. -

-

- "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. -

-

- "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. -

-

- "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. -

-

- "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. -

-

- "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). -

-

- "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. -

-

- "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." -

-

- "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. -

-
-

2. Grant of Copyright License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. -

-
-
-

3. Grant of Patent License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. -

-
-
-

4. Redistribution.

-

- You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: -

-
-
    -
  • - You must give any other recipients of the Work or - Derivative Works a copy of this License; and -
  • -
  • - You must cause any modified files to carry prominent notices - stating that You changed the files; and -
  • -
  • - You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of | - the Derivative Works; and -
  • -
  • - If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. -
  • -
-

- You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. -

-
-

5. Submission of Contributions.

-

- Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. -

-
-
-

6. Trademarks.

-

- This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. -

-
-
-

7. Disclaimer of Warranty.

-

- Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. -

-
-
-

8. Limitation of Liability.

-

- In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. -

-
-
-

9. Accepting Warranty or Additional Liability.

-

- While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. -

-
-

END OF TERMS AND CONDITIONS

-

APPENDIX: How to apply the Apache License to your work.

-

- To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. -

-
Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
-
-
- -

RxAndroid

-

Copyright © The RxAndroid authors. All rights reserved.

-

https://github.com/ReactiveX/RxAndroid

- -
-

- Apache License -
- Version 2.0, January 2004 -
- http://www.apache.org/licenses/ -

-

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

-

1. Definitions.

-

- "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. -

-

- "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. -

-

- "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. -

-

- "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. -

-

- "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. -

-

- "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. -

-

- "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). -

-

- "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. -

-

- "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." -

-

- "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. -

-
-

2. Grant of Copyright License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. -

-
-
-

3. Grant of Patent License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. -

-
-
-

4. Redistribution.

-

- You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: -

-
-
    -
  • - You must give any other recipients of the Work or - Derivative Works a copy of this License; and -
  • -
  • - You must cause any modified files to carry prominent notices - stating that You changed the files; and -
  • -
  • - You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of | - the Derivative Works; and -
  • -
  • - If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. -
  • -
-

- You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. -

-
-

5. Submission of Contributions.

-

- Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. -

-
-
-

6. Trademarks.

-

- This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. -

-
-
-

7. Disclaimer of Warranty.

-

- Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. -

-
-
-

8. Limitation of Liability.

-

- In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. -

-
-
-

9. Accepting Warranty or Additional Liability.

-

- While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. -

-
-

END OF TERMS AND CONDITIONS

-

APPENDIX: How to apply the Apache License to your work.

-

- To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. -

-
Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
-
-
- -

rxjava

-

Copyright © Netflix, Inc. All rights reserved.

-

https://github.com/ReactiveX/RxJava

- -
-

- Apache License -
- Version 2.0, January 2004 -
- http://www.apache.org/licenses/ -

-

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

-

1. Definitions.

-

- "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. -

-

- "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. -

-

- "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. -

-

- "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. -

-

- "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. -

-

- "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. -

-

- "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). -

-

- "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. -

-

- "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." -

-

- "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. -

-
-

2. Grant of Copyright License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. -

-
-
-

3. Grant of Patent License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. -

-
-
-

4. Redistribution.

-

- You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: -

-
-
    -
  • - You must give any other recipients of the Work or - Derivative Works a copy of this License; and -
  • -
  • - You must cause any modified files to carry prominent notices - stating that You changed the files; and -
  • -
  • - You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of | - the Derivative Works; and -
  • -
  • - If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. -
  • -
-

- You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. -

-
-

5. Submission of Contributions.

-

- Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. -

-
-
-

6. Trademarks.

-

- This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. -

-
-
-

7. Disclaimer of Warranty.

-

- Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. -

-
-
-

8. Limitation of Liability.

-

- In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. -

-
-
-

9. Accepting Warranty or Additional Liability.

-

- While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. -

-
-

END OF TERMS AND CONDITIONS

-

APPENDIX: How to apply the Apache License to your work.

-

- To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. -

-
Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
-
-
- -

javax.inject

-

Copyright © The JSR-330 Expert Group. All rights reserved.

-

http://code.google.com/p/atinject/

- -
-

- Apache License -
- Version 2.0, January 2004 -
- http://www.apache.org/licenses/ -

-

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

-

1. Definitions.

-

- "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. -

-

- "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. -

-

- "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. -

-

- "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. -

-

- "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. -

-

- "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. -

-

- "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). -

-

- "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. -

-

- "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." -

-

- "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. -

-
-

2. Grant of Copyright License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. -

-
-
-

3. Grant of Patent License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. -

-
-
-

4. Redistribution.

-

- You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: -

-
-
    -
  • - You must give any other recipients of the Work or - Derivative Works a copy of this License; and -
  • -
  • - You must cause any modified files to carry prominent notices - stating that You changed the files; and -
  • -
  • - You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of | - the Derivative Works; and -
  • -
  • - If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. -
  • -
-

- You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. -

-
-

5. Submission of Contributions.

-

- Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. -

-
-
-

6. Trademarks.

-

- This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. -

-
-
-

7. Disclaimer of Warranty.

-

- Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. -

-
-
-

8. Limitation of Liability.

-

- In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. -

-
-
-

9. Accepting Warranty or Additional Liability.

-

- While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. -

-
-

END OF TERMS AND CONDITIONS

-

APPENDIX: How to apply the Apache License to your work.

-

- To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. -

-
Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
-
-
- -

kotlin-stdlib

-

Copyright © JetBrains. All rights reserved.

-

https://kotlinlang.org/

- -
-

- Apache License -
- Version 2.0, January 2004 -
- http://www.apache.org/licenses/ -

-

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

-

1. Definitions.

-

- "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. -

-

- "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. -

-

- "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. -

-

- "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. -

-

- "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. -

-

- "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. -

-

- "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). -

-

- "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. -

-

- "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." -

-

- "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. -

-
-

2. Grant of Copyright License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. -

-
-
-

3. Grant of Patent License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. -

-
-
-

4. Redistribution.

-

- You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: -

-
-
    -
  • - You must give any other recipients of the Work or - Derivative Works a copy of this License; and -
  • -
  • - You must cause any modified files to carry prominent notices - stating that You changed the files; and -
  • -
  • - You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of | - the Derivative Works; and -
  • -
  • - If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. -
  • -
-

- You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. -

-
-

5. Submission of Contributions.

-

- Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. -

-
-
-

6. Trademarks.

-

- This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. -

-
-
-

7. Disclaimer of Warranty.

-

- Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. -

-
-
-

8. Limitation of Liability.

-

- In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. -

-
-
-

9. Accepting Warranty or Additional Liability.

-

- While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. -

-
-

END OF TERMS AND CONDITIONS

-

APPENDIX: How to apply the Apache License to your work.

-

- To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. -

-
Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
-
-
- -

kotlin-reflect

-

Copyright © JetBrains. All rights reserved.

-

https://kotlinlang.org/

- -
-

- Apache License -
- Version 2.0, January 2004 -
- http://www.apache.org/licenses/ -

-

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

-

1. Definitions.

-

- "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. -

-

- "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. -

-

- "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. -

-

- "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. -

-

- "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. -

-

- "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. -

-

- "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). -

-

- "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. -

-

- "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." -

-

- "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. -

-
-

2. Grant of Copyright License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. -

-
-
-

3. Grant of Patent License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. -

-
-
-

4. Redistribution.

-

- You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: -

-
-
    -
  • - You must give any other recipients of the Work or - Derivative Works a copy of this License; and -
  • -
  • - You must cause any modified files to carry prominent notices - stating that You changed the files; and -
  • -
  • - You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of | - the Derivative Works; and -
  • -
  • - If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. -
  • -
-

- You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. -

-
-

5. Submission of Contributions.

-

- Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. -

-
-
-

6. Trademarks.

-

- This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. -

-
-
-

7. Disclaimer of Warranty.

-

- Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. -

-
-
-

8. Limitation of Liability.

-

- In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. -

-
-
-

9. Accepting Warranty or Additional Liability.

-

- While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. -

-
-

END OF TERMS AND CONDITIONS

-

APPENDIX: How to apply the Apache License to your work.

-

- To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. -

-
Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
-
-
- -

IntelliJ IDEA Annotations

-

Copyright © JetBrains. All rights reserved.

-

http://www.jetbrains.org

- -
-

- Apache License -
- Version 2.0, January 2004 -
- http://www.apache.org/licenses/ -

-

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

-

1. Definitions.

-

- "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. -

-

- "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. -

-

- "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. -

-

- "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. -

-

- "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. -

-

- "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. -

-

- "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). -

-

- "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. -

-

- "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." -

-

- "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. -

-
-

2. Grant of Copyright License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. -

-
-
-

3. Grant of Patent License.

-

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. -

-
-
-

4. Redistribution.

-

- You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: -

-
-
    -
  • - You must give any other recipients of the Work or - Derivative Works a copy of this License; and -
  • -
  • - You must cause any modified files to carry prominent notices - stating that You changed the files; and -
  • -
  • - You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of | - the Derivative Works; and -
  • -
  • - If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. -
  • -
-

- You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. -

-
-

5. Submission of Contributions.

-

- Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. -

-
-
-

6. Trademarks.

-

- This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. -

-
-
-

7. Disclaimer of Warranty.

-

- Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. -

-
-
-

8. Limitation of Liability.

-

- In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. -

-
-
-

9. Accepting Warranty or Additional Liability.

-

- While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. -

-
-

END OF TERMS AND CONDITIONS

-

APPENDIX: How to apply the Apache License to your work.

-

- To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. -

-
Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
-
- - - diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png deleted file mode 100644 index 074ee8936d55f8e89691b905d260e667596f347d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25536 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 h@cIAML*Xm=!k>+GZrcKGoAWoWq5Awug|c = ArrayList() - - var permissionGroups: MutableList = ArrayList() - - var isProfileOrDeviceOwner: Boolean = false // 6.0以降 - - var isLaunchable: Boolean = false // ランチャーから起動可能か。権限拒否可能判定で使用する - - var isDisabledUntilUsed: Boolean = false // 6.0- - - var shouldSkip: Boolean = false - - var isResourceOverlay: Boolean = false // 10.0- - - override fun toString(): String = "$packageName $label" -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/entity/PermissionGroup.kt b/app/src/main/kotlin/com/nagopy/android/aplin/entity/PermissionGroup.kt deleted file mode 100644 index 6b10f8e..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/entity/PermissionGroup.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2017 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.entity - -data class PermissionGroup(val name: String, val label: String, val permissions: List) diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/AplinDevicePolicyManager.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/AplinDevicePolicyManager.kt deleted file mode 100755 index 62ceef9..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/AplinDevicePolicyManager.kt +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model - -import android.app.admin.DevicePolicyManager -import android.content.pm.PackageInfo -import android.content.pm.PackageManager -import android.content.res.Resources -import android.os.Build -import android.os.IBinder -import android.print.PrintManager -import android.webkit.IWebViewUpdateService -import timber.log.Timber -import java.lang.reflect.InvocationTargetException -import java.lang.reflect.Method -import javax.inject.Inject -import javax.inject.Singleton -import kotlin.reflect.full.declaredMemberFunctions -import kotlin.reflect.full.staticFunctions -import kotlin.reflect.full.staticProperties - -@Singleton -open class AplinDevicePolicyManager @Inject constructor() { - - @Inject - lateinit var devicePolicyManager: DevicePolicyManager - - @Inject - lateinit var packageManager: PackageManager - - val mSystemPackageInfo: PackageInfo? by lazy { - try { - packageManager.getPackageInfo("android", PackageManager.GET_SIGNATURES) - } catch (e: PackageManager.NameNotFoundException) { - Timber.e(e, "システムのシグネチャ取得に失敗") - null - } - } - - val packageHasActiveAdmins: Method? by lazy { - try { - DevicePolicyManager::class.java.getDeclaredMethod("packageHasActiveAdmins", String::class.java) - } catch (e: NoSuchMethodException) { - Timber.e(e, "リフレクション失敗") - null - } - } - - val permissionControllerPackageName: String? by lazy { - if (Build.VERSION_CODES.N <= Build.VERSION.SDK_INT) { - try { - val v = PackageManager::class.declaredMemberFunctions.firstOrNull { - it.name == "getPermissionControllerPackageName" - }?.call(packageManager) as? String - Timber.d("permissionControllerPackageName = %s", v) - return@lazy v - } catch (e: Exception) { - Timber.e(e, "getPermissionControllerPackageName の実行に失敗") - } - } - return@lazy null - } - - val servicesSystemSharedLibraryPackageName: String? by lazy { - if (Build.VERSION_CODES.N <= Build.VERSION.SDK_INT) { - try { - val v = PackageManager::class.declaredMemberFunctions.firstOrNull { - it.name == "getServicesSystemSharedLibraryPackageName" - }?.call(packageManager) as? String - Timber.d("servicesSystemSharedLibraryPackageName = %s", v) - return@lazy v - } catch (e: Exception) { - Timber.e(e, "getServicesSystemSharedLibraryPackageName の実行に失敗") - } - } - return@lazy null - } - - val sharedSystemSharedLibraryPackageName: String? by lazy { - if (Build.VERSION_CODES.N <= Build.VERSION.SDK_INT) { - try { - val v = PackageManager::class.declaredMemberFunctions.firstOrNull { - it.name == "getSharedSystemSharedLibraryPackageName" - }?.call(packageManager) as? String - Timber.d("sharedSystemSharedLibraryPackageName = %s", v) - return@lazy v - } catch (e: Exception) { - Timber.e(e, "getSharedSystemSharedLibraryPackageName の実行に失敗") - } - } - return@lazy null - } - - val PRINT_SPOOLER_PACKAGE_NAME: String? by lazy { - if (Build.VERSION_CODES.N_MR1 <= Build.VERSION.SDK_INT) { - try { - val v = PrintManager::class.staticProperties.firstOrNull { - it.name == "PRINT_SPOOLER_PACKAGE_NAME" - }?.call() as? String - Timber.d("PRINT_SPOOLER_PACKAGE_NAME = %s", v) - return@lazy v ?: "com.android.printspooler" - } catch (e: Exception) { - Timber.e(e, "PRINT_SPOOLER_PACKAGE_NAME の取得に失敗") - return@lazy "com.android.printspooler" - } - } - return@lazy null - } - - val deviceProvisioningPackage: String? by lazy { - if (Build.VERSION_CODES.N_MR1 <= Build.VERSION.SDK_INT) { - try { - val r = Resources.getSystem() - val id = r.getIdentifier("config_deviceProvisioningPackage", "string", "android") - val v = r.getString(id) - Timber.d("deviceProvisioningPackage id = %d, value = %s", id, v) - return@lazy v - } catch (e: Exception) { - Timber.e(e, "deviceProvisioningPackage の取得に失敗") - } - } - return@lazy null - } - - val webviewUpdateService: IWebViewUpdateService? by lazy { - if (Build.VERSION_CODES.N <= Build.VERSION.SDK_INT && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - // 7.0 <= version < 10 - try { - val clsServiceManager = Class.forName("android.os.ServiceManager").kotlin - val clsServiceManager_getService = clsServiceManager.staticFunctions.first { - it.name == "getService" && it.parameters.size == 1 - } - val ibinder = clsServiceManager_getService.call("webviewupdate") as? IBinder - val v = IWebViewUpdateService.Stub.asInterface(ibinder) - Timber.d("webviewUpdateService = %s", v) - return@lazy v - } catch (e: Exception) { - Timber.e(e, "webviewUpdateService の取得に失敗") - } - } - return@lazy null - } - - /** - * [DevicePolicyManager]のpackageHasActiveAdminsメソッドを実行する - - * @param packageName パッケージ名 - * * - * @return packageHasActiveAdminsの結果を返す。 - * * エラーがあった場合はfalseを返す。 - */ - open fun packageHasActiveAdmins(packageName: String): Boolean { - try { - return packageHasActiveAdmins?.invoke(devicePolicyManager, packageName) as Boolean - } catch (e: IllegalAccessException) { - Timber.e(e, "実行失敗") - } catch (e: InvocationTargetException) { - Timber.e(e, "実行失敗") - } - return false - } - - open fun isSystemPackage(packageInfo: PackageInfo?): Boolean = when { - Build.VERSION.SDK_INT <= Build.VERSION_CODES.M -> isThisASystemPackage(packageInfo) - Build.VERSION.SDK_INT <= Build.VERSION_CODES.N -> - // 7.0 - isSystemPackageApi24(packageInfo) - else -> - // 7.1- - isSystemPackageApi25(packageInfo) - } - - /** - * [DevicePolicyManager]のisThisASystemPackageメソッドと同じ内容. - * 4.4以下で使用。 - - * @param packageInfo 判定したいpackageInfo - * * - * @return isThisASystemPackageの結果をそのまま返す。 - * * エラーがあった場合はfalseを返す。 - */ - open fun isThisASystemPackage(packageInfo: PackageInfo?): Boolean { - return (packageInfo?.signatures != null - && mSystemPackageInfo != null - && mSystemPackageInfo!!.signatures[0] == packageInfo.signatures[0]) - } - - // Utils#isSystemPackage - open fun isSystemPackageApi24(packageInfo: PackageInfo?): Boolean { - return packageInfo != null - && (isThisASystemPackage(packageInfo) - || packageInfo.packageName == permissionControllerPackageName - || packageInfo.packageName == servicesSystemSharedLibraryPackageName - || packageInfo.packageName == sharedSystemSharedLibraryPackageName - || isFallbackPackage(webviewUpdateService, packageInfo.packageName) - ) - } - - fun isFallbackPackage(webviewUpdateService: IWebViewUpdateService?, packageName: String): Boolean { - return try { - webviewUpdateService?.isFallbackPackage(packageName) ?: false - } catch (e: Error) { - Timber.d(e) - false - } - } - - // Utils#isSystemPackage - open fun isSystemPackageApi25(packageInfo: PackageInfo?): Boolean { - return packageInfo != null - && ( - isSystemPackageApi24(packageInfo) - || packageInfo.packageName == PRINT_SPOOLER_PACKAGE_NAME - || packageInfo.packageName == deviceProvisioningPackage - ) - } - - open fun isProfileOrDeviceOwner(packageName: String): Boolean = devicePolicyManager.isDeviceOwnerApp(packageName) - || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && devicePolicyManager.isProfileOwnerApp(packageName)) - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/Applications.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/Applications.kt deleted file mode 100644 index 2fdd76c..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/Applications.kt +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model - -import android.content.pm.PackageManager -import android.os.Build -import android.os.UserHandle -import com.nagopy.android.aplin.entity.App -import com.nagopy.android.aplin.model.converter.AppConverter -import com.nagopy.android.aplin.model.converter.AppParameters -import io.reactivex.Completable -import io.reactivex.Observable -import io.reactivex.Single -import io.reactivex.subjects.PublishSubject -import timber.log.Timber -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit -import javax.inject.Inject -import javax.inject.Singleton -import kotlin.random.Random - -@Singleton -open class Applications @Inject constructor() { - - @Inject - lateinit var appConverter: AppConverter - - @Inject - lateinit var userSettings: UserSettings - - @Inject - lateinit var shellCmd: ShellCmd - - val appCache: ConcurrentHashMap = ConcurrentHashMap() - - val appObserver: PublishSubject = PublishSubject.create() // onNext(null)が不可になったので、ダミー引数Intを使う - - open fun isLoaded(): Boolean = appCache.isNotEmpty() - - open fun initAppCache(): Completable { - return Completable.create { - Timber.d("initAppCache appCache.size=%s", appCache.size) - loadAppCache() - Timber.d("initAppCache appCache.size=%s refreshed", appCache.size) - it.onComplete() - } - } - - open fun loadAppCache() { - synchronized(appCache) { - if (!isLoaded()) { - appCache.clear() - val all = getInstalledPackageNames() - val executorService = Executors.newCachedThreadPool() - appConverter.prepare() - all.forEach { packageName -> - Timber.v("LOAD start pkg=%s", packageName) - executorService.execute { - Thread.sleep(Random.nextLong(3000) + 100) - val entity = App() - appConverter.setValues(entity, packageName) - appCache.put(packageName, entity) - Timber.v("LOAD fin pkg=%s", packageName) - } - } - executorService.shutdown() - val finished = try { - executorService.awaitTermination(60, TimeUnit.SECONDS) - } catch (e: InterruptedException) { - Timber.d(e, "Interrupted") - true - } - if (!finished) { - executorService.shutdownNow() - } - } - } - } - - open fun getApplicationList(category: Category): Single> = Single.create { - loadAppCache() - it.onSuccess(userSettings.sort.orderBy(category.where(appCache.values)).toList()) - } - - private fun getInstalledPackageNames(): List { - return if (Build.VERSION_CODES.N <= Build.VERSION.SDK_INT) { - // 24- - getInstalledPackageNames24() - } else { - getInstalledPackageNames23() - } - } - - private fun getInstalledPackageNames23(): List { - return shellCmd.exec(listOf("pm", "list", "packages"), { seq -> - seq.filter(String::isNotBlank) - .filter { it.startsWith("package:") } - .map { it.replace("package:", "") } - .toList() - }, emptyList()) - } - - private fun getInstalledPackageNames24(): List { - return shellCmd.exec(listOf("cmd", "package", "list", "packages"), { seq -> - seq.filter(String::isNotBlank) - .filter { it.startsWith("package:") } - .map { it.replace("package:", "") } - .toList() - }, emptyList()) - } - - open fun insert(pkg: String): Observable { - Timber.d("insert %s", pkg) - return upsert(pkg) - } - - open fun update(pkg: String): Observable { - Timber.d("update %s", pkg) - return upsert(pkg) - } - - private fun upsert(pkg: String): Observable { - return Observable.create { - val entity = App() - appConverter.prepare() - appConverter.setValues(entity, pkg) - appCache.put(pkg, entity) - it.onComplete() - - appObserver.onNext(0) - } - } - - open fun delete(pkg: String): Observable { - Timber.d("delete %s", pkg) - return Observable.create { - appCache.remove(pkg) - it.onComplete() - - appObserver.onNext(0) - } - } - - open fun updatePoco(): Observable { - return Observable.create { - val all = getInstalledPackageNames() - var updated = false - appConverter.prepare() - synchronized(appCache) { - all.forEach { packageName -> - val app = appCache[packageName] - if (app != null) { - val newApp = App() - appConverter.setValues(newApp, packageName, AppParameters.isDefaultApp, AppParameters.isEnabled) - - if (newApp.isDefaultApp != app.isDefaultApp || newApp.isEnabled != app.isEnabled) { - app.isDefaultApp = newApp.isDefaultApp - app.isEnabled = app.isEnabled - appCache.put(packageName, app) - updated = true - } - } - } - } - it.onComplete() - - if (updated) { - Timber.d("Updated!") - appObserver.onNext(0) - } - } - } - - companion object { - /** - * [android.content.pm.PackageManager.getInstalledApplications]の引数に使うフラグ。以下のクラスを参照 - * /packages/apps/Settings/src/com/android/settings/applications/ApplicationsState.java - */ - val flags: Int by lazy { - @Suppress("DEPRECATION") - val ownerRetrieveFlags = PackageManager.GET_UNINSTALLED_PACKAGES or - PackageManager.GET_DISABLED_COMPONENTS or - PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS - - @Suppress("DEPRECATION") - val retrieveFlags = PackageManager.GET_DISABLED_COMPONENTS or - PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - val myUserIdMethod = UserHandle::class.java.getDeclaredMethod("myUserId") - if (myUserIdMethod.invoke(null) == 0) { - return@lazy ownerRetrieveFlags - } else { - return@lazy retrieveFlags - } - } else { - val myUserHandle = android.os.Process.myUserHandle() - val isOwnerMethod = UserHandle::class.java.getDeclaredMethod("isOwner") - if (isOwnerMethod.invoke(myUserHandle) as Boolean) { - return@lazy ownerRetrieveFlags - } else { - return@lazy retrieveFlags - } - } - } - } -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/Category.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/Category.kt deleted file mode 100755 index 6d940f0..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/Category.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.nagopy.android.aplin.model - -import android.os.Build -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.constants.Constants -import com.nagopy.android.aplin.entity.App - -enum class Category( - val titleResourceId: Int, val summaryResourceId: Int, val targetSdkVersion: IntRange = Constants.ALL_SDK_VERSION) { - - ALL(titleResourceId = R.string.category_all, summaryResourceId = R.string.category_all_summary) { - override fun filter(list: Collection): Collection = list - }, - SYSTEM( - titleResourceId = R.string.category_system, summaryResourceId = R.string.category_system_summary) { - override fun filter(list: Collection): Collection = list.filter(App::isSystem) - }, - SYSTEM_UNDISABLABLE( - titleResourceId = R.string.category_system_undisablable, summaryResourceId = R.string.category_system_undisablable_summary) { - override fun filter(list: Collection): Collection { - return list.filter { - it.isSystem && (it.isSystemPackage || it.hasActiveAdmins || it.isProfileOrDeviceOwner || it.isHomeApp - || it.isResourceOverlay) - } - } - }, - SYSTEM_DISABLABLE(titleResourceId = R.string.category_system_disablable, summaryResourceId = R.string.category_system_disablable_summary) { - override fun filter(list: Collection): Collection { - return list.filter { - it.isSystem && !it.isProfileOrDeviceOwner && !it.isSystemPackage && !it.hasActiveAdmins && !it.isHomeApp - && !it.isResourceOverlay - } - } - }, - DISABLED(titleResourceId = R.string.category_disabled, summaryResourceId = R.string.category_disabled_summary) { - override fun filter(list: Collection): Collection = list.filter { !it.isEnabled } - }, - DEFAULT(titleResourceId = R.string.category_default, summaryResourceId = R.string.category_default_summary) { - override fun filter(list: Collection): Collection = list.filter(App::isDefaultApp) - }, - USER(titleResourceId = R.string.category_user, summaryResourceId = R.string.category_user_summary) { - override fun filter(list: Collection): Collection = list.filter { !it.isSystem } - }, - INTERNET_PERMISSIONS(titleResourceId = R.string.category_internet_permissions, summaryResourceId = R.string.category_internet_permissions_summary) { - override fun filter(list: Collection): Collection = - list.filter { it.requestedPermissions.contains(android.Manifest.permission.INTERNET) } - }, - DENIABLE_PERMISSIONS(titleResourceId = R.string.category_deniable_permissions, summaryResourceId = R.string.category_deniable_permissions_summary, targetSdkVersion = Build.VERSION_CODES.M..Int.MAX_VALUE) { - override fun filter(list: Collection): Collection { - return list.filter { - !it.isSystemPackage - && it.permissionGroups.isNotEmpty() - } - } - }, - SYSTEM_ALERT_WINDOW_PERMISSION(titleResourceId = R.string.category_system_alert_window_permission, summaryResourceId = R.string.category_system_alert_window_permission_summary, targetSdkVersion = Build.VERSION_CODES.M..Int.MAX_VALUE) { - override fun filter(list: Collection): Collection { - return list.filter { - !it.isSystemPackage - && it.requestedPermissions.contains(android.Manifest.permission.SYSTEM_ALERT_WINDOW) - } - } - }, - ; - - abstract fun filter(list: Collection): Collection - - fun where(list: Collection): Collection = filter(list).filter { !it.shouldSkip } - - companion object { - fun getAll() = values().filter { it.targetSdkVersion.contains(Build.VERSION.SDK_INT) } - } -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/DisplayItem.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/DisplayItem.kt deleted file mode 100755 index 8533c4f..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/DisplayItem.kt +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.nagopy.android.aplin.model - -import android.content.Context -import android.os.Build -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.constants.Constants -import com.nagopy.android.aplin.entity.App -import java.text.DateFormat -import java.util.* - -/** - * アプリ毎に表示する詳細情報の定義クラス - */ -enum class DisplayItem( - val titleResourceId: Int, val summaryResourceId: Int, val targetSdkVersion: IntRange = Constants.ALL_SDK_VERSION, val defaultValue: Boolean = false) { - - /** - * インストール状態 - */ - NOT_INSTALLED( - titleResourceId = R.string.display_item_not_installed, summaryResourceId = R.string.display_item_not_installed_summary) { - override fun append(context: Context, sb: StringBuilder, appData: App): Boolean { - if (!appData.isInstalled) { - sb.append(context.getString(R.string.display_item_not_installed_format)) - return true - } - return false - } - }, - - /** - * 初回インストール日時 - */ - FIRST_INSTALL_TIME( - titleResourceId = R.string.display_item_first_install_time, summaryResourceId = R.string.display_item_first_install_time_summary) { - override fun append(context: Context, sb: StringBuilder, appData: App): Boolean { - if (appData.firstInstallTime < Constants.Y2K) { - return false - } - val format = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault()) - sb.append(context.getString(R.string.display_item_first_install_time_format, format.format(Date(appData.firstInstallTime)))) - return true - } - }, - - /** - * 最終更新日時 - */ - LAST_UPDATE_TIME( - titleResourceId = R.string.display_item_last_update_time, summaryResourceId = R.string.display_item_last_update_time_summary) { - override fun append(context: Context, sb: StringBuilder, appData: App): Boolean { - if (appData.lastUpdateTime < Constants.Y2K) { - return false - } - val format = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault()) - sb.append(context.getString(R.string.display_item_last_update_time_format, format.format(Date(appData.lastUpdateTime)))) - return true - } - }, - - /** - * バージョン情報 - */ - VERSION_NAME( - titleResourceId = R.string.display_item_version_name, summaryResourceId = R.string.display_item_version_name_summary) { - override fun append(context: Context, sb: StringBuilder, appData: App): Boolean { - if (appData.versionName != null) { - sb.append(context.getString(R.string.display_item_version_name_format, appData.versionName)) - } - return true - } - }, - - /** - * パーミッション(インターネット) - */ - INTERNET_PERMISSION( - titleResourceId = R.string.display_item_internet_permission, summaryResourceId = R.string.display_item_internet_permission_summary) { - override fun append(context: Context, sb: StringBuilder, appData: App): Boolean { - if (appData.requestedPermissions.isNotEmpty()) { - val internet = appData.requestedPermissions.contains("android.permission.INTERNET") - if (internet) { - sb.append(context.getString(R.string.display_item_internet_permission_label)) - } - } - return true - } - }, - - /** - * パーミッション(拒否可能、6.0以降) - */ - DENIABLE_PERMISSIONS( - titleResourceId = R.string.display_item_deniable_permissions, summaryResourceId = R.string.display_item_deniable_permissions_summary, targetSdkVersion = Build.VERSION_CODES.M..Int.MAX_VALUE) { - override fun append(context: Context, sb: StringBuilder, appData: App): Boolean { - if (appData.requestedPermissions.isEmpty()) { - return false - } - val core = appData.isSystemPackage || appData.hasActiveAdmins - if (appData.isSystem && core) { - return false - } - - if (Build.VERSION_CODES.Q <= Build.VERSION.SDK_INT) { - // 29- - sb.append(context.getString(R.string.category_deniable_permissions)) - } else { - // -28 - sb.append(appData.permissionGroups.joinToString( - context.getString(R.string.display_item_deniable_permissions_separator)) { it.label } - ) - } - return true - } - }, - PACKAGE_NAME( - titleResourceId = R.string.display_item_package_name, summaryResourceId = R.string.display_item_package_name_summary, targetSdkVersion = Constants.ALL_SDK_VERSION, defaultValue = true) { - override fun append(context: Context, sb: StringBuilder, appData: App): Boolean { - sb.append(appData.packageName) - return true - } - } - ; - - /** - * 定義された情報をStringBuilderに追加する。 - - * @param context Context - * * - * @param sb StringBuilder - * * - * @param appData アプリ情報 - * * - * @return 文字列を追加した場合はtrue、追加しなかった場合はfalse - */ - abstract fun append(context: Context, sb: StringBuilder, appData: App): Boolean - - val key: String = "${javaClass.name}_$name" -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/IconHelper.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/IconHelper.kt deleted file mode 100755 index a4e6003..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/IconHelper.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model - -import android.app.ActivityManager -import android.app.Application -import android.content.pm.PackageManager -import android.graphics.drawable.BitmapDrawable -import android.graphics.drawable.Drawable -import androidx.collection.LruCache -import androidx.core.content.res.ResourcesCompat -import io.reactivex.Single -import timber.log.Timber -import javax.inject.Inject -import javax.inject.Singleton - -/** - * アイコン表示用のプロパティを扱うクラス - */ -@Singleton -open class IconHelper -/** - * コンストラクタ - */ -@Inject -constructor(val application: Application, activityManager: ActivityManager) { - - @Inject - lateinit var packageManager: PackageManager - - /** - * デフォルト表示用のアプリケーションアイコン - */ - private val defaultIcon: Drawable = ResourcesCompat.getDrawable(application.resources, android.R.drawable.sym_def_app_icon, null)!! - - /** - * アイコン画像の大きさ(PX) - */ - open val iconSize: Int = activityManager.launcherLargeIconSize * 4 / 3 - - private val iconCache: IconLruCache = IconLruCache(1024 * 1024 * activityManager.memoryClass / 6) - - fun requestLoadIcon(pkg: String): Single { - return Single.create { - var icon: Drawable? = iconCache.getOrNull(pkg) - if (icon == null) { - icon = try { - packageManager.getApplicationIcon(pkg) - } catch (e: PackageManager.NameNotFoundException) { - Timber.v(e, "Error pkg=%s", pkg) - defaultIcon - } - iconCache.put(pkg, icon!!) - Timber.v("Add cache. pkg=s%s", pkg) - } else { - Timber.v("Cached. pkg=%s", pkg) - } - it.onSuccess(icon) - } - } - - class IconLruCache(maxSize: Int) : LruCache(maxSize) { - - fun getOrNull(key: String): Drawable? = get(key) - - override fun sizeOf(key: String, value: Drawable): Int { - return if (value is BitmapDrawable) { - value.bitmap.byteCount / 1024 - } else { - 0 - } - } - } -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/MenuHandler.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/MenuHandler.kt deleted file mode 100644 index 19d1209..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/MenuHandler.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model - -import android.app.Application -import android.app.SearchManager -import android.content.ActivityNotFoundException -import android.content.Intent -import android.content.pm.PackageManager -import android.net.Uri -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.constants.Constants -import com.nagopy.android.aplin.entity.App -import io.reactivex.Observable -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -open class MenuHandler @Inject constructor() { - - @Inject - lateinit var application: Application - - @Inject - lateinit var packageManager: PackageManager - - fun search(app: App): Observable { - return Observable.create { s -> - val actionWebSearch = Intent(Intent.ACTION_WEB_SEARCH) - .putExtra(SearchManager.QUERY, "${app.label} ${app.packageName}") - - if (isLaunchable(actionWebSearch)) { - application.startActivity(actionWebSearch) - s.onComplete() - } else { - val url = "https://www.google.com/search?q=${app.label}%20${app.packageName}" - val actionView = Intent(Intent.ACTION_VIEW) - .setData(Uri.parse(url)) - if (isLaunchable(actionView)) { - application.startActivity(actionView) - s.onComplete() - } else { - s.onError(ActivityNotFoundException("Searchable application is not found.")) - } - } - } - } - - fun share(subject: String?, text: String): Observable { - return Observable.create { s -> - val intent = Intent(Intent.ACTION_SEND) - .setType(Constants.MIME_TYPE_TEXT_PLAIN) - .putExtra(Intent.EXTRA_SUBJECT, subject - ?: application.getString(R.string.app_name)) - .putExtra(Intent.EXTRA_TEXT, text) - if (isLaunchable(intent)) { - application.startActivity(intent) - s.onComplete() - } else { - s.onError(ActivityNotFoundException("Shareable application is not found.")) - } - } - } - - private fun isLaunchable(intent: Intent): Boolean { - return intent.resolveActivity(packageManager) != null - } - - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/PermissionGroups.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/PermissionGroups.kt deleted file mode 100644 index 313b789..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/PermissionGroups.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.nagopy.android.aplin.model - -import android.content.pm.PackageManager -import android.os.Build -import com.nagopy.android.aplin.entity.PermissionGroup -import timber.log.Timber -import java.util.* -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class PermissionGroups @Inject constructor() { - - @Inject - lateinit var shellCmd: ShellCmd - - @Inject - lateinit var packageManager: PackageManager - - fun getAllPermissionGroups(): List { - val commands = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - // 24- - listOf("cmd", "package", "list", "permissions", "-g", "-d") - } else { - // -23 - listOf("pm", "list", "permissions", "-g", "-d") - } - - var groupName: String? = null - var permissions = ArrayList() - - val result = ArrayList() - - shellCmd.exec(commands, { seq: Sequence -> - seq.map(String::trim) - .filter(String::isNotEmpty) - .forEach { - if (it.startsWith("group:")) { - if (groupName != null) { - result.add(PermissionGroup(groupName!!, getGroupLabel(groupName!!), permissions)) - } - // next group - groupName = it.replace("group:", "") - permissions = ArrayList() - } else if (it.startsWith("permission:")) { - permissions.add(it.replace("permission:", "")) - } - } - }, Unit) - - if (groupName != null) { - // last group - result.add(PermissionGroup(groupName!!, getGroupLabel(groupName!!), permissions)) - } - - return result - } - - private fun getGroupLabel(groupName: String): String { - try { - val pgi = packageManager.getPermissionGroupInfo(groupName, 0) - return pgi.loadLabel(packageManager).toString() - } catch (e: Exception) { - Timber.w(e) - return groupName.split(".").last() - } - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/SharingMethod.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/SharingMethod.kt deleted file mode 100755 index 96667fa..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/SharingMethod.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.nagopy.android.aplin.model - -import com.nagopy.android.aplin.constants.Constants -import com.nagopy.android.aplin.entity.App - -/** - * 共有方法の定義クラス - */ -enum class SharingMethod { - /** - * アプリ名共有 - */ - LABEL { - override fun makeShareString(appList: List): String { - val sb = StringBuilder() - for (app in appList) { - sb.append(makeShareString(app)) - sb.append(Constants.LINE_SEPARATOR) - } - return sb.toString() - } - - override fun makeShareString(appData: App): String { - return appData.label - } - }, - - /** - * パッケージ名 - */ - PACKAGE { - override fun makeShareString(appList: List): String { - val sb = StringBuilder() - for (app in appList) { - sb.append(makeShareString(app)) - sb.append(Constants.LINE_SEPARATOR) - } - return sb.toString() - } - - override fun makeShareString(appData: App): String { - return appData.packageName - } - }, - - /** - * アプリ名とパッケージ名 - */ - LABEL_AND_PACKAGE { - override fun makeShareString(appList: List): String { - val sb = StringBuilder() - for (app in appList) { - sb.append(makeShareString(app)) - sb.append(Constants.LINE_SEPARATOR) - sb.append(Constants.LINE_SEPARATOR) - } - return sb.toString() - } - - override fun makeShareString(appData: App): String { - return appData.label + Constants.LINE_SEPARATOR + appData.packageName - } - }; - - /** - * 共有用の文字列を作成する - - * @param appList 共有対象 - * * - * @return 共有用の文字列 - */ - abstract fun makeShareString(appList: List): String - - /** - * 共有用の文字列を作成する - - * @param appData 共有対象 - * * - * @return 共有用の文字列 - */ - abstract fun makeShareString(appData: App): String - -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/ShellCmd.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/ShellCmd.kt deleted file mode 100644 index bec7753..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/ShellCmd.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model - -import timber.log.Timber -import java.io.BufferedReader -import java.io.InputStreamReader -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class ShellCmd @Inject constructor() { - - @Throws(Exception::class) - fun exec(commands: Collection, useLines: (Sequence) -> T): T { - Timber.d("exec %s", commands) - val pb = ProcessBuilder(commands.toList()) - val p = pb.start() - val s = p.inputStream - val isr = InputStreamReader(s) - val br = BufferedReader(isr) - return br.useLines(useLines) - } - - fun exec(commands: Collection, useLines: (Sequence) -> T, defaultValue: T): T { - return try { - exec(commands, useLines) - } catch (e: Exception) { - Timber.w(e) - defaultValue - } - } -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/Sort.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/Sort.kt deleted file mode 100755 index 87278ea..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/Sort.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.nagopy.android.aplin.model - -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.constants.Constants -import com.nagopy.android.aplin.entity.App - -/** - * ソート順の定義クラス - */ -enum class Sort( - val titleResourceId: Int, val summaryResourceId: Int, val targetSdkVersion: IntRange = Constants.ALL_SDK_VERSION, val defaultValue: Boolean = false) { - - /** - * デフォルトのソート順。 - * - * 1. インストール状態が異なる場合、未インストールを後ろにする。 - * 1. アプリ表示名の昇順に並べる。ただし、アプリ表示名が同一の場合はパッケージ名の昇順で並べる。 - * - */ - DEFAULT(titleResourceId = R.string.sort_default, - summaryResourceId = R.string.sort_default_summary, - defaultValue = true) { - override fun orderBy(list: Collection): Collection { - return list.sortedWith(compareBy(App::isInstalled, App::label, App::packageName)) - } - }, - - /** - * パッケージ名の昇順 - */ - PACKAGE_NAME(titleResourceId = R.string.sort_package_name, summaryResourceId = R.string.sort_package_name_summary) { - override fun orderBy(list: Collection): Collection { - return list.sortedWith(compareBy(App::isInstalled, App::packageName)) - } - }, - - /** - * 初回インストール日時の降順 - */ - FIRST_INSTALL_TIME_DESC(titleResourceId = R.string.sort_install_time_desc, summaryResourceId = R.string.sort_install_time_desc_summary) { - override fun orderBy(list: Collection): Collection { - return list.sortedWith(compareBy({ it.firstInstallTime * -1 }, App::isInstalled, App::label, App::packageName)) - } - }, - - /** - * 最終更新日時の降順 - */ - UPDATE_DATE_DESC(titleResourceId = R.string.sort_update_time_desc, summaryResourceId = R.string.sort_update_time_desc_summary) { - override fun orderBy(list: Collection): Collection { - return list.sortedWith(compareBy({ it.lastUpdateTime * -1 }, App::isInstalled, App::label, App::packageName)) - } - }; - - abstract fun orderBy(list: Collection): Collection - - val key: String = "${javaClass.name}_$name" -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/UserSettings.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/UserSettings.kt deleted file mode 100644 index f6dbfcc..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/UserSettings.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model - -import android.content.SharedPreferences -import java.util.* -import javax.inject.Inject -import javax.inject.Singleton -import kotlin.properties.ReadOnlyProperty -import kotlin.reflect.KProperty - -@Singleton -open class UserSettings -@Inject constructor(var sharedPreferences: SharedPreferences) { - - val sort: Sort by SortProperty() - - val displayItems: List by DisplayItemProperty() - - class DisplayItemProperty : ReadOnlyProperty> { - override fun getValue(thisRef: UserSettings, property: KProperty<*>): List { - val v = ArrayList() - DisplayItem.values().forEach { - val checked = thisRef.sharedPreferences.getBoolean(it.key, it.defaultValue) - if (checked) { - v.add(it) - } - } - return v - } - - } - - class SortProperty : ReadOnlyProperty { - override fun getValue(thisRef: UserSettings, property: KProperty<*>): Sort { - val value = thisRef.sharedPreferences.getString(Sort::class.java.name, "") - return if (value.isNullOrEmpty()) { - Sort.DEFAULT - } else { - Sort.valueOf(value) - } - } - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/converter/AppConverter.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/converter/AppConverter.kt deleted file mode 100644 index aaf9be4..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/converter/AppConverter.kt +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model.converter - -import android.app.Application -import android.content.Intent -import android.content.pm.ApplicationInfo -import android.content.pm.PackageInfo -import android.content.pm.PackageManager -import android.os.Build -import com.nagopy.android.aplin.entity.App -import com.nagopy.android.aplin.entity.PermissionGroup -import com.nagopy.android.aplin.model.AplinDevicePolicyManager -import com.nagopy.android.aplin.model.Applications -import com.nagopy.android.aplin.model.PermissionGroups -import timber.log.Timber -import java.lang.reflect.Field -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -open class AppConverter @Inject constructor() { - - @Inject - open lateinit var application: Application - - @Inject - open lateinit var packageManager: PackageManager - - @Inject - open lateinit var aplinDevicePolicyManager: AplinDevicePolicyManager - - @Inject - lateinit var permissionGroups: PermissionGroups - - lateinit var allPermissionGroups: List - lateinit var homeActivities: List - lateinit var launcherPkgs: List - val enabledSettingField: Field = ApplicationInfo::class.java.getDeclaredField("enabledSetting").apply { - isAccessible = true - } - - open fun prepare() { - allPermissionGroups = permissionGroups.getAllPermissionGroups() - Timber.v("allPermissionGroups %s", allPermissionGroups) - - val intent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) - homeActivities = packageManager.queryIntentActivities(intent, 0) - .map { it.activityInfo.packageName } - .plus("com.google.android.launcher") // 仕組みが未確認だが、これはホームアプリ判定になっているっぽい - - val launcherIntent = Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER) - launcherPkgs = - try { - packageManager.queryIntentActivities(launcherIntent, 0).map { it.activityInfo.packageName } - } catch (e: Exception) { - Timber.w(e, "Error: queryIntentActivities") - emptyList() - } - } - - open fun setValues(app: App, packageName: String, vararg appParameters: AppParameters = AppParameters.values()) { - try { - val pi = getPackageInfo(packageName) - appParameters - .filter { it.targetSdkVersion.contains(Build.VERSION.SDK_INT) } - .forEach { param -> - param.setValue(app, pi, this@AppConverter) - } - } catch (e: PackageManager.NameNotFoundException) { - Timber.w(e, "Not found. pkg=%s", packageName) - } catch (e: Exception) { - Timber.e(e, "Error occurred. pkg=%s", packageName) - } - } - - fun getPackageInfo(packageName: String): PackageInfo { - // 一度に取得する量が多いとエラーになるらしいので、細かく分けて取得する - val packageInfo = packageManager.getPackageInfo( - packageName, - Applications.flags - ) - - try { - val pkg = packageManager.getPackageInfo( - packageName, - PackageManager.GET_PERMISSIONS or Applications.flags - ) - packageInfo.requestedPermissions = pkg.requestedPermissions - } catch (e: Exception) { - Timber.w(e) - } - - try { - val sig = packageManager.getPackageInfo( - packageName, - PackageManager.GET_SIGNATURES or Applications.flags - ) - packageInfo.signatures = sig.signatures - } catch (e: Exception) { - Timber.w(e) - } - - return packageInfo - } - - interface Converter { - fun targetSdkVersion(): IntRange - fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) - } - -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/model/converter/AppParameters.kt b/app/src/main/kotlin/com/nagopy/android/aplin/model/converter/AppParameters.kt deleted file mode 100644 index 2ca8f94..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/model/converter/AppParameters.kt +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model.converter - -import android.content.ComponentName -import android.content.IntentFilter -import android.content.pm.ApplicationInfo -import android.content.pm.PackageInfo -import android.content.pm.PackageManager -import android.os.Build -import com.nagopy.android.aplin.constants.Constants -import com.nagopy.android.aplin.entity.App -import java.util.* - -enum class AppParameters(val targetSdkVersion: IntRange) : AppConverter.Converter { - packageName(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.packageName = packageInfo.applicationInfo.packageName - } - }, - label(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.label = packageInfo.applicationInfo.loadLabel(appConverter.packageManager).toString() - } - }, - isEnabled(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.isEnabled = packageInfo.applicationInfo.enabled - } - }, - isSystem(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.isSystem = - (packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) != 0 - || (packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 - } - }, - isSystemPackage(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.isSystemPackage = appConverter.aplinDevicePolicyManager.isSystemPackage(packageInfo) - } - }, - firstInstallTime(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.firstInstallTime = packageInfo.firstInstallTime - } - }, - lastUpdateTime(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.lastUpdateTime = packageInfo.lastUpdateTime - } - }, - hasActiveAdmins(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.hasActiveAdmins = appConverter.aplinDevicePolicyManager.packageHasActiveAdmins(packageInfo.applicationInfo.packageName) - } - }, - isInstalled(IntRange(Build.VERSION_CODES.JELLY_BEAN_MR1, Int.MAX_VALUE)) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.isInstalled = (packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_INSTALLED) != 0 - } - }, - isDefaultApp(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - val outFilters = ArrayList() - val outActivities = ArrayList() - appConverter.packageManager.getPreferredActivities(outFilters, outActivities, packageInfo.applicationInfo.packageName) - app.isDefaultApp = outActivities.isNotEmpty() - } - }, - isHomeApp(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.isHomeApp = appConverter.homeActivities.contains(packageInfo.applicationInfo.packageName) - } - }, - versionName(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.versionName = packageInfo.versionName - } - }, - requestedPermissions(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - packageInfo.requestedPermissions?.forEach { - app.requestedPermissions.add(it) - } - } - }, - permissionGroups(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - packageInfo.requestedPermissions?.map { p -> - appConverter.allPermissionGroups.filter { it.permissions.contains(p) } - }?.flatMap { it } - ?.distinct() - ?.sortedBy { it.label } - ?.forEach { - app.permissionGroups.add(it) - } - } - }, - isProfileOrDeviceOwner(Build.VERSION_CODES.M..Int.MAX_VALUE) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.isProfileOrDeviceOwner = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - && appConverter.aplinDevicePolicyManager.isProfileOrDeviceOwner(packageInfo.applicationInfo.packageName) - } - }, - isLaunchable(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.isLaunchable = appConverter.launcherPkgs.contains(packageInfo.applicationInfo.packageName) - } - }, - isDisabledUntilUsed(Build.VERSION_CODES.M..Int.MAX_VALUE) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - // 6.0- - val enabledSetting = appConverter.enabledSettingField.get(packageInfo.applicationInfo) - app.isDisabledUntilUsed = enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED - } - } - }, - shouldSkip(Constants.ALL_SDK_VERSION) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.shouldSkip = false - if (packageInfo.applicationInfo.packageName.isEmpty()) { - app.shouldSkip = true - } else if (!packageInfo.applicationInfo.enabled) { - // 無効になっていて、かつenabledSettingが3でないアプリは除外する - val enabledSetting = appConverter.enabledSettingField.get(packageInfo.applicationInfo) - if (enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { - app.shouldSkip = true - } - } - } - }, - isResourceOverlay(Build.VERSION_CODES.Q..Int.MAX_VALUE) { - override fun setValue(app: App, packageInfo: PackageInfo, appConverter: AppConverter) { - app.isResourceOverlay = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - packageInfo.applicationInfo.isResourceOverlay - } else { - false - } - } - }, - ; - - override fun targetSdkVersion(): IntRange = targetSdkVersion -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/presenter/AdPresenter.kt b/app/src/main/kotlin/com/nagopy/android/aplin/presenter/AdPresenter.kt deleted file mode 100755 index 76c3928..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/presenter/AdPresenter.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.presenter - -import com.google.android.gms.ads.AdRequest -import com.google.android.gms.ads.AdView -import com.nagopy.android.aplin.BuildConfig -import javax.inject.Inject -import javax.inject.Singleton - -/** - * 広告表示(AdMob)の処理を移譲するためのクラス - */ -@Singleton -open class AdPresenter @Inject constructor() : Presenter { - - // Show release build only - var showAds = !BuildConfig.DEBUG - - var adView: AdView? = null - - open fun initialize(adView: AdView) { - if (showAds) { - this.adView = adView - adView.loadAd(AdRequest.Builder() - .addTestDevice(AdRequest.DEVICE_ID_EMULATOR) - .addTestDevice("2E21E51466C94A2960FCB4E0BB5DB388") - .addTestDevice("561DC184323F7A23F20080805D44083C") - .addTestDevice("0FDB3E1E20DE9A1E911A85F87903A069") - .addTestDevice("F3D630FD4B16A430A0CB29123A096F71") - .addTestDevice("4EB260715A6D70807B32DAAC473002C9") - .build()) - } - } - - override fun resume() { - showAds.let { - adView?.resume() - } - } - - override fun pause() { - showAds.let { - adView?.pause() - } - } - - override fun destroy() { - showAds.let { - adView?.destroy() - adView = null - } - } -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/presenter/AppListPresenter.kt b/app/src/main/kotlin/com/nagopy/android/aplin/presenter/AppListPresenter.kt deleted file mode 100644 index 765837b..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/presenter/AppListPresenter.kt +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.presenter - -import android.app.Application -import android.view.MenuItem -import android.view.View -import android.widget.ImageView -import androidx.core.content.ContextCompat -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.constants.Constants -import com.nagopy.android.aplin.entity.App -import com.nagopy.android.aplin.model.Applications -import com.nagopy.android.aplin.model.Category -import com.nagopy.android.aplin.model.IconHelper -import com.nagopy.android.aplin.model.UserSettings -import com.nagopy.android.aplin.view.AppListView -import com.nagopy.android.aplin.view.AppListViewParent -import com.nagopy.android.aplin.view.adapter.AppListAdapter -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.schedulers.Schedulers -import timber.log.Timber -import javax.inject.Inject - -/** - * カテゴリ毎アプリ一覧のプレゼンター - */ -open class AppListPresenter @Inject constructor() : Presenter { - - @Inject - lateinit var application: Application - - @Inject - lateinit var userSettings: UserSettings - - @Inject - lateinit var applications: Applications - - @Inject - lateinit var iconHelper: IconHelper - - var defList: List = emptyList() - - val filteredList: MutableList = ArrayList() - - var view: AppListView? = null // onDestroyでnullにするため、NULL可 - - var parentView: AppListViewParent? = null // onDestroyでnullにするため、NULL可 - - lateinit var category: Category - - var searchText: String = "" - - private val compositeDisposable = CompositeDisposable() - - fun initialize(view: AppListView, parentView: AppListViewParent, category: Category) { - this.view = view - this.parentView = parentView - this.category = category - updateAppList() - } - - fun updateAppList() { - applications.getApplicationList(category) - .subscribeOn(Schedulers.computation()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ - defList = it - updateFilter(searchText) - }, { e -> - Timber.e(e, "Error occurred") - }).also { - compositeDisposable.add(it) - } - } - - fun updateFilter(searchText: String) { - this.searchText = searchText - Timber.d("searchText: %s, defList.size = %d, applications.appCache.size = %d", searchText, defList.size, applications.appCache.size) - filteredList.clear() - defList.forEach { - if (it.packageName.contains(searchText, ignoreCase = true) - || it.label.contains(searchText, ignoreCase = true)) { - Timber.v("Hit: %s", it) - filteredList.add(it) - } - } - view?.notifyDataSetChanged() - } - - override fun resume() { - } - - override fun pause() { - } - - override fun destroy() { - view = null - parentView = null - compositeDisposable.clear() - } - - fun onOptionsItemSelected(item: MenuItem) { - parentView?.onOptionsItemSelected(item, filteredList) - } - - fun onItemViewCreated(holder: AppListAdapter.ViewHolder, position: Int) { - val entity = filteredList[position] - - val textColor = ContextCompat.getColor(application, - if (entity.isEnabled) R.color.text_color else R.color.textColorTertiary) - - holder.label.text = entity.label - holder.label.setTextColor(textColor) - - val sb = StringBuilder() - for (item in userSettings.displayItems) { - if (item.append(application, sb, entity)) { - sb.append(Constants.LINE_SEPARATOR) - } - } - - if (sb.isNotEmpty()) { - sb.setLength(sb.length - 1) - var infoString = sb.toString().trim() - infoString = infoString.replace((Constants.LINE_SEPARATOR + "+").toRegex(), Constants.LINE_SEPARATOR) - holder.status.text = infoString - holder.status.visibility = View.VISIBLE - } else { - holder.status.text = "" - holder.status.visibility = View.GONE - } - holder.status.setTextColor(textColor) - - synchronized(holder.icon) { - if (holder.icon.tag != entity.packageName) { - holder.icon.tag = entity.packageName - holder.icon.visibility = View.INVISIBLE - iconHelper.requestLoadIcon(entity.packageName) - .subscribeOn(Schedulers.computation()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ icon -> - synchronized(holder.icon) { - if (holder.icon.tag == entity.packageName) { - holder.icon.setImageDrawable(icon) - holder.icon.visibility = View.VISIBLE - Timber.v("Set icon. pkg=%s", entity.packageName) - } - } - }) - } - } - - holder.icon.scaleType = ImageView.ScaleType.FIT_CENTER - holder.icon.layoutParams.width = iconHelper.iconSize - holder.icon.layoutParams.height = iconHelper.iconSize - } - - fun onItemClicked(position: Int) { - val app = filteredList[position] - Timber.d("open %s", app) - parentView?.onListItemClicked(app, category) - } - - fun onItemLongClicked(position: Int) { - val app = filteredList[position] - parentView?.onListItemLongClicked(app) - } - -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/presenter/MainScreenPresenter.kt b/app/src/main/kotlin/com/nagopy/android/aplin/presenter/MainScreenPresenter.kt deleted file mode 100644 index f272913..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/presenter/MainScreenPresenter.kt +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.presenter - -import android.app.Activity -import android.app.Application -import android.content.Intent -import android.net.Uri -import android.os.Build -import android.provider.Settings -import android.view.MenuItem -import android.widget.Toast -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.entity.App -import com.nagopy.android.aplin.model.Applications -import com.nagopy.android.aplin.model.Category -import com.nagopy.android.aplin.model.MenuHandler -import com.nagopy.android.aplin.model.SharingMethod -import com.nagopy.android.aplin.view.MainScreenView -import com.nagopy.android.aplin.view.SettingsActivity -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.schedulers.Schedulers -import timber.log.Timber -import javax.inject.Inject -import javax.inject.Singleton - -/** - * メイン画面用プレゼンター - */ -@Singleton -open class MainScreenPresenter @Inject constructor() : Presenter { - - @Inject - lateinit var menuHandler: MenuHandler - - @Inject - lateinit var application: Application - - @Inject - lateinit var applications: Applications - - var view: MainScreenView? = null - - private val compositeDisposable = CompositeDisposable() - - open fun initialize(view: MainScreenView) { - this.view = view - - view.hideAppList() - view.showIndicator() - view.setToolbarSpinnerEnabled(false) - - applications.initAppCache() - .subscribeOn(Schedulers.computation()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ - view.hideIndicator() - view.showAppList() - view.setToolbarSpinnerEnabled(true) - }, { e -> - Timber.e(e, "Error occurred") - }).also { - compositeDisposable.add(it) - } - } - - override fun resume() { - applications.updatePoco() - .subscribeOn(Schedulers.computation()) - .subscribe({ - // do nothing - }, { t -> - Timber.e(t, "Default status update error") - // ignore - }).also { - compositeDisposable.add(it) - } - } - - override fun pause() { - } - - override fun destroy() { - view = null - compositeDisposable.clear() - } - - fun listItemClicked(activity: Activity, app: App, category: Category) { - val packageName = app.packageName.split(":")[0] - - val intent = when (category) { - Category.SYSTEM_ALERT_WINDOW_PERMISSION -> - Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName")) - else -> - Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:$packageName")) - - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - if (activity.isInMultiWindowMode) { - intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) - } - } - try { - activity.startActivity(intent) - } catch (e: Exception) { - Timber.w(e) - } - } - - fun listItemLongClicked(app: App) { - menuHandler.search(app) - .subscribeOn(AndroidSchedulers.mainThread()) - .subscribe({}, { e -> - Timber.e(e, "onError") - Toast.makeText(application, e.message, Toast.LENGTH_LONG).show() - }).also { - compositeDisposable.add(it) - } - } - - fun onMenuItemClicked(item: MenuItem, checkedItemList: List) { - val onNext: (Void) -> Unit = {} - val onError: (Throwable) -> Unit = { e -> - Timber.e(e, "onError") - Toast.makeText(application, e.message, Toast.LENGTH_LONG).show() - } - - when (item.itemId) { - R.id.action_settings -> { - val intent = Intent(application, SettingsActivity::class.java) - application.startActivity(intent) - } - R.id.action_share_label -> { - val text = SharingMethod.LABEL.makeShareString(checkedItemList) - menuHandler.share(item.title?.toString(), text) - .subscribeOn(AndroidSchedulers.mainThread()) - .subscribe(onNext, onError) - } - R.id.action_share_package_name -> { - val text = SharingMethod.PACKAGE.makeShareString(checkedItemList) - menuHandler.share(item.title?.toString(), text) - .subscribeOn(AndroidSchedulers.mainThread()) - .subscribe(onNext, onError) - } - R.id.action_share_label_and_package_name -> { - val text = SharingMethod.LABEL_AND_PACKAGE.makeShareString(checkedItemList) - menuHandler.share(item.title?.toString(), text) - .subscribeOn(AndroidSchedulers.mainThread()) - .subscribe(onNext, onError) - } - } - } -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/presenter/Presenter.kt b/app/src/main/kotlin/com/nagopy/android/aplin/presenter/Presenter.kt deleted file mode 100644 index 8fec7b0..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/presenter/Presenter.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.presenter - -interface Presenter { - fun resume() - - fun pause() - - fun destroy() -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/presenter/SettingsPresenter.kt b/app/src/main/kotlin/com/nagopy/android/aplin/presenter/SettingsPresenter.kt deleted file mode 100644 index aef7705..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/presenter/SettingsPresenter.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.presenter - -import android.app.Application -import android.content.Intent -import android.content.SharedPreferences -import com.nagopy.android.aplin.view.MainActivity -import com.nagopy.android.aplin.view.SettingsView -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -open class SettingsPresenter @Inject constructor() : Presenter, SharedPreferences.OnSharedPreferenceChangeListener { - - @Inject - lateinit var application: Application - - @Inject - lateinit var sharedPreferences: SharedPreferences - - var settingChanged: Boolean = false - - lateinit var view: SettingsView - - fun initialize(view: SettingsView) { - this.view = view - settingChanged = false - } - - override fun resume() { - sharedPreferences.registerOnSharedPreferenceChangeListener(this) - } - - override fun pause() { - sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) - } - - override fun destroy() { - } - - /** - * Activity#finish - * @return True if the presenter has consumed the event, false otherwise. - */ - fun finish(): Boolean { - if (settingChanged) { - val mainActivityIntent = Intent(application, MainActivity::class.java) - .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - application.startActivity(mainActivityIntent) - return true - } - return false - } - - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - settingChanged = true - } -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/AppListFragment.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/AppListFragment.kt deleted file mode 100644 index dfa039e..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/AppListFragment.kt +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.view - -import android.app.Application -import android.os.Bundle -import android.view.LayoutInflater -import android.view.MenuItem -import android.view.View -import android.view.ViewGroup -import android.widget.AbsListView -import android.widget.AdapterView -import androidx.fragment.app.Fragment -import com.nagopy.android.aplin.Aplin -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.model.Category -import com.nagopy.android.aplin.presenter.AppListPresenter -import com.nagopy.android.aplin.view.adapter.AppListAdapter -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.Disposable -import io.reactivex.schedulers.Schedulers -import timber.log.Timber -import javax.inject.Inject - -/** - * カテゴリ毎のアプリ一覧を表示するフラグメント - */ -class AppListFragment : Fragment(), AppListView, AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener { - - lateinit var listView: AbsListView - - @Inject - lateinit var presenter: AppListPresenter - - @Inject - lateinit var application: Application - - lateinit var adapter: AppListAdapter - - var disposer: Disposable? = null - var searchTextDisposer: Disposable? = null - - val category: Category by lazy { Category.valueOf(arguments!!.getString("type")!!) } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - retainInstance = true - setHasOptionsMenu(true) - - Aplin.getApplicationComponent().inject(this) - - adapter = AppListAdapter(application, presenter) - - presenter.initialize(this, activity as AppListViewParent, category) - - disposer = presenter.applications.appObserver - .subscribeOn(Schedulers.computation()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ - Timber.d("App changed. category = %s", category) - presenter.updateAppList() - }, { e -> - Timber.e(e, "Error") - }) - - searchTextDisposer = MainActivity.searchTextObserver - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { t -> - Timber.v("searchTextObserver %s", t) - presenter.updateFilter(t) - } - } - - override fun onResume() { - super.onResume() - presenter.resume() - listView.onItemClickListener = this - listView.onItemLongClickListener = this - } - - override fun onPause() { - super.onPause() - presenter.pause() - listView.onItemClickListener = null - listView.onItemLongClickListener = null - } - - override fun onDestroy() { - super.onDestroy() - presenter.destroy() - if (disposer?.isDisposed == false) { - disposer?.dispose() - } - if (searchTextDisposer?.isDisposed == false) { - searchTextDisposer?.dispose() - } - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_app_list, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - listView = view.findViewById(R.id.list) - listView.adapter = adapter - } - - override fun onDestroyView() { - super.onDestroyView() - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - presenter.onOptionsItemSelected(item) - return super.onOptionsItemSelected(item) - } - - override fun notifyDataSetChanged() { - adapter.notifyDataSetChanged() - } - - override fun onItemClick(adapterView: AdapterView<*>?, view: View?, position: Int, id: Long) { - Timber.d("Click pos=%s", position) - presenter.onItemClicked(position) - } - - override fun onItemLongClick(adapterView: AdapterView<*>?, view: View?, position: Int, id: Long): Boolean { - Timber.d("Long-click pos=%s", position) - presenter.onItemLongClicked(position) - return true - } - - companion object { - fun newInstance(category: Category): AppListFragment { - val appListFragment = AppListFragment() - val args = Bundle() - args.putString("type", category.name) - appListFragment.arguments = args - return appListFragment - } - } -} - diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/AppListView.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/AppListView.kt deleted file mode 100644 index b4f769f..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/AppListView.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.view - -/** - * アプリ一覧のビューを表すインターフェース - */ -interface AppListView { - - fun notifyDataSetChanged() - -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/AppListViewParent.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/AppListViewParent.kt deleted file mode 100644 index 512b820..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/AppListViewParent.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.view - -import android.view.MenuItem -import com.nagopy.android.aplin.entity.App -import com.nagopy.android.aplin.model.Category - -/** - * AppListViewの親Viewのインターフェース
- * 主にメニュー操作などの処理を移譲するために使用。 - */ -interface AppListViewParent { - fun onListItemClicked(app: App, category: Category) - - fun onListItemLongClicked(app: App) - - fun onOptionsItemSelected(item: MenuItem, appList: List) - -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/LicenseActivity.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/LicenseActivity.kt deleted file mode 100644 index a9a287a..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/LicenseActivity.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.nagopy.android.aplin.view - -import android.os.Bundle -import android.view.MenuItem -import android.webkit.WebView -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.Toolbar -import com.nagopy.android.aplin.R - -class LicenseActivity : AppCompatActivity() { - - lateinit var webView: WebView - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - setContentView(R.layout.activity_license) - val toolbar = findViewById(R.id.toolbar) - toolbar.setNavigationIcon(R.drawable.ic_action_back) - setSupportActionBar(toolbar) - supportActionBar!!.setDisplayHomeAsUpEnabled(true) - - webView = findViewById(R.id.web_view) - webView.settings.loadWithOverviewMode = true - webView.settings.useWideViewPort = true - webView.loadUrl("file:///android_asset/licenses.html") - } - - override fun onDestroy() { - super.onDestroy() - webView.destroy() - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - android.R.id.home -> finish() - else -> { - // do nothing - } - } - return super.onOptionsItemSelected(item) - } -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/MainActivity.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/MainActivity.kt deleted file mode 100644 index e2a0cf5..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/MainActivity.kt +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.view - -import android.os.Bundle -import android.view.Menu -import android.view.MenuItem -import android.view.View -import android.widget.AdapterView -import android.widget.ProgressBar -import android.widget.Spinner -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.SearchView -import androidx.appcompat.widget.Toolbar -import androidx.viewpager.widget.ViewPager -import com.google.android.gms.ads.AdView -import com.nagopy.android.aplin.Aplin -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.entity.App -import com.nagopy.android.aplin.model.Category -import com.nagopy.android.aplin.presenter.AdPresenter -import com.nagopy.android.aplin.presenter.MainScreenPresenter -import com.nagopy.android.aplin.view.adapter.AppCategoryAdapter -import com.nagopy.android.aplin.view.adapter.MainScreenPagerAdapter -import io.reactivex.subjects.BehaviorSubject -import timber.log.Timber -import javax.inject.Inject - - -/** - * メインになる画面用のActivity - */ -class MainActivity : AppCompatActivity(), - MainScreenView, AppListViewParent // 子Viewから処理を移譲してもらうためのインターフェース - , AdapterView.OnItemSelectedListener, ViewPager.OnPageChangeListener { - - val toolbar: Toolbar by lazy { - findViewById(R.id.toolbar) - } - - private val spinner: Spinner by lazy { findViewById(R.id.spinner) } - - val viewPager: ViewPager by lazy { findViewById(R.id.pager) } - - val adView: AdView by lazy { findViewById(R.id.adView) } - - val progressBar: ProgressBar by lazy { findViewById(R.id.progress) } - - @Inject - lateinit var presenter: MainScreenPresenter - - @Inject - lateinit var adPresenter: AdPresenter - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - Aplin.getApplicationComponent().inject(this) - - setContentView(R.layout.activity_main) - setSupportActionBar(toolbar) - spinner.adapter = AppCategoryAdapter(application) - spinner.onItemSelectedListener = this - viewPager.addOnPageChangeListener(this) - - presenter.initialize(this) - adPresenter.initialize(adView) - } - - override fun onResume() { - super.onResume() - presenter.resume() - adPresenter.resume() - } - - override fun onPause() { - super.onPause() - presenter.pause() - adPresenter.pause() - } - - override fun onDestroy() { - super.onDestroy() - presenter.destroy() - adPresenter.destroy() - spinner.onItemSelectedListener = null - viewPager.removeOnPageChangeListener(this) - } - - override fun showIndicator() { - progressBar.visibility = View.VISIBLE - } - - override fun hideIndicator() { - progressBar.visibility = View.GONE - } - - override fun showAppList() { - viewPager.visibility = View.VISIBLE - - val adapter = MainScreenPagerAdapter(applicationContext, supportFragmentManager) - viewPager.adapter = adapter - } - - override fun hideAppList() { - viewPager.visibility = View.INVISIBLE - } - - override fun setToolbarSpinnerEnabled(enabled: Boolean) { - spinner.isEnabled = enabled - } - - // menu =============================================================================================== - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - super.onCreateOptionsMenu(menu) - menuInflater.inflate(R.menu.main, menu) - - val searchMenu = menu.findItem(R.id.action_search) - val searchView = searchMenu.actionView as SearchView - searchView.queryHint = getString(R.string.action_search_hint) - searchView.setOnQueryTextFocusChangeListener { _, _ -> - Timber.d("onFocusChange") - } - searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { - override fun onQueryTextSubmit(query: String?): Boolean { - Timber.d("onQueryTextSubmit %s", query) - return false - } - - override fun onQueryTextChange(newText: String?): Boolean { - newText?.let { - Timber.d("onQueryTextChange %s", newText) - searchTextObserver.onNext(newText) - } - return true - } - }) - - searchMenu.setOnActionExpandListener(object : MenuItem.OnActionExpandListener { - override fun onMenuItemActionCollapse(item: MenuItem): Boolean { - Timber.d("onMenuItemActionCollapse") - return true - } - - override fun onMenuItemActionExpand(item: MenuItem): Boolean { - Timber.d("onMenuItemActionExpand") - return true - } - }) - return true - } - - override fun onOptionsItemSelected(item: MenuItem, appList: List) { - presenter.onMenuItemClicked(item, appList) - } - - - override fun onListItemClicked(app: App, category: Category) { - presenter.listItemClicked(this, app, category) - } - - override fun onListItemLongClicked(app: App) { - presenter.listItemLongClicked(app) - } - - // Spinner - override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) { - if (viewPager.adapter != null && viewPager.currentItem != position) { - viewPager.setCurrentItem(position, false) - } - } - - override fun onNothingSelected(parent: AdapterView<*>?) { - } - - // ViewPager - override fun onPageScrollStateChanged(state: Int) { - } - - override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { - } - - override fun onPageSelected(position: Int) { - spinner.setSelection(position) - } - - companion object { - val searchTextObserver: BehaviorSubject = BehaviorSubject.create() - - } - -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/MainScreenView.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/MainScreenView.kt deleted file mode 100644 index f27745e..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/MainScreenView.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.view - -/** - * メイン画面の親ビューを表すインターフェース - */ -interface MainScreenView { - - /** - * インジケーターを表示する - */ - fun showIndicator() - - /** - * インジケーターを非表示にする - */ - fun hideIndicator() - - /** - * カテゴリ別アプリ一覧を表示する - */ - fun showAppList() - - /** - * カテゴリ別アプリ一覧を非表示にする - */ - fun hideAppList() - - fun setToolbarSpinnerEnabled(enabled: Boolean) - -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/PackageChangedReceiver.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/PackageChangedReceiver.kt deleted file mode 100644 index 6ce96d9..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/PackageChangedReceiver.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.view - -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import com.nagopy.android.aplin.Aplin -import com.nagopy.android.aplin.model.Applications -import io.reactivex.schedulers.Schedulers -import timber.log.Timber -import javax.inject.Inject - -class PackageChangedReceiver : BroadcastReceiver() { - - @Inject - lateinit var applications: Applications - - override fun onReceive(context: Context, intent: Intent) { - Aplin.getApplicationComponent().inject(this) - - val pkg = intent.data?.schemeSpecificPart - - Timber.d("%s", intent) - if (pkg != null) { - when (intent.action) { - Intent.ACTION_PACKAGE_ADDED -> applications.insert(pkg) - Intent.ACTION_PACKAGE_CHANGED -> applications.update(pkg) - Intent.ACTION_PACKAGE_REPLACED -> applications.update(pkg) - Intent.ACTION_PACKAGE_REMOVED -> applications.delete(pkg) - Intent.ACTION_PACKAGE_FULLY_REMOVED -> applications.delete(pkg) - else -> throw IllegalAccessException("Unknown action: ${intent.action}") - }.subscribeOn(Schedulers.newThread()) - .subscribe({ - // do nothing - }, { t -> - Timber.e(t, "Receiver error") - // ignore - }) - - } - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/SettingsActivity.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/SettingsActivity.kt deleted file mode 100755 index 5efad60..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/SettingsActivity.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.nagopy.android.aplin.view - -import android.os.Bundle -import android.preference.PreferenceFragment -import android.view.MenuItem -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.Toolbar -import com.nagopy.android.aplin.Aplin -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.presenter.SettingsPresenter -import javax.inject.Inject - - -class SettingsActivity : AppCompatActivity(), SettingsView { - - @Inject - lateinit var settingsPresenter: SettingsPresenter - - lateinit var settingsFragment: PreferenceFragment - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - Aplin.getApplicationComponent().inject(this) - settingsPresenter.initialize(this) - - setContentView(R.layout.activity_settings) - - val toolbar = findViewById(R.id.toolbar) - toolbar.setNavigationIcon(R.drawable.ic_action_back) - setSupportActionBar(toolbar) - supportActionBar!!.setDisplayHomeAsUpEnabled(true) - - settingsFragment = SettingsFragment() - fragmentManager.beginTransaction().replace(R.id.content, settingsFragment).commit() - } - - override fun onResume() { - super.onResume() - settingsPresenter.resume() - } - - override fun onPause() { - super.onPause() - settingsPresenter.pause() - } - - override fun onDestroy() { - super.onDestroy() - settingsPresenter.destroy() - } - - override fun finish() { - if (!settingsPresenter.finish()) { - super.finish() - } - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - android.R.id.home -> finish() - else -> throw RuntimeException("unknown id:" + item.itemId) - } - return super.onOptionsItemSelected(item) - } - - companion object { - class SettingsFragment : PreferenceFragment() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - addPreferencesFromResource(R.xml.pref) - } - } - } -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/SettingsView.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/SettingsView.kt deleted file mode 100644 index 1400b08..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/SettingsView.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.view - -interface SettingsView diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/adapter/AppCategoryAdapter.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/adapter/AppCategoryAdapter.kt deleted file mode 100644 index a8197bc..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/adapter/AppCategoryAdapter.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.view.adapter - -import android.app.Application -import android.content.Context -import android.graphics.Point -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.view.WindowManager -import android.widget.BaseAdapter -import android.widget.TextView -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.model.Category - -class AppCategoryAdapter(val application: Application) : BaseAdapter() { - - private val categories = Category.getAll() - - private val inflater = LayoutInflater.from(application)!! - - private val screenWidth: Int - - init { - val wm = application.getSystemService(Context.WINDOW_SERVICE) as WindowManager - val display = wm.defaultDisplay - val point = Point() - display.getSize(point) - screenWidth = point.x - } - - override fun getCount(): Int = categories.size - - override fun getItem(position: Int): Category = categories[position] - - override fun getItemId(position: Int): Long = position.toLong() - - override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup?): View { - val view: View - if (convertView == null || convertView.tag.toString() == "DROPDOWN") { - view = inflater.inflate(R.layout.toolbar_spinner_item_dropdown, parent, false) - view.tag = "DROPDOWN" - } else { - view = convertView - } - - val category = getItem(position) - - val titleView = view.findViewById(android.R.id.text1) - titleView.setText(category.titleResourceId) - - val summaryTextView = view.findViewById(android.R.id.text2) - summaryTextView.setText(category.summaryResourceId) - summaryTextView.visibility = if (summaryTextView.text.isEmpty()) { - View.GONE - } else { - View.VISIBLE - } - summaryTextView.maxWidth = screenWidth * 7 / 10 - - return view - } - - override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { - val view: View - if (convertView == null || convertView.tag.toString() == "NON_DROPDOWN") { - view = inflater.inflate(R.layout.toolbar_spinner_item_actionbar, parent, false) - view.tag = "NON_DROPDOWN" - } else { - view = convertView - } - val textView = view.findViewById(android.R.id.text1) - val category = getItem(position) - textView.setText(category.titleResourceId) - - return view - } -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/adapter/AppListAdapter.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/adapter/AppListAdapter.kt deleted file mode 100644 index 6760bc8..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/adapter/AppListAdapter.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.nagopy.android.aplin.view.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.BaseAdapter -import android.widget.ImageView -import android.widget.TextView -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.presenter.AppListPresenter - -class AppListAdapter(private val context: Context, private val appListPresenter: AppListPresenter) : BaseAdapter() { - - override fun getItem(position: Int): Any = appListPresenter.filteredList[position] - - override fun getItemId(position: Int): Long = position.toLong() - - override fun getCount(): Int = appListPresenter.filteredList.count() - - override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { - val view = convertView - ?: LayoutInflater.from(context).inflate(R.layout.list_item, parent, false) - val holder = (view.tag as? ViewHolder) ?: ViewHolder(view) - view.tag = holder - - appListPresenter.onItemViewCreated(holder, position) - - return view - } - - open class ViewHolder(parentView: View) { - open val icon: ImageView = parentView.findViewById(R.id.icon) - open val label: TextView = parentView.findViewById(R.id.label) - open val status: TextView = parentView.findViewById(R.id.status) - } - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/adapter/MainScreenPagerAdapter.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/adapter/MainScreenPagerAdapter.kt deleted file mode 100644 index 6f7a5af..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/adapter/MainScreenPagerAdapter.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.view.adapter - -import android.content.Context -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter -import com.nagopy.android.aplin.model.Category -import com.nagopy.android.aplin.view.AppListFragment - -/** - * メイン画面のカテゴリ表示用アダプタ - */ -class MainScreenPagerAdapter( - val context: Context, - fragmentManager: FragmentManager, - private val categories: List = Category.getAll()) : FragmentPagerAdapter(fragmentManager) { - - override fun getItem(position: Int): Fragment = - AppListFragment.newInstance(categories[position]) - - override fun getCount(): Int = categories.size - - override fun getPageTitle(position: Int): CharSequence = context.getString(categories[position].titleResourceId) -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/preference/DisplayItemPreference.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/preference/DisplayItemPreference.kt deleted file mode 100644 index 9547065..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/preference/DisplayItemPreference.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.view.preference - -import android.content.Context -import android.os.Build -import android.preference.CheckBoxPreference -import android.preference.PreferenceCategory -import android.preference.PreferenceManager -import android.util.AttributeSet -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.model.DisplayItem - -class DisplayItemPreference : PreferenceCategory { - - @SuppressWarnings("unused") - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) - - @SuppressWarnings("unused") - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) - - @SuppressWarnings("unused") - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - @SuppressWarnings("unused") - constructor(context: Context) : super(context) - - override fun onAttachedToHierarchy(preferenceManager: PreferenceManager) { - super.onAttachedToHierarchy(preferenceManager) - - setTitle(R.string.display_item) - DisplayItem.values() - .filter { it.targetSdkVersion.contains(Build.VERSION.SDK_INT) } - .forEach { - val preference = CheckBoxPreference(context) - preference.setTitle(it.titleResourceId) - preference.setSummary(it.summaryResourceId) - preference.key = it.key - preference.setDefaultValue(it.defaultValue) - addPreference(preference) - } - } -} diff --git a/app/src/main/kotlin/com/nagopy/android/aplin/view/preference/SortPreference.kt b/app/src/main/kotlin/com/nagopy/android/aplin/view/preference/SortPreference.kt deleted file mode 100644 index 1559aa8..0000000 --- a/app/src/main/kotlin/com/nagopy/android/aplin/view/preference/SortPreference.kt +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.view.preference - -import android.content.Context -import android.os.Build -import android.preference.CheckBoxPreference -import android.preference.Preference -import android.preference.PreferenceCategory -import android.preference.PreferenceManager -import android.util.AttributeSet -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.model.Sort - -class SortPreference : PreferenceCategory, Preference.OnPreferenceChangeListener { - - @SuppressWarnings("unused") - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) - - @SuppressWarnings("unused") - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) - - @SuppressWarnings("unused") - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - @SuppressWarnings("unused") - constructor(context: Context) : super(context) - - override fun onAttachedToHierarchy(preferenceManager: PreferenceManager) { - super.onAttachedToHierarchy(preferenceManager) - - setTitle(R.string.sort) - key = Sort::class.java.name - Sort.values() - .filter { it.targetSdkVersion.contains(Build.VERSION.SDK_INT) } - .forEach { - val preference = CheckBoxPreference(context) - preference.widgetLayoutResource = R.layout.preference_widget_checkbox_single - preference.setTitle(it.titleResourceId) - preference.setSummary(it.summaryResourceId) - preference.key = it.key - preference.setDefaultValue(it.defaultValue) - addPreference(preference) - preference.onPreferenceChangeListener = this - } - } - - override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean { - if (newValue == false) { - return false - } - - Sort.values() - .filter { it.targetSdkVersion.contains(Build.VERSION.SDK_INT) } - .forEach { - val p = findPreference(it.key) as CheckBoxPreference - val isChecked = p === preference - p.isChecked = isChecked - if (isChecked) { - sharedPreferences.edit().putString(key, it.name).apply() - } - } - return false - } - -} diff --git a/app/src/main/res/color/text_color.xml b/app/src/main/res/color/text_color.xml deleted file mode 100755 index 8ec3d49..0000000 --- a/app/src/main/res/color/text_color.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_action_back.xml b/app/src/main/res/drawable/ic_action_back.xml deleted file mode 100644 index 50e3cb1..0000000 --- a/app/src/main/res/drawable/ic_action_back.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_action_more.xml b/app/src/main/res/drawable/ic_action_more.xml deleted file mode 100644 index 05491f3..0000000 --- a/app/src/main/res/drawable/ic_action_more.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_action_search.xml b/app/src/main/res/drawable/ic_action_search.xml deleted file mode 100644 index 45a0127..0000000 --- a/app/src/main/res/drawable/ic_action_search.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_action_settings.xml b/app/src/main/res/drawable/ic_action_settings.xml deleted file mode 100644 index 798f865..0000000 --- a/app/src/main/res/drawable/ic_action_settings.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_action_share.xml b/app/src/main/res/drawable/ic_action_share.xml deleted file mode 100644 index 131fcca..0000000 --- a/app/src/main/res/drawable/ic_action_share.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_transparent.xml b/app/src/main/res/drawable/icon_transparent.xml deleted file mode 100755 index 471238d..0000000 --- a/app/src/main/res/drawable/icon_transparent.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/tab_indicator.xml b/app/src/main/res/drawable/tab_indicator.xml deleted file mode 100755 index 6ab8f90..0000000 --- a/app/src/main/res/drawable/tab_indicator.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout-w640dp/fragment_app_list.xml b/app/src/main/res/layout-w640dp/fragment_app_list.xml deleted file mode 100755 index c998a9a..0000000 --- a/app/src/main/res/layout-w640dp/fragment_app_list.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_license.xml b/app/src/main/res/layout/activity_license.xml deleted file mode 100755 index 9d27272..0000000 --- a/app/src/main/res/layout/activity_license.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index 302ac18..0000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml deleted file mode 100755 index 6303272..0000000 --- a/app/src/main/res/layout/activity_settings.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_app_list.xml b/app/src/main/res/layout/fragment_app_list.xml deleted file mode 100755 index 320019c..0000000 --- a/app/src/main/res/layout/fragment_app_list.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - \ No newline at end of file diff --git a/app/src/main/res/layout/list_item.xml b/app/src/main/res/layout/list_item.xml deleted file mode 100755 index beb805b..0000000 --- a/app/src/main/res/layout/list_item.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/layout/preference_widget_checkbox_single.xml b/app/src/main/res/layout/preference_widget_checkbox_single.xml deleted file mode 100644 index d189694..0000000 --- a/app/src/main/res/layout/preference_widget_checkbox_single.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/app/src/main/res/layout/toolbar_spinner_item_actionbar.xml b/app/src/main/res/layout/toolbar_spinner_item_actionbar.xml deleted file mode 100644 index e7252b6..0000000 --- a/app/src/main/res/layout/toolbar_spinner_item_actionbar.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/toolbar_spinner_item_dropdown.xml b/app/src/main/res/layout/toolbar_spinner_item_dropdown.xml deleted file mode 100644 index 0f7e17c..0000000 --- a/app/src/main/res/layout/toolbar_spinner_item_dropdown.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml deleted file mode 100755 index a5137a1..0000000 --- a/app/src/main/res/menu/main.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 73fc804a0b567dc2315a974f45706d4d51d85411..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2058 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 UKo*rSIsgCw07*qoM6N<$g4!OA6951J diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 71ee2241ff5100ff49718732c53740a377b80d42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2801 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 D=O=9Q diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 6b53298aa7ba9364a3de673a4ded295c4048a13e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4628 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 diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml deleted file mode 100644 index d311ef7..0000000 --- a/app/src/main/res/values-ja/strings.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - Aplin - - 共有 - アプリ名 - アプリ名・パッケージ名 - パッケージ名 - 設定 - 検索 - アプリ名・パッケージ名で絞り込み - - カテゴリ - 全て - - システム - - 無効化不可 - - 無効化可能 - システムアプリのうち、無効化ボタンを押すことができるアプリを表示します。無効化は自己責任で行い、万が一端末が不安定になった場合は元に戻してください。 - 無効化済み - - ユーザー - - デフォルト起動 - 特定の操作で常に起動するアプリを表示します。ホームアプリなどが該当します。 - インターネット権限あり - - 拒否可能権限あり - カメラ・位置情報など、設定画面から権限を拒否できるアプリを表示します。不許可設定は自己責任で行い、アプリが正常に動作しない場合は元に戻してください。 - 他のアプリに重ねて表示 - 他のアプリの上に重ねて表示する機能を持つアプリを表示します。設定画面から許可・不許可を選択できます。 - - ソート順 - デフォルト - アプリ名昇順、パッケージ名昇順 - パッケージ名 - パッケージ名昇順 - 初回インストール日時 - 初回インストール日時降順、アプリ名昇順、パッケージ名昇順 - 最終更新日時 - 最終更新日時降順、アプリ名昇順、パッケージ名昇順 - - 表示項目 - 未インストール - マルチアカウントが利用できる状態で、別ユーザーがインストールした(このユーザーではインストールされていない)場合に表示されます。 - 未インストール - 初回インストール日時 - 初回インストール:%1$s - - 最終更新日時 - - 最終更新:%1$s - バージョン - - バージョン:%1$s - インターネット権限 - - インターネット権限あり - 拒否可能権限 - カメラ・位置情報など、設定画面から拒否可能な権限を表示します - / - パッケージ名 - - - このアプリについて - バージョン - ソースコード - オープンソースライセンス - diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml deleted file mode 100644 index 2394b9c..0000000 --- a/app/src/main/res/values-v21/styles.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml deleted file mode 100755 index 7b7321c..0000000 --- a/app/src/main/res/values-w820dp/dimens.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - 6dp - 12dp - 18dp - 24dp - 30dp - 36dp - 42dp - 48dp - 54dp - 60dp - 66dp - 72dp - 78dp - 84dp - 90dp - 96dp - 102dp - 108dp - 114dp - 120dp - diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml deleted file mode 100644 index 2ed2391..0000000 --- a/app/src/main/res/values/colors.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - @color/primary - @color/primary_dark - @color/primary_light - @color/colorPrimaryDark - @color/accent - - #FFAC00 - #E8B60C - #FFE10D - - #7FFF9800 - #7FF57C00 - #7FFFAC00 - #7FE8B60C - #7FFFE10D - - @color/background_material_light - @color/primary_text - @color/secondary_text_default_material_light - #60000000 - - @color/divider - diff --git a/app/src/main/res/values/colors_orange_green.xml b/app/src/main/res/values/colors_orange_green.xml deleted file mode 100644 index b4b1199..0000000 --- a/app/src/main/res/values/colors_orange_green.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - #FF9800 - #F57C00 - #FFE0B2 - #4CAF50 - #212121 - #727272 - #212121 - #B6B6B6 - diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml deleted file mode 100755 index 9a05580..0000000 --- a/app/src/main/res/values/dimens.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - @dimen/unit_4 - @dimen/unit_4 - - @dimen/unit_4 - @dimen/abc_text_size_subtitle_material_toolbar - @dimen/unit_2 - @dimen/unit_6 - @dimen/unit_4 - @dimen/unit_4 - - @dimen/unit_4 - - 1dp - - 3dp - 6dp - 9dp - 12dp - 15dp - 18dp - 21dp - 24dp - 27dp - 30dp - 33dp - 36dp - 39dp - 42dp - 45dp - 48dp - 51dp - 54dp - 57dp - 60dp - 90dp - 120dp - 150dp - 180dp - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml deleted file mode 100644 index 9c63ef4..0000000 --- a/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - ca-app-pub-2998260208076899/9431352962 - - Aplin - - Share - App name - Package name - App name & Package name - Preference - @string/open_source_license - Search - Search app or package names - - Categories - All - - System - - Undisablable - Applications that you cannot click disable button. - Disablable - Applications that you can click disable button. - "Disabled" - - "User" - - Default - Applications that are default for some action. Ex: launcher app - Internet permissions - Applications that requests internet permissions - Deniable permissions - Applications that requests deniable permissions (Storage, Camera and so on) - Draw over other apps - - - Sort - Default - Order by app name, package name - Package name - Order by package name - First install time desc - Order by first install time desc, app name, packagename - Update time desc - Order by update time desc, app name, packagename - - Display items - Not installed - Installed by other user. That means it is on your device but not installed for your current user. - Not installed - First install time - - First install : %1$s - Last update time - - Last update : %1$s - Version name - - Version: %1$s - Internet Permission - - [Internet] - Deniable Permissions - - / - Package name - - - UA-9578951-16 - - About - Version - Source code - https://github.com/75py/Aplin - Open source license - diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml deleted file mode 100644 index 5856c98..0000000 --- a/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - @android:color/white - - diff --git a/app/src/main/res/xml/pref.xml b/app/src/main/res/xml/pref.xml deleted file mode 100755 index 2d04822..0000000 --- a/app/src/main/res/xml/pref.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/test/kotlin/com/nagopy/android/aplin/model/CategoryTest.kt b/app/src/test/kotlin/com/nagopy/android/aplin/model/CategoryTest.kt deleted file mode 100644 index 649d46f..0000000 --- a/app/src/test/kotlin/com/nagopy/android/aplin/model/CategoryTest.kt +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model - -import android.os.Build -import com.nagopy.android.aplin.R -import com.nagopy.android.aplin.constants.Constants -import com.nagopy.android.aplin.entity.App -import com.nagopy.android.aplin.entity.PermissionGroup -import org.junit.Test -import java.lang.reflect.Field -import java.lang.reflect.Modifier -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -class CategoryTest { - - @Test - fun ALL() { - val list = listOf(App().apply { - packageName = "aaa" - }, App().apply { - packageName = "bbb" - }) - val filtered = Category.ALL.where(list) - assertEquals(2, filtered.count()) - assertEquals("aaa", filtered.toMutableList()[0].packageName) - assertEquals("bbb", filtered.toMutableList()[1].packageName) - } - - @Test - fun SYSTEM() { - val list = listOf(App().apply { - isSystem = true - packageName = "aaa" - }, App().apply { - isSystem = false - packageName = "bbb" - }, App().apply { - isSystem = true - packageName = "ccc" - }) - val filtered = Category.SYSTEM.where(list) - assertEquals(2, filtered.count()) - assertEquals("aaa", filtered.toMutableList()[0].packageName) - assertEquals("ccc", filtered.toMutableList()[1].packageName) - } - - @Test - fun SYSTEM_UNDISABLABLE() { - val list = listOf(App().apply { - isSystem = true - isProfileOrDeviceOwner = true - isSystemPackage = false - hasActiveAdmins = false - isHomeApp = false - packageName = "ProfileOrDeviceOwner" - }, App().apply { - isSystem = true - isProfileOrDeviceOwner = false - isSystemPackage = true - hasActiveAdmins = false - isHomeApp = false - packageName = "SystemPackage" - }, App().apply { - isSystem = true - isProfileOrDeviceOwner = false - isSystemPackage = false - hasActiveAdmins = true - isHomeApp = false - packageName = "ActiveAdmins" - }, App().apply { - isSystem = true - isProfileOrDeviceOwner = false - isSystemPackage = false - hasActiveAdmins = false - isHomeApp = true - packageName = "HomeApp" - }, App().apply { - isSystem = true - isProfileOrDeviceOwner = false - isSystemPackage = false - hasActiveAdmins = false - isHomeApp = false - packageName = "Disablable" - }, App().apply { - isSystem = false - isProfileOrDeviceOwner = false - isSystemPackage = false - hasActiveAdmins = false - isHomeApp = false - packageName = "user" - } - ) - val filtered = Category.SYSTEM_UNDISABLABLE.where(list) - assertEquals(4, filtered.count()) - assertEquals("ProfileOrDeviceOwner", filtered.toMutableList()[0].packageName) - assertEquals("SystemPackage", filtered.toMutableList()[1].packageName) - assertEquals("ActiveAdmins", filtered.toMutableList()[2].packageName) - assertEquals("HomeApp", filtered.toMutableList()[3].packageName) - } - - @Test - fun SYSTEM_DISABLABLE() { - val list = listOf(App().apply { - isSystem = true - isProfileOrDeviceOwner = true - isSystemPackage = false - hasActiveAdmins = false - isHomeApp = false - packageName = "ProfileOrDeviceOwner" - }, App().apply { - isSystem = true - isProfileOrDeviceOwner = false - isSystemPackage = true - hasActiveAdmins = false - isHomeApp = false - packageName = "SystemPackage" - }, App().apply { - isSystem = true - isProfileOrDeviceOwner = false - isSystemPackage = false - hasActiveAdmins = true - isHomeApp = false - packageName = "ActiveAdmins" - }, App().apply { - isSystem = true - isProfileOrDeviceOwner = false - isSystemPackage = false - hasActiveAdmins = false - isHomeApp = true - packageName = "HomeApp" - }, App().apply { - isSystem = true - isProfileOrDeviceOwner = false - isSystemPackage = false - hasActiveAdmins = false - isHomeApp = false - packageName = "Disablable" - }, App().apply { - isSystem = false - isProfileOrDeviceOwner = false - isSystemPackage = false - hasActiveAdmins = false - isHomeApp = false - packageName = "user" - } - ) - val filtered = Category.SYSTEM_DISABLABLE.where(list) - assertEquals(1, filtered.count()) - assertEquals("Disablable", filtered.toMutableList()[0].packageName) - } - - @Test - fun DISABLED() { - val list = listOf(App().apply { - isEnabled = true - packageName = "enable" - }, App().apply { - isEnabled = false - packageName = "disable" - }) - val filtered = Category.DISABLED.where(list) - assertEquals(1, filtered.count()) - assertEquals("disable", filtered.toMutableList()[0].packageName) - } - - @Test - fun DEFAULT() { - val list = listOf(App().apply { - isDefaultApp = true - packageName = "DefaultApp" - }, App().apply { - isDefaultApp = false - packageName = "no" - }) - val filtered = Category.DEFAULT.where(list) - assertEquals(1, filtered.count()) - assertEquals("DefaultApp", filtered.toMutableList()[0].packageName) - } - - @Test - fun USER() { - val list = listOf(App().apply { - isSystem = true - packageName = "System" - }, App().apply { - isSystem = false - packageName = "User" - }) - val filtered = Category.USER.where(list) - assertEquals(1, filtered.count()) - assertEquals("User", filtered.toMutableList()[0].packageName) - } - - @Test - fun INTERNET_PERMISSIONS() { - val list = listOf(App().apply { - requestedPermissions.clear() - packageName = "Empty" - }, App().apply { - requestedPermissions.add(android.Manifest.permission.INTERNET) - packageName = "Internet1" - }, App().apply { - requestedPermissions.add(android.Manifest.permission.INTERNET) - requestedPermissions.add(android.Manifest.permission.WAKE_LOCK) - packageName = "Internet2" - }, App().apply { - requestedPermissions.add(android.Manifest.permission.WAKE_LOCK) - packageName = "others" - }) - val filtered = Category.INTERNET_PERMISSIONS.where(list) - assertEquals(2, filtered.count()) - assertEquals("Internet1", filtered.toMutableList()[0].packageName) - assertEquals("Internet2", filtered.toMutableList()[1].packageName) - } - - @Test - fun DENIABLE_PERMISSIONS() { - val list = listOf(App().apply { - permissionGroups.clear() - packageName = "Empty" - }, App().apply { - permissionGroups.add(PermissionGroup("group1", "group1 label", emptyList())) - packageName = "Target" - }) - val filtered = Category.DENIABLE_PERMISSIONS.where(list) - assertEquals(1, filtered.count()) - assertEquals("Target", filtered.toMutableList()[0].packageName) - } - - @Test - fun SYSTEM_ALERT_WINDOW_PERMISSION() { - val list = listOf(App().apply { - // false - isSystemPackage = true - }, App().apply { - // false - isSystemPackage = true - requestedPermissions.add(android.Manifest.permission.SYSTEM_ALERT_WINDOW) - }, App().apply { - // false - isSystemPackage = false - }, App().apply { - // false - isSystemPackage = false - requestedPermissions.add(android.Manifest.permission.INTERNET) - }, App().apply { - // true - isSystemPackage = false - requestedPermissions.add(android.Manifest.permission.SYSTEM_ALERT_WINDOW) - }) - val filtered = Category.SYSTEM_ALERT_WINDOW_PERMISSION.where(list) - assertEquals(1, filtered.count()) - } - - @Test - fun getAll() { - setFinalStatic(Build.VERSION::class.java, "SDK_INT", Build.VERSION_CODES.KITKAT) - Category.getAll().let { - assertFalse(it.contains(Category.DENIABLE_PERMISSIONS)) - assertFalse(it.contains(Category.SYSTEM_ALERT_WINDOW_PERMISSION)) - } - setFinalStatic(Build.VERSION::class.java, "SDK_INT", Build.VERSION_CODES.LOLLIPOP) - Category.getAll().let { - assertFalse(it.contains(Category.DENIABLE_PERMISSIONS)) - assertFalse(it.contains(Category.SYSTEM_ALERT_WINDOW_PERMISSION)) - } - setFinalStatic(Build.VERSION::class.java, "SDK_INT", Build.VERSION_CODES.LOLLIPOP_MR1) - Category.getAll().let { - assertFalse(it.contains(Category.DENIABLE_PERMISSIONS)) - assertFalse(it.contains(Category.SYSTEM_ALERT_WINDOW_PERMISSION)) - } - setFinalStatic(Build.VERSION::class.java, "SDK_INT", Build.VERSION_CODES.M) - Category.getAll().let { - assertTrue(it.contains(Category.DENIABLE_PERMISSIONS)) - assertTrue(it.contains(Category.SYSTEM_ALERT_WINDOW_PERMISSION)) - } - } - - fun setFinalStatic(cls: Class<*>, name: String, newValue: Any) { - cls.getDeclaredField(name).let { - it.isAccessible = true - - val modifiersField = Field::class.java.getDeclaredField("modifiers") - modifiersField.isAccessible = true - modifiersField.setInt(it, it.modifiers and Modifier.FINAL.inv()) - - it.set(null, newValue) - } - } - - @Test - fun resIds() { - assertEquals(R.string.category_all, Category.ALL.titleResourceId) - assertEquals(R.string.category_all_summary, Category.ALL.summaryResourceId) - assertEquals(Constants.ALL_SDK_VERSION, Category.ALL.targetSdkVersion) - } - -} \ No newline at end of file diff --git a/app/src/test/kotlin/com/nagopy/android/aplin/model/DisplayItemTest.kt b/app/src/test/kotlin/com/nagopy/android/aplin/model/DisplayItemTest.kt deleted file mode 100644 index 19821ff..0000000 --- a/app/src/test/kotlin/com/nagopy/android/aplin/model/DisplayItemTest.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model - -import android.app.Application -import com.nagopy.android.aplin.entity.App -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner -import org.robolectric.RuntimeEnvironment -import org.robolectric.annotation.Config -import kotlin.test.assertEquals - - -@RunWith(RobolectricTestRunner::class) -@Config(manifest = Config.NONE) -class DisplayItemTest { - - lateinit var context: Application - - var app = App() - - @Before - fun setup() { - context = RuntimeEnvironment.application - } - - @Test - fun packageName() { - val sb = StringBuilder() - app.packageName = "com.nagopy.android.test" - DisplayItem.PACKAGE_NAME.append(context, sb, app) - - assertEquals(app.packageName, sb.toString()) - } - -} \ No newline at end of file diff --git a/app/src/test/kotlin/com/nagopy/android/aplin/model/converter/AppParametersTest.kt b/app/src/test/kotlin/com/nagopy/android/aplin/model/converter/AppParametersTest.kt deleted file mode 100644 index 7d4ac15..0000000 --- a/app/src/test/kotlin/com/nagopy/android/aplin/model/converter/AppParametersTest.kt +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.model.converter - -import android.content.ComponentName -import android.content.pm.ApplicationInfo -import android.content.pm.PackageInfo -import com.nagopy.android.aplin.entity.App -import org.junit.Before -import org.junit.Test -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Mockito -import org.mockito.MockitoAnnotations -import java.util.* -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -class AppParametersTest { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var appConverter: AppConverter - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var packageInfo: PackageInfo - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var applicationInfo: ApplicationInfo - - @Before - fun setup() { - MockitoAnnotations.initMocks(this) - packageInfo.applicationInfo = applicationInfo - } - - @Test - fun packageName() { - packageInfo.applicationInfo.packageName = "com.nagopy.android.test" - val app = App() - AppParameters.packageName.setValue(app, packageInfo, appConverter) - assertEquals("com.nagopy.android.test", app.packageName) - } - - @Test - fun label() { - Mockito.`when`(packageInfo.applicationInfo.loadLabel(Mockito.any())).thenReturn("Aplin!") - val app = App() - AppParameters.label.setValue(app, packageInfo, appConverter) - assertEquals("Aplin!", app.label) - } - - @Test - fun isEnabled() { - packageInfo.applicationInfo.enabled = true - val app = App() - AppParameters.isEnabled.setValue(app, packageInfo, appConverter) - assertTrue(app.isEnabled) - } - - @Test - fun isSystem_FLAG_SYSTEM() { - packageInfo.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM - val app = App() - AppParameters.isSystem.setValue(app, packageInfo, appConverter) - assertTrue(app.isSystem) - } - - @Test - fun isSystem_FLAG_UPDATED_SYSTEM_APP() { - packageInfo.applicationInfo.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP - val app = App() - AppParameters.isSystem.setValue(app, packageInfo, appConverter) - assertTrue(app.isSystem) - } - - @Test - fun isSystem_false() { - packageInfo.applicationInfo.flags = 0 - val app = App() - AppParameters.isSystem.setValue(app, packageInfo, appConverter) - assertFalse(app.isSystem) - } - - @Test - fun isThisASystemPackage() { - Mockito.`when`(appConverter.aplinDevicePolicyManager.isSystemPackage(packageInfo)).thenReturn(true) - val app = App() - AppParameters.isSystemPackage.setValue(app, packageInfo, appConverter) - assertTrue(app.isSystemPackage) - } - - @Test - fun firstInstallTime() { - packageInfo.firstInstallTime = 999 - val app = App() - AppParameters.firstInstallTime.setValue(app, packageInfo, appConverter) - assertEquals(999, app.firstInstallTime) - } - - @Test - fun lastUpdateTime() { - packageInfo.lastUpdateTime = 999 - val app = App() - AppParameters.lastUpdateTime.setValue(app, packageInfo, appConverter) - assertEquals(999, app.lastUpdateTime) - } - - @Test - fun hasActiveAdmins() { - packageInfo.applicationInfo.packageName = "com.nagopy.android.test" - Mockito.`when`(appConverter.aplinDevicePolicyManager.packageHasActiveAdmins("com.nagopy.android.test")).thenReturn(true) - val app = App() - AppParameters.hasActiveAdmins.setValue(app, packageInfo, appConverter) - assertTrue(app.hasActiveAdmins) - } - - @Test - fun isInstalled_true() { - packageInfo.applicationInfo.flags = ApplicationInfo.FLAG_INSTALLED - val app = App() - AppParameters.isInstalled.setValue(app, packageInfo, appConverter) - assertTrue(app.isInstalled) - } - - @Test - fun isInstalled_false() { - packageInfo.applicationInfo.flags = 0 - val app = App() - AppParameters.isInstalled.setValue(app, packageInfo, appConverter) - assertFalse(app.isInstalled) - } - - @Test - fun isDefaultApp_true() { - Mockito.`when`(appConverter.packageManager.getPreferredActivities(Mockito.any(), Mockito.any(), Mockito.any())) - .then { - @Suppress("UNCHECKED_CAST") - val outActivities: ArrayList = it.arguments[1] as ArrayList - outActivities.add(Mockito.mock(ComponentName::class.java)) - return@then 0 - } - - val app = App() - AppParameters.isDefaultApp.setValue(app, packageInfo, appConverter) - assertTrue(app.isDefaultApp) - } - - @Test - fun isDefaultApp_false() { - val app = App() - AppParameters.isDefaultApp.setValue(app, packageInfo, appConverter) - assertFalse(app.isDefaultApp) - } - - @Test - fun versionName() { - packageInfo.versionName = "version_x" - val app = App() - AppParameters.versionName.setValue(app, packageInfo, appConverter) - assertEquals("version_x", app.versionName) - } - - @Test - fun permissions() { - // TODO 気力があるときに書く - } -} \ No newline at end of file diff --git a/app/src/test/kotlin/com/nagopy/android/aplin/presenter/AdPresenterTest.kt b/app/src/test/kotlin/com/nagopy/android/aplin/presenter/AdPresenterTest.kt deleted file mode 100644 index bbf3b26..0000000 --- a/app/src/test/kotlin/com/nagopy/android/aplin/presenter/AdPresenterTest.kt +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2017 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.nagopy.android.aplin.presenter - -import com.google.android.gms.ads.AdView -import org.junit.Before -import org.junit.Test -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Mockito -import org.mockito.MockitoAnnotations -import kotlin.test.assertEquals -import kotlin.test.assertNotNull -import kotlin.test.assertNull - -class AdPresenterTest { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - lateinit var adView: AdView - - lateinit var adPresenter: AdPresenter - - @Before - fun setup() { - MockitoAnnotations.initMocks(this) - assertNotNull(adView) - - adPresenter = AdPresenter() - } - - @Test - fun initialize() { - Mockito.doNothing().`when`(adView).loadAd(Mockito.any()) - - adPresenter.showAds = true - adPresenter.initialize(adView) - assertNotNull(adPresenter.adView) - assertEquals(adView, adPresenter.adView) - Mockito.verify(adView, Mockito.times(1)).loadAd(Mockito.any()) - } - - - @Test - fun initialize_debug() { - Mockito.doNothing().`when`(adView).loadAd(Mockito.any()) - - adPresenter.showAds = false - adPresenter.initialize(adView) - assertNull(adPresenter.adView) - Mockito.verify(adView, Mockito.times(0)).loadAd(Mockito.any()) - } - - @Test - fun resume() { - Mockito.doNothing().`when`(adView).resume() - adPresenter.adView = adView - adPresenter.showAds = true - adPresenter.resume() - - Mockito.verify(adView, Mockito.times(1)).resume() - } - - - @Test - fun resume_debug() { - Mockito.doNothing().`when`(adView).resume() - adPresenter.adView = null - adPresenter.showAds = false - adPresenter.resume() - - Mockito.verify(adView, Mockito.times(0)).resume() - } - - @Test - fun pause() { - Mockito.doNothing().`when`(adView).pause() - adPresenter.adView = adView - adPresenter.showAds = true - adPresenter.pause() - - Mockito.verify(adView, Mockito.times(1)).pause() - } - - @Test - fun pause_debug() { - Mockito.doNothing().`when`(adView).pause() - adPresenter.adView = null - adPresenter.showAds = false - adPresenter.pause() - - Mockito.verify(adView, Mockito.times(0)).pause() - } - - @Test - fun destroy() { - Mockito.doNothing().`when`(adView).destroy() - adPresenter.adView = adView - adPresenter.showAds = true - adPresenter.destroy() - - Mockito.verify(adView, Mockito.times(1)).destroy() - assertNull(adPresenter.adView) - } - - @Test - fun destroy_debug() { - Mockito.doNothing().`when`(adView).destroy() - adPresenter.adView = null - adPresenter.showAds = false - adPresenter.destroy() - - Mockito.verify(adView, Mockito.times(0)).destroy() - } -} diff --git a/app/src/test/kotlin/com/nagopy/android/aplin/presenter/AppListPresenterTest.kt b/app/src/test/kotlin/com/nagopy/android/aplin/presenter/AppListPresenterTest.kt deleted file mode 100644 index 13eac47..0000000 --- a/app/src/test/kotlin/com/nagopy/android/aplin/presenter/AppListPresenterTest.kt +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nagopy.android.aplin.presenter - -import android.app.Application -import android.os.Build -import android.view.MenuItem -import com.nagopy.android.aplin.BuildConfig -import com.nagopy.android.aplin.entity.App -import com.nagopy.android.aplin.model.Applications -import com.nagopy.android.aplin.model.Category -import com.nagopy.android.aplin.model.IconHelper -import com.nagopy.android.aplin.model.UserSettings -import com.nagopy.android.aplin.view.AppListView -import com.nagopy.android.aplin.view.AppListViewParent -import io.reactivex.Single -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.InjectMocks -import org.mockito.Mock -import org.mockito.Mockito.* -import org.mockito.MockitoAnnotations -import org.robolectric.RobolectricTestRunner -import org.robolectric.annotation.Config -import kotlin.test.assertEquals -import kotlin.test.assertNull - -@RunWith(RobolectricTestRunner::class) -@Config(manifest = Config.NONE) -class AppListPresenterTest { - - @Mock - lateinit var application: Application - - @Mock - lateinit var userSettings: UserSettings - - @Mock - lateinit var applications: Applications - - @Mock - lateinit var iconHelper: IconHelper - - @Mock - lateinit var appListView: AppListView - - @Mock - lateinit var appListViewParent: AppListViewParent - - @InjectMocks - lateinit var appListPresenter: AppListPresenter - - @Mock - lateinit var item: MenuItem - - val mockList = ArrayList().apply { - add(App().apply { - packageName = BuildConfig.APPLICATION_ID - }) - } - - @Before - fun setup() { - MockitoAnnotations.initMocks(this) - `when`(applications.getApplicationList(Category.ALL)).thenReturn(Single.create { it.onSuccess(mockList) }) - appListPresenter.defList = mockList - appListPresenter.filteredList.addAll(mockList) - } - - @Test - fun initialize() { - callInitialize() - - assertEquals(appListView, appListPresenter.view) - assertEquals(appListViewParent, appListPresenter.parentView) - assertEquals(Category.ALL, appListPresenter.category) - verify(applications, times(1)).getApplicationList(Category.ALL) - } - - private fun callInitialize() { - appListPresenter.initialize(appListView, appListViewParent, Category.ALL) - } - - @Test - fun resume() { - appListPresenter.resume() - } - - @Test - fun pause() { - appListPresenter.pause() - } - - @Test - fun destroy() { - callInitialize() - appListPresenter.destroy() - - assertNull(appListPresenter.view) - assertNull(appListPresenter.parentView) - } - - @Test - fun onOptionsItemSelected() { - callInitialize() - - appListPresenter.onOptionsItemSelected(item) - verify(appListViewParent, times(1)) - .onOptionsItemSelected(item, mockList) - } - - @Test - fun onItemClicked() { - callInitialize() - - appListPresenter.onItemClicked(0) - verify(appListViewParent, times(1)) - .onListItemClicked(mockList[0], Category.ALL) - } - - - @Test - fun onItemLongClicked() { - callInitialize() - - appListPresenter.onItemLongClicked(0) - verify(appListViewParent, times(1)) - .onListItemLongClicked(mockList[0]) - } - -} diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 17dd614..0000000 --- a/build.gradle +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -buildscript { - repositories { - jcenter() - google() - maven { url "https://plugins.gradle.org/m2/" } - } - dependencies { - classpath 'com.android.tools.build:gradle:4.1.2' - classpath 'com.cookpad.android.licensetools:license-tools-plugin:1.0.0' - classpath 'com.google.gms:google-services:4.3.5' - classpath 'com.hiya:jacoco-android:0.2' - classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.1' - } -} - -allprojects { - repositories { - jcenter() - maven { - url "https://maven.google.com" - } - google() - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} - -ext { - publish_version_name = versionName() - publish_version_code = versionCode() -} - -task bumpMajor { - doLast { - ant.propertyfile(file: 'version.properties') { - entry(key: 'major', type: 'int', operation: '+', value: 1) - entry(key: 'minor', type: 'int', operation: '=', value: 0) - entry(key: 'patch', type: 'int', operation: '=', value: 0) - entry(key: 'id', type: 'int', operation: '+', value: 1) - } - generateReadme() - } -} - -task bumpMinor { - doLast { - ant.propertyfile(file: 'version.properties') { - entry(key: 'minor', type: 'int', operation: '+', value: 1) - entry(key: 'patch', type: 'int', operation: '=', value: 0) - entry(key: 'id', type: 'int', operation: '+', value: 1) - } - generateReadme() - } -} - -task bumpPatch { - doLast { - ant.propertyfile(file: 'version.properties') { - entry(key: 'patch', type: 'int', operation: '+', value: 1) - entry(key: 'id', type: 'int', operation: '+', value: 1) - } - generateReadme() - } -} - -task version { - doLast { - println "Version name : " + versionName() - println "Version code : " + versionCode() - } -} - -String versionName() { - Properties properties = new Properties() - properties.load(project.rootProject.file('version.properties').newDataInputStream()) - return properties['major'] + "." + properties['minor'] + "." + properties['patch'] -} - -Integer versionCode() { - Properties properties = new Properties() - properties.load(project.rootProject.file('version.properties').newDataInputStream()) - return Integer.valueOf(properties['id'].toString()) -} - -task generateReadme { - doLast { - generateReadme() - } -} - -void generateReadme() { - def template = file('README.md.template').text - def result = template.replaceAll("%%version%%", versionName()) - file("README.md").withWriter { it << result } -} diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 7c6924b..0000000 --- a/gradle.properties +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright 2015 75py -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true - -android.enableJetifier=true -android.useAndroidX=true -org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 8c0fb64a8698b08ecc4158d828ca593c4928e9dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49896 zcmagFb986H(k`5d^NVfUwr$(C?M#x1ZQHiZiEVpg+jrjgoQrerx!>1o_ul)D>ebz~ zs=Mmxr&>W81QY-S1PKWQ%N-;H^tS;2*XwVA`dej1RRn1z<;3VgfE4~kaG`A%QSPsR z#ovnZe+tS9%1MfeDyz`RirvdjPRK~p(#^q2(^5@O&NM19EHdvN-A&StN>0g6QA^VN z0Gx%Gq#PD$QMRFzmK+utjS^Y1F0e8&u&^=w5K<;4Rz|i3A=o|IKLY+g`iK6vfr9?+ z-`>gmU&i?FGSL5&F?TXFu`&Js6h;15QFkXp2M1H9|Eq~bpov-GU(uz%mH0n55wUl- zv#~ccAz`F5wlQ>e_KlJS3@{)B?^v*EQM=IxLa&76^y51a((wq|2-`qON>+4dLc{Oo z51}}o^Zen(oAjxDK7b++9_Yg`67p$bPo3~BCpGM7uAWmvIhWc5Gi+gQZ|Pwa-Gll@<1xmcPy z|NZmu6m)g5Ftu~BG&Xdxclw7Cij{xbBMBn-LMII#Slp`AElb&2^Hw+w>(3crLH!;I zN+Vk$D+wP1#^!MDCiad@vM>H#6+`Ct#~6VHL4lzmy;lSdk>`z6)=>Wh15Q2)dQtGqvn0vJU@+(B5{MUc*qs4!T+V=q=wy)<6$~ z!G>e_4dN@lGeF_$q9`Ju6Ncb*x?O7=l{anm7Eahuj_6lA{*#Gv*TaJclevPVbbVYu z(NY?5q+xxbO6%g1xF0r@Ix8fJ~u)VRUp`S%&rN$&e!Od`~s+64J z5*)*WSi*i{k%JjMSIN#X;jC{HG$-^iX+5f5BGOIHWAl*%15Z#!xntpk($-EGKCzKa zT7{siZ9;4TICsWQ$pu&wKZQTCvpI$Xvzwxoi+XkkpeE&&kFb!B?h2hi%^YlXt|-@5 zHJ~%AN!g_^tmn1?HSm^|gCE#!GRtK2(L{9pL#hp0xh zME}|DB>(5)`iE7CM)&_+S}-Bslc#@B5W4_+k4Cp$l>iVyg$KP>CN?SVGZ(&02>iZK zB<^HP$g$Lq*L$BWd?2(F?-MUbNWTJVQdW7$#8a|k_30#vHAD1Z{c#p;bETk0VnU5A zBgLe2HFJ3032$G<`m*OB!KM$*sdM20jm)It5OSru@tXpK5LT>#8)N!*skNu1$TpIw zufjjdp#lyH5bZ%|Iuo|iu9vG1HrIVWLH>278xo>aVBkPN3V$~!=KnlXQ4eDqS7%E% zQ!z^$Q$b^6Q)g#cLpwur(|<0gWHo6A6jc;n`t(V9T;LzTAU{IAu*uEQ%Ort1k+Kn+f_N`9|bxYC+~Z1 zCC1UCWv*Orx$_@ydv9mIe(liLfOr7mhbV@tKw{6)q^1DH1nmvZ0cj215R<~&I<4S| zgnr;9Cdjqpz#o8i0CQjtl`}{c*P)aSdH|abxGdrR)-3z+02-eX(k*B)Uqv6~^nh** z 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index aec9973..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 8b005a5..0000000 --- a/settings.gradle +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2015 75py - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -include ':app' diff --git a/version.properties b/version.properties deleted file mode 100644 index 37733d5..0000000 --- a/version.properties +++ /dev/null @@ -1,22 +0,0 @@ -#Wed, 17 Mar 2021 22:50:13 +0900 - -# -# Copyright 2015 75py -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -major=4 -minor=0 -patch=1 -id=34 From e8fb3861d3dc66e058fa9cf692faa9261af998ff Mon Sep 17 00:00:00 2001 From: 75py Date: Sat, 30 Apr 2022 16:48:44 +0900 Subject: [PATCH 2/9] renewal --- .gitignore | 16 +- app/.gitignore | 1 + app/build.gradle | 96 ++++++++ app/proguard-rules.pro | 21 ++ .../domain/usecase/LoadPackagesUseCaseTest.kt | 100 ++++++++ app/src/androidTest/res/values-ja/strings.xml | 4 + app/src/androidTest/res/values/strings.xml | 4 + app/src/main/AndroidManifest.xml | 43 ++++ app/src/main/ic_launcher-playstore.png | Bin 0 -> 32893 bytes .../nagopy/android/aplin/AplinApplication.kt | 25 ++ .../com/nagopy/android/aplin/AppModule.kt | 15 ++ .../nagopy/android/aplin/DispatcherModule.kt | 13 ++ .../data/repository/DevicePolicyRepository.kt | 17 ++ .../repository/DevicePolicyRepositoryImpl.kt | 36 +++ .../data/repository/PackageRepository.kt | 29 +++ .../data/repository/PackageRepositoryImpl.kt | 156 +++++++++++++ .../aplin/data/repository/RepositoryModule.kt | 10 + .../aplin/domain/model/PackageModel.kt | 13 ++ .../aplin/domain/model/PackagesModel.kt | 7 + .../usecase/CategorizePackageUseCase.kt | 188 +++++++++++++++ .../domain/usecase/LoadPackagesUseCase.kt | 63 +++++ .../aplin/domain/usecase/UseCaseModule.kt | 9 + .../com/nagopy/android/aplin/ui/UiModule.kt | 19 ++ .../nagopy/android/aplin/ui/ads/AdsStatus.kt | 9 + .../android/aplin/ui/ads/AdsViewModel.kt | 216 ++++++++++++++++++ .../android/aplin/ui/ads/compose/AdBanner.kt | 70 ++++++ .../android/aplin/ui/main/MainActivity.kt | 48 ++++ .../android/aplin/ui/main/MainUiState.kt | 14 ++ .../android/aplin/ui/main/MainViewModel.kt | 79 +++++++ .../aplin/ui/main/compose/AppListScreen.kt | 80 +++++++ .../ui/main/compose/HorizontalAppList.kt | 89 ++++++++ .../ui/main/compose/HorizontalAppSection.kt | 48 ++++ .../android/aplin/ui/main/compose/Loading.kt | 18 ++ .../aplin/ui/main/compose/MainScreen.kt | 131 +++++++++++ .../aplin/ui/main/compose/RootScreen.kt | 98 ++++++++ .../aplin/ui/main/compose/VerticalAppList.kt | 78 +++++++ .../nagopy/android/aplin/ui/theme/Color.kt | 8 + .../nagopy/android/aplin/ui/theme/Shape.kt | 11 + .../nagopy/android/aplin/ui/theme/Theme.kt | 44 ++++ .../com/nagopy/android/aplin/ui/theme/Type.kt | 28 +++ .../ic_baseline_arrow_forward.xml | 10 + .../ic_baseline_arrow_forward.xml | 10 + .../drawable/ic_baseline_arrow_forward.xml | 10 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2323 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 3269 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4350 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1515 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 2094 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2723 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 3262 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 4749 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6246 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 5114 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 8135 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10055 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 7196 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 12281 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 14730 bytes app/src/main/res/values-ja/strings.xml | 8 + .../res/values/ic_launcher_background.xml | 4 + app/src/main/res/values/strings.xml | 9 + app/src/main/res/values/themes.xml | 7 + .../nagopy/android/aplin/ExampleUnitTest.kt | 16 ++ build.gradle | 21 ++ gradle.properties | 23 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 +++++++++++++++ gradlew.bat | 89 ++++++++ settings.gradle | 16 ++ 72 files changed, 2373 insertions(+), 5 deletions(-) create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/com/nagopy/android/aplin/domain/usecase/LoadPackagesUseCaseTest.kt create mode 100644 app/src/androidTest/res/values-ja/strings.xml create mode 100644 app/src/androidTest/res/values/strings.xml create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/ic_launcher-playstore.png create mode 100644 app/src/main/java/com/nagopy/android/aplin/AplinApplication.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/AppModule.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/DispatcherModule.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepository.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepositoryImpl.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/data/repository/PackageRepository.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/data/repository/PackageRepositoryImpl.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/data/repository/RepositoryModule.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/domain/model/PackageModel.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/domain/model/PackagesModel.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/domain/usecase/CategorizePackageUseCase.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/domain/usecase/LoadPackagesUseCase.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/domain/usecase/UseCaseModule.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/UiModule.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/ads/AdsStatus.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/ads/AdsViewModel.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/ads/compose/AdBanner.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/main/MainActivity.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/main/MainUiState.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/main/MainViewModel.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/main/compose/AppListScreen.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/main/compose/HorizontalAppList.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/main/compose/HorizontalAppSection.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/main/compose/Loading.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/main/compose/MainScreen.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/main/compose/RootScreen.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/main/compose/VerticalAppList.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/theme/Color.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/theme/Shape.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/theme/Theme.kt create mode 100644 app/src/main/java/com/nagopy/android/aplin/ui/theme/Type.kt create mode 100644 app/src/main/res/drawable-night/ic_baseline_arrow_forward.xml create mode 100644 app/src/main/res/drawable-notnight/ic_baseline_arrow_forward.xml create mode 100644 app/src/main/res/drawable/ic_baseline_arrow_forward.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values-ja/strings.xml create mode 100644 app/src/main/res/values/ic_launcher_background.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 app/src/test/java/com/nagopy/android/aplin/ExampleUnitTest.kt create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore index bec795a..c8d0c45 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,17 @@ +*.iml .gradle /local.properties -/.idea/workspace.xml +/.idea/caches /.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml .DS_Store /build /captures -*.iml -.idea -app/signingConfigs -fabric.properties +.externalNativeBuild +.cxx +local.properties +ads.properties +.idea/ diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..92c673c --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,96 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' + id 'com.google.android.gms.oss-licenses-plugin' + id 'org.jlleitschuh.gradle.ktlint' +} + +def adsPropertiesFile = rootProject.file("ads.properties") +def adsProperties = new Properties() +adsProperties.load(new FileInputStream(adsPropertiesFile)) + +android { + compileSdk 32 + + defaultConfig { + applicationId "com.nagopy.android.aplin" + minSdk 26 + targetSdk 32 + versionCode 35 + versionName "5.0.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary true + } + + resValue "string", "ad_app_id", adsProperties["appId"] + } + + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + + buildConfigField("String", "AD_UNIT_ID", "\"${adsProperties["unitId"]}\"") + // signingConfig signingConfigs.debug + } + debug { + buildConfigField("String", "AD_UNIT_ID", "\"ca-app-pub-3940256099942544/6300978111\"") + // sample id + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures { + compose true + } + composeOptions { + kotlinCompilerExtensionVersion compose_version + } + packagingOptions { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } +} + +dependencies { + implementation 'androidx.core:core-ktx:1.7.0' + implementation "androidx.compose.ui:ui:$compose_version" + implementation "androidx.compose.material:material:$compose_version" + implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' + implementation 'androidx.activity:activity-compose:1.4.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + androidTestImplementation 'androidx.test:runner:1.4.0' + androidTestImplementation 'androidx.test:rules:1.4.0' + androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' + androidTestImplementation 'org.jetbrains.kotlin:kotlin-test' + androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" + debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" + + + implementation "io.insert-koin:koin-android:3.1.6" + implementation "org.jetbrains.kotlin:kotlin-reflect:1.6.10" + implementation "com.google.accompanist:accompanist-drawablepainter:0.23.1" + implementation 'com.squareup.logcat:logcat:0.1' + + implementation "androidx.navigation:navigation-compose:2.4.2" + + implementation 'com.google.android.gms:play-services-oss-licenses:17.0.0' + def appcompat_version = "1.4.1" + implementation "androidx.appcompat:appcompat:$appcompat_version" + + implementation 'com.google.android.gms:play-services-ads:20.6.0' + + implementation 'com.google.android.ump:user-messaging-platform:2.0.0' + implementation 'androidx.preference:preference:1.2.0' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/nagopy/android/aplin/domain/usecase/LoadPackagesUseCaseTest.kt b/app/src/androidTest/java/com/nagopy/android/aplin/domain/usecase/LoadPackagesUseCaseTest.kt new file mode 100644 index 0000000..f33ca21 --- /dev/null +++ b/app/src/androidTest/java/com/nagopy/android/aplin/domain/usecase/LoadPackagesUseCaseTest.kt @@ -0,0 +1,100 @@ +package com.nagopy.android.aplin.domain.usecase + +import android.app.admin.DevicePolicyManager +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.provider.Settings +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.By +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiSelector +import androidx.test.uiautomator.Until +import com.nagopy.android.aplin.data.repository.DevicePolicyRepositoryImpl +import com.nagopy.android.aplin.data.repository.PackageRepositoryImpl +import kotlinx.coroutines.runBlocking +import logcat.LogPriority +import logcat.logcat +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class LoadPackagesUseCaseTest { + + @Test + fun test() { + val context = ApplicationProvider.getApplicationContext() + val useCase = LoadPackagesUseCase( + PackageRepositoryImpl(context.packageManager), + CategorizePackageUseCase( + PackageRepositoryImpl(context.packageManager), + DevicePolicyRepositoryImpl(context.getSystemService(DevicePolicyManager::class.java)), + ), + ) + + val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + val timeout = 3000L + + uiDevice.pressHome() + + runBlocking { + val result = useCase.execute() + result.disableablePackages.forEach { model -> + // sleep対策 + uiDevice.pressBack() + uiDevice.wait( + Until.hasObject(By.pkg(uiDevice.launcherPackageName).depth(0)), + timeout + ) + + startDetailSettingsActivity(context, model.packageName) + uiDevice.wait( + Until.hasObject(By.pkg("com.android.settings").depth(0)), + timeout + ) + + val isLabelFound = + uiDevice.findObject(UiSelector().text(model.label)).waitForExists(timeout) + if (!isLabelFound) { + logcat(LogPriority.ERROR) { "label not found: ${model.packageName} ${model.label}" } + return@forEach + } + + val disableButtonLabel = + InstrumentationRegistry.getInstrumentation().context.getString( + if (model.isEnabled) { + com.nagopy.android.aplin.test.R.string.test_btn_enable + } else { + com.nagopy.android.aplin.test.R.string.test_btn_disable + } + ) + + val isDisableButtonFound = + uiDevice.findObject(UiSelector().textStartsWith(disableButtonLabel)) + .waitForExists(timeout) + if (!isDisableButtonFound) { + logcat(LogPriority.ERROR) { "disable button not found: ${model.packageName} ${model.label}" } + return@forEach + } + + val isDisableButtonEnabled = + uiDevice.findObject(UiSelector().textStartsWith(disableButtonLabel)).isEnabled + if (!isDisableButtonEnabled) { + logcat(LogPriority.ERROR) { "disable button is not enabled: ${model.packageName} ${model.label}" } + return@forEach + } + } + } + } + + private fun startDetailSettingsActivity(context: Context, pkg: String) { + val packageName = pkg.split(":")[0] + val intent = + Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:$packageName")) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) + context.startActivity(intent) + } +} diff --git a/app/src/androidTest/res/values-ja/strings.xml b/app/src/androidTest/res/values-ja/strings.xml new file mode 100644 index 0000000..554c226 --- /dev/null +++ b/app/src/androidTest/res/values-ja/strings.xml @@ -0,0 +1,4 @@ + + 無効にする + 有効にする + diff --git a/app/src/androidTest/res/values/strings.xml b/app/src/androidTest/res/values/strings.xml new file mode 100644 index 0000000..941e622 --- /dev/null +++ b/app/src/androidTest/res/values/strings.xml @@ -0,0 +1,4 @@ + + Enable + Disable + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7284f71 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000000000000000000000000000000000000..263d7a1906808dd05dd80b4f2d8cf62f36e72dbc GIT binary patch literal 32893 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 ng@q;ZQeH;)|M_HXU~q+WTkIV1&lJG_z { androidContext().getSystemService(DevicePolicyManager::class.java) } + single { androidContext().packageManager } + single { androidContext().getSystemService(ActivityManager::class.java) } + single { PreferenceManager.getDefaultSharedPreferences(androidContext()) } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/DispatcherModule.kt b/app/src/main/java/com/nagopy/android/aplin/DispatcherModule.kt new file mode 100644 index 0000000..ccda5d2 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/DispatcherModule.kt @@ -0,0 +1,13 @@ +package com.nagopy.android.aplin + +import kotlinx.coroutines.Dispatchers +import org.koin.core.qualifier.named +import org.koin.dsl.module + +val dispatcherModule = module { + single(named(CoroutineDispatcherType.IO)) { Dispatchers.IO } +} + +enum class CoroutineDispatcherType { + IO +} diff --git a/app/src/main/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepository.kt b/app/src/main/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepository.kt new file mode 100644 index 0000000..bc75a88 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepository.kt @@ -0,0 +1,17 @@ +package com.nagopy.android.aplin.data.repository + +import android.app.admin.DevicePolicyManager + +interface DevicePolicyRepository { + + /** + * [DevicePolicyManager]のpackageHasActiveAdminsメソッドを実行する + * @param packageName パッケージ名 + * * + * @return packageHasActiveAdminsの結果を返す。 + * * エラーがあった場合はfalseを返す。 + */ + fun packageHasActiveAdmins(packageName: String): Boolean + + fun isProfileOrDeviceOwner(packageName: String): Boolean +} diff --git a/app/src/main/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepositoryImpl.kt b/app/src/main/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepositoryImpl.kt new file mode 100644 index 0000000..6ec4855 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepositoryImpl.kt @@ -0,0 +1,36 @@ +package com.nagopy.android.aplin.data.repository + +import android.app.admin.DevicePolicyManager +import logcat.LogPriority +import logcat.logcat +import java.lang.reflect.Method + +class DevicePolicyRepositoryImpl( + private val devicePolicyManager: DevicePolicyManager, +) : DevicePolicyRepository { + + private val packageHasActiveAdmins: Method? by lazy { + try { + DevicePolicyManager::class.java.getDeclaredMethod( + "packageHasActiveAdmins", + String::class.java + ) + } catch (t: Throwable) { + logcat(LogPriority.VERBOSE) { "packageHasActiveAdmins: $t" } + null + } + } + + override fun packageHasActiveAdmins(packageName: String): Boolean { + try { + return packageHasActiveAdmins?.invoke(devicePolicyManager, packageName) as Boolean + } catch (t: Throwable) { + logcat(LogPriority.VERBOSE) { "packageHasActiveAdmins: $t" } + } + return false + } + + override fun isProfileOrDeviceOwner(packageName: String): Boolean = + devicePolicyManager.isDeviceOwnerApp(packageName) || + devicePolicyManager.isProfileOwnerApp(packageName) +} diff --git a/app/src/main/java/com/nagopy/android/aplin/data/repository/PackageRepository.kt b/app/src/main/java/com/nagopy/android/aplin/data/repository/PackageRepository.kt new file mode 100644 index 0000000..5f693d8 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/data/repository/PackageRepository.kt @@ -0,0 +1,29 @@ +package com.nagopy.android.aplin.data.repository + +import android.content.pm.ApplicationInfo +import android.content.pm.PackageInfo +import android.graphics.drawable.Drawable + +interface PackageRepository { + suspend fun loadAll(): List + + suspend fun loadHomePackageNames(): Set + + suspend fun loadCurrentDefaultHomePackageName(): String? + + fun loadLabel(applicationInfo: ApplicationInfo): String + + fun loadIcon(applicationInfo: ApplicationInfo): Drawable + + val systemPackage: PackageInfo? + + val permissionControllerPackageName: String? + + val servicesSystemSharedLibraryPackageName: String? + + val sharedSystemSharedLibraryPackageName: String? + + val printSpoolerPackageName: String? + + val deviceProvisioningPackage: String? +} diff --git a/app/src/main/java/com/nagopy/android/aplin/data/repository/PackageRepositoryImpl.kt b/app/src/main/java/com/nagopy/android/aplin/data/repository/PackageRepositoryImpl.kt new file mode 100644 index 0000000..f24430c --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/data/repository/PackageRepositoryImpl.kt @@ -0,0 +1,156 @@ +package com.nagopy.android.aplin.data.repository + +import android.content.Intent +import android.content.pm.ApplicationInfo +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.content.res.Resources +import android.graphics.drawable.Drawable +import android.os.Build +import android.print.PrintManager +import logcat.LogPriority +import logcat.logcat +import kotlin.reflect.full.declaredMemberFunctions +import kotlin.reflect.full.staticProperties + +class PackageRepositoryImpl( + private val packageManager: PackageManager, +) : PackageRepository { + + companion object { + private val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + PackageManager.GET_SIGNING_CERTIFICATES + } else { + @Suppress("DEPRECATION") + PackageManager.GET_SIGNATURES + } + } + + override suspend fun loadAll(): List { + // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java;drc=8cb6c27e8e2f171a0d9f9c4580092ebc4ce562fa + + val hiddenModules = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + packageManager.getInstalledModules(0) + .map { it.packageName } + .toHashSet() + } else { + emptySet() + } + logcat(LogPriority.VERBOSE) { "loadAll() hiddenmodules = $hiddenModules" } + + val retrieveFlags = PackageManager.MATCH_DISABLED_COMPONENTS or + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS + val apps = packageManager.getInstalledApplications(retrieveFlags) + .filterNot { hiddenModules.contains(it.packageName) } + .map { + logcat(LogPriority.VERBOSE) { "loadAll() ${it.packageName}" } + packageManager.getPackageInfo(it.packageName, flags) + } + return apps + } + + override suspend fun loadHomePackageNames(): Set { + val intent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) + val pkgs = packageManager.queryIntentActivities(intent, 0) + .map { it.activityInfo.packageName } + logcat(LogPriority.VERBOSE) { "loadHomePackageNames = $pkgs" } + return pkgs.toHashSet() + } + + override suspend fun loadCurrentDefaultHomePackageName(): String? { + val res = packageManager.resolveActivity( + Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME), + PackageManager.MATCH_DEFAULT_ONLY, + ) + logcat(LogPriority.VERBOSE) { "loadCurrentDefaultHome = ${res?.activityInfo?.applicationInfo?.packageName}" } + return res?.activityInfo?.applicationInfo?.packageName + } + + override fun loadLabel(applicationInfo: ApplicationInfo): String { + return applicationInfo.loadLabel(packageManager).toString() + } + + override fun loadIcon(applicationInfo: ApplicationInfo): Drawable { + return applicationInfo.loadIcon(packageManager) + } + + override val systemPackage: PackageInfo? by lazy { + try { + packageManager.getPackageInfo("android", flags) + } catch (t: Throwable) { + logcat(LogPriority.VERBOSE) { "mSystemPackageInfo: $t" } + null + } + } + + override val permissionControllerPackageName: String? by lazy { + if (Build.VERSION_CODES.N <= Build.VERSION.SDK_INT) { + try { + val v = PackageManager::class.declaredMemberFunctions.firstOrNull { + it.name == "getPermissionControllerPackageName" + }?.call(packageManager) as? String + logcat(LogPriority.VERBOSE) { "permissionControllerPackageName = $v" } + return@lazy v + } catch (t: Throwable) { + logcat(LogPriority.VERBOSE) { "permissionControllerPackageName: $t" } + } + } + return@lazy null + } + + override val servicesSystemSharedLibraryPackageName: String? by lazy { + if (Build.VERSION_CODES.N <= Build.VERSION.SDK_INT) { + try { + val v = PackageManager::class.declaredMemberFunctions.firstOrNull { + it.name == "getServicesSystemSharedLibraryPackageName" + }?.call(packageManager) as? String + logcat(LogPriority.VERBOSE) { "servicesSystemSharedLibraryPackageName = $v" } + return@lazy v + } catch (t: Throwable) { + logcat(LogPriority.VERBOSE) { "servicesSystemSharedLibraryPackageName: $t" } + } + } + return@lazy null + } + + override val sharedSystemSharedLibraryPackageName: String? by lazy { + if (Build.VERSION_CODES.N <= Build.VERSION.SDK_INT) { + try { + val v = PackageManager::class.declaredMemberFunctions.firstOrNull { + it.name == "getSharedSystemSharedLibraryPackageName" + }?.call(packageManager) as? String + logcat(LogPriority.VERBOSE) { "sharedSystemSharedLibraryPackageName = $v" } + return@lazy v + } catch (t: Throwable) { + logcat(LogPriority.VERBOSE) { "sharedSystemSharedLibraryPackageName: $t" } + } + } + return@lazy null + } + + override val printSpoolerPackageName: String? by lazy { + try { + val v = PrintManager::class.staticProperties.firstOrNull { + it.name == "PRINT_SPOOLER_PACKAGE_NAME" + }?.call() as? String + logcat(LogPriority.VERBOSE) { "PRINT_SPOOLER_PACKAGE_NAME = $v" } + return@lazy v ?: "com.android.printspooler" + } catch (t: Throwable) { + logcat(LogPriority.VERBOSE) { "PRINT_SPOOLER_PACKAGE_NAME: $t" } + return@lazy "com.android.printspooler" + } + } + + override val deviceProvisioningPackage: String? by lazy { + try { + val r = Resources.getSystem() + val id = r.getIdentifier("config_deviceProvisioningPackage", "string", "android") + val v = r.getString(id) + logcat(LogPriority.VERBOSE) { "deviceProvisioningPackage = $v" } + return@lazy v + } catch (t: Throwable) { + logcat(LogPriority.VERBOSE) { "deviceProvisioningPackage: $t" } + return@lazy null + } + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/data/repository/RepositoryModule.kt b/app/src/main/java/com/nagopy/android/aplin/data/repository/RepositoryModule.kt new file mode 100644 index 0000000..62f0de9 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/data/repository/RepositoryModule.kt @@ -0,0 +1,10 @@ +package com.nagopy.android.aplin.data.repository + +import org.koin.dsl.module + +val repositoryModule = module { + + single { PackageRepositoryImpl(get()) } + + single { DevicePolicyRepositoryImpl(get()) } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/domain/model/PackageModel.kt b/app/src/main/java/com/nagopy/android/aplin/domain/model/PackageModel.kt new file mode 100644 index 0000000..4d3c081 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/domain/model/PackageModel.kt @@ -0,0 +1,13 @@ +package com.nagopy.android.aplin.domain.model + +import android.graphics.drawable.Drawable + +data class PackageModel( + val packageName: String, + val label: String, + val icon: Drawable, + val isEnabled: Boolean, + val firstInstallTime: Long, + val lastUpdateTime: Long, + val versionName: String?, +) diff --git a/app/src/main/java/com/nagopy/android/aplin/domain/model/PackagesModel.kt b/app/src/main/java/com/nagopy/android/aplin/domain/model/PackagesModel.kt new file mode 100644 index 0000000..cec0431 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/domain/model/PackagesModel.kt @@ -0,0 +1,7 @@ +package com.nagopy.android.aplin.domain.model + +data class PackagesModel( + val disableablePackages: List, + val userPackages: List, + val allPackages: List, +) diff --git a/app/src/main/java/com/nagopy/android/aplin/domain/usecase/CategorizePackageUseCase.kt b/app/src/main/java/com/nagopy/android/aplin/domain/usecase/CategorizePackageUseCase.kt new file mode 100644 index 0000000..f12c69a --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/domain/usecase/CategorizePackageUseCase.kt @@ -0,0 +1,188 @@ +package com.nagopy.android.aplin.domain.usecase + +import android.content.pm.ApplicationInfo +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.os.Build +import com.nagopy.android.aplin.data.repository.DevicePolicyRepository +import com.nagopy.android.aplin.data.repository.PackageRepository +import java.lang.reflect.Field + +class CategorizePackageUseCase( + private val packageRepository: PackageRepository, + private val devicePolicyRepository: DevicePolicyRepository, +) { + + private val systemPackageSignatures: List by lazy { + getSignatureStrings(packageRepository.systemPackage) + } + + private fun isSystemPackage(packageInfo: PackageInfo?): Boolean { + return packageInfo != null && + ( + isThisASystemPackage(packageInfo) || + packageInfo.packageName == packageRepository.permissionControllerPackageName || + packageInfo.packageName == packageRepository.servicesSystemSharedLibraryPackageName || + packageInfo.packageName == packageRepository.sharedSystemSharedLibraryPackageName || + packageInfo.packageName == packageRepository.printSpoolerPackageName || + packageInfo.packageName == packageRepository.deviceProvisioningPackage + ) + } + + private fun getSignatureStrings(packageInfo: PackageInfo?): List { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + packageInfo?.signingInfo?.let { signingInfo -> + if (signingInfo.hasMultipleSigners()) { + signingInfo.apkContentsSigners.map { sig -> sig.toCharsString() } + } else { + signingInfo.signingCertificateHistory.map { sig -> sig.toCharsString() } + } + } + } else { + @Suppress("DEPRECATION") + packageInfo?.signatures?.map { sig -> sig.toCharsString() } + } ?: emptyList() + } + + private fun isThisASystemPackage(packageInfo: PackageInfo?): Boolean { + val signatures = getSignatureStrings(packageInfo) + return systemPackageSignatures == signatures + } + + fun isBundled(packageInfo: PackageInfo): Boolean { + return packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM > 0 + } + + fun isDisableable( + packageInfo: PackageInfo, + homePackages: Set, + currentDefaultHomePackageName: String? + ): Boolean { + val isBundled = isBundled(packageInfo) + var enabled = true + if (isBundled) { + enabled = handleDisableable(packageInfo, homePackages) + } else { + // not system app + return false + } + + if (isBundled && devicePolicyRepository.packageHasActiveAdmins(packageInfo.packageName)) { + enabled = false + } + + // 不完全な再現 + if (devicePolicyRepository.isProfileOrDeviceOwner(packageInfo.packageName)) { + enabled = false + } + + // not implemented: R.string.config_deviceProvisioningPackage + + if (enabled && homePackages.contains(packageInfo.packageName)) { + if (isBundled) { + enabled = false + } else { + if (homePackages.size == 1) { + enabled = false + } else { + if (currentDefaultHomePackageName == packageInfo.packageName) { + enabled = false + } + } + } + } + + // not implemented: hasBaseUserRestriction + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && packageInfo.applicationInfo.isResourceOverlay) { + if (isBundled) { + enabled = false + } else { + // not implemented + } + } + + return enabled + } + + private fun handleDisableable(packageInfo: PackageInfo, homePackages: Set): Boolean { + var disableable = false + if (homePackages.contains(packageInfo.packageName) || isSystemPackage(packageInfo) + ) { + // Disable button for core system applications. + } else if (packageInfo.applicationInfo.enabled && !isDisabledUntilUsed(packageInfo)) { + disableable = !keepEnabledPackages.contains(packageInfo.applicationInfo.packageName) + } else { + disableable = true + } + return disableable + } + + private val enabledSettingField: Field? by lazy { + try { + ApplicationInfo::class.java.getDeclaredField("enabledSetting").apply { + isAccessible = true + } + } catch (t: Throwable) { + null + } + } + + private fun isDisabledUntilUsed(packageInfo: PackageInfo): Boolean { + val enabledSetting = enabledSettingField?.get(packageInfo.applicationInfo) + return enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED + } + + // not implemented: DefaultDialerManager.getDefaultDialerApplication + // not implemented: SmsApplication.getDefaultSmsApplication + // not implemented: locationManager.getExtraLocationControllerPackage + private val keepEnabledPackages = setOf( + // R.string.config_settingsintelligence_package_name + "com.android.settings.intelligence", + // R.string.config_package_installer_package_name + "com.android.packageinstaller", + + // Pixel 3a, Android 12 + "com.google.android.ims", + "com.google.android.cellbroadcastservice", + "com.google.android.apps.wellbeing", + "com.google.android.inputmethod.latin", + "com.google.android.gms.location.history", + "com.google.android.hotspot2.osulogin", + "com.google.android.euicc", + "com.google.android.networkstack.tethering", + "com.android.cts.ctsshim", + "com.android.cts.priv.ctsshim", + "com.google.android.wifi.resources", + "com.google.android.connectivity.resources", + "com.google.android.packageinstaller", + "com.google.android.apps.messaging", + "com.google.android.providers.media.module", + "com.google.android.cellbroadcastreceiver", + "com.google.android.settings.intelligence", + "com.google.android.dialer", + + // Emulator, Android 11 + "com.android.dialer", + + // Emulator, Android 13 Preview + "com.android.uwb.resources", + "com.android.supplemental.process", + "com.google.android.auxiliary.service", + "com.google.android.nearby.halfsheet", + "com.google.android.ondevicepersonalization.services", + "com.google.android.wifi.dialog", + + // Emulator, Android Tiramisu Privacy Sandbox + "com.google.android.adservices.api", + "com.google.android.bluetooth.services", + "com.google.android.safetycenter.resources", + "com.google.android.sdksandbox", + + // SO-02K, Android 8.0 + "com.sonyericsson.providers.cnap", // 発信者名表示プロバイダー + "com.sonymobile.android.contacts", // 連絡先 + "com.nttdocomo.android.wipe", // 遠隔初期化 + "com.sonymobile.android.dialer", // 電話 + ) +} diff --git a/app/src/main/java/com/nagopy/android/aplin/domain/usecase/LoadPackagesUseCase.kt b/app/src/main/java/com/nagopy/android/aplin/domain/usecase/LoadPackagesUseCase.kt new file mode 100644 index 0000000..601d05b --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/domain/usecase/LoadPackagesUseCase.kt @@ -0,0 +1,63 @@ +package com.nagopy.android.aplin.domain.usecase + +import android.content.pm.PackageInfo +import com.nagopy.android.aplin.data.repository.PackageRepository +import com.nagopy.android.aplin.domain.model.PackageModel +import com.nagopy.android.aplin.domain.model.PackagesModel +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.withContext + +class LoadPackagesUseCase( + private val packageRepository: PackageRepository, + private val categorizePackageUseCase: CategorizePackageUseCase, +) { + + suspend fun execute(): PackagesModel = coroutineScope { + withContext(coroutineContext) { + val loadAllAsync = async { packageRepository.loadAll() } + val loadHomePackageNamesAsync = async { packageRepository.loadHomePackageNames() } + val loadCurrentDefaultHomePackageNameAsync = + async { packageRepository.loadCurrentDefaultHomePackageName() } + + val src = loadAllAsync.await() + val homePackages = loadHomePackageNamesAsync.await() + val currentDefaultHomePackageName = loadCurrentDefaultHomePackageNameAsync.await() + val disableable = src + .filter { + categorizePackageUseCase.isDisableable( + it, + homePackages, + currentDefaultHomePackageName + ) + } + .map { it.toPackageModel() } + .sortedWith(compareBy({ it.label }, { it.packageName })) + val users = src + .filter { !categorizePackageUseCase.isBundled(it) } + .map { it.toPackageModel() } + .sortedWith(compareBy({ it.label }, { it.packageName })) + val all = src + .map { it.toPackageModel() } + .sortedWith(compareBy({ it.label }, { it.packageName })) + + PackagesModel( + disableablePackages = disableable, + userPackages = users, + allPackages = all, + ) + } + } + + private fun PackageInfo.toPackageModel(): PackageModel { + return PackageModel( + packageName, + packageRepository.loadLabel(applicationInfo), + packageRepository.loadIcon(applicationInfo), + applicationInfo.enabled, + firstInstallTime, + lastUpdateTime, + packageName, + ) + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/domain/usecase/UseCaseModule.kt b/app/src/main/java/com/nagopy/android/aplin/domain/usecase/UseCaseModule.kt new file mode 100644 index 0000000..2658c2d --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/domain/usecase/UseCaseModule.kt @@ -0,0 +1,9 @@ +package com.nagopy.android.aplin.domain.usecase + +import org.koin.dsl.module + +val useCaseModule = module { + single { LoadPackagesUseCase(get(), get()) } + + single { CategorizePackageUseCase(get(), get()) } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/UiModule.kt b/app/src/main/java/com/nagopy/android/aplin/ui/UiModule.kt new file mode 100644 index 0000000..cf9d5eb --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/UiModule.kt @@ -0,0 +1,19 @@ +package com.nagopy.android.aplin.ui + +import com.nagopy.android.aplin.CoroutineDispatcherType +import com.nagopy.android.aplin.ui.ads.AdsViewModel +import com.nagopy.android.aplin.ui.main.MainViewModel +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.core.qualifier.named +import org.koin.dsl.module + +val uiModule = module { + viewModel { + MainViewModel( + get(), + get(), + get(named(CoroutineDispatcherType.IO)) + ) + } + viewModel { AdsViewModel(get()) } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/ads/AdsStatus.kt b/app/src/main/java/com/nagopy/android/aplin/ui/ads/AdsStatus.kt new file mode 100644 index 0000000..53c5a87 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/ads/AdsStatus.kt @@ -0,0 +1,9 @@ +package com.nagopy.android.aplin.ui.ads + +enum class AdsStatus { + NotInitialized, + NonPersonalized, + Personalized, + Denied, + Error, +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/ads/AdsViewModel.kt b/app/src/main/java/com/nagopy/android/aplin/ui/ads/AdsViewModel.kt new file mode 100644 index 0000000..b292815 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/ads/AdsViewModel.kt @@ -0,0 +1,216 @@ +package com.nagopy.android.aplin.ui.ads + +import android.app.Activity +import android.content.SharedPreferences +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.google.android.ump.ConsentDebugSettings +import com.google.android.ump.ConsentInformation +import com.google.android.ump.ConsentRequestParameters +import com.google.android.ump.UserMessagingPlatform +import com.nagopy.android.aplin.BuildConfig +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update +import logcat.LogPriority +import logcat.logcat + +class AdsViewModel( + private val prefs: SharedPreferences, +) : ViewModel() { + + private val _adsState = MutableStateFlow(AdsStatus.NotInitialized) + val adsState = + _adsState.stateIn(viewModelScope, SharingStarted.Eagerly, _adsState.value) + + private val _isGDPRState = MutableStateFlow(false) + val isGDPRState = + _isGDPRState.stateIn(viewModelScope, SharingStarted.Eagerly, _isGDPRState.value) + + private lateinit var consentInformation: ConsentInformation + + private fun updateState() { + _adsState.update { + if (isGDPR()) { + when { + canShowPersonalizedAds() -> { + AdsStatus.Personalized + } + canShowAds() -> { + AdsStatus.NonPersonalized + } + else -> { + AdsStatus.Denied + } + } + } else { + AdsStatus.Personalized + } + } + } + + private fun updateGDPRState() { + val isGDPR = isGDPR() + _isGDPRState.update { isGDPR } + } + + fun init(activity: Activity) { + // Set tag for underage of consent. false means users are not underage. + val params = ConsentRequestParameters.Builder() + .apply { + if (BuildConfig.DEBUG) { + setConsentDebugSettings( + ConsentDebugSettings.Builder(activity) + .setDebugGeography(ConsentDebugSettings.DebugGeography.DEBUG_GEOGRAPHY_EEA) + // .setDebugGeography(ConsentDebugSettings.DebugGeography.DEBUG_GEOGRAPHY_NOT_EEA) + .build() + ) + } + } + .build() + + consentInformation = UserMessagingPlatform.getConsentInformation(activity) + + printLogs("showConsentFormIfNeeded 1") + + consentInformation.requestConsentInfoUpdate( + activity, + params, + { // The consent information state was updated. + printLogs("requestConsentInfoUpdate") + updateGDPRState() + updateState() + + // You are now ready to check if a form is available. + if (consentInformation.isConsentFormAvailable) { + loadForm(activity) + } + }, + { + // Handle the error. + logcat { "$it" } + printLogs("requestConsentInfoUpdate error") + updateGDPRState() + _adsState.update { AdsStatus.Error } + } + ) + } + + fun loadForm(activity: Activity, force: Boolean = false) { + UserMessagingPlatform.loadConsentForm( + activity, + { consentForm -> + printLogs("loadConsentForm") + updateState() + if (force || consentInformation.consentStatus == ConsentInformation.ConsentStatus.REQUIRED) { + consentForm.show(activity) { + // Handle dismissal by reloading form. + logcat { "consentForm.show FormError=$it" } + loadForm(activity) + } + } + } + ) { + // / Handle Error. + logcat { "$it" } + printLogs("loadConsentForm error") + _adsState.update { AdsStatus.Error } + } + } + + private fun isGDPR(): Boolean { + val gdpr = prefs.getInt("IABTCF_gdprApplies", 0) + return gdpr == 1 + } + + private fun canShowAds(): Boolean { + // https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#in-app-details + // https://support.google.com/admob/answer/9760862?hl=en&ref_topic=9756841 + + val purposeConsent = prefs.getString("IABTCF_PurposeConsents", "") ?: "" + val vendorConsent = prefs.getString("IABTCF_VendorConsents", "") ?: "" + val vendorLI = prefs.getString("IABTCF_VendorLegitimateInterests", "") ?: "" + val purposeLI = prefs.getString("IABTCF_PurposeLegitimateInterests", "") ?: "" + + val googleId = 755 + val hasGoogleVendorConsent = hasAttribute(vendorConsent, index = googleId) + val hasGoogleVendorLI = hasAttribute(vendorLI, index = googleId) + + // Minimum required for at least non-personalized ads + return hasConsentFor(listOf(1), purposeConsent, hasGoogleVendorConsent) && + hasConsentOrLegitimateInterestFor( + listOf(2, 7, 9, 10), + purposeConsent, + purposeLI, + hasGoogleVendorConsent, + hasGoogleVendorLI + ) + } + + private fun canShowPersonalizedAds(): Boolean { + // https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#in-app-details + // https://support.google.com/admob/answer/9760862?hl=en&ref_topic=9756841 + + val purposeConsent = prefs.getString("IABTCF_PurposeConsents", "") ?: "" + val vendorConsent = prefs.getString("IABTCF_VendorConsents", "") ?: "" + val vendorLI = prefs.getString("IABTCF_VendorLegitimateInterests", "") ?: "" + val purposeLI = prefs.getString("IABTCF_PurposeLegitimateInterests", "") ?: "" + + val googleId = 755 + val hasGoogleVendorConsent = hasAttribute(vendorConsent, index = googleId) + val hasGoogleVendorLI = hasAttribute(vendorLI, index = googleId) + + return hasConsentFor(listOf(1, 3, 4), purposeConsent, hasGoogleVendorConsent) && + hasConsentOrLegitimateInterestFor( + listOf(2, 7, 9, 10), + purposeConsent, + purposeLI, + hasGoogleVendorConsent, + hasGoogleVendorLI + ) + } + + // Check if a binary string has a "1" at position "index" (1-based) + private fun hasAttribute(input: String, index: Int): Boolean { + return input.length >= index && input[index - 1] == '1' + } + + // Check if consent is given for a list of purposes + private fun hasConsentFor( + purposes: List, + purposeConsent: String, + hasVendorConsent: Boolean + ): Boolean { + return purposes.all { p -> hasAttribute(purposeConsent, p) } && hasVendorConsent + } + + // Check if a vendor either has consent or legitimate interest for a list of purposes + private fun hasConsentOrLegitimateInterestFor( + purposes: List, + purposeConsent: String, + purposeLI: String, + hasVendorConsent: Boolean, + hasVendorLI: Boolean + ): Boolean { + return purposes.all { p -> + (hasAttribute(purposeLI, p) && hasVendorLI) || + (hasAttribute(purposeConsent, p) && hasVendorConsent) + } + } + + private fun printLogs(msg: String) { + logcat(LogPriority.VERBOSE) { + """ +---------------------- +msg: $msg +isGDPR: ${isGDPR()} +canShowAds: ${canShowAds()} +canShowPersonalizedAds: ${canShowPersonalizedAds()} +consentStatus: ${consentInformation.consentStatus} +isConsentFormAvailable: ${consentInformation.isConsentFormAvailable} +---------------------- + """ + } + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/ads/compose/AdBanner.kt b/app/src/main/java/com/nagopy/android/aplin/ui/ads/compose/AdBanner.kt new file mode 100644 index 0000000..529fe2f --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/ads/compose/AdBanner.kt @@ -0,0 +1,70 @@ +package com.nagopy.android.aplin.ui.ads.compose + +import android.content.res.Resources +import android.os.Bundle +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView +import com.google.ads.mediation.admob.AdMobAdapter +import com.google.android.gms.ads.AdRequest +import com.google.android.gms.ads.AdSize +import com.google.android.gms.ads.AdView +import com.google.android.gms.ads.MobileAds +import com.nagopy.android.aplin.BuildConfig +import com.nagopy.android.aplin.ui.ads.AdsStatus + +@Composable +fun AdBanner(state: AdsStatus) { + if (state != AdsStatus.Personalized && state != AdsStatus.NonPersonalized) { + return + } + + if (LocalInspectionMode.current) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(36.dp) + .background(Color.Red) + ) + } else { + AndroidView( + modifier = Modifier.fillMaxWidth(), + factory = { context -> + val adView = AdView(context) + val displayMetrics = Resources.getSystem().displayMetrics + val width = (displayMetrics.widthPixels / displayMetrics.density).toInt() + adView.adSize = + AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(context, width) + adView.adUnitId = BuildConfig.AD_UNIT_ID + adView + }, + update = { + when (state) { + AdsStatus.Personalized -> { + MobileAds.initialize(it.context) + it.loadAd(AdRequest.Builder().build()) + } + AdsStatus.NonPersonalized -> { + MobileAds.initialize(it.context) + val extras = Bundle() + extras.putString("npa", "1") + val request = AdRequest.Builder() + .addNetworkExtrasBundle(AdMobAdapter::class.java, extras) + .build() + it.loadAd(request) + } + else -> { + // noop + } + } + } + ) + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/MainActivity.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/MainActivity.kt new file mode 100644 index 0000000..546c7a8 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/MainActivity.kt @@ -0,0 +1,48 @@ +package com.nagopy.android.aplin.ui.main + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.runtime.collectAsState +import com.nagopy.android.aplin.ui.ads.AdsViewModel +import com.nagopy.android.aplin.ui.main.compose.RootScreen +import org.koin.androidx.viewmodel.ext.android.viewModel + +class MainActivity : ComponentActivity() { + + private val mainViewModel: MainViewModel by viewModel() + + private val adsViewModel: AdsViewModel by viewModel() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + val state = mainViewModel.viewModelState.collectAsState().value + RootScreen( + state = state, + mainViewModel = mainViewModel, + startDetailSettingsActivity = { pkg: String -> + mainViewModel.startDetailSettingsActivity( + this@MainActivity, + pkg + ) + }, + startOssLicensesActivity = { + mainViewModel.startOssLicensesActivity(this) + }, + adsStatus = adsViewModel.adsState.collectAsState().value, + isGDPR = adsViewModel.isGDPRState.collectAsState().value, + showConsentForm = { + adsViewModel.loadForm(this, force = true) + } + ) + } + + adsViewModel.init(this) + } + + override fun onRestart() { + super.onRestart() + mainViewModel.updatePackages() + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/MainUiState.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/MainUiState.kt new file mode 100644 index 0000000..a650d89 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/MainUiState.kt @@ -0,0 +1,14 @@ +package com.nagopy.android.aplin.ui.main + +import com.nagopy.android.aplin.domain.model.PackagesModel + +data class MainUiState( + val isLoading: Boolean, + val packagesModel: PackagesModel? = null, +) + +enum class AppCategory { + USERS, + DISABLEABLE, + ALL, +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/MainViewModel.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/MainViewModel.kt new file mode 100644 index 0000000..a7500c6 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/MainViewModel.kt @@ -0,0 +1,79 @@ +package com.nagopy.android.aplin.ui.main + +import android.app.Activity +import android.app.ActivityManager +import android.content.Intent +import android.net.Uri +import android.provider.Settings +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.google.android.gms.oss.licenses.OssLicensesMenuActivity +import com.nagopy.android.aplin.domain.model.PackagesModel +import com.nagopy.android.aplin.domain.usecase.LoadPackagesUseCase +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import logcat.logcat + +class MainViewModel( + activityManager: ActivityManager, + private val loadPackagesUseCase: LoadPackagesUseCase, + private val ioDispatcher: CoroutineDispatcher +) : ViewModel() { + + private val _viewModelState = MutableStateFlow(MainUiState(isLoading = false)) + val viewModelState = + _viewModelState.stateIn(viewModelScope, SharingStarted.Eagerly, _viewModelState.value) + + val launcherLargeIconSize = activityManager.launcherLargeIconSize + + init { + updatePackages() + } + + fun updatePackages() { + if (_viewModelState.value.isLoading) { + return + } + _viewModelState.update { + it.copy(isLoading = true) + } + + viewModelScope.launch(ioDispatcher) { + val result = loadPackagesUseCase.execute() + _viewModelState.update { + it.copy( + isLoading = false, + packagesModel = PackagesModel( + result.disableablePackages, + result.userPackages, + result.allPackages + ) + ) + } + } + } + + fun startDetailSettingsActivity(activity: Activity, pkg: String) { + val packageName = pkg.split(":")[0] + val intent = + Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:$packageName")) + if (activity.isInMultiWindowMode) { + intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) + } + try { + activity.startActivity(intent) + } catch (e: Exception) { + logcat { "$e" } + } + } + + fun startOssLicensesActivity(activity: Activity) { + activity.startActivity(Intent(activity, OssLicensesMenuActivity::class.java)) + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/AppListScreen.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/AppListScreen.kt new file mode 100644 index 0000000..8447353 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/AppListScreen.kt @@ -0,0 +1,80 @@ +package com.nagopy.android.aplin.ui.main.compose + +import androidx.appcompat.content.res.AppCompatResources +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.nagopy.android.aplin.R +import com.nagopy.android.aplin.domain.model.PackageModel +import com.nagopy.android.aplin.domain.model.PackagesModel +import com.nagopy.android.aplin.ui.main.AppCategory +import com.nagopy.android.aplin.ui.main.MainUiState +import com.nagopy.android.aplin.ui.theme.AplinTheme + +@Composable +fun AppListScreen( + state: MainUiState, + appCategory: AppCategory, + launcherLargeIconSize: Int, + startDetailSettingsActivity: (String) -> Unit, +) { + if (state.packagesModel == null) { + Loading() + } else { + AppListScreenLoaded( + appCategory = appCategory, + packagesModel = state.packagesModel, + launcherLargeIconSize = launcherLargeIconSize, + startDetailSettingsActivity = startDetailSettingsActivity, + ) + } +} + +@Preview +@Composable +fun AppListScreenLoadedPreview() { + val packages = IntRange(0, 20).map { + PackageModel( + packageName = "com.example$it", + label = "Example Label $it", + icon = AppCompatResources.getDrawable( + LocalContext.current, + R.mipmap.ic_launcher + )!!, + isEnabled = it % 2 == 0, + firstInstallTime = 0L, + lastUpdateTime = 0L, + versionName = "1.0.0", + ) + } + AplinTheme { + AppListScreenLoaded( + appCategory = AppCategory.ALL, + packagesModel = PackagesModel(packages, packages, packages), + launcherLargeIconSize = 36, + startDetailSettingsActivity = {}, + ) + } +} + +@Composable +fun AppListScreenLoaded( + appCategory: AppCategory, + packagesModel: PackagesModel, + launcherLargeIconSize: Int, + startDetailSettingsActivity: (String) -> Unit, +) { + VerticalAppList( + modifier = Modifier.padding(8.dp), + packages = when (appCategory) { + AppCategory.USERS -> packagesModel.userPackages + AppCategory.DISABLEABLE -> packagesModel.disableablePackages + AppCategory.ALL -> packagesModel.allPackages + }, + launcherLargeIconSize = launcherLargeIconSize, + startDetailSettingsActivity = startDetailSettingsActivity, + ) +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/HorizontalAppList.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/HorizontalAppList.kt new file mode 100644 index 0000000..6ee3af4 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/HorizontalAppList.kt @@ -0,0 +1,89 @@ +package com.nagopy.android.aplin.ui.main.compose + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.material.Card +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.google.accompanist.drawablepainter.rememberDrawablePainter +import com.nagopy.android.aplin.domain.model.PackageModel + +@Composable +fun HorizontalAppList( + disableablePackages: List, + onClick: (String) -> Unit +) { + BoxWithConstraints { + val itemWidth = maxWidth / 2.6f + val iconSize = itemWidth / 2.0f + LazyRow { + items(disableablePackages) { pkg -> + Item(itemWidth, iconSize, onClick, pkg) + } + } + } +} + +@Composable +private fun Item( + itemWidth: Dp, + iconSize: Dp, + onClick: (String) -> Unit, + pkg: PackageModel, +) { + Card( + modifier = Modifier + .width(itemWidth) + .wrapContentHeight() + .padding(8.dp) + .alpha(if (pkg.isEnabled) 1.0f else 0.5f) + .clickable { + onClick.invoke(pkg.packageName) + }, + ) { + Column( + modifier = Modifier.padding(8.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Image( + painter = rememberDrawablePainter(drawable = pkg.icon), + contentDescription = "", + modifier = Modifier.size(iconSize) + ) + Column(modifier = Modifier.padding(horizontal = 8.dp)) { + Text( + text = pkg.label, + modifier = Modifier.fillMaxWidth(), + fontSize = 16.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + textAlign = TextAlign.Center + ) + Text( + text = pkg.packageName, + fontSize = 12.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + textAlign = TextAlign.End, + ) + } + } + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/HorizontalAppSection.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/HorizontalAppSection.kt new file mode 100644 index 0000000..27c9ec2 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/HorizontalAppSection.kt @@ -0,0 +1,48 @@ +package com.nagopy.android.aplin.ui.main.compose + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.nagopy.android.aplin.R +import com.nagopy.android.aplin.domain.model.PackageModel + +@Composable +fun HorizontalAppSection( + title: String, + packages: List, + navigateToVerticalList: () -> Unit, + startDetailSettingsActivity: (String) -> Unit +) { + Column { + Row( + modifier = Modifier + .clickable { + navigateToVerticalList.invoke() + } + .padding(8.dp) + ) { + Text( + text = title + " (${packages.size})", + fontWeight = FontWeight.Bold, + modifier = Modifier + .weight(1f) + ) + Image( + painter = painterResource(id = R.drawable.ic_baseline_arrow_forward), + contentDescription = "", + ) + } + Spacer(modifier = Modifier.height(8.dp)) + HorizontalAppList(packages, startDetailSettingsActivity) + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/Loading.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/Loading.kt new file mode 100644 index 0000000..9fe50b2 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/Loading.kt @@ -0,0 +1,18 @@ +package com.nagopy.android.aplin.ui.main.compose + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier + +@Composable +fun Loading() { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + CircularProgressIndicator() + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/MainScreen.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/MainScreen.kt new file mode 100644 index 0000000..56c7d2b --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/MainScreen.kt @@ -0,0 +1,131 @@ +package com.nagopy.android.aplin.ui.main.compose + +import androidx.appcompat.content.res.AppCompatResources +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.nagopy.android.aplin.R +import com.nagopy.android.aplin.domain.model.PackageModel +import com.nagopy.android.aplin.domain.model.PackagesModel +import com.nagopy.android.aplin.ui.main.MainUiState +import com.nagopy.android.aplin.ui.theme.AplinTheme + +@Composable +fun MainScreen( + navController: NavController, + state: MainUiState, + startDetailSettingsActivity: (String) -> Unit, + startOssLicensesActivity: () -> Unit, + isGDPR: Boolean, + showConsentForm: () -> Unit, +) { + if (state.packagesModel == null) { + Loading() + } else { + MainScreenLoaded( + navController, + state.packagesModel, + startDetailSettingsActivity, + startOssLicensesActivity, + isGDPR, + showConsentForm, + ) + } +} + +@Composable +fun MainScreenLoaded( + navController: NavController, + packagesModel: PackagesModel, + startDetailSettingsActivity: (String) -> Unit, + startOssLicensesActivity: () -> Unit, + isGDPR: Boolean, + showConsentForm: () -> Unit, +) { + Column( + modifier = Modifier + .padding(8.dp) + .verticalScroll(rememberScrollState()) + ) { + HorizontalAppSection( + title = stringResource(id = R.string.category_users), + packages = packagesModel.userPackages, + navigateToVerticalList = { + navController.navigate("userAppList") + }, + startDetailSettingsActivity = startDetailSettingsActivity, + ) + Spacer(modifier = Modifier.height(12.dp)) + HorizontalAppSection( + title = stringResource(id = R.string.category_disableable), + packages = packagesModel.disableablePackages, + navigateToVerticalList = { + navController.navigate("disableableAppList") + }, + startDetailSettingsActivity = startDetailSettingsActivity, + ) + Spacer(modifier = Modifier.height(12.dp)) + HorizontalAppSection( + title = stringResource(id = R.string.category_all), + packages = packagesModel.allPackages, + navigateToVerticalList = { + navController.navigate("allAppList") + }, + startDetailSettingsActivity = startDetailSettingsActivity, + ) + + Spacer(modifier = Modifier.height(12.dp)) + Button(onClick = startOssLicensesActivity) { + Text(stringResource(id = R.string.licenses)) + } + + if (isGDPR) { + Spacer(modifier = Modifier.height(12.dp)) + Button(onClick = showConsentForm) { + Text(stringResource(id = R.string.change_consent_state)) + } + } + } +} + +@Preview +@Composable +fun MainScreenLoadedPreview() { + val packages = IntRange(0, 20).map { + PackageModel( + packageName = "com.example$it", + label = "Example Label $it", + icon = AppCompatResources.getDrawable( + LocalContext.current, + R.mipmap.ic_launcher + )!!, + isEnabled = it % 2 == 0, + firstInstallTime = 0L, + lastUpdateTime = 0L, + versionName = "1.0.0", + ) + } + AplinTheme { + MainScreenLoaded( + navController = rememberNavController(), + packagesModel = PackagesModel(packages, packages, packages), + startOssLicensesActivity = {}, + startDetailSettingsActivity = {}, + isGDPR = true, + showConsentForm = {}, + ) + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/RootScreen.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/RootScreen.kt new file mode 100644 index 0000000..0f7cb83 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/RootScreen.kt @@ -0,0 +1,98 @@ +package com.nagopy.android.aplin.ui.main.compose + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.nagopy.android.aplin.R +import com.nagopy.android.aplin.ui.ads.AdsStatus +import com.nagopy.android.aplin.ui.ads.compose.AdBanner +import com.nagopy.android.aplin.ui.main.AppCategory +import com.nagopy.android.aplin.ui.main.MainUiState +import com.nagopy.android.aplin.ui.main.MainViewModel +import com.nagopy.android.aplin.ui.theme.AplinTheme + +@Composable +fun RootScreen( + state: MainUiState, + mainViewModel: MainViewModel, + startDetailSettingsActivity: (String) -> Unit, + startOssLicensesActivity: () -> Unit, + adsStatus: AdsStatus, + isGDPR: Boolean, + showConsentForm: () -> Unit, +) { + val navController = rememberNavController() + AplinTheme { + // A surface container using the 'background' color from the theme + Scaffold( + modifier = Modifier.fillMaxSize(), + topBar = { + TopAppBar( + title = { + Text(text = stringResource(id = R.string.app_name)) + }, + actions = { + if (state.isLoading && state.packagesModel != null) { + CircularProgressIndicator(color = Color.LightGray) + } + } + ) + } + ) { + Column(Modifier.fillMaxSize()) { + NavHost( + navController = navController, + startDestination = "main", + modifier = Modifier.weight(1f) + ) { + composable("main") { + MainScreen( + navController = navController, + state = state, + startDetailSettingsActivity = startDetailSettingsActivity, + startOssLicensesActivity = startOssLicensesActivity, + isGDPR = isGDPR, + showConsentForm = showConsentForm, + ) + } + composable("userAppList") { + AppListScreen( + state = state, + appCategory = AppCategory.USERS, + launcherLargeIconSize = mainViewModel.launcherLargeIconSize, + startDetailSettingsActivity = startDetailSettingsActivity, + ) + } + composable("disableableAppList") { + AppListScreen( + state = state, + appCategory = AppCategory.DISABLEABLE, + launcherLargeIconSize = mainViewModel.launcherLargeIconSize, + startDetailSettingsActivity = startDetailSettingsActivity, + ) + } + composable("allAppList") { + AppListScreen( + state = state, + appCategory = AppCategory.ALL, + launcherLargeIconSize = mainViewModel.launcherLargeIconSize, + startDetailSettingsActivity = startDetailSettingsActivity, + ) + } + } + + AdBanner(adsStatus) + } + } + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/VerticalAppList.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/VerticalAppList.kt new file mode 100644 index 0000000..08b47ec --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/VerticalAppList.kt @@ -0,0 +1,78 @@ +package com.nagopy.android.aplin.ui.main.compose + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.Card +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.google.accompanist.drawablepainter.rememberDrawablePainter +import com.nagopy.android.aplin.domain.model.PackageModel + +@Composable +fun VerticalAppList( + modifier: Modifier = Modifier, + packages: List, + launcherLargeIconSize: Int, + startDetailSettingsActivity: (String) -> Unit, +) { + val iconSize = with(LocalDensity.current) { launcherLargeIconSize.toDp() } + LazyColumn(modifier) { + items(packages) { pkg -> + Item(startDetailSettingsActivity, iconSize, pkg) + } + } +} + +@Composable +private fun Item( + startDetailSettingsActivity: (String) -> Unit, + iconSize: Dp, + pkg: PackageModel, +) { + Card( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(8.dp) + .alpha(if (pkg.isEnabled) 1.0f else 0.5f) + .clickable { + startDetailSettingsActivity.invoke(pkg.packageName) + }, + ) { + Row( + modifier = Modifier.padding(8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Image( + painter = rememberDrawablePainter(drawable = pkg.icon), + contentDescription = "", + modifier = Modifier.size(iconSize) + ) + Column(modifier = Modifier.padding(horizontal = 8.dp)) { + Text( + text = pkg.label, + fontSize = 18.sp, + ) + Text( + text = pkg.packageName, + fontSize = 14.sp, + ) + } + } + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/theme/Color.kt b/app/src/main/java/com/nagopy/android/aplin/ui/theme/Color.kt new file mode 100644 index 0000000..91d83cd --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/theme/Color.kt @@ -0,0 +1,8 @@ +package com.nagopy.android.aplin.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple200 = Color(0xFFFFE10D) +val Purple500 = Color(0xFFFFAC00) +val Purple700 = Color(0xFFE8B60C) +val Teal200 = Color(0xFF0083EF) diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/theme/Shape.kt b/app/src/main/java/com/nagopy/android/aplin/ui/theme/Shape.kt new file mode 100644 index 0000000..bb241d6 --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/theme/Shape.kt @@ -0,0 +1,11 @@ +package com.nagopy.android.aplin.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + small = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(4.dp), + large = RoundedCornerShape(0.dp) +) diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/theme/Theme.kt b/app/src/main/java/com/nagopy/android/aplin/ui/theme/Theme.kt new file mode 100644 index 0000000..f60324b --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/theme/Theme.kt @@ -0,0 +1,44 @@ +package com.nagopy.android.aplin.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable + +private val DarkColorPalette = darkColors( + primary = Purple200, + primaryVariant = Purple700, + secondary = Teal200 +) + +private val LightColorPalette = lightColors( + primary = Purple500, + primaryVariant = Purple700, + secondary = Teal200 + + /* Other default colors to override + background = Color.White, + surface = Color.White, + onPrimary = Color.White, + onSecondary = Color.Black, + onBackground = Color.Black, + onSurface = Color.Black, + */ +) + +@Composable +fun AplinTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { + val colors = if (darkTheme) { + DarkColorPalette + } else { + LightColorPalette + } + + MaterialTheme( + colors = colors, + typography = Typography, + shapes = Shapes, + content = content + ) +} diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/theme/Type.kt b/app/src/main/java/com/nagopy/android/aplin/ui/theme/Type.kt new file mode 100644 index 0000000..b87786b --- /dev/null +++ b/app/src/main/java/com/nagopy/android/aplin/ui/theme/Type.kt @@ -0,0 +1,28 @@ +package com.nagopy.android.aplin.ui.theme + +import androidx.compose.material.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + body1 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp + ) + /* Other default text styles to override + button = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.W500, + fontSize = 14.sp + ), + caption = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 12.sp + ) + */ +) diff --git a/app/src/main/res/drawable-night/ic_baseline_arrow_forward.xml b/app/src/main/res/drawable-night/ic_baseline_arrow_forward.xml new file mode 100644 index 0000000..1893bce --- /dev/null +++ b/app/src/main/res/drawable-night/ic_baseline_arrow_forward.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable-notnight/ic_baseline_arrow_forward.xml b/app/src/main/res/drawable-notnight/ic_baseline_arrow_forward.xml new file mode 100644 index 0000000..2b54967 --- /dev/null +++ b/app/src/main/res/drawable-notnight/ic_baseline_arrow_forward.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_arrow_forward.xml b/app/src/main/res/drawable/ic_baseline_arrow_forward.xml new file mode 100644 index 0000000..2b54967 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_arrow_forward.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..c9ad5f9 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..c9ad5f9 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..35daea381bdc7ff37af70d8a5ef50a6a08842c86 GIT binary patch literal 2323 zcmV+u3GDWXP){7Zfb@qA+3uh4bm)%l8q&ex=yXsZhx%nqGs*(#~xwH zL{pq4ArHEUkw6RNK}kqLfCdsUTnr{I5A(2jhj)NrV;mdfx1D@<&gBvN9$&DDF}CF+ zeRT2lJ->T?AI`bwo@@K5r(z{mVkK5$C9(^Eb%ga%#yVl1D=H+=)53kxQl2U*lI;dU&7((;KzaD^VZ<|^OO457+TfY1-vu7y zlLV5{fNr;zCF8|C&S&UQf4nyZu)Sa)kedNQdO*vRbX^?CgBqGiSfb z{K4zYX7jOV6-013olf-h^n5~dU5TKljYeZ84Hk`pXilV1K{+(nl?Ym|)9KDG1QVVh z3g88))#_ZD>q-TkqrswFP#(>7MS`?iZ59m{GC^)P+%5;dW!?)uydafIb)M!L)`DCX z15Djzm@5A#G}r$GUB$m)8I;5AurkL6k;o8apX$TJrQc%k$a946FEVs&6Lgg+aM?^u zogfkZf}AD|#&dt|CB}>YJdb--r|9{ax6(5oUtOy^Oy0G`Y7~{=!V5y{9_w5NtLZ8!I@3 zmmr6J7{ezvGa|&Ol_X$vsE>&gM8Zdq+i54$`d=6cV)UeLL~U^v=mRZbtRNCTf-FPz z7&`tUBSMVov^|)f(lBwvA;Z@+2%96Ibz67{a#;-rC z>^*e#Dw+3|ARGj_$+Uh2Lq|6kerVAl zb6K&M5hEnGCIRPV+fl-$kqf$mZNt*6t)RKp`YVhGG3q5h!^rU9V*Qq(9OTLp7%BfN z+Ktbv_7ORWi~BAsUL(Wq4(N~*wqps_P>{FH@E&cLJ;=WDllh)6(X z+aWX$W(oGsQ6PTMwtc@U}@?t=%_3DiG=$8nXI15ZXXu&1ZLRm*|_T2nJRG2ISNA7QKrp%qoZAV$_ey{gGBR7v%%hO=7&Z4^G(Bl63#tNpb zYa(c-wZQN77NsKNeON4Jex@q8vzrwn;B46rG$^^n^GzC5%p$g|@$VSaaJbg+Cja`= zssyyD8kx2VSbae*a`7C`+rvl@qv7z&=<8DP(|1kRM~n<1nK!qi=vD@-*2gmvz1YgS zQ{g$(_(iLSv@=CJpwZrE+8c5~fy`X=6H;m3NBm<{qj>^1YX8A6Iv0`dLxJ>t6jTwU z`%zGS5Q-)#-`j-eeL$xDrF!3IMSq6fZfEKVSbae@O*j8F6`>4Y$Rr6EyEnquqt_pk zX$D54(TkaxnMLR~P=)97L^+u4bG4r>O$1k0%AZ46N5JX}a_C1ek{-{<5YjDq0kYz3 zrv8&KYtu3_AiZE`Uirh4OBWATUyzF|Oz&U*9V5h(0W!3>v^{vB*E98>l%9!_$JZV* z+hrENhIVxmbDRjPFNk99=P;D^BSy@e9J=2636%0>r`#1`cbNFQaK7i<*bBKLp!0-A z5PdkNZ#<9wquw9u&~If_OSYq__7-SEn0i5CRNIV8rT;=_cR&xzC?OKW2yAh4I4r!Xbw7a&}n>?KM@TUp%)Zk!~`uvOwcj}MNriLR)Yx2 zqq(j~5SfLdwg=IisGyFHj+OTyjYg9m?LVk%XlTfyxvof%LZNtPA($VFzlee6LVuD; z*KGOu`TJ;o(-=6=^^cJSw2M(41OYT2v&*@6lZ6bN0U! z78X)L&n6`$C8*VEmBC zUBb)h>FLSk<>mP@ne2LXb@kPnnwo2#a2)6LxA3*U$E-%o`R!HOcA5jth2}(a+p=ZL z*Sxb1tgMTVkN-N^ew(m~@DgEjghO+nxqK@wF76v-8`#kDRfwc#NN;+UY&Vdg-;88v t4)eMAe^CygP}|W!ti(#J#7abz{{zYaTGtERq~8Dl002ovPDHLkV1kb0g53ZB literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..9b69c11fbafc7a431467fc717b1ce0e1b68b83b6 GIT binary patch literal 3269 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..419b71f5afa2a2ab862cfac5baaddd5824ffd467 GIT binary patch literal 4350 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..1ef83ec354d4e17f307c798b448233cb7f9b440a GIT binary patch literal 1515 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 E0q@Z9&j0`b literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..a270f84cac6a3359ae2f10cf27703d5cbcffef66 GIT binary patch literal 2723 zcmV;U3S9MxP)wpo~|MCQwD!Ra;Zqt(!!*g>KQP7*Z$DR#mL4s04@&6}E+t zvW}H@<=rGe9t3D8DS;%!CW(m?;*fWO^CTf8IB{$zb{so)a&~?<_uAL@bBGP;dZZt| z_WjN|zw>?PJKwoC%$V_jLPRl)hZwW)slBfi^;qa?@BiO~oqvHbQ~NuFf1ksc$5j+TTAj2}hj2FJ}CKacF#e{OZ`)SPR3#*LDEc_zm|kMjpFZW8DeC&aryd(Ou9@(9E5!M)DVgUf-ZkAgO6~&?@Kh~-(=#LKE=6m{lJiIL6BOwelr}0 zs6?&E20v70U7j^<3QPx(g0L-p9~~V%6pl+oLaJ)O#?oZ+O8#mcPYS=+O`}71$>(+m z_a;MdF~-R2^`BvsQkpy-PaXzGoBQ5@Th#gAp9qB2X#D3Qswp}T+k$>1P&ipE zmMb%Ydm#q@NC!k;U*94g7A@U+at_;s-vj<8+HvaW=tyD8 zffgSUGdw(8q72e1hKHYA&4po4Ts2HdKc+5o6^;5v$nNT-TYUy^>ao>M(`LIaR8&vzA4LQYr+C5&pAll z{Z(}F#%4;s`W$_ve>Q-V#Xl!~!)|J`=qSgyjcV%eeM*BH(!9UFzb!E_@zFp4)z#JC z=7Zv{GDxc^fS1u;ew^C&E)+-y$TO}by+C%GmHIHd*M1#B{Mo{Y7pDc$f(={xR~w;UqRs7vstKnZ~NtNrZRvr7X36crUMiY9=*OFO77 zaq^7|7>{h?nF>A!xIH#HWBgqpfHQ_oWWIBW(n{8-R)&KxA7c(a!KcDa2_PjUMJlC| z+r zOI>%X1YJN0fJ=VgfddB?1_Ic=efy(sw|mM>>>C-PyXW5!2&>V;CAEyprh8aS1((Ol zoB4HtbSPpe-;}^Nck=o6k^JM=N#qU!%P0 zwz0H14s zx=*|;5LTlpVKG%?|C{sOP8Tc1nZ8*023hQ8($(*jW?Fkc0Nt}x*Q}=z?;yh=ogoT0 z2G!Noonp>-zdBQCC1Pr8Yd6be(Mp826TGSH#-meqo7dm_6AlE|?OGQ;j zsL#`cH6I_CaxR z@t=`nW2!XrSemHw!+ZDowcKr*t4pcZUPGDJ;soNr;mglc_LU^EI|c%z8oSR6<0b-q zj&3&BsL78r$8m0VC_6hF>4SHt!Cr{u$Fo(dR(+S3s99E$9w~?04P1Ga2&5G>bGKP~ zVjJEZkY%8qN-9rNiD?3c$}GB8d6w}p)!!^7r)wx=Rj>R72tyM z$sGH=lc< z7lY)lJWqw3X5b)?Q_ud};21Ldil`!**VEHuf->^XYwxD+k6sdp17@E6iriyrXHf&~ zw5|?imB|;z(&@avajOtA`%3QLU~b<5!K|#T@UI!=$Y$@~zdw#2@V!_zzi-q(Saq7( zG^^0KXDJyDZ6e1&zd$Nl^w_E?y(pft^53SO-p;`9JTZP$9-GbP-MxEvJh*Y=8UDqV zB61L4&&|zEK+VPS`9{5CmWoWOJM=P@C;o^^-}?xAT7M(kHE(x5%rjAy4P)vM$JeKG&qtTd#&B=mylw)|W>2*8FJK}zzw3!Mr`7unO zUa!vt7jObME#I&r?*}Z^f{KcY3-U@xOR9A?-B8j7K1)kWKV=S&gUh6OKbg?P2|b&! zu%x6Uox4>j2y7};HLc?Z1#H4Ld?0PO8e-Yxc2r5NGLjyJ)_KC7O`2P=Ik%4RchI)?to&_D~ d1})v6{0|$qC_Qsj>wW+L002ovPDHLkV1mKlF=qe( literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..cf50977c7b27d3c5f44d92f35091d940ff177350 GIT binary patch literal 3262 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..cc7c20217bea72b48c256774babd3736698a826b GIT binary patch literal 4749 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..8aae3a1393807d206aa18912a56f443d569b795f GIT binary patch literal 6246 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 QqW}N^07*qoM6N<$f=9eck^lez literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..613372268b2bfba6cb28c10d66ddb36c61c001c9 GIT binary patch literal 5114 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 TDF6VVP<^2U0RXNkU43u= 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 Wo40n&lnXf^2PH49B2_P88umY2YHTzB literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..514caa7dc06cf00faff90a977a3e8c729ebe97b6 GIT binary patch literal 7196 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 HX&3b$RY0B= literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..a686a90f850b86647e99c91bf2b419ec0ae96d17 GIT binary patch literal 12281 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 EKX+C9Pyhe` literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..c0738ee7d9dc280bc7e94bdfe57114e0ff5bbc71 GIT binary patch literal 14730 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 C3a;n? literal 0 HcmV?d00001 diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml new file mode 100644 index 0000000..068c150 --- /dev/null +++ b/app/src/main/res/values-ja/strings.xml @@ -0,0 +1,8 @@ + + Aplin + + アンインストールできるアプリ + 無効にできるアプリ + 全てのアプリ + オープンソースライセンス + diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 0000000..c5d5899 --- /dev/null +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..7a0bc56 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,9 @@ + + Aplin + + Uninstallable Apps + Maybe Disableable Apps + All Apps + Open source licenses + Change consent state + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..ac139ec --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/app/src/test/java/com/nagopy/android/aplin/ExampleUnitTest.kt b/app/src/test/java/com/nagopy/android/aplin/ExampleUnitTest.kt new file mode 100644 index 0000000..f266a29 --- /dev/null +++ b/app/src/test/java/com/nagopy/android/aplin/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.nagopy.android.aplin + +import org.junit.Assert.assertEquals +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..220bb3e --- /dev/null +++ b/build.gradle @@ -0,0 +1,21 @@ +buildscript { + ext { + compose_version = '1.1.1' + } + repositories { + google() + } + dependencies { + classpath("com.google.android.gms:oss-licenses-plugin:0.10.5") + } +}// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '7.1.3' apply false + id 'com.android.library' version '7.1.3' apply false + id 'org.jetbrains.kotlin.android' version '1.6.10' apply false + id("org.jlleitschuh.gradle.ktlint") version "10.2.1" +} + +task clean(type: Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..3c7a8bd --- /dev/null +++ b/gradle.properties @@ -0,0 +1,23 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f GIT binary patch literal 59203 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

K7UpUK$>l@ zw`1S}(D?mUXu_C{wupRS-jiX~w=Uqqhf|Vb3Cm9L=T+w91Cu^ z*&Ty%sN?x*h~mJc4g~k{xD4ZmF%FXZNC;oVDwLZ_WvrnzY|{v8hc1nmx4^}Z;yriXsAf+Lp+OFLbR!&Ox?xABwl zu8w&|5pCxmu#$?Cv2_-Vghl2LZ6m7}VLEfR5o2Ou$x02uA-%QB2$c(c1rH3R9hesc zfpn#oqpbKuVsdfV#cv@5pV4^f_!WS+F>SV6N0JQ9E!T90EX((_{bSSFv9ld%I0&}9 zH&Jd4MEX1e0iqDtq~h?DBrxQX1iI0lIs<|kB$Yrh&cpeK0-^K%=FBsCBT46@h#yi!AyDq1V(#V}^;{{V*@T4WJ&U-NTq43w=|K>z8%pr_nC>%C(Wa_l78Ufib$r8Od)IIN=u>417 z`Hl{9A$mI5A(;+-Q&$F&h-@;NR>Z<2U;Y21>>Z;s@0V@SbkMQQj%_;~+qTuQ?c|AV zcWm3XZQHhP&R%QWarS%mJ!9R^&!_)*s(v+VR@I#QrAT}`17Y+l<`b-nvmDNW`De%y zrwTZ9EJrj1AFA>B`1jYDow}~*dfPs}IZMO3=a{Fy#IOILc8F0;JS4x(k-NSpbN@qM z`@aE_e}5{!$v3+qVs7u?sOV(y@1Os*Fgu`fCW9=G@F_#VQ%xf$hj0~wnnP0$hFI+@ zkQj~v#V>xn)u??YutKsX>pxKCl^p!C-o?+9;!Nug^ z{rP!|+KsP5%uF;ZCa5F;O^9TGac=M|=V z_H(PfkV1rz4jl?gJ(ArXMyWT4y(86d3`$iI4^l9`vLdZkzpznSd5Ikfrs8qcSy&>z zTIZgWZGXw0n9ibQxYWE@gI0(3#KA-dAdPcsL_|hg2@~C!VZDM}5;v_Nykfq!*@*Zf zE_wVgx82GMDryKO{U{D>vSzSc%B~|cjDQrt5BN=Ugpsf8H8f1lR4SGo#hCuXPL;QQ z#~b?C4MoepT3X`qdW2dNn& zo8)K}%Lpu>0tQei+{>*VGErz|qjbK#9 zvtd8rcHplw%YyQCKR{kyo6fgg!)6tHUYT(L>B7er5)41iG`j$qe*kSh$fY!PehLcD zWeKZHn<492B34*JUQh=CY1R~jT9Jt=k=jCU2=SL&&y5QI2uAG2?L8qd2U(^AW#{(x zThSy=C#>k+QMo^7caQcpU?Qn}j-`s?1vXuzG#j8(A+RUAY})F@=r&F(8nI&HspAy4 z4>(M>hI9c7?DCW8rw6|23?qQMSq?*Vx?v30U%luBo)B-k2mkL)Ljk5xUha3pK>EEj z@(;tH|M@xkuN?gsz;*bygizwYR!6=(Xgcg^>WlGtRYCozY<rFX2E>kaZo)O<^J7a`MX8Pf`gBd4vrtD|qKn&B)C&wp0O-x*@-|m*0egT=-t@%dD zgP2D+#WPptnc;_ugD6%zN}Z+X4=c61XNLb7L1gWd8;NHrBXwJ7s0ce#lWnnFUMTR& z1_R9Fin4!d17d4jpKcfh?MKRxxQk$@)*hradH2$3)nyXep5Z;B z?yX+-Bd=TqO2!11?MDtG0n(*T^!CIiF@ZQymqq1wPM_X$Iu9-P=^}v7npvvPBu!d$ z7K?@CsA8H38+zjA@{;{kG)#AHME>Ix<711_iQ@WWMObXyVO)a&^qE1GqpP47Q|_AG zP`(AD&r!V^MXQ^e+*n5~Lp9!B+#y3#f8J^5!iC@3Y@P`;FoUH{G*pj*q7MVV)29+j z>BC`a|1@U_v%%o9VH_HsSnM`jZ-&CDvbiqDg)tQEnV>b%Ptm)T|1?TrpIl)Y$LnG_ zzKi5j2Fx^K^PG1=*?GhK;$(UCF-tM~^=Z*+Wp{FSuy7iHt9#4n(sUuHK??@v+6*|10Csdnyg9hAsC5_OrSL;jVkLlf zHXIPukLqbhs~-*oa^gqgvtpgTk_7GypwH><53riYYL*M=Q@F-yEPLqQ&1Sc zZB%w}T~RO|#jFjMWcKMZccxm-SL)s_ig?OC?y_~gLFj{n8D$J_Kw%{r0oB8?@dWzn zB528d-wUBQzrrSSLq?fR!K%59Zv9J4yCQhhDGwhptpA5O5U?Hjqt>8nOD zi{)0CI|&Gu%zunGI*XFZh(ix)q${jT8wnnzbBMPYVJc4HX*9d^mz|21$=R$J$(y7V zo0dxdbX3N#=F$zjstTf*t8vL)2*{XH!+<2IJ1VVFa67|{?LP&P41h$2i2;?N~RA30LV`BsUcj zfO9#Pg1$t}7zpv#&)8`mis3~o+P(DxOMgz-V*(?wWaxi?R=NhtW}<#^Z?(BhSwyar zG|A#Q7wh4OfK<|DAcl9THc-W4*>J4nTevsD%dkj`U~wSUCh15?_N@uMdF^Kw+{agk zJ`im^wDqj`Ev)W3k3stasP`88-M0ZBs7;B6{-tSm3>I@_e-QfT?7|n0D~0RRqDb^G zyHb=is;IwuQ&ITzL4KsP@Z`b$d%B0Wuhioo1CWttW8yhsER1ZUZzA{F*K=wmi-sb#Ju+j z-l@In^IKnb{bQG}Ps>+Vu_W#grNKNGto+yjA)?>0?~X`4I3T@5G1)RqGUZuP^NJCq&^HykuYtMDD8qq+l8RcZNJsvN(10{ zQ1$XcGt}QH-U^WU!-wRR1d--{B$%vY{JLWIV%P4-KQuxxDeJaF#{eu&&r!3Qu{w}0f--8^H|KwE>)ORrcR+2Qf zb})DRcH>k0zWK8@{RX}NYvTF;E~phK{+F;MkIP$)T$93Ba2R2TvKc>`D??#mv9wg$ zd~|-`Qx5LwwsZ2hb*Rt4S9dsF%Cny5<1fscy~)d;0m2r$f=83<->c~!GNyb!U)PA; zq^!`@@)UaG)Ew(9V?5ZBq#c%dCWZrplmuM`o~TyHjAIMh0*#1{B>K4po-dx$Tk-Cq z=WZDkP5x2W&Os`N8KiYHRH#UY*n|nvd(U>yO=MFI-2BEp?x@=N<~CbLJBf6P)}vLS?xJXYJ2^<3KJUdrwKnJnTp{ zjIi|R=L7rn9b*D#Xxr4*R<3T5AuOS+#U8hNlfo&^9JO{VbH!v9^JbK=TCGR-5EWR@ zN8T-_I|&@A}(hKeL4_*eb!1G8p~&_Im8|wc>Cdir+gg90n1dw?QaXcx6Op_W1r=axRw>4;rM*UOpT#Eb9xU1IiWo@h?|5uP zka>-XW0Ikp@dIe;MN8B01a7+5V@h3WN{J=HJ*pe0uwQ3S&MyWFni47X32Q7SyCTNQ z+sR!_9IZa5!>f&V$`q!%H8ci!a|RMx5}5MA_kr+bhtQy{-^)(hCVa@I!^TV4RBi zAFa!Nsi3y37I5EK;0cqu|9MRj<^r&h1lF}u0KpKQD^5Y+LvFEwM zLU@@v4_Na#Axy6tn3P%sD^5P#<7F;sd$f4a7LBMk zGU^RZHBcxSA%kCx*eH&wgA?Qwazm8>9SCSz_!;MqY-QX<1@p$*T8lc?@`ikEqJ>#w zcG``^CoFMAhdEXT9qt47g0IZkaU)4R7wkGs^Ax}usqJ5HfDYAV$!=6?>J6+Ha1I<5 z|6=9soU4>E))tW$<#>F ziZ$6>KJf0bPfbx_)7-}tMINlc=}|H+$uX)mhC6-Hz+XZxsKd^b?RFB6et}O#+>Wmw9Ec9) z{q}XFWp{3@qmyK*Jvzpyqv57LIR;hPXKsrh{G?&dRjF%Zt5&m20Ll?OyfUYC3WRn{cgQ?^V~UAv+5 z&_m#&nIwffgX1*Z2#5^Kl4DbE#NrD&Hi4|7SPqZ}(>_+JMz=s|k77aEL}<=0Zfb)a z%F(*L3zCA<=xO)2U3B|pcTqDbBoFp>QyAEU(jMu8(jLA61-H!ucI804+B!$E^cQQa z)_ERrW3g!B9iLb3nn3dlkvD7KsY?sRvls3QC0qPi>o<)GHx%4Xb$5a3GBTJ(k@`e@ z$RUa^%S15^1oLEmA=sayrP5;9qtf!Z1*?e$ORVPsXpL{jL<6E)0sj&swP3}NPmR%FM?O>SQgN5XfHE< zo(4#Cv11(%Nnw_{_Ro}r6=gKd{k?NebJ~<~Kv0r(r0qe4n3LFx$5%x(BKvrz$m?LG zjLIc;hbj0FMdb9aH9Lpsof#yG$(0sG2%RL;d(n>;#jb!R_+dad+K;Ccw!|RY?uS(a zj~?=&M!4C(5LnlH6k%aYvz@7?xRa^2gml%vn&eKl$R_lJ+e|xsNfXzr#xuh(>`}9g zLHSyiFwK^-p!;p$yt7$F|3*IfO3Mlu9e>Dpx8O`37?fA`cj`C0B-m9uRhJjs^mRp# zWB;Aj6|G^1V6`jg7#7V9UFvnB4((nIwG?k%c7h`?0tS8J3Bn0t#pb#SA}N-|45$-j z$R>%7cc2ebAClXc(&0UtHX<>pd)akR3Kx_cK+n<}FhzmTx!8e9^u2e4%x{>T6pQ`6 zO182bh$-W5A3^wos0SV_TgPmF4WUP-+D25KjbC{y_6W_9I2_vNKwU(^qSdn&>^=*t z&uvp*@c8#2*paD!ZMCi3;K{Na;I4Q35zw$YrW5U@Kk~)&rw;G?d7Q&c9|x<Hg|CNMsxovmfth*|E*GHezPTWa^Hd^F4!B3sF;)? z(NaPyAhocu1jUe(!5Cy|dh|W2=!@fNmuNOzxi^tE_jAtzNJ0JR-avc_H|ve#KO}#S z#a(8secu|^Tx553d4r@3#6^MHbH)vmiBpn0X^29xEv!Vuh1n(Sr5I0V&`jA2;WS|Y zbf0e}X|)wA-Pf5gBZ>r4YX3Mav1kKY(ulAJ0Q*jB)YhviHK)w!TJsi3^dMa$L@^{` z_De`fF4;M87vM3Ph9SzCoCi$#Fsd38u!^0#*sPful^p5oI(xGU?yeYjn;Hq1!wzFk zG&2w}W3`AX4bxoVm03y>ts{KaDf!}b&7$(P4KAMP=vK5?1In^-YYNtx1f#}+2QK@h zeSeAI@E6Z8a?)>sZ`fbq9_snl6LCu6g>o)rO;ijp3|$vig+4t} zylEo7$SEW<_U+qgVcaVhk+4k+C9THI5V10qV*dOV6pPtAI$)QN{!JRBKh-D zk2^{j@bZ}yqW?<#VVuI_27*cI-V~sJiqQv&m07+10XF+#ZnIJdr8t`9s_EE;T2V;B z4UnQUH9EdX%zwh-5&wflY#ve!IWt0UE-My3?L#^Bh%kcgP1q{&26eXLn zTkjJ*w+(|_>Pq0v8{%nX$QZbf)tbJaLY$03;MO=Ic-uqYUmUCuXD>J>o6BCRF=xa% z3R4SK9#t1!K4I_d>tZgE>&+kZ?Q}1qo4&h%U$GfY058s%*=!kac{0Z+4Hwm!)pFLR zJ+5*OpgWUrm0FPI2ib4NPJ+Sk07j(`diti^i#kh&f}i>P4~|d?RFb#!JN)~D@)beox}bw?4VCf^y*`2{4`-@%SFTry2h z>9VBc9#JxEs1+0i2^LR@B1J`B9Ac=#FW=(?2;5;#U$0E0UNag_!jY$&2diQk_n)bT zl5Me_SUvqUjwCqmVcyb`igygB_4YUB*m$h5oeKv3uIF0sk}~es!{D>4r%PC*F~FN3owq5e0|YeUTSG#Vq%&Gk7uwW z0lDo#_wvflqHeRm*}l?}o;EILszBt|EW*zNPmq#?4A+&i0xx^?9obLyY4xx=Y9&^G;xYXYPxG)DOpPg!i_Ccl#3L}6xAAZzNhPK1XaC_~ z!A|mlo?Be*8Nn=a+FhgpOj@G7yYs(Qk(8&|h@_>w8Y^r&5nCqe0V60rRz?b5%J;GYeBqSAjo|K692GxD4` zRZyM2FdI+-jK2}WAZTZ()w_)V{n5tEb@>+JYluDozCb$fA4H)$bzg(Ux{*hXurjO^ zwAxc+UXu=&JV*E59}h3kzQPG4M)X8E*}#_&}w*KEgtX)cU{vm9b$atHa;s>| z+L6&cn8xUL*OSjx4YGjf6{Eq+Q3{!ZyhrL&^6Vz@jGbI%cAM9GkmFlamTbcQGvOlL zmJ?(FI)c86=JEs|*;?h~o)88>12nXlpMR4@yh%qdwFNpct;vMlc=;{FSo*apJ;p}! zAX~t;3tb~VuP|ZW;z$=IHf->F@Ml)&-&Bnb{iQyE#;GZ@C$PzEf6~q}4D>9jic@mTO5x76ulDz@+XAcm35!VSu zT*Gs>;f0b2TNpjU_BjHZ&S6Sqk6V1370+!eppV2H+FY!q*n=GHQ!9Rn6MjY!Jc77A zG7Y!lFp8?TIHN!LXO?gCnsYM-gQxsm=Ek**VmZu7vnuufD7K~GIxfxbsQ@qv2T zPa`tvHB$fFCyZl>3oYg?_wW)C>^_iDOc^B7klnTOoytQH18WkOk)L2BSD0r%xgRSW zQS9elF^?O=_@|58zKLK;(f77l-Zzu}4{fXed2saq!5k#UZAoDBqYQS{sn@j@Vtp|$ zG%gnZ$U|9@u#w1@11Sjl8ze^Co=)7yS(}=;68a3~g;NDe_X^}yJj;~s8xq9ahQ5_r zxAlTMnep*)w1e(TG%tWsjo3RR;yVGPEO4V{Zp?=a_0R#=V^ioQu4YL=BO4r0$$XTX zZfnw#_$V}sDAIDrezGQ+h?q24St0QNug_?{s-pI(^jg`#JRxM1YBV;a@@JQvH8*>> zIJvku74E0NlXkYe_624>znU0J@L<-c=G#F3k4A_)*;ky!C(^uZfj%WB3-*{*B$?9+ zDm$WFp=0(xnt6`vDQV3Jl5f&R(Mp};;q8d3I%Kn>Kx=^;uSVCw0L=gw53%Bp==8Sw zxtx=cs!^-_+i{2OK`Q;913+AXc_&Z5$@z3<)So0CU3;JAv=H?@Zpi~riQ{z-zLtVL z!oF<}@IgJp)Iyz1zVJ42!SPHSkjYNS4%ulVVIXdRuiZ@5Mx8LJS}J#qD^Zi_xQ@>DKDr-_e#>5h3dtje*NcwH_h;i{Sx7}dkdpuW z(yUCjckQsagv*QGMSi9u1`Z|V^}Wjf7B@q%j2DQXyd0nOyqg%m{CK_lAoKlJ7#8M} z%IvR?Vh$6aDWK2W!=i?*<77q&B8O&3?zP(Cs@kapc)&p7En?J;t-TX9abGT#H?TW? ztO5(lPKRuC7fs}zwcUKbRh=7E8wzTsa#Z{a`WR}?UZ%!HohN}d&xJ=JQhpO1PI#>X zHkb>pW04pU%Bj_mf~U}1F1=wxdBZu1790>3Dm44bQ#F=T4V3&HlOLsGH)+AK$cHk6 zia$=$kog?)07HCL*PI6}DRhpM^*%I*kHM<#1Se+AQ!!xyhcy6j7`iDX7Z-2i73_n# zas*?7LkxS-XSqv;YBa zW_n*32D(HTYQ0$feV_Fru1ZxW0g&iwqixPX3=9t4o)o|kOo79V$?$uh?#8Q8e>4e)V6;_(x&ViUVxma+i25qea;d-oK7ouuDsB^ab{ zu1qjQ%`n56VtxBE#0qAzb7lph`Eb-}TYpXB!H-}3Ykqyp`otprp7{VEuW*^IR2n$Fb99*nAtqT&oOFIf z@w*6>YvOGw@Ja?Pp1=whZqydzx@9X4n^2!n83C5{C?G@|E?&$?p*g68)kNvUTJ)I6 z1Q|(#UuP6pj78GUxq11m-GSszc+)X{C2eo-?8ud9sB=3(D47v?`JAa{V(IF zPZQ_0AY*9M97>Jf<o%#O_%Wq}8>YM=q0|tGY+hlXcpE=Z4Od z`NT7Hu2hnvRoqOw@g1f=bv`+nba{GwA$Ak0INlqI1k<9!x_!sL()h?hEWoWrdU3w` zZ%%)VR+Bc@_v!C#koM1p-3v_^L6)_Ktj4HE>aUh%2XZE@JFMOn)J~c`_7VWNb9c-N z2b|SZMR4Z@E7j&q&9(6H3yjEu6HV7{2!1t0lgizD;mZ9$r(r7W5G$ky@w(T_dFnOD z*p#+z$@pKE+>o@%eT(2-p_C}wbQ5s(%Sn_{$HDN@MB+Ev?t@3dPy`%TZ!z}AThZSu zN<1i$siJhXFdjV zP*y|V<`V8t=h#XTRUR~5`c`Z9^-`*BZf?WAehGdg)E2Je)hqFa!k{V(u+(hTf^Yq& zoruUh2(^3pe)2{bvt4&4Y9CY3js)PUHtd4rVG57}uFJL)D(JfSIo^{P=7liFXG zq5yqgof0V8paQcP!gy+;^pp-DA5pj=gbMN0eW=-eY+N8~y+G>t+x}oa!5r>tW$xhI zPQSv=pi;~653Gvf6~*JcQ%t1xOrH2l3Zy@8AoJ+wz@daW@m7?%LXkr!bw9GY@ns3e zSfuWF_gkWnesv?s3I`@}NgE2xwgs&rj?kH-FEy82=O8`+szN ziHch`vvS`zNfap14!&#i9H@wF7}yIPm=UB%(o(}F{wsZ(wA0nJ2aD^@B41>>o-_U6 zUqD~vdo48S8~FTb^+%#zcbQiiYoDKYcj&$#^;Smmb+Ljp(L=1Kt_J!;0s%1|JK}Wi z;={~oL!foo5n8=}rs6MmUW~R&;SIJO3TL4Ky?kh+b2rT9B1Jl4>#Uh-Bec z`Hsp<==#UEW6pGPhNk8H!!DUQR~#F9jEMI6T*OWfN^Ze&X(4nV$wa8QUJ>oTkruH# zm~O<`J7Wxseo@FqaZMl#Y(mrFW9AHM9Kb|XBMqaZ2a)DvJgYipkDD_VUF_PKd~dT7 z#02}bBfPn9a!X!O#83=lbJSK#E}K&yx-HI#T6ua)6o0{|={*HFusCkHzs|Fn&|C3H zBck1cmfcWVUN&i>X$YU^Sn6k2H;r3zuXbJFz)r5~3$d$tUj(l1?o={MM){kjgqXRO zc5R*#{;V7AQh|G|)jLM@wGAK&rm2~@{Pewv#06pHbKn#wL0P6F1!^qw9g&cW3Z=9} zj)POhOlwsh@eF=>z?#sIs*C-Nl(yU!#DaiaxhEs#iJqQ8w%(?+6lU02MYSeDkr!B- zPjMv+on6OLXgGnAtl(ao>|X2Y8*Hb}GRW5}-IzXnoo-d0!m4Vy$GS!XOLy>3_+UGs z2D|YcQx@M#M|}TDOetGi{9lGo9m-=0-^+nKE^*?$^uHkxZh}I{#UTQd;X!L+W@jm( zDg@N4+lUqI92o_rNk{3P>1gxAL=&O;x)ZT=q1mk0kLlE$WeWuY_$0`0jY-Kkt zP*|m3AF}Ubd=`<>(Xg0har*_@x2YH}bn0Wk*OZz3*e5;Zc;2uBdnl8?&XjupbkOeNZsNh6pvsq_ydmJI+*z**{I{0K)-;p1~k8cpJXL$^t!-`E}=*4G^-E8>H!LjTPxSx zcF+cS`ommfKMhNSbas^@YbTpH1*RFrBuATUR zt{oFWSk^$xU&kbFQ;MCX22RAN5F6eq9UfR$ut`Jw--p2YX)A*J69m^!oYfj2y7NYcH6&r+0~_sH^c^nzeN1AU4Ga7=FlR{S|Mm~MpzY0$Z+p2W(a={b-pR9EO1Rs zB%KY|@wLcAA@)KXi!d2_BxrkhDn`DT1=Dec}V!okd{$+wK z4E{n8R*xKyci1(CnNdhf$Dp2(Jpof0-0%-38X=Dd9PQgT+w%Lshx9+loPS~MOm%ZT zt%2B2iL_KU_ita%N>xjB!#71_3=3c}o zgeW~^U_ZTJQ2!PqXulQd=3b=XOQhwATK$y(9$#1jOQ4}4?~l#&nek)H(04f(Sr=s| zWv7Lu1=%WGk4FSw^;;!8&YPM)pQDCY9DhU`hMty1@sq1=Tj7bFsOOBZOFlpR`W>-J$-(kezWJj;`?x-v>ev{*8V z8p|KXJPV$HyQr1A(9LVrM47u-XpcrIyO`yWvx1pVYc&?154aneRpLqgx)EMvRaa#|9?Wwqs2+W8n5~79G z(}iCiLk;?enn}ew`HzhG+tu+Ru@T+K5juvZN)wY;x6HjvqD!&!)$$;1VAh~7fg0K| zEha#aN=Yv|3^~YFH}cc38ovVb%L|g@9W6fo(JtT6$fa?zf@Ct88e}m?i)b*Jgc{fl zExfdvw-BYDmH6>(4QMt#p0;FUIQqkhD}aH?a7)_%JtA~soqj{ppP_82yi9kaxuK>~ ze_)Zt>1?q=ZH*kF{1iq9sr*tVuy=u>Zev}!gEZx@O6-fjyu9X00gpIl-fS_pzjpqJ z1yqBmf9NF!jaF<+YxgH6oXBdK)sH(>VZ)1siyA$P<#KDt;8NT*l_0{xit~5j1P)FN zI8hhYKhQ)i z37^aP13B~u65?sg+_@2Kr^iWHN=U;EDSZ@2W2!5ALhGNWXnFBY%7W?1 z=HI9JzQ-pLKZDYTv<0-lt|6c-RwhxZ)mU2Os{bsX_i^@*fKUj8*aDO5pks=qn3Dv6 zwggpKLuyRCTVPwmw1r}B#AS}?X7b837UlXwp~E2|PJw2SGVueL7){Y&z!jL!XN=0i zU^Eig`S2`{+gU$68aRdWx?BZ{sU_f=8sn~>s~M?GU~`fH5kCc; z8ICp+INM3(3{#k32RZdv6b9MQYdZXNuk7ed8;G?S2nT+NZBG=Tar^KFl2SvhW$bGW#kdWL-I)s_IqVnCDDM9fm8g;P;8 z7t4yZn3^*NQfx7SwmkzP$=fwdC}bafQSEF@pd&P8@H#`swGy_rz;Z?Ty5mkS%>m#% zp_!m9e<()sfKiY(nF<1zBz&&`ZlJf6QLvLhl`_``%RW&{+O>Xhp;lwSsyRqGf=RWd zpftiR`={2(siiPAS|p}@q=NhVc0ELprt%=fMXO3B)4ryC2LT(o=sLM7hJC!}T1@)E zA3^J$3&1*M6Xq>03FX`R&w*NkrZE?FwU+Muut;>qNhj@bX17ZJxnOlPSZ=Zeiz~T_ zOu#yc3t6ONHB;?|r4w+pI)~KGN;HOGC)txxiUN8#mexj+W(cz%9a4sx|IRG=}ia zuEBuba3AHsV2feqw-3MvuL`I+2|`Ud4~7ZkN=JZ;L20|Oxna5vx1qbIh#k2O4$RQF zo`tL()zxaqibg^GbB+BS5#U{@K;WWQj~GcB1zb}zJkPwH|5hZ9iH2308!>_;%msji zJHSL~s)YHBR=Koa1mLEOHos*`gp=s8KA-C zu0aE+W!#iJ*0xqKm3A`fUGy#O+X+5W36myS>Uh2!R*s$aCU^`K&KKLCCDkejX2p=5 z%o7-fl03x`gaSNyr?3_JLv?2RLS3F*8ub>Jd@^Cc17)v8vYEK4aqo?OS@W9mt%ITJ z9=S2%R8M){CugT@k~~0x`}Vl!svYqX=E)c_oU6o}#Hb^%G1l3BudxA{F*tbjG;W_>=xV73pKY53v%>I)@D36I_@&p$h|Aw zonQS`07z_F#@T-%@-Tb|)7;;anoD_WH>9ewFy(ZcEOM$#Y)8>qi7rCnsH9GO-_7zF zu*C87{Df1P4TEOsnzZ@H%&lvV(3V@;Q!%+OYRp`g05PjY^gL$^$-t0Y>H*CDDs?FZly*oZ&dxvsxaUWF!{em4{A>n@vpXg$dwvt@_rgmHF z-MER`ABa8R-t_H*kv>}CzOpz;!>p^^9ztHMsHL|SRnS<-y5Z*r(_}c4=fXF`l^-i}>e7v!qs_jv zqvWhX^F=2sDNWA9c@P0?lUlr6ecrTKM%pNQ^?*Lq?p-0~?_j50xV%^(+H>sMul#Tw zeciF*1=?a7cI(}352%>LO96pD+?9!fNyl^9v3^v&Y4L)mNGK0FN43&Xf8jUlxW1Bw zyiu2;qW-aGNhs=zbuoxnxiwZ3{PFZM#Kw)9H@(hgX23h(`Wm~m4&TvoZoYp{plb^> z_#?vXcxd>r7K+1HKJvhed>gtK`TAbJUazUWQY6T~t2af%#<+Veyr%7-#*A#@&*;@g58{i|E%6yC_InGXCOd{L0;$)z#?n7M`re zh!kO{6=>7I?*}czyF7_frt#)s1CFJ_XE&VrDA?Dp3XbvF{qsEJgb&OLSNz_5g?HpK z9)8rsr4JN!Af3G9!#Qn(6zaUDqLN(g2g8*M)Djap?WMK9NKlkC)E2|-g|#-rp%!Gz zAHd%`iq|81efi93m3yTBw3g0j#;Yb2X{mhRAI?&KDmbGqou(2xiRNb^sV}%%Wu0?< z?($L>(#BO*)^)rSgyNRni$i`R4v;GhlCZ8$@e^ROX(p=2_v6Y!%^As zu022)fHdv_-~Yu_H6WVPLpHQx!W%^6j)cBhS`O3QBW#x(eX54d&I22op(N59b*&$v zFiSRY6rOc^(dgSV1>a7-5C;(5S5MvKcM2Jm-LD9TGqDpP097%52V+0>Xqq!! zq4e3vj53SE6i8J`XcQB|MZPP8j;PAOnpGnllH6#Ku~vS42xP*Nz@~y%db7Xi8s09P z1)e%8ys6&M8D=Dt6&t`iKG_4X=!kgRQoh%Z`dc&mlOUqXk-k`jKv9@(a^2-Upw>?< zt5*^DV~6Zedbec4NVl($2T{&b)zA@b#dUyd>`2JC0=xa_fIm8{5um zr-!ApXZhC8@=vC2WyxO|!@0Km)h8ep*`^he92$@YwP>VcdoS5OC^s38e#7RPsg4j+ zbVGG}WRSET&ZfrcR(x~k8n1rTP%CnfUNKUonD$P?FtNFF#cn!wEIab-;jU=B1dHK@ z(;(yAQJ`O$sMn>h;pf^8{JISW%d+@v6@CnXh9n5TXGC}?FI9i-D0OMaIg&mAg=0Kn zNJ7oz5*ReJukD55fUsMuaP+H4tDN&V9zfqF@ zr=#ecUk9wu{0;!+gl;3Bw=Vn^)z$ahVhhw)io!na&9}LmWurLb0zubxK=UEnU*{5P z+SP}&*(iBKSO4{alBHaY^)5Q=mZ+2OwIooJ7*Q5XJ+2|q`9#f?6myq!&oz?klihLq z4C)$XP!BNS0G_Z1&TM>?Jk{S~{F3n83ioli=IO6f%wkvCl(RFFw~j0tb{GvXTx>*sB0McY0s&SNvj4+^h`9nJ_wM>F!Uc>X}9PifQekn0sKI2SAJP!a4h z5cyGTuCj3ZBM^&{dRelIlT^9zcfaAuL5Y~bl!ppSf`wZbK$z#6U~rdclk``e+!qhe z6Qspo*%<)eu6?C;Bp<^VuW6JI|Ncvyn+LlSl;Mp22Bl7ARQ0Xc24%29(ZrdsIPw&-=yHQ7_Vle|5h>AST0 zUGX2Zk34vp?U~IHT|;$U86T+UUHl_NE4m|}>E~6q``7hccCaT^#y+?wD##Q%HwPd8 zV3x4L4|qqu`B$4(LXqDJngNy-{&@aFBvVsywt@X^}iH7P%>bR?ciC$I^U-4Foa`YKI^qDyGK7k%E%c_P=yzAi`YnxGA%DeNd++j3*h^ z=rn>oBd0|~lZ<6YvmkKY*ZJlJ;Im0tqgWu&E92eqt;+NYdxx`eS(4Hw_Jb5|yVvBg z*tbdY^!AN;luEyN4VRhS@-_DC{({ziH{&Z}iGElSV~qvT>L-8G%+yEL zX#MFOhj{InyKG=mvW-<1B@c-}x$vA(nU?>S>0*eN#!SLzQ)Ex7fvQ)S4D<8|I#N$3 zT5Ei`Z?cxBODHX8(Xp73v`IsAYC@9b;t}z0wxVuQSY1J^GRwDPN@qbM-ZF48T$GZ< z8WU+;Pqo?{ghI-KZ-i*ydXu`Ep0Xw^McH_KE9J0S7G;x8Fe`DVG?j3Pv=0YzJ}yZR z%2=oqHiUjvuk0~Ca>Kol4CFi0_xQT~;_F?=u+!kIDl-9g`#ZNZ9HCy17Ga1v^Jv9# z{T4Kb1-AzUxq*MutfOWWZgD*HnFfyYg0&e9f(5tZ>krPF6{VikNeHoc{linPPt#Si z&*g>(c54V8rT_AX!J&bNm-!umPvOR}vDai#`CX___J#=zeB*{4<&2WpaDncZsOkp* zsg<%@@rbrMkR_ux9?LsQxzoBa1s%$BBn6vk#{&&zUwcfzeCBJUwFYSF$08qDsB;gWQN*g!p8pxjofWbqNSZOEKOaTx@+* zwdt5*Q47@EOZ~EZL9s?1o?A%9TJT=Ob_13yyugvPg*e&ZU(r6^k4=2+D-@n=Hv5vu zSXG|hM(>h9^zn=eQ=$6`JO&70&2|%V5Lsx>)(%#;pcOfu>*nk_3HB_BNaH$`jM<^S zcSftDU1?nL;jy)+sfonQN}(}gUW?d_ikr*3=^{G)=tjBtEPe>TO|0ddVB zTklrSHiW+!#26frPXQQ(YN8DG$PZo?(po(QUCCf_OJC`pw*uey00%gmH!`WJkrKXj2!#6?`T25mTu9OJp2L8z3! z=arrL$ZqxuE{%yV)14Kd>k}j7pxZ6#$Dz8$@WV5p8kTqN<-7W)Q7Gt2{KoOPK_tZ| zf2WG~O5@{qPI+W<4f_;reuFVdO^5`ADC1!JQE|N`s3cq@(0WB!n0uh@*c{=LAd;~} zyGK@hbF-Oo+!nN)@i*O(`@FA#u?o=~e{`4O#5}z&=UkU*50fOrzi11D^&FOqe>wii z?*k+2|EcUs;Gx{!@KBT~>PAwLrIDT7Th=Utu?~?np@t^gFs?zgX=D${RwOY^WGh-+ z+#4$066ISh8eYW#FXWp~S`<*%O^ZuItL1Tyqt8#tZ zY120E;^VG`!lZn&3sPd$RkdHpU#|w+bYV)pJC|SH9g%|5IkxVTQcBA4CL0}$&}ef@ zW^Vtj%M;;_1xxP9x#ex17&4N*{ksO*_4O}xYu(p*JkL#yr}@7b)t5X?%CY<+s5_MJ zuiqt+N_;A(_)%lumoyRFixWa-M7qK_9s6<1X?JDa9fP!+_6u~~M$5L=ipB=7(j#f< zZ34J%=bs549%~_mA(|={uZNs_0?o7;-LBP(ZRnkd{-^|2|=4vUTmtByHL8 zEph`(LSEzQj68a+`d$V<45J7cyv^#|^|%fD#si1Nx!4NW*`l*{->HEWNh6-|g>-=r zXmQ|-i}Ku$ndUeHQ^&ieT!Lf}vf6GaqW9$DJ2NWrqwPY%%4nip$@vK$nRp*_C-v<| zuKz~ZyN&<%!NS26&x?jhy+@awJipMQ-8(X4#Ae5??U<1QMt1l9R=w9fAnEF}NYu$2 z>6}Vkc zIb*A?G*z8^IvibmBKn_u^5&T_1oey0gZS2~obf(#xk=erZGTEdQnt3DMGM+0oPwss zj5zXD;(oWhB_T@~Ig#9@v)AKtXu3>Inmgf@A|-lD-1U>cNyl3h?ADD9)GG4}zUGPk zZzaXe!~Kf?<~@$G?Uql3t8jy9{2!doq4=J}j9ktTxss{p6!9UdjyDERlA*xZ!=Q)KDs5O)phz>Vq3BNGoM(H|=1*Q4$^2fTZw z(%nq1P|5Rt81}SYJpEEzMPl5VJsV5&4e)ZWKDyoZ>1EwpkHx-AQVQc8%JMz;{H~p{=FXV>jIxvm4X*qv52e?Y-f%DJ zxEA165GikEASQ^fH6K#d!Tpu2HP{sFs%E=e$gYd$aj$+xue6N+Wc(rAz~wUsk2`(b z8Kvmyz%bKQxpP}~baG-rwYcYCvkHOi zlkR<=>ZBTU*8RF_d#Bl@zZsRIhx<%~Z@Z=ik z>adw3!DK(8R|q$vy{FTxw%#xliD~6qXmY^7_9kthVPTF~Xy1CfBqbU~?1QmxmU=+k z(ggxvEuA;0e&+ci-zQR{-f7aO{O(Pz_OsEjLh_K>MbvoZ4nxtk5u{g@nPv)cgW_R} z9}EA4K4@z0?7ue}Z(o~R(X&FjejUI2g~08PH1E4w>9o{)S(?1>Z0XMvTb|;&EuyOE zGvWNpYX)Nv<8|a^;1>bh#&znEcl-r!T#pn= z4$?Yudha6F%4b>*8@=BdtXXY4N+`U4Dmx$}>HeVJk-QdTG@t!tVT#0(LeV0gvqyyw z2sEp^9eY0N`u10Tm4n8No&A=)IeEC|gnmEXoNSzu!1<4R<%-9kY_8~5Ej?zRegMn78wuMs#;i&eUA0Zk_RXQ3b&TT} z;SCI=7-FUB@*&;8|n>(_g^HGf3@QODE3LpmX~ELnymQm{Sx9xrKS zK29p~?v@R$0=v6Dr5aW>-!{+h@?Q58|Kz8{{W`%J+lDAdb&M5VHrX_mDY;1-JLnf)ezmPau$)1;=`-FU=-r-83tX=C`S#}GZufju zQ>sXNT0Ny=k@nc%cFnvA_i4SC)?_ORXHq8B4D%el1uPX`c~uG#S1M7C+*MMqLw78E zhY2dI8@+N^qrMI1+;TUda(vGqGSRyU{Fnm`aqrr7bz42c5xsOO-~oZpkzorD1g}Y<6rk&3>PsSGy}W?MtqFky@A(X# zIuNZK0cK?^=;PUAu>j0#HtjbHCV*6?jzA&OoE$*Jlga*}LF`SF?WLhv1O|zqC<>*> zYB;#lsYKx0&kH@BFpW8n*yDcc6?;_zaJs<-jPSkCsSX-!aV=P5kUgF@Nu<{a%#K*F z134Q{9|YX7X(v$62_cY3^G%t~rD>Q0z@)1|zs)vjJ6Jq9;7#Ki`w+eS**En?7;n&7 zu==V3T&eFboN3ZiMx3D8qYc;VjFUk_H-WWCau(VFXSQf~viH0L$gwD$UfFHqNcgN`x}M+YQ6RnN<+@t>JUp#)9YOkqst-Ga?{FsDpEeX0(5v{0J~SEbWiL zXC2}M4?UH@u&|;%0y`eb33ldo4~z-x8zY!oVmV=c+f$m?RfDC35mdQ2E>Pze7KWP- z>!Bh<&57I+O_^s}9Tg^k)h7{xx@0a0IA~GAOt2yy!X%Q$1rt~LbTB6@Du!_0%HV>N zlf)QI1&gvERKwso23mJ!Ou6ZS#zCS5W`gxE5T>C#E|{i<1D35C222I33?Njaz`On7 zi<+VWFP6D{e-{yiN#M|Jgk<44u1TiMI78S5W`Sdb5f+{zu34s{CfWN7a3Cf^@L%!& zN$?|!!9j2c)j$~+R6n#891w-z8(!oBpL2K=+%a$r2|~8-(vQj5_XT`<0Ksf;oP+tz z9CObS!0m)Tgg`K#xBM8B(|Z)Wb&DYL{WTYv`;A=q6~Nnx2+!lTIXtj8J7dZE!P_{z z#f8w6F}^!?^KE#+ZDv+xd5O&3EmomZzsv?>E-~ygGum45fk!SBN&|eo1rKw^?aZJ4 E2O(~oYXATM literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..dbb974e --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sat Apr 09 16:13:59 JST 2022 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..6e549ca --- /dev/null +++ b/settings.gradle @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "Aplin" +include ':app' From ca5a22a2a639d39bce47e2394b0301a0110bce11 Mon Sep 17 00:00:00 2001 From: 75py Date: Sat, 30 Apr 2022 18:08:21 +0900 Subject: [PATCH 3/9] add tests --- app/build.gradle | 3 ++ .../DevicePolicyRepositoryImplTest.kt | 41 +++++++++++++++ .../repository/PackageRepositoryImplTest.kt | 52 +++++++++++++++++++ .../repository/DevicePolicyRepositoryImpl.kt | 4 +- 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 app/src/androidTest/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepositoryImplTest.kt create mode 100644 app/src/androidTest/java/com/nagopy/android/aplin/data/repository/PackageRepositoryImplTest.kt diff --git a/app/build.gradle b/app/build.gradle index 92c673c..6f57ded 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -93,4 +93,7 @@ dependencies { implementation 'com.google.android.ump:user-messaging-platform:2.0.0' implementation 'androidx.preference:preference:1.2.0' + + testImplementation "io.mockk:mockk:1.12.3" + androidTestImplementation "io.mockk:mockk-android:1.12.3" } diff --git a/app/src/androidTest/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepositoryImplTest.kt b/app/src/androidTest/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepositoryImplTest.kt new file mode 100644 index 0000000..67f0558 --- /dev/null +++ b/app/src/androidTest/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepositoryImplTest.kt @@ -0,0 +1,41 @@ +package com.nagopy.android.aplin.data.repository + +import android.app.admin.DevicePolicyManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertNotNull +import kotlin.test.assertTrue + +@RunWith(AndroidJUnit4::class) +class DevicePolicyRepositoryImplTest { + + private lateinit var devicePolicyManager: DevicePolicyManager + private lateinit var devicePolicyRepositoryImpl: DevicePolicyRepositoryImpl + + @Before + fun setUp() { + devicePolicyManager = mockk(relaxed = true) + devicePolicyRepositoryImpl = DevicePolicyRepositoryImpl(devicePolicyManager) + } + + @Test + fun packageHasActiveAdmins() { + assertNotNull(devicePolicyRepositoryImpl.packageHasActiveAdmins) + } + + @Test + fun isProfileOrDeviceOwner() { + val pkg = "foo" + every { devicePolicyManager.isDeviceOwnerApp(pkg) }.returns(false) + every { devicePolicyManager.isProfileOwnerApp(pkg) }.returns(true) + + assertTrue(devicePolicyRepositoryImpl.isProfileOrDeviceOwner(pkg)) + verify { devicePolicyManager.isDeviceOwnerApp(pkg) } + verify { devicePolicyManager.isProfileOwnerApp(pkg) } + } +} diff --git a/app/src/androidTest/java/com/nagopy/android/aplin/data/repository/PackageRepositoryImplTest.kt b/app/src/androidTest/java/com/nagopy/android/aplin/data/repository/PackageRepositoryImplTest.kt new file mode 100644 index 0000000..1d1d40f --- /dev/null +++ b/app/src/androidTest/java/com/nagopy/android/aplin/data/repository/PackageRepositoryImplTest.kt @@ -0,0 +1,52 @@ +package com.nagopy.android.aplin.data.repository + +import android.content.pm.PackageManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.mockk.mockk +import org.junit.Assert.assertNotNull +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class PackageRepositoryImplTest { + + private lateinit var packageManager: PackageManager + private lateinit var packRepositoryImpl: PackageRepositoryImpl + + @Before + fun setUp() { + packageManager = mockk(relaxed = true) + packRepositoryImpl = PackageRepositoryImpl(packageManager) + } + + @Test + fun getSystemPackage() { + assertNotNull(packRepositoryImpl.systemPackage) + } + + @Test + fun getPermissionControllerPackageName() { + assertNotNull(packRepositoryImpl.permissionControllerPackageName) + } + + @Test + fun getServicesSystemSharedLibraryPackageName() { + assertNotNull(packRepositoryImpl.servicesSystemSharedLibraryPackageName) + } + + @Test + fun getSharedSystemSharedLibraryPackageName() { + assertNotNull(packRepositoryImpl.sharedSystemSharedLibraryPackageName) + } + + @Test + fun getPrintSpoolerPackageName() { + assertNotNull(packRepositoryImpl.printSpoolerPackageName) + } + + @Test + fun getDeviceProvisioningPackage() { + assertNotNull(packRepositoryImpl.deviceProvisioningPackage) + } +} diff --git a/app/src/main/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepositoryImpl.kt b/app/src/main/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepositoryImpl.kt index 6ec4855..bb3380d 100644 --- a/app/src/main/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepositoryImpl.kt +++ b/app/src/main/java/com/nagopy/android/aplin/data/repository/DevicePolicyRepositoryImpl.kt @@ -1,6 +1,7 @@ package com.nagopy.android.aplin.data.repository import android.app.admin.DevicePolicyManager +import androidx.annotation.VisibleForTesting import logcat.LogPriority import logcat.logcat import java.lang.reflect.Method @@ -9,7 +10,8 @@ class DevicePolicyRepositoryImpl( private val devicePolicyManager: DevicePolicyManager, ) : DevicePolicyRepository { - private val packageHasActiveAdmins: Method? by lazy { + @VisibleForTesting + val packageHasActiveAdmins: Method? by lazy { try { DevicePolicyManager::class.java.getDeclaredMethod( "packageHasActiveAdmins", From 2eb8087202294dbdf19d52ba51afa2343e863da3 Mon Sep 17 00:00:00 2001 From: 75py Date: Sun, 1 May 2022 14:25:58 +0900 Subject: [PATCH 4/9] add preview --- .../aplin/ui/main/compose/VerticalAppList.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/VerticalAppList.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/VerticalAppList.kt index 08b47ec..1836ae1 100644 --- a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/VerticalAppList.kt +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/VerticalAppList.kt @@ -1,5 +1,6 @@ package com.nagopy.android.aplin.ui.main.compose +import androidx.appcompat.content.res.AppCompatResources import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -16,11 +17,14 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.google.accompanist.drawablepainter.rememberDrawablePainter +import com.nagopy.android.aplin.R import com.nagopy.android.aplin.domain.model.PackageModel @Composable @@ -76,3 +80,22 @@ private fun Item( } } } + +@Preview +@Composable +fun ItemPreview() { + Item( + startDetailSettingsActivity = {}, iconSize = 32.dp, pkg = PackageModel( + packageName = "com.example", + label = "Example Label", + icon = AppCompatResources.getDrawable( + LocalContext.current, + R.mipmap.ic_launcher + )!!, + isEnabled = true, + firstInstallTime = 0L, + lastUpdateTime = 0L, + versionName = "1.0.0", + ) + ) +} From 59c06c3e0bee14db211a300b72a88000e3f10348 Mon Sep 17 00:00:00 2001 From: 75py Date: Sun, 1 May 2022 15:42:31 +0900 Subject: [PATCH 5/9] add sharing feature --- .../android/aplin/ui/main/MainActivity.kt | 3 + .../android/aplin/ui/main/MainUiState.kt | 10 +- .../android/aplin/ui/main/MainViewModel.kt | 13 +++ .../aplin/ui/main/compose/AppListScreen.kt | 97 +++++++++++++------ .../aplin/ui/main/compose/RootScreen.kt | 5 + .../drawable-night/ic_baseline_share_24.xml | 9 ++ .../ic_baseline_share_24.xml | 10 ++ .../res/drawable/ic_baseline_share_24.xml | 10 ++ app/src/main/res/values-ja/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 10 files changed, 128 insertions(+), 31 deletions(-) create mode 100644 app/src/main/res/drawable-night/ic_baseline_share_24.xml create mode 100644 app/src/main/res/drawable-notnight/ic_baseline_share_24.xml create mode 100644 app/src/main/res/drawable/ic_baseline_share_24.xml diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/MainActivity.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/MainActivity.kt index 546c7a8..23c59ce 100644 --- a/app/src/main/java/com/nagopy/android/aplin/ui/main/MainActivity.kt +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/MainActivity.kt @@ -27,6 +27,9 @@ class MainActivity : ComponentActivity() { pkg ) }, + sharePackages = { packages -> + mainViewModel.sharePackages(this@MainActivity, packages) + }, startOssLicensesActivity = { mainViewModel.startOssLicensesActivity(this) }, diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/MainUiState.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/MainUiState.kt index a650d89..cbfe206 100644 --- a/app/src/main/java/com/nagopy/android/aplin/ui/main/MainUiState.kt +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/MainUiState.kt @@ -1,5 +1,7 @@ package com.nagopy.android.aplin.ui.main +import androidx.annotation.StringRes +import com.nagopy.android.aplin.R import com.nagopy.android.aplin.domain.model.PackagesModel data class MainUiState( @@ -7,8 +9,8 @@ data class MainUiState( val packagesModel: PackagesModel? = null, ) -enum class AppCategory { - USERS, - DISABLEABLE, - ALL, +enum class AppCategory(@StringRes val labelId: Int) { + USERS(R.string.category_users), + DISABLEABLE(R.string.category_disableable), + ALL(R.string.category_users), } diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/MainViewModel.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/MainViewModel.kt index a7500c6..fd7dcf0 100644 --- a/app/src/main/java/com/nagopy/android/aplin/ui/main/MainViewModel.kt +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/MainViewModel.kt @@ -5,9 +5,11 @@ import android.app.ActivityManager import android.content.Intent import android.net.Uri import android.provider.Settings +import androidx.core.app.ShareCompat import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.google.android.gms.oss.licenses.OssLicensesMenuActivity +import com.nagopy.android.aplin.domain.model.PackageModel import com.nagopy.android.aplin.domain.model.PackagesModel import com.nagopy.android.aplin.domain.usecase.LoadPackagesUseCase import kotlinx.coroutines.CoroutineDispatcher @@ -76,4 +78,15 @@ class MainViewModel( fun startOssLicensesActivity(activity: Activity) { activity.startActivity(Intent(activity, OssLicensesMenuActivity::class.java)) } + + fun sharePackages(activity: Activity, packages: List) { + ShareCompat.IntentBuilder(activity) + .setText(packages.joinToString(separator = LINE_SEPARATOR) { it.packageName }) + .setType("text/plain") + .startChooser() + } + + companion object { + private val LINE_SEPARATOR: String = System.getProperty("line.separator") ?: "\n" + } } diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/AppListScreen.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/AppListScreen.kt index 8447353..d147b04 100644 --- a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/AppListScreen.kt +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/AppListScreen.kt @@ -1,10 +1,20 @@ package com.nagopy.android.aplin.ui.main.compose import androidx.appcompat.content.res.AppCompatResources +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding +import androidx.compose.material.Surface +import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.nagopy.android.aplin.R @@ -12,7 +22,6 @@ import com.nagopy.android.aplin.domain.model.PackageModel import com.nagopy.android.aplin.domain.model.PackagesModel import com.nagopy.android.aplin.ui.main.AppCategory import com.nagopy.android.aplin.ui.main.MainUiState -import com.nagopy.android.aplin.ui.theme.AplinTheme @Composable fun AppListScreen( @@ -20,6 +29,7 @@ fun AppListScreen( appCategory: AppCategory, launcherLargeIconSize: Int, startDetailSettingsActivity: (String) -> Unit, + sharePackages: (List) -> Unit, ) { if (state.packagesModel == null) { Loading() @@ -29,6 +39,56 @@ fun AppListScreen( packagesModel = state.packagesModel, launcherLargeIconSize = launcherLargeIconSize, startDetailSettingsActivity = startDetailSettingsActivity, + sharePackages = sharePackages, + ) + } +} + +@Composable +fun AppListScreenLoaded( + appCategory: AppCategory, + packagesModel: PackagesModel, + launcherLargeIconSize: Int, + startDetailSettingsActivity: (String) -> Unit, + sharePackages: (List) -> Unit, +) { + val packages = when (appCategory) { + AppCategory.USERS -> packagesModel.userPackages + AppCategory.DISABLEABLE -> packagesModel.disableablePackages + AppCategory.ALL -> packagesModel.allPackages + } + + Column { + Surface(elevation = 3.dp) { + Row( + modifier = Modifier + .clickable { + sharePackages.invoke(packages) + } + .padding(12.dp) + ) { + Text( + text = stringResource(id = appCategory.labelId) + " (${packages.size})", + fontWeight = FontWeight.Bold, + modifier = Modifier + .weight(1f) + .align(Alignment.CenterVertically) + ) + Image( + painter = painterResource(id = R.drawable.ic_baseline_share_24), + contentDescription = stringResource(id = R.string.share), + modifier = Modifier.align(Alignment.CenterVertically) + ) + } + } + + VerticalAppList( + modifier = Modifier + .padding(8.dp) + .weight(1.0f), + packages = packages, + launcherLargeIconSize = launcherLargeIconSize, + startDetailSettingsActivity = startDetailSettingsActivity, ) } } @@ -50,31 +110,14 @@ fun AppListScreenLoadedPreview() { versionName = "1.0.0", ) } - AplinTheme { - AppListScreenLoaded( - appCategory = AppCategory.ALL, - packagesModel = PackagesModel(packages, packages, packages), - launcherLargeIconSize = 36, - startDetailSettingsActivity = {}, - ) - } -} - -@Composable -fun AppListScreenLoaded( - appCategory: AppCategory, - packagesModel: PackagesModel, - launcherLargeIconSize: Int, - startDetailSettingsActivity: (String) -> Unit, -) { - VerticalAppList( - modifier = Modifier.padding(8.dp), - packages = when (appCategory) { - AppCategory.USERS -> packagesModel.userPackages - AppCategory.DISABLEABLE -> packagesModel.disableablePackages - AppCategory.ALL -> packagesModel.allPackages - }, - launcherLargeIconSize = launcherLargeIconSize, - startDetailSettingsActivity = startDetailSettingsActivity, + AppListScreen( + state = MainUiState( + isLoading = false, + packagesModel = PackagesModel(packages, packages, packages) + ), + appCategory = AppCategory.ALL, + launcherLargeIconSize = 36, + startDetailSettingsActivity = {}, + sharePackages = {}, ) } diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/RootScreen.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/RootScreen.kt index 0f7cb83..f2e5104 100644 --- a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/RootScreen.kt +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/RootScreen.kt @@ -14,6 +14,7 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.nagopy.android.aplin.R +import com.nagopy.android.aplin.domain.model.PackageModel import com.nagopy.android.aplin.ui.ads.AdsStatus import com.nagopy.android.aplin.ui.ads.compose.AdBanner import com.nagopy.android.aplin.ui.main.AppCategory @@ -26,6 +27,7 @@ fun RootScreen( state: MainUiState, mainViewModel: MainViewModel, startDetailSettingsActivity: (String) -> Unit, + sharePackages: (List) -> Unit, startOssLicensesActivity: () -> Unit, adsStatus: AdsStatus, isGDPR: Boolean, @@ -71,6 +73,7 @@ fun RootScreen( appCategory = AppCategory.USERS, launcherLargeIconSize = mainViewModel.launcherLargeIconSize, startDetailSettingsActivity = startDetailSettingsActivity, + sharePackages = sharePackages, ) } composable("disableableAppList") { @@ -79,6 +82,7 @@ fun RootScreen( appCategory = AppCategory.DISABLEABLE, launcherLargeIconSize = mainViewModel.launcherLargeIconSize, startDetailSettingsActivity = startDetailSettingsActivity, + sharePackages = sharePackages, ) } composable("allAppList") { @@ -87,6 +91,7 @@ fun RootScreen( appCategory = AppCategory.ALL, launcherLargeIconSize = mainViewModel.launcherLargeIconSize, startDetailSettingsActivity = startDetailSettingsActivity, + sharePackages = sharePackages, ) } } diff --git a/app/src/main/res/drawable-night/ic_baseline_share_24.xml b/app/src/main/res/drawable-night/ic_baseline_share_24.xml new file mode 100644 index 0000000..6d59fd7 --- /dev/null +++ b/app/src/main/res/drawable-night/ic_baseline_share_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable-notnight/ic_baseline_share_24.xml b/app/src/main/res/drawable-notnight/ic_baseline_share_24.xml new file mode 100644 index 0000000..2f13bb3 --- /dev/null +++ b/app/src/main/res/drawable-notnight/ic_baseline_share_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_share_24.xml b/app/src/main/res/drawable/ic_baseline_share_24.xml new file mode 100644 index 0000000..2f13bb3 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_share_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 068c150..ee632c3 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -5,4 +5,5 @@ 無効にできるアプリ 全てのアプリ オープンソースライセンス + 共有 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7a0bc56..23af147 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6,4 +6,5 @@ All Apps Open source licenses Change consent state + Share From c8f0656da7906ca9112b20cb81241298ba6ef7a6 Mon Sep 17 00:00:00 2001 From: 75py Date: Sun, 1 May 2022 15:42:36 +0900 Subject: [PATCH 6/9] add preview --- .../aplin/ui/main/compose/VerticalAppList.kt | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/VerticalAppList.kt b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/VerticalAppList.kt index 1836ae1..bbe73b1 100644 --- a/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/VerticalAppList.kt +++ b/app/src/main/java/com/nagopy/android/aplin/ui/main/compose/VerticalAppList.kt @@ -85,7 +85,8 @@ private fun Item( @Composable fun ItemPreview() { Item( - startDetailSettingsActivity = {}, iconSize = 32.dp, pkg = PackageModel( + startDetailSettingsActivity = {}, iconSize = 32.dp, + pkg = PackageModel( packageName = "com.example", label = "Example Label", icon = AppCompatResources.getDrawable( @@ -99,3 +100,27 @@ fun ItemPreview() { ) ) } + +@Preview +@Composable +fun VerticalAppListPreview() { + val packages = IntRange(0, 20).map { + PackageModel( + packageName = "com.example$it", + label = "Example Label $it", + icon = AppCompatResources.getDrawable( + LocalContext.current, + R.mipmap.ic_launcher + )!!, + isEnabled = it % 2 == 0, + firstInstallTime = 0L, + lastUpdateTime = 0L, + versionName = "1.0.0", + ) + } + VerticalAppList( + packages = packages, + launcherLargeIconSize = 32, + startDetailSettingsActivity = {} + ) +} From f73a672835dcc41c84f84624f1041ac39af7a835 Mon Sep 17 00:00:00 2001 From: 75py Date: Sun, 1 May 2022 17:13:58 +0900 Subject: [PATCH 7/9] chore: bump up versionCode --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 6f57ded..392c496 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,7 +16,7 @@ android { applicationId "com.nagopy.android.aplin" minSdk 26 targetSdk 32 - versionCode 35 + versionCode 36 versionName "5.0.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" From a71cb92b9d189476ce4678e27018e80dd8176337 Mon Sep 17 00:00:00 2001 From: 75py Date: Wed, 4 May 2022 10:35:22 +0900 Subject: [PATCH 8/9] fix test --- app/src/androidTest/AndroidManifest.xml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 app/src/androidTest/AndroidManifest.xml diff --git a/app/src/androidTest/AndroidManifest.xml b/app/src/androidTest/AndroidManifest.xml new file mode 100644 index 0000000..8da0d57 --- /dev/null +++ b/app/src/androidTest/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From 9c353fc4273878646c88ebda40bbe27ba59e92ee Mon Sep 17 00:00:00 2001 From: 75py Date: Wed, 4 May 2022 10:38:01 +0900 Subject: [PATCH 9/9] update README --- README.md | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/README.md b/README.md index 480b7e1..fc12049 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Aplin [![Build Status](https://travis-ci.org/75py/Aplin.svg?branch=master)](https://travis-ci.org/75py/Aplin) [![codecov](https://codecov.io/gh/75py/Aplin/branch/master/graph/badge.svg)](https://codecov.io/gh/75py/Aplin) +Aplin ===== Application manager for Android! @@ -10,28 +10,6 @@ Download https://play.google.com/store/apps/details?id=com.nagopy.android.aplin -Latest version --------------- - -4.0.1 - - -For Developers --------------- - -Unit test -========= - -* Command -``` -cd Aplin/app -../gradlew testDebug --info -``` - -* Android Studio -"VM Options -noverify" is required. - - License -------