├── log ├── consumer-rules.pro ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── org │ │ └── xdty │ │ └── log │ │ └── NoLog.kt ├── proguard-rules.pro └── build.gradle ├── app ├── .gitignore ├── src │ ├── main │ │ ├── assets │ │ │ └── sugar_upgrades │ │ │ │ ├── 4.sql │ │ │ │ ├── 5.sql │ │ │ │ └── 6.sql │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── drawable-hdpi │ │ │ │ ├── status_icon.png │ │ │ │ ├── ic_call_white_18dp.png │ │ │ │ ├── ic_flag_white_18dp.png │ │ │ │ ├── ic_timer_white_18dp.png │ │ │ │ ├── ic_search_white_24dp.png │ │ │ │ ├── ic_update_white_18dp.png │ │ │ │ ├── ic_cloud_done_white_18dp.png │ │ │ │ ├── ic_date_range_white_18dp.png │ │ │ │ ├── ic_mode_edit_white_18dp.png │ │ │ │ ├── ic_mode_edit_white_48dp.png │ │ │ │ ├── ic_money_off_white_18dp.png │ │ │ │ ├── ic_restaurant_black_48dp.png │ │ │ │ ├── ic_restaurant_white_18dp.png │ │ │ │ ├── ic_attach_money_black_48dp.png │ │ │ │ ├── ic_location_on_white_18dp.png │ │ │ │ ├── ic_location_on_white_24dp.png │ │ │ │ ├── ic_my_location_black_18dp.png │ │ │ │ ├── ic_bookmark_border_white_18dp.png │ │ │ │ ├── ic_cloud_download_white_18dp.png │ │ │ │ ├── ic_do_not_disturb_white_18dp.png │ │ │ │ ├── ic_local_shipping_black_48dp.png │ │ │ │ ├── ic_local_shipping_white_18dp.png │ │ │ │ ├── ic_record_voice_over_black_48dp.png │ │ │ │ ├── ic_local_grocery_store_black_48dp.png │ │ │ │ ├── ic_notifications_none_white_18dp.png │ │ │ │ └── ic_remove_shopping_cart_white_18dp.png │ │ │ ├── drawable-mdpi │ │ │ │ ├── status_icon.png │ │ │ │ ├── ic_call_white_18dp.png │ │ │ │ ├── ic_flag_white_18dp.png │ │ │ │ ├── ic_timer_white_18dp.png │ │ │ │ ├── ic_search_white_24dp.png │ │ │ │ ├── ic_update_white_18dp.png │ │ │ │ ├── ic_cloud_done_white_18dp.png │ │ │ │ ├── ic_date_range_white_18dp.png │ │ │ │ ├── ic_mode_edit_white_18dp.png │ │ │ │ ├── ic_mode_edit_white_48dp.png │ │ │ │ ├── ic_money_off_white_18dp.png │ │ │ │ ├── ic_restaurant_black_48dp.png │ │ │ │ ├── ic_restaurant_white_18dp.png │ │ │ │ ├── ic_attach_money_black_48dp.png │ │ │ │ ├── ic_location_on_white_18dp.png │ │ │ │ ├── ic_location_on_white_24dp.png │ │ │ │ ├── ic_my_location_black_18dp.png │ │ │ │ ├── ic_bookmark_border_white_18dp.png │ │ │ │ ├── ic_cloud_download_white_18dp.png │ │ │ │ ├── ic_do_not_disturb_white_18dp.png │ │ │ │ ├── ic_local_shipping_black_48dp.png │ │ │ │ ├── ic_local_shipping_white_18dp.png │ │ │ │ ├── ic_record_voice_over_black_48dp.png │ │ │ │ ├── ic_local_grocery_store_black_48dp.png │ │ │ │ ├── ic_notifications_none_white_18dp.png │ │ │ │ └── ic_remove_shopping_cart_white_18dp.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── drawable-xhdpi │ │ │ │ ├── status_icon.png │ │ │ │ ├── ic_call_white_18dp.png │ │ │ │ ├── ic_flag_white_18dp.png │ │ │ │ ├── ic_search_white_24dp.png │ │ │ │ ├── ic_timer_white_18dp.png │ │ │ │ ├── ic_update_white_18dp.png │ │ │ │ ├── ic_mode_edit_white_18dp.png │ │ │ │ ├── ic_mode_edit_white_48dp.png │ │ │ │ ├── ic_money_off_white_18dp.png │ │ │ │ ├── ic_cloud_done_white_18dp.png │ │ │ │ ├── ic_date_range_white_18dp.png │ │ │ │ ├── ic_location_on_white_18dp.png │ │ │ │ ├── ic_location_on_white_24dp.png │ │ │ │ ├── ic_my_location_black_18dp.png │ │ │ │ ├── ic_restaurant_black_48dp.png │ │ │ │ ├── ic_restaurant_white_18dp.png │ │ │ │ ├── ic_attach_money_black_48dp.png │ │ │ │ ├── ic_cloud_download_white_18dp.png │ │ │ │ ├── ic_do_not_disturb_white_18dp.png │ │ │ │ ├── ic_local_shipping_black_48dp.png │ │ │ │ ├── ic_local_shipping_white_18dp.png │ │ │ │ ├── ic_bookmark_border_white_18dp.png │ │ │ │ ├── ic_local_grocery_store_black_48dp.png │ │ │ │ ├── ic_notifications_none_white_18dp.png │ │ │ │ ├── ic_record_voice_over_black_48dp.png │ │ │ │ └── ic_remove_shopping_cart_white_18dp.png │ │ │ ├── drawable-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_call_white_18dp.png │ │ │ │ ├── ic_flag_white_18dp.png │ │ │ │ ├── ic_timer_white_18dp.png │ │ │ │ ├── ic_search_white_24dp.png │ │ │ │ ├── ic_update_white_18dp.png │ │ │ │ ├── ic_cloud_done_white_18dp.png │ │ │ │ ├── ic_date_range_white_18dp.png │ │ │ │ ├── ic_mode_edit_white_18dp.png │ │ │ │ ├── ic_mode_edit_white_48dp.png │ │ │ │ ├── ic_money_off_white_18dp.png │ │ │ │ ├── ic_restaurant_black_48dp.png │ │ │ │ ├── ic_restaurant_white_18dp.png │ │ │ │ ├── ic_attach_money_black_48dp.png │ │ │ │ ├── ic_location_on_white_18dp.png │ │ │ │ ├── ic_location_on_white_24dp.png │ │ │ │ ├── ic_my_location_black_18dp.png │ │ │ │ ├── ic_bookmark_border_white_18dp.png │ │ │ │ ├── ic_cloud_download_white_18dp.png │ │ │ │ ├── ic_do_not_disturb_white_18dp.png │ │ │ │ ├── ic_local_shipping_black_48dp.png │ │ │ │ ├── ic_local_shipping_white_18dp.png │ │ │ │ ├── ic_notifications_none_white_18dp.png │ │ │ │ ├── ic_record_voice_over_black_48dp.png │ │ │ │ ├── ic_local_grocery_store_black_48dp.png │ │ │ │ └── ic_remove_shopping_cart_white_18dp.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ ├── status_icon.png │ │ │ │ ├── ic_call_white_18dp.png │ │ │ │ ├── ic_flag_white_18dp.png │ │ │ │ ├── ic_search_white_24dp.png │ │ │ │ ├── ic_timer_white_18dp.png │ │ │ │ ├── ic_update_white_18dp.png │ │ │ │ ├── ic_mode_edit_white_18dp.png │ │ │ │ ├── ic_mode_edit_white_48dp.png │ │ │ │ ├── ic_money_off_white_18dp.png │ │ │ │ ├── ic_attach_money_black_48dp.png │ │ │ │ ├── ic_cloud_done_white_18dp.png │ │ │ │ ├── ic_date_range_white_18dp.png │ │ │ │ ├── ic_location_on_white_18dp.png │ │ │ │ ├── ic_location_on_white_24dp.png │ │ │ │ ├── ic_my_location_black_18dp.png │ │ │ │ ├── ic_restaurant_black_48dp.png │ │ │ │ ├── ic_restaurant_white_18dp.png │ │ │ │ ├── ic_cloud_download_white_18dp.png │ │ │ │ ├── ic_do_not_disturb_white_18dp.png │ │ │ │ ├── ic_local_shipping_black_48dp.png │ │ │ │ ├── ic_local_shipping_white_18dp.png │ │ │ │ ├── ic_bookmark_border_white_18dp.png │ │ │ │ ├── ic_record_voice_over_black_48dp.png │ │ │ │ ├── ic_local_grocery_store_black_48dp.png │ │ │ │ ├── ic_notifications_none_white_18dp.png │ │ │ │ └── ic_remove_shopping_cart_white_18dp.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── layout │ │ │ │ ├── activity_mark.xml │ │ │ │ ├── activity_licenses.xml │ │ │ │ ├── dialog_text.xml │ │ │ │ ├── dialog_radio.xml │ │ │ │ ├── dialog_edit.xml │ │ │ │ ├── dialog_seek.xml │ │ │ │ ├── dialog_custom_api.xml │ │ │ │ ├── settings_toolbar.xml │ │ │ │ ├── activity_main.xml │ │ │ │ ├── float_window.xml │ │ │ │ ├── content_main.xml │ │ │ │ ├── preference.xml │ │ │ │ ├── mark_window.xml │ │ │ │ └── activity_appeal.xml │ │ │ ├── values-v21 │ │ │ │ └── styles.xml │ │ │ ├── values │ │ │ │ ├── dimens.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── arrays.xml │ │ │ │ └── styles.xml │ │ │ ├── drawable │ │ │ │ ├── ic_send_white_24dp.xml │ │ │ │ ├── ic_phone_auricular_with_a_cross_sign.xml │ │ │ │ └── ic_call_disconnected_24dp.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ ├── raw-zh │ │ │ │ └── privacy_notice.html │ │ │ ├── menu │ │ │ │ └── menu_main.xml │ │ │ └── raw │ │ │ │ └── privacy_notice.html │ │ ├── java │ │ │ └── org │ │ │ │ └── xdty │ │ │ │ └── callerinfo │ │ │ │ ├── contract │ │ │ │ ├── BasePresenter.kt │ │ │ │ ├── BaseView.kt │ │ │ │ ├── UpgradeContact.kt │ │ │ │ ├── MainBottomContact.kt │ │ │ │ ├── PhoneStateContract.kt │ │ │ │ └── MainContract.kt │ │ │ │ ├── model │ │ │ │ ├── SearchMode.kt │ │ │ │ ├── permission │ │ │ │ │ ├── Permission.kt │ │ │ │ │ └── PermissionImpl.kt │ │ │ │ ├── Status.kt │ │ │ │ ├── MarkType.kt │ │ │ │ ├── db │ │ │ │ │ ├── BaseInCall.java │ │ │ │ │ └── BaseMarkedRecord.java │ │ │ │ ├── database │ │ │ │ │ └── Database.kt │ │ │ │ ├── setting │ │ │ │ │ └── Setting.kt │ │ │ │ ├── CallRecord.kt │ │ │ │ └── TextColorPair.kt │ │ │ │ ├── settings │ │ │ │ ├── PluginStatus.kt │ │ │ │ ├── PreferenceDelegate.kt │ │ │ │ ├── PreferenceActions.kt │ │ │ │ └── dialog │ │ │ │ │ ├── TextDialog.kt │ │ │ │ │ ├── CustomApiDialog.kt │ │ │ │ │ ├── EditDialog.kt │ │ │ │ │ ├── SeekBarDialog.kt │ │ │ │ │ └── RadioDialog.kt │ │ │ │ ├── utils │ │ │ │ ├── Resource.kt │ │ │ │ ├── Config.kt │ │ │ │ ├── Constants.kt │ │ │ │ ├── Networks.kt │ │ │ │ ├── Toasts.kt │ │ │ │ ├── Alarm.kt │ │ │ │ ├── Contact.kt │ │ │ │ └── Window.kt │ │ │ │ ├── di │ │ │ │ ├── MainComponent.kt │ │ │ │ ├── UpgradeComponent.kt │ │ │ │ ├── MainBottomComponent.kt │ │ │ │ ├── PhoneStatusComponent.kt │ │ │ │ ├── modules │ │ │ │ │ ├── MainModule.kt │ │ │ │ │ ├── UpgradeModule.kt │ │ │ │ │ ├── MainBottomModule.kt │ │ │ │ │ ├── PhoneStatusModule.kt │ │ │ │ │ └── AppModule.kt │ │ │ │ └── AppComponent.kt │ │ │ │ ├── activity │ │ │ │ ├── BaseActivity.kt │ │ │ │ ├── SettingsActivity.kt │ │ │ │ └── LicensesActivity.kt │ │ │ │ ├── data │ │ │ │ └── CallerDataSource.kt │ │ │ │ ├── application │ │ │ │ └── Application.kt │ │ │ │ ├── presenter │ │ │ │ └── MainBottomPresenter.kt │ │ │ │ ├── service │ │ │ │ └── ScheduleService.kt │ │ │ │ └── exporter │ │ │ │ └── Exporter.kt │ │ └── aidl │ │ │ └── org │ │ │ └── xdty │ │ │ └── callerinfo │ │ │ └── plugin │ │ │ ├── IPluginServiceCallback.aidl │ │ │ └── IPluginService.aidl │ ├── androidTest │ │ └── AndroidManifest.xml │ ├── test │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── org │ │ │ └── xdty │ │ │ └── callerinfo │ │ │ ├── ExampleUnitTest.java │ │ │ ├── exporter │ │ │ └── ExporterTest.java │ │ │ └── CallerRepositoryTest.java │ └── debug │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── org │ │ └── xdty │ │ └── callerinfo │ │ └── application │ │ └── DebugApplication.java ├── proguard-test-rules.pro └── proguard-rules.pro ├── plugin ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_plugin_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_plugin_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_plugin_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_plugin_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_plugin_launcher.png │ │ │ ├── values │ │ │ │ ├── dimens.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── styles.xml │ │ │ │ └── strings.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ ├── menu │ │ │ │ └── plugin_menu.xml │ │ │ ├── layout │ │ │ │ ├── activity_licenses.xml │ │ │ │ └── activity_main.xml │ │ │ ├── values-zh │ │ │ │ └── strings.xml │ │ │ ├── drawable │ │ │ │ └── ic_puzzle_black_24dp.xml │ │ │ ├── raw-zh │ │ │ │ └── privacy_notice.html │ │ │ └── raw │ │ │ │ └── privacy_notice.html │ │ ├── aidl │ │ │ └── org │ │ │ │ └── xdty │ │ │ │ └── callerinfo │ │ │ │ └── plugin │ │ │ │ ├── IPluginServiceCallback.aidl │ │ │ │ └── IPluginService.aidl │ │ ├── java │ │ │ └── org │ │ │ │ └── xdty │ │ │ │ └── callerinfo │ │ │ │ └── plugin │ │ │ │ ├── Utils.java │ │ │ │ └── LicensesActivity.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── org │ │ │ └── xdty │ │ │ └── callerinfo │ │ │ └── plugin │ │ │ └── ExampleUnitTest.java │ ├── androidTest │ │ └── java │ │ │ └── org │ │ │ └── xdty │ │ │ └── callerinfo │ │ │ └── plugin │ │ │ └── ApplicationTest.java │ └── google │ │ └── AndroidManifest.xml ├── proguard-rules.pro └── build.gradle ├── public.tar.enc ├── secrets.tar.enc ├── screenshots ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png ├── 9.png ├── p-1.png ├── p-2.png ├── en-play-badge.png └── en-play-badge-border.png ├── art ├── web_hi_res_512.png ├── plugin_web_hi_res_512.png └── phone_auricular_with-a_cross_sign.svg ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── signing.properties.example ├── manifest.properties.example ├── ISSUE_TEMPLATE.md ├── settings.gradle ├── .gitmodules ├── .gitlab-ci.yml ├── .gitignore ├── gradle.properties ├── .travis ├── env.sh ├── changelog.sh └── github_release.rb ├── signing.gradle ├── manifest.gradle ├── DEVELOPMENT-CN.md ├── .github └── workflows │ └── android.yml └── gradlew.bat /log/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /log/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /plugin/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /public.tar.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/public.tar.enc -------------------------------------------------------------------------------- /secrets.tar.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/secrets.tar.enc -------------------------------------------------------------------------------- /screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/1.png -------------------------------------------------------------------------------- /screenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/2.png -------------------------------------------------------------------------------- /screenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/3.png -------------------------------------------------------------------------------- /screenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/4.png -------------------------------------------------------------------------------- /screenshots/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/5.png -------------------------------------------------------------------------------- /screenshots/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/6.png -------------------------------------------------------------------------------- /screenshots/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/7.png -------------------------------------------------------------------------------- /screenshots/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/8.png -------------------------------------------------------------------------------- /screenshots/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/9.png -------------------------------------------------------------------------------- /screenshots/p-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/p-1.png -------------------------------------------------------------------------------- /screenshots/p-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/p-2.png -------------------------------------------------------------------------------- /art/web_hi_res_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/art/web_hi_res_512.png -------------------------------------------------------------------------------- /app/src/main/assets/sugar_upgrades/4.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE CALLER ADD IS_OFFLINE boolean NOT NULL default 1; 2 | -------------------------------------------------------------------------------- /art/plugin_web_hi_res_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/art/plugin_web_hi_res_512.png -------------------------------------------------------------------------------- /screenshots/en-play-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/en-play-badge.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /screenshots/en-play-badge-border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/screenshots/en-play-badge-border.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /log/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /signing.properties.example: -------------------------------------------------------------------------------- 1 | storeFile=release.jks 2 | storePassword=keystore_password 3 | keyAlias=key_alias 4 | keyPassword=key_password 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/status_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/status_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/status_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/status_icon.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /manifest.properties.example: -------------------------------------------------------------------------------- 1 | API_KEY=YOUR_API_KEY 2 | JUHE_API_KEY=YOUR_API_KEY 3 | LEANCLOUD_APP_ID=YOUR_APP_ID 4 | LEANCLOUD_APP_KEY=YOUR_APP_KEY -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/status_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/status_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/status_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/status_icon.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/contract/BasePresenter.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.contract 2 | 3 | interface BasePresenter { 4 | fun start() 5 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/model/SearchMode.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.model 2 | 3 | enum class SearchMode { 4 | ONLINE, OFFLINE, IGNORE 5 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_call_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_call_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_flag_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_flag_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_timer_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_timer_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_call_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_call_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_flag_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_flag_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_timer_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_timer_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_call_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_call_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_flag_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_flag_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /plugin/src/main/res/mipmap-hdpi/ic_plugin_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/plugin/src/main/res/mipmap-hdpi/ic_plugin_launcher.png -------------------------------------------------------------------------------- /plugin/src/main/res/mipmap-mdpi/ic_plugin_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/plugin/src/main/res/mipmap-mdpi/ic_plugin_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_search_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_search_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_update_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_update_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_search_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_search_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_update_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_update_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_search_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_search_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_timer_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_timer_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_update_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_update_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_call_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_call_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_flag_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_flag_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_timer_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_timer_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_call_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_call_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_flag_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_flag_white_18dp.png -------------------------------------------------------------------------------- /plugin/src/main/res/mipmap-xhdpi/ic_plugin_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/plugin/src/main/res/mipmap-xhdpi/ic_plugin_launcher.png -------------------------------------------------------------------------------- /plugin/src/main/res/mipmap-xxhdpi/ic_plugin_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/plugin/src/main/res/mipmap-xxhdpi/ic_plugin_launcher.png -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/contract/BaseView.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.contract 2 | 3 | interface BaseView { 4 | fun setPresenter(presenter: T) 5 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_cloud_done_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_cloud_done_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_date_range_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_date_range_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_mode_edit_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_mode_edit_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_mode_edit_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_mode_edit_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_money_off_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_money_off_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_restaurant_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_restaurant_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_restaurant_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_restaurant_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_cloud_done_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_cloud_done_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_date_range_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_date_range_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_mode_edit_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_mode_edit_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_mode_edit_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_mode_edit_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_money_off_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_money_off_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_restaurant_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_restaurant_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_restaurant_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_restaurant_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_mode_edit_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_mode_edit_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_mode_edit_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_mode_edit_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_money_off_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_money_off_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_update_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_update_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_timer_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_timer_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_update_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_update_white_18dp.png -------------------------------------------------------------------------------- /plugin/src/main/res/mipmap-xxxhdpi/ic_plugin_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/plugin/src/main/res/mipmap-xxxhdpi/ic_plugin_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_attach_money_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_attach_money_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_location_on_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_location_on_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_location_on_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_location_on_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_my_location_black_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_my_location_black_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_attach_money_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_attach_money_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_location_on_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_location_on_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_location_on_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_location_on_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_my_location_black_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_my_location_black_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_cloud_done_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_cloud_done_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_date_range_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_date_range_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_location_on_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_location_on_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_location_on_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_location_on_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_my_location_black_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_my_location_black_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_restaurant_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_restaurant_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_restaurant_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_restaurant_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_cloud_done_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_cloud_done_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_date_range_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_date_range_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_mode_edit_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_mode_edit_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_mode_edit_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_mode_edit_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_money_off_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_money_off_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_restaurant_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_restaurant_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_restaurant_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_restaurant_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_mode_edit_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_mode_edit_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_mode_edit_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_mode_edit_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_money_off_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_money_off_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_bookmark_border_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_bookmark_border_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_cloud_download_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_cloud_download_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_do_not_disturb_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_do_not_disturb_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_local_shipping_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_local_shipping_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_local_shipping_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_local_shipping_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_bookmark_border_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_bookmark_border_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_cloud_download_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_cloud_download_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_do_not_disturb_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_do_not_disturb_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_local_shipping_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_local_shipping_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_local_shipping_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_local_shipping_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_attach_money_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_attach_money_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_cloud_download_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_cloud_download_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_do_not_disturb_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_do_not_disturb_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_local_shipping_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_local_shipping_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_local_shipping_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_local_shipping_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_attach_money_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_attach_money_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_location_on_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_location_on_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_location_on_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_location_on_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_my_location_black_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_my_location_black_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_attach_money_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_attach_money_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_cloud_done_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_cloud_done_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_date_range_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_date_range_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_location_on_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_location_on_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_location_on_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_location_on_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_my_location_black_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_my_location_black_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_restaurant_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_restaurant_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_restaurant_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_restaurant_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_record_voice_over_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_record_voice_over_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_record_voice_over_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_record_voice_over_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_bookmark_border_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_bookmark_border_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_bookmark_border_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_bookmark_border_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_cloud_download_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_cloud_download_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_do_not_disturb_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_do_not_disturb_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_local_shipping_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_local_shipping_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_local_shipping_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_local_shipping_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_cloud_download_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_cloud_download_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_do_not_disturb_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_do_not_disturb_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_local_shipping_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_local_shipping_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_local_shipping_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_local_shipping_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_local_grocery_store_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_local_grocery_store_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_notifications_none_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_notifications_none_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_remove_shopping_cart_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-hdpi/ic_remove_shopping_cart_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_local_grocery_store_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_local_grocery_store_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_notifications_none_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_notifications_none_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_remove_shopping_cart_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-mdpi/ic_remove_shopping_cart_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_local_grocery_store_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_local_grocery_store_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_notifications_none_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_notifications_none_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_record_voice_over_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_record_voice_over_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_notifications_none_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_notifications_none_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_record_voice_over_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_record_voice_over_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_bookmark_border_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_bookmark_border_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_record_voice_over_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_record_voice_over_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_remove_shopping_cart_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xhdpi/ic_remove_shopping_cart_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_local_grocery_store_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_local_grocery_store_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_remove_shopping_cart_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxhdpi/ic_remove_shopping_cart_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_local_grocery_store_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_local_grocery_store_black_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_notifications_none_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_notifications_none_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_remove_shopping_cart_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdtianyu/CallerInfo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_remove_shopping_cart_white_18dp.png -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/settings/PluginStatus.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.settings 2 | 3 | object PluginStatus { 4 | @JvmField 5 | var isCheckStorageExport = false 6 | 7 | @JvmField 8 | var isCheckRingOnce = false 9 | } -------------------------------------------------------------------------------- /plugin/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /plugin/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/androidTest/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/assets/sugar_upgrades/5.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE CALLER; 2 | CREATE TABLE IF NOT EXISTS CALLER ( ID INTEGER PRIMARY KEY AUTOINCREMENT , CITY TEXT, COUNT INTEGER, IS_OFFLINE INTEGER, LAST_UPDATE INTEGER, NAME TEXT, NUMBER TEXT UNIQUE, OPERATORS TEXT, PROVINCE TEXT, TYPE TEXT ); -------------------------------------------------------------------------------- /app/src/test/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *感谢您对【来电信息】应用的反馈* 2 | *如果您正在提交一个 BUG,请按照模板填写信息。* 3 | *如果您正在提交一个功能请求,请填写使用情景以便我们获取必要的信息* 4 | 5 | #### 应用版本: 6 | 7 | #### 系统版本: 8 | 9 | #### 手机品牌及型号: 10 | 11 | #### 预置条件: 12 | 13 | #### 复现步骤: 14 | 1. 15 | 2. 16 | 17 | #### 期望结果: 18 | 19 | #### 实际结果: 20 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':plugin' 2 | include ':standOut' 3 | include ':phone-number' 4 | include ':config' 5 | 6 | project(':phone-number').projectDir = new File('PhoneNumber/phone-number') 7 | project(':config').projectDir = new File('config/config') 8 | include ':log' 9 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/settings/PreferenceDelegate.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.settings 2 | 3 | class PreferenceDelegate { 4 | lateinit var clicker: PreferenceClicker 5 | lateinit var dialogs: PreferenceDialogs 6 | lateinit var actions: PreferenceActions 7 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Mar 22 16:12:18 CST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https://services.gradle.org/distributions/gradle-6.5-bin.zip 7 | -------------------------------------------------------------------------------- /log/src/main/java/org/xdty/log/NoLog.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.log 2 | 3 | import android.util.Log 4 | 5 | object NoLog { 6 | fun d(tag: String, msg: String) { 7 | Log.d(tag, msg) 8 | } 9 | 10 | fun e(tag: String, msg: String) { 11 | Log.e(tag, msg) 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_mark.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | > 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "standOut"] 2 | path = standOut 3 | url = https://github.com/xdtianyu/StandOut.git 4 | [submodule "PhoneNumber"] 5 | path = PhoneNumber 6 | url = https://github.com/xdtianyu/PhoneNumber.git 7 | [submodule "config"] 8 | path = config 9 | url = https://github.com/xdtianyu/AppConfig.git 10 | -------------------------------------------------------------------------------- /app/src/main/aidl/org/xdty/callerinfo/plugin/IPluginServiceCallback.aidl: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.plugin; 2 | 3 | interface IPluginServiceCallback { 4 | void onCallPermissionResult(boolean success); 5 | void onCallLogPermissionResult(boolean success); 6 | void onStoragePermissionResult(boolean success); 7 | } 8 | -------------------------------------------------------------------------------- /plugin/src/main/aidl/org/xdty/callerinfo/plugin/IPluginServiceCallback.aidl: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.plugin; 2 | 3 | interface IPluginServiceCallback { 4 | void onCallPermissionResult(boolean success); 5 | void onCallLogPermissionResult(boolean success); 6 | void onStoragePermissionResult(boolean success); 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/utils/Resource.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.utils 2 | 3 | import android.content.Context 4 | import android.content.res.Resources 5 | 6 | object Resource { 7 | lateinit var resources: Resources 8 | 9 | fun init(context: Context) { 10 | resources = context.resources 11 | } 12 | } -------------------------------------------------------------------------------- /app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/utils/Config.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.utils 2 | 3 | class Config private constructor() { 4 | companion object { 5 | const val MAX_UPDATE_CIRCLE = 2 * 24 * 3600 * 1000.toLong() 6 | } 7 | 8 | init { 9 | throw AssertionError("Config class is not meant to be instantiated or subclassed.") 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/assets/sugar_upgrades/6.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE CALLER; 2 | CREATE TABLE IF NOT EXISTS CALLER ( 3 | ID INTEGER PRIMARY KEY AUTOINCREMENT, 4 | CITY TEXT, 5 | COUNT INTEGER, 6 | IS_OFFLINE INTEGER, 7 | LAST_UPDATE INTEGER, 8 | NAME TEXT, 9 | NUMBER TEXT UNIQUE, 10 | OPERATORS TEXT, 11 | PROVINCE TEXT, 12 | TYPE TEXT, 13 | SOURCE INTEGER 14 | ); -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /plugin/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_send_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/test/java/org/xdty/callerinfo/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /plugin/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/test/java/org/xdty/callerinfo/exporter/ExporterTest.java: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.exporter; 2 | 3 | import org.junit.Test; 4 | 5 | public class ExporterTest { 6 | 7 | @Test 8 | public void export() { 9 | } 10 | 11 | @Test 12 | public void exportSync() { 13 | } 14 | 15 | @Test 16 | public void fromString() { 17 | } 18 | 19 | @Test 20 | public void fromStringSync() { 21 | } 22 | } -------------------------------------------------------------------------------- /plugin/src/test/java/org/xdty/callerinfo/plugin/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.plugin; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /plugin/src/main/res/menu/plugin_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/di/MainComponent.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.di 2 | 3 | import dagger.Component 4 | import org.xdty.callerinfo.activity.MainActivity 5 | import org.xdty.callerinfo.di.modules.AppModule 6 | import org.xdty.callerinfo.di.modules.MainModule 7 | import javax.inject.Singleton 8 | 9 | @Singleton 10 | @Component(modules = [MainModule::class, AppModule::class]) 11 | interface MainComponent { 12 | fun inject(view: MainActivity) 13 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/utils/Constants.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.utils 2 | 3 | object Constants { 4 | const val DB_NAME = "phone_number.db" 5 | const val DB_VERSION = 6 6 | const val CONTACT_CACHE_INTERVAL = 60 * 1000 7 | const val VERBOSE_NOTIFICATION_CHANNEL_NAME = "CallerInfo" 8 | const val VERBOSE_NOTIFICATION_CHANNEL_DESCRIPTION = "CallerInfo" 9 | const val CHANNEL_ID = "caller" 10 | const val NOTIFICATION_ID = 10001 11 | } -------------------------------------------------------------------------------- /plugin/src/androidTest/java/org/xdty/callerinfo/plugin/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.plugin; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/proguard-test-rules.pro: -------------------------------------------------------------------------------- 1 | # Proguard rules that are applied to your test apk/code. 2 | -dontobfuscate 3 | 4 | -ignorewarnings 5 | 6 | -keepattributes *Annotation* 7 | 8 | -dontnote junit.framework.** 9 | -dontnote junit.runner.** 10 | 11 | -dontwarn android.test.** 12 | -dontwarn android.support.test.** 13 | -dontwarn org.junit.** 14 | -dontwarn org.hamcrest.** 15 | -dontwarn com.squareup.javawriter.JavaWriter 16 | # Uncomment this if you use Mockito 17 | #-dontwarn org.mockito.** -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_licenses.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /plugin/src/main/res/layout/activity_licenses.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/di/UpgradeComponent.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.di 2 | 3 | import dagger.Component 4 | import org.xdty.callerinfo.di.modules.AppModule 5 | import org.xdty.callerinfo.di.modules.UpgradeModule 6 | import org.xdty.callerinfo.worker.UpgradeWorker 7 | import javax.inject.Singleton 8 | 9 | 10 | @Singleton 11 | @Component(modules = [AppModule::class, UpgradeModule::class]) 12 | interface UpgradeComponent { 13 | fun inject(upgradeWorker: UpgradeWorker) 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/model/permission/Permission.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.model.permission 2 | 3 | import android.content.Context 4 | 5 | interface Permission { 6 | fun canDrawOverlays(): Boolean 7 | fun requestDrawOverlays(context: Context, requestCode: Int) 8 | fun checkPermission(permission: String): Int 9 | fun requestPermissions(context: Context, permissions: Array, requestCode: Int) 10 | fun canReadPhoneState(): Boolean 11 | fun canReadContact(): Boolean 12 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/di/MainBottomComponent.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.di 2 | 3 | import dagger.Component 4 | import org.xdty.callerinfo.di.modules.AppModule 5 | import org.xdty.callerinfo.di.modules.MainBottomModule 6 | import org.xdty.callerinfo.fragment.MainBottomSheetFragment 7 | import javax.inject.Singleton 8 | 9 | @Singleton 10 | @Component(modules = [MainBottomModule::class, AppModule::class]) 11 | interface MainBottomComponent { 12 | fun inject(mainBottomSheetFragment: MainBottomSheetFragment) 13 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/di/PhoneStatusComponent.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.di 2 | 3 | import dagger.Component 4 | import org.xdty.callerinfo.di.modules.AppModule 5 | import org.xdty.callerinfo.di.modules.PhoneStatusModule 6 | import org.xdty.callerinfo.receiver.IncomingCall.PhoneStateListener 7 | import javax.inject.Singleton 8 | 9 | @Singleton 10 | @Component(modules = [PhoneStatusModule::class, AppModule::class]) 11 | interface PhoneStatusComponent { 12 | fun inject(phoneStateListener: PhoneStateListener) 13 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/model/Status.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.model 2 | 3 | import androidx.annotation.Keep 4 | 5 | @Keep 6 | data class Status( 7 | var version: Int, 8 | var count: Int, 9 | var newCount: Int, 10 | var timestamp: Long, 11 | var md5: String, 12 | var url: String 13 | ) { 14 | override fun toString(): String { 15 | return "Status(version=$version, count=$count, newCount=$newCount, timestamp=$timestamp, md5='$md5', url='$url')" 16 | } 17 | } -------------------------------------------------------------------------------- /plugin/src/google/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/contract/UpgradeContact.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.contract 2 | 3 | import android.content.Context 4 | import androidx.work.ListenableWorker 5 | import org.xdty.callerinfo.model.Status 6 | 7 | interface UpgradeContact { 8 | 9 | interface View : BaseView { 10 | fun showSucceedNotification(status: Status) 11 | 12 | fun showFailedNotification(error: Exception) 13 | } 14 | 15 | interface Presenter : BasePresenter { 16 | fun upgradeOfflineData(context: Context): ListenableWorker.Result 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/aidl/org/xdty/callerinfo/plugin/IPluginService.aidl: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.plugin; 2 | 3 | import org.xdty.callerinfo.plugin.IPluginServiceCallback; 4 | 5 | interface IPluginService { 6 | void checkCallPermission(); 7 | void checkCallLogPermission(); 8 | void hangUpPhoneCall(); 9 | void updateCallLog(String number, String name); 10 | void registerCallback(IPluginServiceCallback callback); 11 | String exportData(String data); 12 | String importData(); 13 | void checkStoragePermission(); 14 | void setIconStatus(boolean enabled); 15 | } 16 | -------------------------------------------------------------------------------- /plugin/src/main/aidl/org/xdty/callerinfo/plugin/IPluginService.aidl: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.plugin; 2 | 3 | import org.xdty.callerinfo.plugin.IPluginServiceCallback; 4 | 5 | interface IPluginService { 6 | void checkCallPermission(); 7 | void checkCallLogPermission(); 8 | void hangUpPhoneCall(); 9 | void updateCallLog(String number, String name); 10 | void registerCallback(IPluginServiceCallback callback); 11 | String exportData(String data); 12 | String importData(); 13 | void checkStoragePermission(); 14 | void setIconStatus(boolean enabled); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/settings/PreferenceActions.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.settings 2 | 3 | import android.preference.Preference 4 | 5 | interface PreferenceActions { 6 | fun findPreference(key: CharSequence?): Preference? 7 | fun setChecked(key: Int, checked: Boolean) 8 | fun onConfirmed(key: Int) 9 | fun onConfirmCanceled(key: Int) 10 | fun checkOfflineData() 11 | fun resetOfflineDataUpgradeWorker() 12 | fun addPreference(parent: Int, child: Int) 13 | fun removePreference(parent: Int, child: Int) 14 | fun getKeyId(key: String?): Int 15 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_radio.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | #ff33b5e5 7 | #ffff8800 8 | #ffff4444 9 | #00000000 10 | #60000000 11 | #ffffffff 12 | 13 | #20000000 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/di/modules/MainModule.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.di.modules 2 | 3 | import dagger.Module 4 | import dagger.Provides 5 | import org.xdty.callerinfo.contract.MainContract.Presenter 6 | import org.xdty.callerinfo.contract.MainContract.View 7 | import org.xdty.callerinfo.presenter.MainPresenter 8 | 9 | @Module 10 | class MainModule(private val mView: View) { 11 | @Provides 12 | internal fun provideView(): View { 13 | return mView 14 | } 15 | 16 | @Provides 17 | internal fun providePresenter(): Presenter { 18 | return MainPresenter(mView) 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/utils/Networks.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.utils 2 | 3 | import okhttp3.OkHttpClient 4 | import okhttp3.Request 5 | 6 | object Networks { 7 | 8 | private const val url_204 = "https://ip.xdty.org/generate_204" 9 | 10 | fun hasNetwork(): Boolean { 11 | return try { 12 | val request = Request.Builder() 13 | .url(url_204) 14 | .build() 15 | OkHttpClient().newCall(request).execute().code == 204 16 | } catch (e: Exception) { 17 | e.printStackTrace() 18 | false 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/di/modules/UpgradeModule.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.di.modules 2 | 3 | import dagger.Module 4 | import dagger.Provides 5 | import org.xdty.callerinfo.contract.UpgradeContact 6 | import org.xdty.callerinfo.presenter.UpgradePresenter 7 | 8 | @Module 9 | class UpgradeModule(view: UpgradeContact.View) { 10 | private var mView: UpgradeContact.View = view 11 | 12 | @Provides 13 | fun provideView(): UpgradeContact.View { 14 | return mView 15 | } 16 | 17 | @Provides 18 | fun providePresenter(): UpgradeContact.Presenter { 19 | return UpgradePresenter(mView) 20 | } 21 | } -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: xdtianyu/docker:openjdk8 2 | before_script: 3 | - git submodule sync --recursive 4 | - git submodule update --init --recursive 5 | - source .travis/env.sh 6 | - source /opt/setup-android-sdk.sh 7 | - openssl aes-256-cbc -K $encrypted_75846693d905_key -iv $encrypted_75846693d905_iv -in secrets.tar.enc -out secrets.tar -d 8 | - tar xvf secrets.tar 9 | - touch local.properties 10 | stages: 11 | - build 12 | build: 13 | stage: build 14 | script: 15 | - ./gradlew assembleDebug 16 | after_script: 17 | - mkdir -p dist/ && find -name \*.apk -exec cp {} dist/ \; 18 | artifacts: 19 | paths: 20 | - "dist/*.apk" 21 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/di/modules/MainBottomModule.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.di.modules 2 | 3 | import dagger.Module 4 | import dagger.Provides 5 | import org.xdty.callerinfo.contract.MainBottomContact.Presenter 6 | import org.xdty.callerinfo.contract.MainBottomContact.View 7 | import org.xdty.callerinfo.presenter.MainBottomPresenter 8 | 9 | @Module 10 | class MainBottomModule(private val mView: View) { 11 | @Provides 12 | internal fun provideView(): View { 13 | return mView 14 | } 15 | 16 | @Provides 17 | internal fun providePresenter(): Presenter { 18 | return MainBottomPresenter(mView) 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/contract/MainBottomContact.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.contract 2 | 3 | import org.xdty.callerinfo.model.db.Caller 4 | import org.xdty.callerinfo.model.db.InCall 5 | 6 | interface MainBottomContact { 7 | interface View : BaseView { 8 | fun init(inCall: InCall, caller: Caller) 9 | fun updateMark(viewId: Int, caller: Caller) 10 | fun updateMarkName(name: String?) 11 | } 12 | 13 | interface Presenter : BasePresenter { 14 | fun bindData(inCall: InCall?) 15 | fun canMark(): Boolean 16 | fun markClicked(viewId: Int) 17 | fun markCustom(text: String?) 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/di/modules/PhoneStatusModule.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.di.modules 2 | 3 | import dagger.Module 4 | import dagger.Provides 5 | import org.xdty.callerinfo.contract.PhoneStateContract.Presenter 6 | import org.xdty.callerinfo.contract.PhoneStateContract.View 7 | import org.xdty.callerinfo.presenter.PhoneStatePresenter 8 | import javax.inject.Singleton 9 | 10 | @Module 11 | class PhoneStatusModule(private var mView: View) { 12 | @Provides 13 | internal fun provideView(): View { 14 | return mView 15 | } 16 | 17 | @Singleton 18 | @Provides 19 | internal fun providePresenter(): Presenter { 20 | return PhoneStatePresenter(mView) 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/settings/dialog/TextDialog.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.settings.dialog 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import android.view.View 6 | import android.widget.TextView 7 | import org.xdty.callerinfo.R 8 | 9 | class TextDialog(context: Context, sharedPrefs: SharedPreferences) : SettingsDialog(context, sharedPrefs) { 10 | 11 | override fun bindViews() { 12 | val layout = View.inflate(context, R.layout.dialog_text, null) 13 | builder.setView(layout) 14 | 15 | val textView: TextView = layout.findViewById(R.id.text) 16 | textView.text = text 17 | } 18 | 19 | override fun onConfirm() { 20 | 21 | } 22 | } -------------------------------------------------------------------------------- /plugin/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 来电信息插件 4 | 隐私权声明 5 | 开放源代码许可 6 | 插件版本:%1$s 7 | 插件版本号:%1$d 8 | 来电信息主程序未安装 9 | 安装 10 | 设置 11 | 请更新主应用以支持此操作 12 | 此版本不支持写入通话记录,建议更新到 完整版本 13 | 插件服务正在运行 14 | -------------------------------------------------------------------------------- /plugin/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/ty/Android/Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -dontobfuscate 19 | -keep class org.xdty.** { *; } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/activity/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.activity 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import androidx.appcompat.app.AppCompatActivity 6 | import org.xdty.callerinfo.utils.Utils 7 | 8 | abstract class BaseActivity : AppCompatActivity() { 9 | 10 | override fun onCreate(savedInstanceState: Bundle?) { 11 | super.onCreate(savedInstanceState) 12 | setContentView(layoutId) 13 | setTitle(titleId) 14 | } 15 | 16 | override fun attachBaseContext(newBase: Context) { 17 | val context: Context = Utils.changeLang(newBase) 18 | super.attachBaseContext(context) 19 | } 20 | 21 | protected abstract val layoutId: Int 22 | protected abstract val titleId: Int 23 | } -------------------------------------------------------------------------------- /plugin/src/main/res/drawable/ic_puzzle_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # Windows thumbnail db 19 | Thumbs.db 20 | 21 | # OSX files 22 | .DS_Store 23 | 24 | # Eclipse project files 25 | .classpath 26 | .project 27 | 28 | # Android Studio 29 | *.iml 30 | .idea 31 | #.idea/workspace.xml - remove # and delete .idea if it better suit your needs. 32 | .gradle 33 | build/ 34 | 35 | #NDK 36 | obj/ 37 | 38 | /*/out 39 | /*/*/build 40 | /*/*/production 41 | *.iws 42 | *.ipr 43 | *~ 44 | *.swp 45 | 46 | # release key file 47 | release.jks 48 | signing.properties 49 | manifest.properties 50 | 51 | *.log 52 | 53 | google-services.json 54 | secrets.tar 55 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_seek.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | -------------------------------------------------------------------------------- /log/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_custom_api.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/data/CallerDataSource.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.data 2 | 3 | import io.reactivex.Observable 4 | import org.xdty.callerinfo.model.SearchMode 5 | import org.xdty.callerinfo.model.db.Caller 6 | 7 | interface CallerDataSource { 8 | fun getCallerFromCache(number: String): Caller 9 | fun getCaller(number: String): Observable 10 | fun getCaller(number: String, forceOffline: Boolean): Observable 11 | fun loadCallerMap(): Observable> 12 | fun setOnDataUpdateListener(listener: OnDataUpdateListener) 13 | fun clearCache(): Observable 14 | fun updateCaller(number: String, type: Int, typeText: String) 15 | fun isIgnoreContact(number: String): Boolean 16 | fun getSearchMode(number: String): SearchMode 17 | 18 | interface OnDataUpdateListener { 19 | fun onDataUpdate(caller: Caller) 20 | } 21 | } -------------------------------------------------------------------------------- /plugin/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CallerInfo Plugin 3 | Privacy policy 4 | License 5 | Plugin Version: %1$s 6 | Plugin Version code: %1$d 7 | CallerInfo main app is not installed 8 | Install 9 | Setting 10 | Please update CallerInfo to support this action 11 | This plugin version does not support write to call log, please upgrade to full version 12 | Plugin service is running 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/settings_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Thu May 12 20:19:27 CST 2016 16 | android.useAndroidX=true 17 | android.enableJetifier=true 18 | 19 | org.gradle.daemon=true 20 | org.gradle.parallel=true 21 | org.gradle.configureondemand=true 22 | org.gradle.jvmargs=-Xmx3g -XX:MaxPermSize=2048m 23 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/model/MarkType.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.model 2 | 3 | import org.xdty.callerinfo.R 4 | 5 | enum class MarkType(private val mType: Int) { 6 | 7 | HARASSMENT(0), 8 | FRAUD(1), 9 | ADVERTISING(2), 10 | EXPRESS_DELIVERY(3), 11 | RESTAURANT_DELIVER(4), 12 | CUSTOM(5); 13 | 14 | fun toInt(): Int { 15 | return mType 16 | } 17 | 18 | companion object { 19 | fun fromInt(value: Int): MarkType { 20 | return if (value >= 0 && value < values().size) { 21 | values()[value] 22 | } else CUSTOM 23 | } 24 | 25 | fun fromResourceId(id: Int): MarkType { 26 | return when (id) { 27 | R.id.fraud -> FRAUD 28 | R.id.harassment -> HARASSMENT 29 | R.id.advertising -> ADVERTISING 30 | R.id.express -> EXPRESS_DELIVERY 31 | R.id.restaurant -> RESTAURANT_DELIVER 32 | else -> CUSTOM 33 | } 34 | } 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /app/src/test/java/org/xdty/callerinfo/CallerRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo; 2 | 3 | import org.junit.Test; 4 | import org.xdty.callerinfo.data.CallerRepository; 5 | 6 | import static org.junit.Assert.assertEquals; 7 | 8 | public class CallerRepositoryTest { 9 | 10 | @Test 11 | public void testFixNumber() { 12 | assertEquals(CallerRepository.fixNumber("+400123456"), "400123456"); 13 | assertEquals(CallerRepository.fixNumber("+8612345678"), "12345678"); 14 | assertEquals(CallerRepository.fixNumber("8612345678"), "12345678"); 15 | assertEquals(CallerRepository.fixNumber("8612583112345678"), "12345678"); 16 | assertEquals(CallerRepository.fixNumber("8612583212345678"), "12345678"); 17 | assertEquals(CallerRepository.fixNumber("8612583312345678"), "12345678"); 18 | assertEquals(CallerRepository.fixNumber("12583312345678"), "12345678"); 19 | assertEquals(CallerRepository.fixNumber("125902312345678"), "12345678"); 20 | assertEquals(CallerRepository.fixNumber("118334812345678"), "12345678"); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_phone_auricular_with_a_cross_sign.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/contract/PhoneStateContract.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.contract 2 | 3 | import android.content.Context 4 | import org.xdty.phone.number.model.INumber 5 | 6 | interface PhoneStateContract { 7 | interface View { 8 | fun show(number: INumber) 9 | fun showFailed(isOnline: Boolean) 10 | fun showSearching() 11 | fun hide(number: String) 12 | fun close(number: String) 13 | val isShowing: Boolean 14 | val context: Context 15 | fun showMark(number: String) 16 | } 17 | 18 | interface Presenter : BasePresenter { 19 | fun matchIgnore(number: String): Boolean 20 | fun handleRinging(number: String) 21 | fun handleOffHook(number: String) 22 | fun handleIdle(number: String) 23 | fun resetCallRecord() 24 | fun checkClose(number: String): Boolean 25 | fun isIncoming(number: String): Boolean 26 | fun saveInCall() 27 | val isRingOnce: Boolean 28 | fun searchNumber(number: String) 29 | fun setOutGoingNumber(number: String) 30 | fun canReadPhoneState(): Boolean 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/utils/Toasts.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.utils 2 | 3 | import android.content.Context 4 | import android.os.Handler 5 | import android.os.Looper 6 | import android.widget.Toast 7 | 8 | object Toasts { 9 | private val handler = Handler(Looper.getMainLooper()) 10 | private val map: HashMap = HashMap() 11 | private const val DURATION = 4000L 12 | 13 | fun show(context: Context, msg: Int) { 14 | show(context, context.getText(msg)) 15 | } 16 | 17 | fun show(context: Context, msg: CharSequence) { 18 | handler.post { 19 | checkExpires() 20 | val toast = Toast.makeText(context, msg, Toast.LENGTH_LONG) 21 | map[toast] = System.currentTimeMillis() 22 | val delay = DURATION * (map.size - 1) 23 | handler.postDelayed({ toast.show() }, delay) 24 | } 25 | } 26 | 27 | private fun checkExpires() { 28 | with(map.entries.iterator()) { 29 | forEach { 30 | if (it.value < System.currentTimeMillis() - DURATION) { 31 | remove() 32 | } 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/res/raw-zh/privacy_notice.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 19 | Privacy Notice 20 | 21 | 22 | 23 |

隐私权声明

24 |
25 |

26 |

来电信息是一个 GitHub 开放源代码项目, 我们承诺不会收集您的任何隐私信息。

27 |

28 |

联系人信息使用的说明

29 |

根据您的设置, 我们仅在本地使用您的联系人信息来略过查找号码的过程, 此信息不会分享给任何人。

30 |

31 |

电话状态信息使用的说明

32 |

我们使用电话状态信息来获取您的来电号码或去电号码,来电或去电号码可能会被发送给百度或聚合数据(360)用于查询号码信息, 但是它并没有关联到您的手机号码或您的任何个人信息。

33 |

34 |

通话记录信息使用的说明

35 |

根据您的设置, 我们仅在本地读写您的通话记录信息, 此信息不会分享给任何人。

36 |

37 |

38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /plugin/src/main/res/raw-zh/privacy_notice.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 19 | Privacy Notice 20 | 21 | 22 | 23 |

隐私权声明

24 |
25 |

26 |

来电信息是一个 GitHub 开放源代码项目, 我们承诺不会收集您的任何隐私信息。

27 |

28 |

联系人信息使用的说明

29 |

根据您的设置, 我们仅在本地使用您的联系人信息来略过查找号码的过程, 此信息不会分享给任何人。

30 |

31 |

电话状态信息使用的说明

32 |

我们使用电话状态信息来获取您的来电号码或去电号码,来电或去电号码可能会被发送给百度或聚合数据(360)用于查询号码信息, 但是它并没有关联到您的手机号码或您的任何个人信息。

33 |

34 |

通话记录信息使用的说明

35 |

根据您的设置, 我们仅在本地读写您的通话记录信息, 此信息不会分享给任何人。

36 |

37 |

38 | 39 | -------------------------------------------------------------------------------- /log/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | compileSdkVersion 29 7 | buildToolsVersion "29.0.2" 8 | 9 | defaultConfig { 10 | minSdkVersion 16 11 | targetSdkVersion 29 12 | versionCode 1 13 | versionName "1.0" 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | consumerProguardFiles 'consumer-rules.pro' 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | 26 | } 27 | 28 | dependencies { 29 | implementation fileTree(dir: 'libs', include: ['*.jar']) 30 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 31 | implementation 'androidx.appcompat:appcompat:1.1.0' 32 | implementation 'androidx.core:core-ktx:1.2.0' 33 | testImplementation 'junit:junit:4.12' 34 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 35 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_call_disconnected_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/activity/SettingsActivity.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.activity 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import android.view.MenuItem 6 | import androidx.appcompat.app.AppCompatActivity 7 | import org.xdty.callerinfo.R 8 | import org.xdty.callerinfo.fragment.SettingsFragment 9 | import org.xdty.callerinfo.utils.Utils 10 | 11 | class SettingsActivity : AppCompatActivity() { 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | setTitle(R.string.action_settings) 15 | val actionBar = supportActionBar 16 | actionBar?.setDisplayHomeAsUpEnabled(true) 17 | if (savedInstanceState == null) { 18 | fragmentManager.beginTransaction() 19 | .add(android.R.id.content, SettingsFragment.newInstance(intent)) 20 | .commit() 21 | } 22 | } 23 | 24 | override fun attachBaseContext(newBase: Context) { 25 | val context: Context = Utils.changeLang(newBase) 26 | super.attachBaseContext(context) 27 | } 28 | 29 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 30 | val id = item.itemId 31 | if (id == android.R.id.home) { 32 | finish() 33 | } 34 | return true 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/float_window.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 14 | 15 | 23 | 24 | 25 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | 15 | 20 | 25 | 30 | -------------------------------------------------------------------------------- /art/phone_auricular_with-a_cross_sign.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /plugin/src/main/java/org/xdty/callerinfo/plugin/Utils.java: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.plugin; 2 | 3 | import android.content.ComponentName; 4 | import android.content.Context; 5 | import android.content.pm.PackageManager; 6 | 7 | public class Utils { 8 | 9 | static void hideIcon(Context context) { 10 | PackageManager p = context.getPackageManager(); 11 | ComponentName componentName = new ComponentName(context, 12 | context.getPackageName() + ".Launcher"); 13 | p.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 14 | PackageManager.DONT_KILL_APP); 15 | } 16 | 17 | static void showIcon(Context context) { 18 | PackageManager p = context.getPackageManager(); 19 | ComponentName componentName = new ComponentName(context, 20 | context.getPackageName() + ".Launcher"); 21 | p.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 22 | PackageManager.DONT_KILL_APP); 23 | } 24 | 25 | static boolean isAppInstalled(Context context, String packageName) { 26 | try { 27 | context.getPackageManager().getApplicationInfo(packageName, 0); 28 | return true; 29 | } catch (PackageManager.NameNotFoundException e) { 30 | return false; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/settings/dialog/CustomApiDialog.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.settings.dialog 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import android.view.View 6 | import android.widget.EditText 7 | import org.xdty.callerinfo.R 8 | 9 | class CustomApiDialog(context: Context, sharedPrefs: SharedPreferences) : SettingsDialog(context, sharedPrefs) { 10 | 11 | private lateinit var apiUri: EditText 12 | private lateinit var apiKey: EditText 13 | 14 | private lateinit var customApiKey: String 15 | 16 | override fun bindViews() { 17 | val layout = View.inflate(context, R.layout.dialog_custom_api, null) 18 | builder.setView(layout) 19 | 20 | apiUri = layout.findViewById(R.id.api_uri) 21 | apiKey = layout.findViewById(R.id.api_key) 22 | 23 | customApiKey = context.getString(R.string.custom_api_key) 24 | 25 | apiUri.setText(sharedPrefs.getString(key, "")) 26 | apiKey.setText(sharedPrefs.getString(customApiKey, "")) 27 | } 28 | 29 | override fun onConfirm() { 30 | val value: String = apiUri.text.toString() 31 | val key: String = apiKey.text.toString() 32 | val editor = sharedPrefs.edit() 33 | editor.putString(key, value) 34 | editor.putString(customApiKey, key) 35 | editor.apply() 36 | 37 | super.onConfirm(value) 38 | } 39 | } -------------------------------------------------------------------------------- /.travis/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script generates environment variables for pull requests and forks. 4 | 5 | VERSION_NAME="$(git describe --abbrev=0 --tags)" 6 | export VERSION_NAME="${VERSION_NAME//v/}" 7 | export VERSION_CODE="$(git rev-list --tags --no-walk --count)" 8 | 9 | if [ -z "$encrypted_75846693d905_key" ] ; then 10 | # It's running from pull requests or forks, set vars. 11 | 12 | TEXT="I_AM_PUBLIC_AND_NOT_USED_FOR_RELEASE" 13 | 14 | # encrypted key and iv is taking from 'openssl enc -nosalt -aes-256-cbc -pass pass:I_AM_PUBLIC_AND_NOT_USED_FOR_RELEASE -P' 15 | 16 | export encrypted_75846693d905_key="12CF1B5E0D192628AA922230549EEDFD889E6CF7463933C6DABD9A1300FCA23D" 17 | export encrypted_75846693d905_iv="66813CF28D04CD129D57436B78DECBA4" 18 | 19 | export GITHUB_TOKEN="$TEXT" 20 | export KEYSTORE_PASSWORD="$TEXT" 21 | export ALIAS_PASSWORD="$TEXT" 22 | export ALIAS="$TEXT" 23 | export API_KEY="$TEXT" 24 | export JUHE_API_KEY="$TEXT" 25 | export LEANCLOUD_APP_ID="$TEXT" 26 | export LEANCLOUD_APP_KEY="$TEXT" 27 | 28 | # Overlay secrets.tar.enc 29 | 30 | # Travis-ci is using 'openssl aes-256-cbc -K 12CF1B5E0D192628AA922230549EEDFD889E6CF7463933C6DABD9A1300FCA23D -iv 66813CF28D04CD129D57436B78DECBA4 -in public.tar.enc -out public.tar -d' to decrypt the file. 31 | mv "public.tar.enc" "secrets.tar.enc" 32 | fi 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 18 | 19 | 26 | 27 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /signing.gradle: -------------------------------------------------------------------------------- 1 | def signingProperties = "signing.properties" 2 | def signingKeys = [ 3 | storeFile : { x -> rootProject.file(x) }, 4 | storePassword: { x -> x }, 5 | keyAlias : { x -> x }, 6 | keyPassword : { x -> x }, 7 | ] 8 | 9 | // Find signing.properties in project root, or in $HOME/.gradle 10 | def f = ["${rootDir}/${signingProperties}", "${gradle.gradleUserHomeDir}/${signingProperties}"].find { 11 | file(it).exists() 12 | } 13 | 14 | if (f) { 15 | logger.info "Loading signing properties from ${f}" 16 | def props = new Properties() 17 | props.load(new FileInputStream(f)) 18 | 19 | // For each property apply it to the release signing config 20 | signingKeys.any { k, fn -> 21 | if (!props.containsKey(k)) { 22 | logger.error "Missing property ${k}" 23 | android.buildTypes.release.signingConfig = null 24 | return true 25 | } 26 | android.signingConfigs.release[k] = fn(props[k]) 27 | logger.info "Setting property ${k}" 28 | } 29 | } else { 30 | logger.info "Missing ${signingProperties} file" 31 | android.signingConfigs.release["storeFile"] = rootProject.file("release.jks") 32 | android.signingConfigs.release["storePassword"] = "${System.env.KEYSTORE_PASSWORD}" 33 | android.signingConfigs.release["keyAlias"] = "${System.env.ALIAS}" 34 | android.signingConfigs.release["keyPassword"] = "${System.env.ALIAS_PASSWORD}" 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/settings/dialog/EditDialog.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.settings.dialog 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import android.text.InputType 6 | import android.view.View 7 | import android.widget.EditText 8 | import org.xdty.callerinfo.R 9 | 10 | class EditDialog(context: Context, sharedPreferences: SharedPreferences) : SettingsDialog(context, sharedPreferences) { 11 | 12 | private lateinit var editText: EditText 13 | 14 | override fun bindViews() { 15 | val layout = View.inflate(context, R.layout.dialog_edit, null) 16 | builder.setView(layout) 17 | editText = layout.findViewById(R.id.text) 18 | if (defaultText > 0) { 19 | editText.setText(sharedPrefs.getString(key, context.getString(defaultText))) 20 | } else { 21 | editText.setText(sharedPrefs.getString(key, "")) 22 | } 23 | editText.setInputType(InputType.TYPE_CLASS_TEXT) 24 | if (hint > 0) { 25 | editText.setHint(hint) 26 | } 27 | } 28 | 29 | override fun onConfirm() { 30 | var value = editText.text.toString() 31 | 32 | if (value.isEmpty() && defaultText != 0) { 33 | value = context.getString(defaultText) 34 | } 35 | 36 | val editor = sharedPrefs.edit() 37 | editor.putString(key, value) 38 | editor.apply() 39 | 40 | super.onConfirm(value) 41 | } 42 | } -------------------------------------------------------------------------------- /manifest.gradle: -------------------------------------------------------------------------------- 1 | def manifestProperties = "manifest.properties" 2 | def manifestKeys = [ 3 | API_KEY : { x -> x }, 4 | JUHE_API_KEY: { x -> x }, 5 | LEANCLOUD_APP_ID: { x -> x }, 6 | LEANCLOUD_APP_KEY: { x -> x } 7 | ] 8 | 9 | // Find manifest.properties in project root, or in $HOME/.gradle 10 | def f = ["${rootDir}/${manifestProperties}", "${gradle.gradleUserHomeDir}/${manifestProperties}"].find { 11 | file(it).exists() 12 | } 13 | 14 | if (f) { 15 | logger.info "Loading manifest properties from ${f}" 16 | def props = new Properties() 17 | props.load(new FileInputStream(f)) 18 | 19 | // For each property apply it to the release manifest config 20 | manifestKeys.any { k, fn -> 21 | if (!props.containsKey(k)) { 22 | logger.error "Missing property ${k}" 23 | android.defaultConfig.manifestPlaceholders = null 24 | return true 25 | } 26 | android.defaultConfig.manifestPlaceholders[k] = fn(props[k]) 27 | logger.info "Setting property ${k}" 28 | } 29 | } else { 30 | logger.info "Missing ${manifestProperties} file" 31 | android.defaultConfig.manifestPlaceholders["API_KEY"] = "${System.env.API_KEY}" 32 | android.defaultConfig.manifestPlaceholders["JUHE_API_KEY"] = "${System.env.JUHE_API_KEY}" 33 | android.defaultConfig.manifestPlaceholders["LEANCLOUD_APP_ID"] = "${System.env.LEANCLOUD_APP_ID}" 34 | android.defaultConfig.manifestPlaceholders["LEANCLOUD_APP_KEY"] = "${System.env.LEANCLOUD_APP_KEY}" 35 | } 36 | -------------------------------------------------------------------------------- /.travis/changelog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | 5 | TAG=$(git describe --abbrev=0) 6 | PREV_TAG=$(git describe --abbrev=0 HEAD^) 7 | PLUGIN_VERSION=$(cat build.gradle |grep pluginVersionName|cut -d \" -f 2) 8 | 9 | if [ ! -z "$TRAVIS_BUILD_ID" ]; then 10 | MD5_LINE=$(curl -s https://api.travis-ci.org/v3/job/$TRAVIS_JOB_ID/log.txt | grep -n 'exec md5sum' | cut -d : -f 1 | head -n 1) 11 | fi 12 | 13 | echo " 14 | [![Download (github release)](https://img.shields.io/github/downloads/$TRAVIS_REPO_SLUG/$TAG/total.svg)](https://github.com/$TRAVIS_REPO_SLUG/releases/download/$TAG/callerinfo-$TAG-release.apk) 15 | [![Download (github release)](https://img.shields.io/github/downloads/$TRAVIS_REPO_SLUG/$TAG/CallerInfo-plugin-v$PLUGIN_VERSION-full-release.apk.svg)](https://github.com/$TRAVIS_REPO_SLUG/releases/download/$TAG/CallerInfo-plugin-v$PLUGIN_VERSION-full-release.apk) 16 | 17 | --- 18 | 19 | Release files are generated and deployed by Travis-ci, check sha1 and md5 from **build log:** 20 | 21 | [https://travis-ci.org/$TRAVIS_REPO_SLUG/builds/$TRAVIS_BUILD_ID#L$MD5_LINE](https://travis-ci.org/$TRAVIS_REPO_SLUG/builds/$TRAVIS_BUILD_ID#L$MD5_LINE) 22 | " 23 | 24 | echo "## commits" 25 | git --no-pager log $PREV_TAG...$TAG \ 26 | --pretty=format:" - [%s](https://github.com/$TRAVIS_REPO_SLUG/commit/%H)" \ 27 | --reverse | \ 28 | grep -v 'Merge pull request' | \ 29 | grep -v 'build' | \ 30 | grep -v 'bump' 31 | 32 | echo " 33 | ## changes 34 | 35 | - [$PREV_TAG - $TAG](https://github.com/$TRAVIS_REPO_SLUG/compare/$PREV_TAG...$TAG?diff=split) 36 | " 37 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/di/AppComponent.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.di 2 | 3 | import dagger.Component 4 | import org.xdty.callerinfo.activity.MarkActivity 5 | import org.xdty.callerinfo.application.Application 6 | import org.xdty.callerinfo.data.CallerRepository 7 | import org.xdty.callerinfo.di.modules.AppModule 8 | import org.xdty.callerinfo.fragment.SettingsFragment 9 | import org.xdty.callerinfo.model.database.DatabaseImpl 10 | import org.xdty.callerinfo.presenter.MainBottomPresenter 11 | import org.xdty.callerinfo.presenter.MainPresenter 12 | import org.xdty.callerinfo.presenter.PhoneStatePresenter 13 | import org.xdty.callerinfo.presenter.UpgradePresenter 14 | import org.xdty.callerinfo.service.FloatWindow 15 | import org.xdty.callerinfo.service.ScheduleService 16 | import org.xdty.callerinfo.utils.Alarm 17 | import org.xdty.callerinfo.utils.Contact 18 | import javax.inject.Singleton 19 | 20 | @Singleton 21 | @Component(modules = [AppModule::class]) 22 | interface AppComponent { 23 | fun inject(presenter: MainPresenter) 24 | fun inject(presenter: PhoneStatePresenter) 25 | fun inject(application: Application) 26 | fun inject(service: ScheduleService) 27 | fun inject(service: FloatWindow) 28 | fun inject(alarm: Alarm) 29 | fun inject(markActivity: MarkActivity) 30 | fun inject(settingsFragment: SettingsFragment) 31 | fun inject(callerRepository: CallerRepository) 32 | fun inject(mainBottomPresenter: MainBottomPresenter) 33 | fun inject(database: DatabaseImpl) 34 | fun inject(contact: Contact) 35 | fun inject(upgradePresenter: UpgradePresenter) 36 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/model/db/BaseInCall.java: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.model.db; 2 | 3 | import android.text.TextUtils; 4 | 5 | import org.xdty.callerinfo.utils.Utils; 6 | 7 | import io.requery.Column; 8 | import io.requery.Entity; 9 | import io.requery.Generated; 10 | import io.requery.Key; 11 | import io.requery.Table; 12 | import io.requery.Transient; 13 | 14 | @Table(name = "IN_CALL") 15 | @Entity 16 | public abstract class BaseInCall { 17 | 18 | @Key 19 | @Generated 20 | @Column(name = "ID") 21 | int id; 22 | 23 | @Column(name = "NUMBER") 24 | String number; 25 | 26 | @Column(name = "TIME") 27 | long time; 28 | 29 | @Column(name = "RING_TIME") 30 | long ringTime; 31 | 32 | @Column(name = "DURATION") 33 | long duration; 34 | 35 | @Transient 36 | boolean isExpanded = false; 37 | 38 | public BaseInCall() { 39 | } 40 | 41 | public BaseInCall(String number, long time, long ringTime, long duration) { 42 | 43 | if (!TextUtils.isEmpty(number)) { 44 | number = number.replaceAll(" ", ""); 45 | } 46 | 47 | this.number = number; 48 | this.time = time; 49 | this.ringTime = ringTime; 50 | this.duration = duration; 51 | } 52 | 53 | public boolean isExpanded() { 54 | return isExpanded; 55 | } 56 | 57 | public void setExpanded(boolean expanded) { 58 | isExpanded = expanded; 59 | } 60 | 61 | public String getReadableTime() { 62 | return Utils.Companion.readableDate(time) + " " + Utils.Companion.getTime(time); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /plugin/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | defaultConfig { 6 | applicationId rootProject.ext.pluginId 7 | 8 | minSdkVersion rootProject.ext.minSdkVersion 9 | targetSdkVersion rootProject.ext.targetSdkVersion 10 | 11 | versionCode rootProject.ext.pluginVersionCode 12 | versionName rootProject.ext.pluginVersionName 13 | setProperty("archivesBaseName", "CallerInfo-plugin-v$versionName") 14 | } 15 | signingConfigs { 16 | release 17 | } 18 | buildTypes { 19 | debug { 20 | minifyEnabled true 21 | shrinkResources true 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | signingConfig signingConfigs.release 24 | } 25 | release { 26 | minifyEnabled true 27 | shrinkResources true 28 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 29 | signingConfig signingConfigs.release 30 | } 31 | } 32 | 33 | flavorDimensions("default") 34 | 35 | productFlavors { 36 | google { 37 | versionNameSuffix '.lite' 38 | } 39 | full {} 40 | } 41 | } 42 | 43 | dependencies { 44 | implementation fileTree(include: ['*.jar'], dir: 'libs') 45 | testImplementation 'junit:junit:4.13' 46 | implementation 'androidx.appcompat:appcompat:1.1.0' 47 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 48 | } 49 | 50 | apply from: '../signing.gradle' -------------------------------------------------------------------------------- /app/src/main/res/raw/privacy_notice.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 19 | Privacy Notice 20 | 21 | 22 | 23 |

Privacy Notice

24 |
25 |

26 |

CallerInfo is an open source project on GitHub, 27 | and does never collect your privacy data.

28 |

29 |

Notice for contact information

30 |

According to your settings, we use contact information locally to match the phone number and skip the search process, this information is never shared with others.

31 |

32 |

Notice for phone status information

33 |

We use phone status information to get the incoming or outgoing phone number and then start the search process, the incoming or outgoing phone number may be sent to Baidu or JuHe(360), but it is not linked to your own phone number or other personal information.

34 |

35 |

Notice for call log information

36 |

According to your settings, we read or write extra data to your phone's call log locally, this information is never shared with others.

37 |

38 |

39 | 40 | -------------------------------------------------------------------------------- /plugin/src/main/res/raw/privacy_notice.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 19 | Privacy Notice 20 | 21 | 22 | 23 |

Privacy Notice

24 |
25 |

26 |

CallerInfo is an open source project on GitHub, 27 | and does never collect your privacy data.

28 |

29 |

Notice for contact information

30 |

According to your settings, we use contact information locally to match the phone number and skip the search process, this information is never shared with others.

31 |

32 |

Notice for phone status information

33 |

We use phone status information to get the incoming or outgoing phone number and then start the search process, the incoming or outgoing phone number may be sent to Baidu or JuHe(360), but it is not linked to your own phone number or other personal information.

34 |

35 |

Notice for call log information

36 |

According to your settings, we read or write extra data to your phone's call log locally, this information is never shared with others.

37 |

38 |

39 | 40 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/model/database/Database.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.model.database 2 | 3 | import io.reactivex.Observable 4 | import org.xdty.callerinfo.model.db.Caller 5 | import org.xdty.callerinfo.model.db.InCall 6 | import org.xdty.callerinfo.model.db.MarkedRecord 7 | import org.xdty.phone.number.model.INumber 8 | 9 | interface Database { 10 | fun fetchInCalls(): Observable> 11 | fun fetchCallers(): Observable> 12 | fun clearAllInCalls(): Observable 13 | fun clearAllInCallSync() 14 | fun removeInCall(inCall: InCall) 15 | fun findCaller(number: String): Observable 16 | fun findCallerSync(number: String): Caller? 17 | fun removeCaller(caller: Caller) 18 | fun clearAllCallerSync(): Int 19 | fun updateCaller(caller: Caller) 20 | fun saveInCall(inCall: InCall) 21 | fun saveMarked(markedRecord: MarkedRecord) 22 | fun updateMarked(markedRecord: MarkedRecord) 23 | fun updateCaller(markedRecord: MarkedRecord) 24 | fun fetchMarkedRecords(): Observable> 25 | fun findMarkedRecord(number: String): Observable 26 | fun updateMarkedRecord(number: String) 27 | fun fetchCallersSync(): List 28 | fun fetchInCallsSync(): List 29 | fun fetchMarkedRecordsSync(): List 30 | fun addCallers(callers: List) 31 | fun addInCallers(inCalls: List) 32 | fun addMarkedRecords(markedRecords: List) 33 | fun clearAllMarkedRecordSync() 34 | fun getInCallCount(number: String): Int 35 | fun addInCallersSync(inCalls: List) 36 | fun saveMarkedRecord(number: INumber, uid: String) 37 | fun removeRecord(record: MarkedRecord) 38 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/contract/MainContract.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.contract 2 | 3 | import android.content.Context 4 | import org.xdty.callerinfo.model.db.Caller 5 | import org.xdty.callerinfo.model.db.InCall 6 | import org.xdty.phone.number.model.INumber 7 | import org.xdty.phone.number.model.caller.Status 8 | 9 | interface MainContract { 10 | interface View : BaseView { 11 | fun showNoCallLog(show: Boolean) 12 | fun showLoading(active: Boolean) 13 | fun showCallLogs(inCalls: List) 14 | fun showEula() 15 | fun showSearchResult(number: INumber) 16 | fun showSearching() 17 | fun showSearchFailed(isOnline: Boolean) 18 | fun attachCallerMap(callerMap: Map) 19 | val context: Context 20 | fun notifyUpdateData(status: Status) 21 | fun showUpdateData(status: Status) 22 | fun updateDataFinished(result: Boolean) 23 | fun showBottomSheet(inCall: InCall) 24 | } 25 | 26 | interface Presenter : BasePresenter { 27 | fun result(requestCode: Int, resultCode: Int) 28 | fun loadInCallList() 29 | fun loadCallerMap() 30 | fun removeInCallFromList(inCall: InCall) 31 | fun removeInCall(inCall: InCall) 32 | fun clearAll() 33 | fun search(number: String) 34 | fun checkEula() 35 | fun setEula() 36 | fun canDrawOverlays(): Boolean 37 | fun checkPermission(permission: String): Int 38 | fun clearSearch() 39 | fun dispatchUpdate(status: Status) 40 | fun getCaller(number: String): Caller 41 | fun clearCache() 42 | fun itemOnLongClicked(inCall: InCall) 43 | fun invalidateDataUpdate(isInvalidate: Boolean) 44 | } 45 | } -------------------------------------------------------------------------------- /app/src/debug/java/org/xdty/callerinfo/application/DebugApplication.java: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.application; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.os.StrictMode; 5 | 6 | import com.facebook.stetho.Stetho; 7 | 8 | import io.reactivex.Completable; 9 | import io.reactivex.functions.Action; 10 | import io.reactivex.schedulers.Schedulers; 11 | 12 | public class DebugApplication extends Application { 13 | public final static String TAG = Application.class.getSimpleName(); 14 | 15 | @SuppressLint("CheckResult") 16 | @Override 17 | public void onCreate() { 18 | 19 | StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() 20 | .detectAll() 21 | .penaltyLog() 22 | .build()); 23 | StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() 24 | .detectLeakedSqlLiteObjects() 25 | .detectLeakedClosableObjects() 26 | .penaltyLog() 27 | //.penaltyDeath() 28 | .build()); 29 | 30 | Completable.fromAction(new Action() { 31 | @Override 32 | public void run() throws Exception { 33 | Stetho.initialize( 34 | Stetho.newInitializerBuilder(DebugApplication.this) 35 | .enableDumpapp( 36 | Stetho.defaultDumperPluginsProvider(DebugApplication.this)) 37 | .enableWebKitInspector(Stetho.defaultInspectorModulesProvider( 38 | DebugApplication.this)) 39 | .build()); 40 | } 41 | }).subscribeOn(Schedulers.io()).subscribe(); 42 | 43 | super.onCreate(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/model/db/BaseMarkedRecord.java: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.model.db; 2 | 3 | import org.xdty.phone.number.model.cloud.CloudNumber; 4 | 5 | import io.requery.Column; 6 | import io.requery.Entity; 7 | import io.requery.Generated; 8 | import io.requery.Key; 9 | import io.requery.Table; 10 | 11 | @Table(name = "MARKED_RECORD") 12 | @Entity 13 | public abstract class BaseMarkedRecord { 14 | public final static int API_ID_USER_MARKED = 8; 15 | public final static int TYPE_IGNORE = 32; 16 | 17 | @Key 18 | @Generated 19 | @Column(name = "ID") 20 | int id; 21 | 22 | @Column(name = "NUMBER", unique = true) 23 | String number; 24 | 25 | @Column(name = "UID") 26 | String uid; 27 | 28 | @Column(name = "TYPE") 29 | int type; 30 | 31 | @Column(name = "TIME") 32 | long time; 33 | 34 | @Column(name = "COUNT") 35 | int count; 36 | 37 | @Column(name = "SOURCE") 38 | int source; 39 | 40 | @Column(name = "IS_REPORTED") 41 | boolean reported; 42 | 43 | @Column(name = "TYPE_NAME") 44 | String typeName; 45 | 46 | public BaseMarkedRecord() { 47 | this.source = API_ID_USER_MARKED; 48 | this.time = System.currentTimeMillis(); 49 | this.count = 0; 50 | this.reported = false; 51 | } 52 | 53 | public CloudNumber toNumber() { 54 | CloudNumber number = new CloudNumber(); 55 | number.setNumber(this.number); 56 | number.setCount(this.count); 57 | number.setType(this.type); 58 | number.setFrom(this.source); 59 | number.setName(this.typeName); 60 | number.setUid(this.uid); 61 | return number; 62 | } 63 | 64 | public boolean isIgnore() { 65 | return this.type == TYPE_IGNORE; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /.travis/github_release.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'optparse' 4 | require 'octokit' 5 | 6 | options = {} 7 | OptionParser.new do |opt| 8 | opt.on('-s', '--secret SECRET', 'GitHub access token') { |o| options[:secret] = o } 9 | opt.on('-r', '--repo-slug REPO_SLUG', 'Repo slug. i.e.: apple/swift') { |o| options[:repo_slug] = o } 10 | opt.on('-c', '--changelog-file CHANGELOG_FILE', 'Changelog path') { |o| options[:changelog_file] = o } 11 | opt.on('-t', '--tag TAG', 'Tag name') { |o| options[:tag_name] = o } 12 | end.parse! 13 | 14 | raise OptionParser::MissingArgument if options[:secret].nil? 15 | raise OptionParser::MissingArgument if options[:repo_slug].nil? 16 | raise OptionParser::MissingArgument if options[:changelog_file].nil? 17 | raise OptionParser::MissingArgument if options[:tag_name].nil? 18 | 19 | client = Octokit::Client.new(:access_token => options[:secret]) 20 | user = client.user 21 | user.login 22 | 23 | unless client.scopes.include? 'public_repo' or client.scopes.include? 'repo' 24 | raise Error, "Insufficient permissions. Make sure your token contains the repo or public_repo scope." 25 | end 26 | 27 | puts "Logged in as #{user.name}" 28 | puts "Deploying to repo: #{options[:repo_slug]}" 29 | 30 | tag_matched = false 31 | release_url = nil 32 | releases = client.releases(options[:repo_slug]) 33 | body = File.open(options[:changelog_file], "rb").read 34 | 35 | releases.each do |release| 36 | if release.tag_name == options[:tag_name] 37 | release_url = release.rels[:self].href 38 | tag_matched = true 39 | end 40 | end 41 | 42 | # if tag has been pushed directly to git, create a github release 43 | if tag_matched == false 44 | client.create_release(options[:repo_slug], options[:tag_name], { :name => options[:tag_name], :body => body }) 45 | else 46 | client.update_release(release_url, { :name => options[:tag_name], :body => body }) 47 | end 48 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/activity/LicensesActivity.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.activity 2 | 3 | import android.os.Bundle 4 | import android.view.MenuItem 5 | import android.webkit.WebView 6 | import org.xdty.callerinfo.R 7 | 8 | class LicensesActivity : BaseActivity() { 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | val actionBar = supportActionBar 12 | actionBar?.setDisplayHomeAsUpEnabled(true) 13 | val webView = findViewById(R.id.webView) 14 | val action = intent.action 15 | var url = "file:///android_res/raw/licenses.html" 16 | when (action) { 17 | ACTION_LICENSE -> { 18 | } 19 | ACTION_PRIVACY -> { 20 | setTitle(R.string.privacy_notice) 21 | url = "file:///android_res/raw/privacy_notice.html" 22 | } 23 | ACTION_FEATURE -> { 24 | setTitle(R.string.feature_notice) 25 | url = "file:///android_res/raw/feature_notice.html" 26 | } 27 | } 28 | webView?.loadUrl(url) 29 | } 30 | 31 | override val layoutId: Int 32 | get() = R.layout.activity_licenses 33 | 34 | override val titleId: Int 35 | get() = R.string.license 36 | 37 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 38 | val id = item.itemId 39 | if (id == android.R.id.home) { 40 | finish() 41 | return true 42 | } 43 | return super.onOptionsItemSelected(item) 44 | } 45 | 46 | companion object { 47 | private const val ACTION_LICENSE = "org.xdty.callerinfo.action.VIEW_LICENSES" 48 | private const val ACTION_PRIVACY = "org.xdty.callerinfo.action.VIEW_PRIVACY" 49 | private const val ACTION_FEATURE = "org.xdty.callerinfo.action.VIEW_FEATURE" 50 | } 51 | } -------------------------------------------------------------------------------- /plugin/src/main/java/org/xdty/callerinfo/plugin/LicensesActivity.java: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.plugin; 2 | 3 | import android.os.Bundle; 4 | import androidx.appcompat.app.ActionBar; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | import android.view.MenuItem; 7 | import android.webkit.WebView; 8 | 9 | public class LicensesActivity extends AppCompatActivity { 10 | 11 | public final static String ACTION_LICENSE = "org.xdty.callerinfo.plugin.action.VIEW_LICENSES"; 12 | public final static String ACTION_PRIVACY = "org.xdty.callerinfo.plugin.action.VIEW_PRIVACY"; 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | 18 | setContentView(R.layout.activity_licenses); 19 | 20 | ActionBar actionBar = getSupportActionBar(); 21 | if (actionBar != null) { 22 | actionBar.setDisplayHomeAsUpEnabled(true); 23 | } 24 | 25 | WebView webView = (WebView) findViewById(R.id.webView); 26 | 27 | String action = getIntent().getAction(); 28 | String url = "file:///android_res/raw/licenses.html"; 29 | 30 | switch (action) { 31 | case ACTION_LICENSE: 32 | setTitle(R.string.license); 33 | break; 34 | case ACTION_PRIVACY: 35 | setTitle(R.string.plugin_privacy); 36 | url = "file:///android_res/raw/privacy_notice.html"; 37 | break; 38 | default: 39 | break; 40 | } 41 | if (webView != null) { 42 | webView.loadUrl(url); 43 | } 44 | } 45 | 46 | @Override 47 | public boolean onOptionsItemSelected(MenuItem item) { 48 | int id = item.getItemId(); 49 | if (id == android.R.id.home) { 50 | finish(); 51 | return true; 52 | } 53 | return super.onOptionsItemSelected(item); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/application/Application.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.application 2 | 3 | import android.annotation.SuppressLint 4 | import android.util.Log 5 | import com.google.firebase.analytics.FirebaseAnalytics 6 | import com.tencent.bugly.crashreport.CrashReport 7 | import io.reactivex.plugins.RxJavaPlugins 8 | import org.xdty.callerinfo.di.AppComponent 9 | import org.xdty.callerinfo.di.DaggerAppComponent 10 | import org.xdty.callerinfo.di.modules.AppModule 11 | import org.xdty.callerinfo.model.setting.Setting 12 | import org.xdty.callerinfo.utils.Alarm 13 | import org.xdty.callerinfo.utils.Resource 14 | import org.xdty.callerinfo.utils.Utils 15 | import javax.inject.Inject 16 | 17 | @SuppressLint("Registered") 18 | open class Application : android.app.Application() { 19 | lateinit var analytics: FirebaseAnalytics 20 | @Inject 21 | internal lateinit var setting: Setting 22 | @Inject 23 | internal lateinit var alarm: Alarm 24 | 25 | override fun onCreate() { 26 | super.onCreate() 27 | application = this 28 | RxJavaPlugins.setErrorHandler { throwable -> Log.e(TAG, Log.getStackTraceString(throwable)) } 29 | init() 30 | } 31 | 32 | protected fun init() { 33 | appComponent = DaggerAppComponent.builder().appModule(AppModule(this)).build() 34 | appComponent.inject(this) 35 | analytics = FirebaseAnalytics.getInstance(this) 36 | analytics.logEvent(FirebaseAnalytics.Event.APP_OPEN, null) 37 | Resource.init(Utils.changeLang(this)) 38 | if (!setting.isCatchCrash) { 39 | CrashReport.initCrashReport(applicationContext, "0eaf845a04", false) 40 | } 41 | setting.fix() 42 | alarm.alarm() 43 | alarm.enqueueUpgradeWork() 44 | } 45 | 46 | companion object { 47 | val TAG = Application::class.java.simpleName 48 | lateinit var application: Application 49 | lateinit var appComponent: AppComponent 50 | } 51 | } -------------------------------------------------------------------------------- /DEVELOPMENT-CN.md: -------------------------------------------------------------------------------- 1 | [来电信息](https://github.com/xdtianyu/CallerInfo) 开发者文档 2 | 3 | 注意此文档仅供开发者使用,用于编译源码等。如果是初学者,对于文档中不明白的内容或遇到错误,请务必优先 Google 搜索。 4 | 5 | ---------------- 6 | 7 | **1\. 下载最新源码** 8 | 9 | ``` 10 | git clone https://github.com/xdtianyu/CallerInfo.git 11 | cd CallerInfo/ 12 | git submodule update --init --recursive 13 | ``` 14 | 15 | **2\. 配置编译环境** 16 | 17 | 参考 `.travis/env.sh` 文件,首先解码内置的用于公开使用的 `release.jsk` 文件 18 | 19 | ``` 20 | openssl aes-256-cbc -K 12CF1B5E0D192628AA922230549EEDFD889E6CF7463933C6DABD9A1300FCA23D -iv 66813CF28D04CD129D57436B78DECBA4 -in public.tar.enc -out public.tar -d 21 | tar xvf public.tar 22 | ``` 23 | 24 | 导出环境变量,注意修改 `ANDROID_HOME` 为你的 `Android SDK` 目录 25 | 26 | ``` 27 | export ANDROID_HOME=/home/ty/Android/Sdk 28 | 29 | TEXT="I_AM_PUBLIC_AND_NOT_USED_FOR_RELEASE" 30 | export KEYSTORE_PASSWORD="$TEXT" 31 | export ALIAS_PASSWORD="$TEXT" 32 | export ALIAS="$TEXT" 33 | ``` 34 | 35 | **3\. 运行编译** 36 | 37 | ``` 38 | ./gradlew assembleDebug 39 | ``` 40 | 41 | 或使用如下命令生成 `release` 版本 42 | 43 | ``` 44 | ./gradlew assembleRelease 45 | ``` 46 | 47 | 编译成功后,最终会在 `CallerInfo/app/build/outputs/apk` 目录生成 `CallerInfo-v2.1.5-debug.apk` 及 `CallerInfo-v2.1.5-release.apk` 文件。注意版本号可能会增加。 48 | 49 | 50 | **4\. 环境变量** 51 | 52 | 参考 `.travis/env.sh` 文件, 上文用到的 `KEYSTORE_PASSWORD` `ALIAS_PASSWORD` `ALIAS` 都是 `public.jks` 文件相关验证,`GITHUB_TOKEN` 用于作者 `GitHub Release` 自动部署。 53 | 54 | `API_KEY` 是百度号码服务 `API` 密钥,由于服务终止,已停止使用。`JUHE_API_KEY` 是聚合数据(360) 数据源 `API` 密钥。 55 | 56 | `LEANCLOUD_APP_ID` 和 `LEANCLOUD_APP_KEY` 是 `LeanCloud` 的 `API` 凭证,用于接收用户上报的号码数据。 57 | 58 | **5\. 版本配置说明** 59 | 60 | 版本配置在 `gradle.properties` 文件中。 61 | 62 | **6\. 部分文件说明** 63 | 64 | `manifest.gradle` 是用于自动写入环境变量到 `manifest` 的配置文件,可以将环境变量或 `manifest.properties` 文件内的配置导入。 65 | 66 | `signing.gradle` 类似 `manifest.gradle` 文件,用于导入环境变量或 `signing.properties` 文件内容,用于编译时证书验证配置的自动化。 67 | 68 | **7\. Android Studio 说明** 69 | 70 | `Android Studio` 导入项目后,需要修改上文提到的 `manifest.properties` `signing.properties` 文件来导入环境变量。 71 | 72 | 73 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/ty/Android/Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -dontobfuscate 19 | 20 | ##---------------Begin: proguard configuration for Gson ---------- 21 | # Gson uses generic type information stored in a class file when working with fields. Proguard 22 | # removes such information by default, so configure it to keep all of it. 23 | -keepattributes Signature 24 | 25 | # Gson specific classes 26 | -keep class sun.misc.Unsafe { *; } 27 | -keep class com.google.gson.stream.** { *; } 28 | -keepattributes *Annotation* 29 | -dontwarn javax.annotation.** 30 | -dontwarn javax.inject.** 31 | -dontwarn sun.misc.Unsafe 32 | 33 | # Application classes that will be serialized/deserialized over Gson 34 | -keep class org.xdty.phone.number.model.** { *; } 35 | 36 | # OKHttp 37 | -dontwarn rx.** 38 | 39 | -dontwarn okio.** 40 | 41 | -dontwarn com.squareup.okhttp.** 42 | -keep class com.squareup.okhttp.** { *; } 43 | -keep interface com.squareup.okhttp.** { *; } 44 | 45 | -dontwarn retrofit.** 46 | -dontwarn retrofit.appengine.UrlFetchClient 47 | -keep class retrofit.** { *; } 48 | -keepclasseswithmembers class * { 49 | @retrofit.http.* ; 50 | } 51 | 52 | # Sugar 53 | -keep public class * extends com.orm.SugarApp 54 | -keep public class * extends com.orm.SugarRecord 55 | 56 | -keep class android.support.v7.** { public protected *; } 57 | -keep class android.support.v4.** { public protected *; } 58 | 59 | -keep class org.xdty.** { *; } 60 | -keep class com.facebook.stetho.** {*;} 61 | 62 | # minio 63 | -keep class io.minio.** { *; } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/model/setting/Setting.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.model.setting 2 | 3 | import org.xdty.callerinfo.model.Status 4 | 5 | interface Setting { 6 | val isEulaSet: Boolean 7 | fun setEula() 8 | val ignoreRegex: String 9 | val isHidingOffHook: Boolean 10 | val isShowingOnOutgoing: Boolean 11 | val isIgnoreKnownContact: Boolean 12 | val isShowingContactOffline: Boolean 13 | val isAutoHangup: Boolean 14 | val isAddingCallLog: Boolean 15 | val isCatchCrash: Boolean 16 | val isForceChinese: Boolean 17 | val keywords: String 18 | val geoKeyword: String 19 | val numberKeyword: String 20 | val windowX: Int 21 | val windowY: Int 22 | fun setWindow(x: Int, y: Int) 23 | val screenWidth: Int 24 | val screenHeight: Int 25 | val statusBarHeight: Int 26 | val windowHeight: Int 27 | val defaultHeight: Int 28 | val isShowCloseAnim: Boolean 29 | val isHidingWhenTouch: Boolean 30 | val isTransBackOnly: Boolean 31 | val isEnableTextColor: Boolean 32 | val textPadding: Int 33 | val textAlignment: Int 34 | val textSize: Int 35 | val windowTransparent: Int 36 | val isDisableMove: Boolean 37 | val isAutoReportEnabled: Boolean 38 | val isMarkingEnabled: Boolean 39 | fun addPaddingMark(number: String) 40 | fun removePaddingMark(number: String) 41 | val paddingMarks: ArrayList 42 | val uid: String 43 | fun updateLastScheduleTime() 44 | fun updateLastScheduleTime(timestamp: Long) 45 | fun lastScheduleTime(): Long 46 | fun lastCheckDataUpdateTime(): Long 47 | fun updateLastCheckDataUpdateTime(timestamp: Long) 48 | var status: Status 49 | val isNotMarkContact: Boolean 50 | val isDisableOutGoingHangup: Boolean 51 | val isTemporaryDisableHangup: Boolean 52 | val repeatedCountIndex: Int 53 | fun clear() 54 | val normalColor: Int 55 | val poiColor: Int 56 | val reportColor: Int 57 | val isOnlyOffline: Boolean 58 | fun fix() 59 | fun setOutgoing(isOutgoing: Boolean) 60 | val isOutgoingPositionEnabled: Boolean 61 | val isAddingRingOnceCallLog: Boolean 62 | val isOfflineDataAutoUpgrade: Boolean 63 | } -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v1 13 | 14 | - name: Checkout submodule 15 | run: git submodule sync --recursive && git submodule update --init --recursive 16 | 17 | - name: Before build 18 | uses: xdtianyu/actions-android-ci@master 19 | #env: 20 | #ENCRYPTED_KEY: ${{ secrets.ENCRYPTED_KEY }} 21 | #ENCRYPTED_IV: ${{ secrets.ENCRYPTED_IV }} 22 | with: 23 | args: '" 24 | . .travis/env.sh; 25 | openssl aes-256-cbc -K $encrypted_75846693d905_key -iv $encrypted_75846693d905_iv -in secrets.tar.enc -out secrets.tar -d; 26 | tar xvf secrets.tar; 27 | touch local.properties 28 | "' 29 | 30 | - name: Cache gradle and sdk 31 | uses: actions/cache@v2 32 | env: 33 | cache-name: cache-gradle-and-sdk 34 | with: 35 | path: | 36 | ${{ github.workspace }}/.opt/cache/gradle/wrapper 37 | ${{ github.workspace }}/.opt/cache/gradle/caches 38 | ${{ github.workspace }}/.opt/sdk 39 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/wrapper/gradle-wrapper.properties', '**/build.gradle') }} 40 | restore-keys: | 41 | ${{ runner.os }}-build-${{ env.cache-name }}- 42 | ${{ runner.os }}-build- 43 | ${{ runner.os }}- 44 | 45 | - name: Build 46 | #env: 47 | # ENCRYPTED_KEY: ${{ secrets.ENCRYPTED_KEY }} 48 | # ENCRYPTED_IV: ${{ secrets.ENCRYPTED_IV }} 49 | # ALIAS: ${{ secrets.ALIAS }} 50 | # ALIAS_PASSWORD: ${{ secrets.ALIAS_PASSWORD }} 51 | # KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} 52 | uses: xdtianyu/actions-android-ci@master 53 | with: 54 | args: '" 55 | . .travis/env.sh; 56 | . /opt/setup-android-sdk.sh; 57 | ./gradlew assembleDebug 58 | "' 59 | 60 | - name: Upload artifacts 61 | uses: actions/upload-artifact@v2 62 | with: 63 | name: artifacts 64 | path: | 65 | app/**/apk/release/* 66 | app/**/mapping/release/mapping.txt 67 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/settings/dialog/SeekBarDialog.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.settings.dialog 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import android.view.View 6 | import android.widget.SeekBar 7 | import android.widget.SeekBar.OnSeekBarChangeListener 8 | import app.minimize.com.seek_bar_compat.SeekBarCompat 9 | import org.xdty.callerinfo.R 10 | 11 | class SeekBarDialog(context: Context, sharedPreferences: SharedPreferences) : 12 | SettingsDialog(context, sharedPreferences) { 13 | 14 | lateinit var seekBar: SeekBarCompat 15 | var max: Int = 100 16 | var defaultValue: Int = 0 17 | 18 | lateinit var listener: SeekListener 19 | 20 | fun max(max: Int): SeekBarDialog { 21 | this.max = max 22 | return this 23 | } 24 | 25 | fun defaultValue(value: Int): SeekBarDialog { 26 | defaultValue = value 27 | return this 28 | } 29 | 30 | fun seek(listener: SeekListener): SeekBarDialog { 31 | this.listener = listener 32 | return this 33 | } 34 | 35 | override fun bindViews() { 36 | 37 | val layout = View.inflate(context, R.layout.dialog_seek, null) 38 | builder.setView(layout) 39 | 40 | val value = sharedPrefs.getInt(key, defaultValue) 41 | seekBar = layout.findViewById(R.id.seek_bar) 42 | seekBar.max = max 43 | seekBar.progress = value 44 | seekBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener { 45 | override fun onProgressChanged(p0: SeekBar?, progress: Int, p2: Boolean) { 46 | var fixed = progress 47 | if (fixed == 0) { 48 | fixed = 1 49 | } 50 | listener.onSeek(fixed) 51 | } 52 | 53 | override fun onStartTrackingTouch(p0: SeekBar?) {} 54 | 55 | override fun onStopTrackingTouch(p0: SeekBar?) {} 56 | }) 57 | } 58 | 59 | override fun onConfirm() { 60 | val value = seekBar.progress 61 | val editor = sharedPrefs.edit() 62 | editor.putInt(key, value) 63 | editor.apply() 64 | } 65 | 66 | fun interface SeekListener { 67 | fun onSeek(progress: Int) 68 | } 69 | } -------------------------------------------------------------------------------- /plugin/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 25 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/presenter/MainBottomPresenter.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.presenter 2 | 3 | import android.util.Log 4 | import org.xdty.callerinfo.application.Application.Companion.appComponent 5 | import org.xdty.callerinfo.contract.MainBottomContact.Presenter 6 | import org.xdty.callerinfo.contract.MainBottomContact.View 7 | import org.xdty.callerinfo.data.CallerDataSource 8 | import org.xdty.callerinfo.model.MarkType 9 | import org.xdty.callerinfo.model.database.Database 10 | import org.xdty.callerinfo.model.db.Caller 11 | import org.xdty.callerinfo.model.db.InCall 12 | import org.xdty.callerinfo.model.setting.Setting 13 | import org.xdty.callerinfo.utils.Alarm 14 | import org.xdty.callerinfo.utils.Utils 15 | import javax.inject.Inject 16 | 17 | class MainBottomPresenter(private val mView: View) : Presenter { 18 | @Inject 19 | internal lateinit var mSetting: Setting 20 | @Inject 21 | internal lateinit var mCallerDataSource: CallerDataSource 22 | @Inject 23 | internal lateinit var mDatabase: Database 24 | @Inject 25 | internal lateinit var mAlarm: Alarm 26 | 27 | private var mInCall: InCall? = null 28 | private var mCaller: Caller? = null 29 | override fun start() { 30 | if (mInCall != null) { 31 | mView.init(mInCall!!, mCaller!!) 32 | } else { 33 | Log.e(TAG, "mInCall is null") 34 | } 35 | } 36 | 37 | override fun bindData(inCall: InCall?) { 38 | mInCall = inCall 39 | mCaller = mCallerDataSource.getCallerFromCache(inCall!!.number) 40 | } 41 | 42 | override fun canMark(): Boolean { 43 | return mCaller!!.isMark || mCaller!!.canMark() && mInCall!!.duration > 0 44 | } 45 | 46 | override fun markClicked(viewId: Int) { 47 | val type: MarkType = MarkType.fromResourceId(viewId) 48 | if (type != MarkType.CUSTOM) { 49 | val typeText = Utils.typeFromId(type.toInt()) 50 | mCallerDataSource.updateCaller(mInCall!!.number, type.toInt(), typeText) 51 | mView.updateMarkName(typeText) 52 | } 53 | mView.updateMark(viewId, mCaller!!) 54 | } 55 | 56 | override fun markCustom(text: String?) { 57 | mCallerDataSource.updateCaller(mInCall!!.number, MarkType.CUSTOM.toInt(), 58 | text!!) 59 | mView.updateMarkName(text) 60 | } 61 | 62 | companion object { 63 | private val TAG = MainBottomPresenter::class.java.simpleName 64 | } 65 | 66 | init { 67 | appComponent.inject(this) 68 | } 69 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/settings/dialog/RadioDialog.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.settings.dialog 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import android.view.View 6 | import android.widget.LinearLayout 7 | import android.widget.RadioButton 8 | import android.widget.RadioGroup 9 | import org.xdty.callerinfo.R 10 | import java.util.* 11 | 12 | class RadioDialog(context: Context, sharedPrefs: SharedPreferences) : SettingsDialog(context, sharedPrefs) { 13 | 14 | private var defaultValue: Int = 0 15 | private var listId: Int = 0 16 | private var offset: Int = 0 17 | lateinit var listener: CheckedListener 18 | 19 | override fun bindViews() { 20 | val layout = View.inflate(context, R.layout.dialog_radio, null) 21 | builder.setView(layout) 22 | 23 | val radioGroup: RadioGroup = layout.findViewById(R.id.radio) 24 | val layoutParams = LinearLayout.LayoutParams( 25 | LinearLayout.LayoutParams.MATCH_PARENT, 26 | LinearLayout.LayoutParams.WRAP_CONTENT) 27 | 28 | 29 | val list = Arrays.asList(*context.resources.getStringArray(listId)) 30 | 31 | for (s in list) { 32 | val radioButton = RadioButton(context) 33 | radioButton.text = s 34 | radioGroup.addView(radioButton, layoutParams) 35 | } 36 | 37 | val button = radioGroup.getChildAt( 38 | sharedPrefs.getInt(key, defaultValue) - offset) as RadioButton 39 | 40 | button.isChecked = true 41 | button.setOnClickListener { dialog.dismiss() } 42 | 43 | 44 | radioGroup.setOnCheckedChangeListener { group, checkedId -> 45 | val index = group.indexOfChild(group.findViewById(checkedId)) 46 | val editor = sharedPrefs.edit() 47 | editor.putInt(key, index + offset) 48 | editor.apply() 49 | dialog.dismiss() 50 | 51 | listener.onChecked(list[index]) 52 | } 53 | } 54 | 55 | override fun onConfirm() { 56 | 57 | } 58 | 59 | fun defaultValue(defaultValue: Int): RadioDialog { 60 | this.defaultValue = defaultValue 61 | return this 62 | } 63 | 64 | fun offset(offset: Int): RadioDialog { 65 | this.offset = offset 66 | return this 67 | } 68 | 69 | fun listId(listId: Int): RadioDialog { 70 | this.listId = listId 71 | return this 72 | } 73 | 74 | fun check(listener: CheckedListener): RadioDialog { 75 | this.listener = listener 76 | return this 77 | } 78 | 79 | fun interface CheckedListener { 80 | fun onChecked(value: String) 81 | } 82 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/preference.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 21 | 22 | 32 | 33 | 42 | 43 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/utils/Alarm.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.utils 2 | 3 | import android.app.AlarmManager 4 | import android.app.PendingIntent 5 | import android.content.Context 6 | import android.content.Intent 7 | import android.util.Log 8 | import androidx.lifecycle.LiveData 9 | import androidx.work.* 10 | import androidx.work.PeriodicWorkRequest.Builder 11 | import org.xdty.callerinfo.application.Application 12 | import org.xdty.callerinfo.model.setting.Setting 13 | import org.xdty.callerinfo.service.ScheduleService 14 | import org.xdty.callerinfo.worker.UpgradeWorker 15 | import java.util.concurrent.TimeUnit 16 | import javax.inject.Inject 17 | 18 | class Alarm { 19 | 20 | @Inject 21 | internal lateinit var setting: Setting 22 | @Inject 23 | internal lateinit var application: Application 24 | 25 | init { 26 | Application.appComponent.inject(this) 27 | } 28 | 29 | fun alarm() { 30 | Log.v(TAG, "alarm") 31 | if (!setting.isAutoReportEnabled && !setting.isMarkingEnabled) { 32 | Log.v(TAG, "alarm is not installed") 33 | return 34 | } 35 | val intent = Intent(application, ScheduleService::class.java) 36 | val pIntent = PendingIntent.getService(application, 0, intent, 0) 37 | val alarm = application.getSystemService(Context.ALARM_SERVICE) as AlarmManager 38 | alarm.cancel(pIntent) 39 | val now = System.currentTimeMillis() 40 | alarm.setRepeating(AlarmManager.RTC_WAKEUP, now + 5 * 1000, 60 * 60 * 1000.toLong(), pIntent) 41 | } 42 | 43 | fun enqueueUpgradeWork() { 44 | if (!setting.isOfflineDataAutoUpgrade) { 45 | Log.d(TAG, "Offline data auto upgrade is not enabled.") 46 | return 47 | } 48 | val builder = Builder(UpgradeWorker::class.java, 6, TimeUnit.HOURS) 49 | val constraints: Constraints = Constraints.Builder() 50 | // .setRequiredNetworkType(NetworkType.CONNECTED) 51 | // .setRequiresBatteryNotLow(true) 52 | // .setRequiresStorageNotLow(true) 53 | .build() 54 | builder.setConstraints(constraints) 55 | val request = builder.build() 56 | WorkManager.getInstance().enqueueUniquePeriodicWork(UpgradeWorker::class.java.simpleName, 57 | ExistingPeriodicWorkPolicy.KEEP, request) 58 | } 59 | 60 | fun cancelUpgradeWork() { 61 | WorkManager.getInstance().cancelUniqueWork(UpgradeWorker::class.java.simpleName) 62 | } 63 | 64 | fun runUpgradeWorkOnce(): LiveData { 65 | val request: OneTimeWorkRequest = OneTimeWorkRequest.Builder(UpgradeWorker::class.java).build() 66 | val workManager = WorkManager.getInstance() 67 | workManager.enqueue(request) 68 | return workManager.getWorkInfoByIdLiveData(request.id) 69 | } 70 | 71 | companion object { 72 | private val TAG = Alarm::class.java.simpleName 73 | } 74 | 75 | } -------------------------------------------------------------------------------- /app/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @color/tomato 5 | @color/red_light 6 | @color/tangerine 7 | @color/orange_dark 8 | @color/banana 9 | @color/basil 10 | @color/sage 11 | @color/blue_light 12 | @color/peacock 13 | @color/blueberry 14 | @color/lavender 15 | @color/grape 16 | @color/flamingo 17 | @color/graphite 18 | 19 | 20 | @string/api_juhe 21 | @string/api_sogou 22 | 23 | 24 | @string/align_left 25 | @string/align_center 26 | @string/align_right 27 | 28 | 29 | @string/harassment 30 | @string/fraud 31 | @string/advertising 32 | @string/express_delivery 33 | @string/restaurant_deliver 34 | 35 | 36 | 37 | @string/type_harassment 38 | @string/type_fraud 39 | @string/type_advertising 40 | @string/type_express_delivery 41 | @string/type_restaurant_deliver 42 | 43 | 44 | @string/repeated_incoming_twice 45 | @string/repeated_incoming_third 46 | @string/repeated_incoming_fourth 47 | @string/repeated_incoming_fifth 48 | 49 | 50 | -1000 51 | -200 52 | -150 53 | -100 54 | -50 55 | -2 56 | -1 57 | 0 58 | 1 59 | 2 60 | 8 61 | 1000 62 | 63 | 64 | @string/source_special 65 | @string/source_common 66 | @string/source_caller 67 | @string/source_marked 68 | @string/source_mvno 69 | @string/source_offline 70 | @string/source_google 71 | @string/source_baidu 72 | @string/source_juhe 73 | @string/source_soguo 74 | @string/source_cloud 75 | @string/source_custom 76 | 77 | -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/model/CallRecord.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.model 2 | 3 | class CallRecord { 4 | private var ring: Long = -1 5 | var hook: Long = -1 6 | private set 7 | private var idle: Long = -1 8 | private var ringDuration: Long = -1 9 | private var callDuration: Long = -1 10 | var logNumber: String = "" 11 | var logName: String = "" 12 | var logGeo: String = "" 13 | 14 | val isIncoming: Boolean 15 | get() = ring != -1L 16 | 17 | val isValid: Boolean 18 | get() = logNumber.isNotEmpty() 19 | 20 | val isNameValid: Boolean 21 | get() = logName.isNotEmpty() 22 | 23 | val isGeoValid: Boolean 24 | get() = logGeo.isNotEmpty() 25 | 26 | val isActive: Boolean 27 | get() = ring != -1L || hook != -1L || idle != -1L 28 | 29 | val isAnswered: Boolean 30 | get() = isIncoming && callDuration > 0 31 | 32 | fun setLogName(name: String, append: Boolean) { 33 | if (append) { 34 | appendName(name) 35 | } else { 36 | logName = name 37 | } 38 | } 39 | 40 | fun ring() { 41 | ring = System.currentTimeMillis() 42 | } 43 | 44 | fun hook() { 45 | hook = System.currentTimeMillis() 46 | } 47 | 48 | fun idle() { 49 | idle = System.currentTimeMillis() 50 | if (isIncoming) { 51 | if (hook == -1L) { // missed or hangup incoming call 52 | ringDuration = idle - ring 53 | callDuration = 0 54 | } else { // answered incoming call 55 | ringDuration = hook - ring 56 | callDuration = idle - hook 57 | } 58 | } else { // outgoing call 59 | ringDuration = 0 60 | callDuration = idle - hook 61 | } 62 | } 63 | 64 | fun ringDuration(): Long { 65 | return ringDuration 66 | } 67 | 68 | fun callDuration(): Long { 69 | return callDuration 70 | } 71 | 72 | fun reset() { 73 | ring = -1 74 | hook = -1 75 | idle = -1 76 | ringDuration = -1 77 | callDuration = -1 78 | logNumber = "" 79 | logGeo = "" 80 | logName = "" 81 | } 82 | 83 | fun time(): Long { 84 | return if (ring != -1L) ring else hook 85 | } 86 | 87 | private fun appendName(s: String) { 88 | logName += " $s" 89 | } 90 | 91 | fun matchName(keyword: String?): Boolean { 92 | return logName.contains(keyword!!) 93 | } 94 | 95 | fun matchGeo(keyword: String?): Boolean { 96 | return logGeo.contains(keyword!!) 97 | } 98 | 99 | fun matchNumber(keyword: String?): Boolean { 100 | return logNumber.startsWith(keyword!!) 101 | } 102 | 103 | fun isEqual(number: String?): Boolean { 104 | return (number == null || logNumber == number) 105 | } 106 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/utils/Contact.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.utils 2 | 3 | import android.annotation.SuppressLint 4 | import android.provider.ContactsContract 5 | import io.reactivex.Observable 6 | import io.reactivex.android.schedulers.AndroidSchedulers 7 | import io.reactivex.schedulers.Schedulers 8 | import org.xdty.callerinfo.application.Application.Companion.appComponent 9 | import org.xdty.callerinfo.application.Application.Companion.application 10 | import org.xdty.callerinfo.model.permission.Permission 11 | import javax.inject.Inject 12 | 13 | @SuppressLint("CheckResult") 14 | class Contact private constructor() { 15 | @Inject 16 | internal lateinit var mPermission: Permission 17 | 18 | private val mContactMap: MutableMap = HashMap() 19 | private var lastUpdateTime: Long = 0 20 | fun isExist(number: String?): Boolean { 21 | loadContactCache() 22 | return mContactMap.containsKey(number) 23 | } 24 | 25 | fun getName(number: String): String { 26 | return if (mContactMap.containsKey(number)) { 27 | mContactMap[number]!! 28 | } else "" 29 | } 30 | 31 | private fun loadContactCache() { 32 | if (mPermission.canReadContact() && System.currentTimeMillis() - lastUpdateTime 33 | > Constants.CONTACT_CACHE_INTERVAL) { 34 | loadContactMap().subscribe { map -> 35 | mContactMap.clear() 36 | mContactMap.putAll(map!!) 37 | lastUpdateTime = System.currentTimeMillis() 38 | } 39 | } 40 | } 41 | 42 | private fun loadContactMap(): Observable> { 43 | return Observable.create> { emitter -> 44 | val contactsMap: MutableMap = HashMap() 45 | val cursor = application 46 | .contentResolver 47 | .query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, 48 | null) 49 | if (cursor != null) { 50 | while (cursor.moveToNext()) { 51 | val name = cursor.getString(cursor.getColumnIndex( 52 | ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)) 53 | var number = cursor.getString( 54 | cursor.getColumnIndex( 55 | ContactsContract.CommonDataKinds.Phone.NUMBER)) 56 | if (number != null) { 57 | number = number.replace("[^\\d]".toRegex(), "") 58 | contactsMap[number] = name 59 | } 60 | } 61 | cursor.close() 62 | } 63 | emitter.onNext(contactsMap) 64 | emitter.onComplete() 65 | }.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) 66 | } 67 | 68 | companion object { 69 | val instance = Contact() 70 | } 71 | 72 | init { 73 | appComponent.inject(this) 74 | loadContactCache() 75 | } 76 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/utils/Window.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.utils 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import android.util.Log 6 | import androidx.core.content.ContextCompat 7 | import org.xdty.callerinfo.R 8 | import org.xdty.callerinfo.application.Application 9 | import org.xdty.callerinfo.model.TextColorPair 10 | import org.xdty.callerinfo.service.FloatWindow 11 | import org.xdty.phone.number.model.INumber 12 | import wei.mark.standout.StandOutWindow 13 | 14 | class Window { 15 | private val mContext: Context 16 | var isShowing = false 17 | private set 18 | 19 | fun showTextWindow(resId: Int, type: Type) { 20 | isShowing = true 21 | val frontType = type.value() 22 | val bundle = Bundle() 23 | bundle.putString(FloatWindow.NUMBER_INFO, Resource.resources.getString(resId)) 24 | bundle.putInt(FloatWindow.WINDOW_COLOR, ContextCompat.getColor(mContext, 25 | R.color.colorPrimary)) 26 | Log.d(TAG, "showTextWindow: " + Utils.bundleToString(bundle)) 27 | StandOutWindow.show(mContext, FloatWindow::class.java, frontType) 28 | StandOutWindow.sendData(mContext, FloatWindow::class.java, 29 | frontType, 0, bundle, FloatWindow::class.java, 0) 30 | } 31 | 32 | fun sendData(key: String?, value: Int, type: Type) { 33 | Log.d(TAG, "sendData") 34 | isShowing = true 35 | val frontType = type.value() 36 | val bundle = Bundle() 37 | bundle.putInt(key, value) 38 | StandOutWindow.show(mContext, FloatWindow::class.java, frontType) 39 | StandOutWindow.sendData(mContext, FloatWindow::class.java, 40 | frontType, 0, bundle, FloatWindow::class.java, 0) 41 | } 42 | 43 | fun closeWindow() { 44 | Log.d(TAG, "closeWindow") 45 | if (isShowing) { 46 | isShowing = false 47 | StandOutWindow.closeAll(mContext, FloatWindow::class.java) 48 | } 49 | } 50 | 51 | fun showWindow(number: INumber?, type: Type) { 52 | isShowing = true 53 | val frontType = type.value() 54 | val textColor = TextColorPair.from(number!!) 55 | val bundle = Bundle() 56 | bundle.putString(FloatWindow.NUMBER_INFO, textColor.text) 57 | bundle.putInt(FloatWindow.WINDOW_COLOR, textColor.color) 58 | Log.d(TAG, "showWindow: " + Utils.bundleToString(bundle)) 59 | StandOutWindow.show(mContext, FloatWindow::class.java, 60 | frontType) 61 | StandOutWindow.sendData(mContext, FloatWindow::class.java, 62 | frontType, 0, bundle, FloatWindow::class.java, 0) 63 | } 64 | 65 | fun hideWindow() { 66 | Log.d(TAG, "hideWindow") 67 | if (isShowing) { 68 | StandOutWindow.hide(mContext, FloatWindow::class.java, Type.CALLER.value()) 69 | } 70 | } 71 | 72 | enum class Type(private val mType: Int) { 73 | CALLER(FloatWindow.CALLER_FRONT), POSITION(FloatWindow.SET_POSITION_FRONT), SETTING(FloatWindow.SETTING_FRONT), SEARCH(FloatWindow.SEARCH_FRONT); 74 | 75 | fun value(): Int { 76 | return mType 77 | } 78 | 79 | } 80 | 81 | companion object { 82 | private val TAG = Window::class.java.simpleName 83 | } 84 | 85 | init { 86 | mContext = Application.application 87 | } 88 | } -------------------------------------------------------------------------------- /app/src/main/java/org/xdty/callerinfo/model/permission/PermissionImpl.kt: -------------------------------------------------------------------------------- 1 | package org.xdty.callerinfo.model.permission 2 | 3 | import android.Manifest 4 | import android.app.Activity 5 | import android.content.Context 6 | import android.content.Intent 7 | import android.content.pm.PackageManager 8 | import android.graphics.PixelFormat 9 | import android.net.Uri 10 | import android.os.Build 11 | import android.provider.Settings 12 | import android.view.View 13 | import android.view.WindowManager 14 | import android.view.WindowManager.LayoutParams 15 | 16 | class PermissionImpl(private val mContext: Context) : Permission { 17 | override fun canDrawOverlays(): Boolean { 18 | return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 19 | true 20 | } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) { 21 | Settings.canDrawOverlays(mContext) 22 | } else { 23 | if (Settings.canDrawOverlays(mContext)) { 24 | return true 25 | } 26 | try { 27 | val mgr = mContext.getSystemService( 28 | Context.WINDOW_SERVICE) as WindowManager 29 | ?: return false //getSystemService might return null 30 | val viewToAdd = View(mContext) 31 | val params = LayoutParams(0, 0, 32 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) LayoutParams.TYPE_APPLICATION_OVERLAY else LayoutParams.TYPE_SYSTEM_ALERT, LayoutParams.FLAG_NOT_TOUCHABLE 33 | or LayoutParams.FLAG_NOT_FOCUSABLE, 34 | PixelFormat.TRANSPARENT) 35 | viewToAdd.layoutParams = params 36 | mgr.addView(viewToAdd, params) 37 | mgr.removeView(viewToAdd) 38 | return true 39 | } catch (e: Exception) { 40 | e.printStackTrace() 41 | } 42 | false 43 | } 44 | } 45 | 46 | override fun requestDrawOverlays(context: Context, requestCode: Int) { 47 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 48 | val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, 49 | Uri.parse("package:" + context.packageName)) 50 | if (context is Activity) { 51 | context.startActivityForResult(intent, requestCode) 52 | } 53 | } 54 | } 55 | 56 | override fun checkPermission(permission: String): Int { 57 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 58 | mContext.checkSelfPermission(permission) 59 | } else PackageManager.PERMISSION_GRANTED 60 | } 61 | 62 | override fun requestPermissions(context: Context, permissions: Array, 63 | requestCode: Int) { 64 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 65 | if (context is Activity) { 66 | context.requestPermissions(permissions, requestCode) 67 | } 68 | } 69 | } 70 | 71 | override fun canReadPhoneState(): Boolean { 72 | return checkPermission( 73 | Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED 74 | } 75 | 76 | override fun canReadContact(): Boolean { 77 | return checkPermission( 78 | Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/mark_window.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 21 | 22 | 28 | 29 | 38 | 39 | 43 | 44 | 48 | 49 | 53 | 54 | 58 | 59 | 63 | 64 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 | 29 | 30 | 44 | 45 | 51 | 52 | 59 | 60 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /plugin/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 24 | 25 | 37 | 38 | 55 | 56 |