├── .gitignore ├── app ├── .gitignore ├── ExampleDemo ├── ExampleDemoFlavor.jks ├── build.gradle ├── google-services.json ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── chenyihong │ │ └── exampledemo │ │ └── ExampleInstrumentedTest.kt │ ├── exampleflavor │ ├── assets │ │ └── flavor_config.json │ └── res │ │ ├── drawable │ │ └── icon_android.png │ │ ├── layout │ │ └── layout_flavor_example_activity.xml │ │ └── values │ │ └── strings.xml │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── index.html │ │ ├── index_intercept_request.html │ │ ├── index_new_tab.html │ │ ├── index_open_tab.html │ │ └── test_icon.jpg │ ├── java │ │ └── com │ │ │ └── chenyihong │ │ │ └── exampledemo │ │ │ ├── adapter │ │ │ ├── TestFunctionAdapter.kt │ │ │ ├── TestFunctionGroupAdapter.kt │ │ │ ├── TextDataAdapter.kt │ │ │ └── ViewPager2Adapter.kt │ │ │ ├── androidapi │ │ │ ├── animation │ │ │ │ └── AnimatorSetExampleActivity.kt │ │ │ ├── autofill │ │ │ │ ├── AutofillExampleActivity.kt │ │ │ │ └── ExampleAutofillServices.kt │ │ │ ├── autohide │ │ │ │ └── AutoEdgeHideActivity.kt │ │ │ ├── backpress │ │ │ │ ├── BackPressApiActivity.kt │ │ │ │ ├── FragmentA.kt │ │ │ │ └── FragmentB.kt │ │ │ ├── biometrics │ │ │ │ ├── BiometricActivity.kt │ │ │ │ └── CryptographyManager.kt │ │ │ ├── camerax │ │ │ │ ├── CameraActivity.kt │ │ │ │ └── CameraLifecycle.kt │ │ │ ├── downloadablefont │ │ │ │ └── DownloadableFontActivity.kt │ │ │ ├── fragmentresultapi │ │ │ │ ├── DialogFragment.kt │ │ │ │ ├── FragmentA.kt │ │ │ │ ├── FragmentB.kt │ │ │ │ └── FragmentResultApiActivity.kt │ │ │ ├── fullscreen │ │ │ │ ├── FullScreenActivity.kt │ │ │ │ ├── FullScreenExampleActivity.kt │ │ │ │ └── ImmersionActivity.kt │ │ │ ├── gaid │ │ │ │ └── GaIdActivity.kt │ │ │ ├── gesturedetector │ │ │ │ ├── BaseGestureDetectorActivity.kt │ │ │ │ ├── GestureDetectorAActivity.kt │ │ │ │ └── GestureDetectorBActivity.kt │ │ │ ├── gps │ │ │ │ └── GpsSignalActivity.kt │ │ │ ├── ipandua │ │ │ │ └── IPAndUAExample.kt │ │ │ ├── motionlayout │ │ │ │ └── MotionLayoutExampleActivity.kt │ │ │ ├── resultapi │ │ │ │ ├── ResultApiActivity.kt │ │ │ │ └── custom │ │ │ │ │ ├── MultipleLauncherOptions.kt │ │ │ │ │ ├── PickMultipleMediumContract.kt │ │ │ │ │ └── PickSingleMediumContract.kt │ │ │ ├── search │ │ │ │ ├── RecentSearchProvider.kt │ │ │ │ ├── SearchActivity.kt │ │ │ │ └── SearchExampleActivity.kt │ │ │ ├── setting │ │ │ │ ├── ExampleDataStore.kt │ │ │ │ ├── HelperFragment.kt │ │ │ │ ├── SettingActivity.kt │ │ │ │ ├── SettingFragment.kt │ │ │ │ └── UserInfoFragment.kt │ │ │ ├── sharesheet │ │ │ │ └── SystemShareActivity.kt │ │ │ ├── shortcuts │ │ │ │ ├── CreateCameraShortcutActivity.kt │ │ │ │ ├── CreateLocationShortcutActivity.kt │ │ │ │ └── ShortcutsActivity.kt │ │ │ ├── timechange │ │ │ │ └── TimeChangeExample.kt │ │ │ ├── toolbar │ │ │ │ └── ToolbarActivity.kt │ │ │ ├── trafficstats │ │ │ │ ├── NetSpeedUtils.kt │ │ │ │ └── TrafficStatsActivity.kt │ │ │ └── wifi │ │ │ │ ├── WIFIAdapter.kt │ │ │ │ ├── WIFIEntity.kt │ │ │ │ └── WIFIExampleActivity.kt │ │ │ ├── base │ │ │ ├── ExampleApplication.kt │ │ │ └── MimeType.kt │ │ │ ├── customview │ │ │ ├── CustomChartViewActivity.kt │ │ │ ├── CustomShadowViewActivity.kt │ │ │ └── view │ │ │ │ ├── GradientLineChart.kt │ │ │ │ ├── ShadowView.kt │ │ │ │ └── VolumeControllerDialog.kt │ │ │ ├── entity │ │ │ ├── LineEntity.kt │ │ │ ├── OptionsChildEntity.kt │ │ │ ├── OptionsEntity.kt │ │ │ └── PersonEntity.kt │ │ │ ├── flavor │ │ │ └── FlavorExampleActivity.kt │ │ │ ├── home │ │ │ └── HomeActivity.kt │ │ │ ├── tripartite │ │ │ ├── admob │ │ │ │ ├── AdmobExampleActivity.kt │ │ │ │ ├── AppOpenAdActivity.kt │ │ │ │ └── AppOpenAdManager.kt │ │ │ ├── fcm │ │ │ │ └── ExampleFCMService.kt │ │ │ ├── login │ │ │ │ └── TripartiteLoginActivity.kt │ │ │ └── share │ │ │ │ ├── FacebookShareActivity.kt │ │ │ │ └── TripartiteShareActivity.kt │ │ │ ├── utils │ │ │ ├── DateUtils.kt │ │ │ ├── DensityUtil.kt │ │ │ └── ShapeDrawableUtils.kt │ │ │ └── web │ │ │ ├── JsInteractive.kt │ │ │ ├── WebViewActivity.kt │ │ │ └── customtab │ │ │ ├── CustomTabExampleActivity.kt │ │ │ └── CustomTabHelper.kt │ └── res │ │ ├── anim │ │ ├── slide_in_right.xml │ │ └── slide_out_left.xml │ │ ├── drawable │ │ ├── facebook.webp │ │ ├── google.webp │ │ ├── icon_android.png │ │ ├── icon_back.webp │ │ ├── icon_biometrics.webp │ │ ├── icon_camera.webp │ │ ├── icon_juejin.jpeg │ │ ├── icon_location.webp │ │ ├── icon_lock.webp │ │ ├── icon_scan.webp │ │ ├── icon_scan_32_black.webp │ │ ├── icon_search.webp │ │ ├── icon_search_48.webp │ │ ├── icon_setting.webp │ │ ├── icon_thumb_up.webp │ │ ├── icon_unlock.webp │ │ ├── layer_progress.xml │ │ ├── login.webp │ │ ├── notification.webp │ │ ├── shape_float_bg.xml │ │ ├── shape_float_bg1.xml │ │ ├── shape_oval.xml │ │ ├── shape_red_oval.xml │ │ ├── shape_vollume_controller.xml │ │ ├── wifi_strength_0.webp │ │ ├── wifi_strength_1.webp │ │ ├── wifi_strength_2.webp │ │ └── wifi_strength_3.webp │ │ ├── font │ │ ├── noto_sans.xml │ │ ├── noto_sans_bold.xml │ │ ├── noto_sanssc_bold.otf │ │ ├── noto_sanssc_regular.otf │ │ ├── noto_serif.xml │ │ └── noto_serif_bold.xml │ │ ├── layout │ │ ├── layout_admob_example_activity.xml │ │ ├── layout_admob_native_ad.xml │ │ ├── layout_animatorset_example_activity.xml │ │ ├── layout_app_open_activity.xml │ │ ├── layout_auto_edge_hide_activity.xml │ │ ├── layout_autofill_example_activity.xml │ │ ├── layout_back_press_api_activity.xml │ │ ├── layout_back_press_api_fragment.xml │ │ ├── layout_biometric_activity.xml │ │ ├── layout_camera_activity.xml │ │ ├── layout_connectivity_example_activity.xml │ │ ├── layout_create_shortcuts_activity.xml │ │ ├── layout_custom_chart_view_activity.xml │ │ ├── layout_custom_shadow_view_activity.xml │ │ ├── layout_custom_tab_activity.xml │ │ ├── layout_downloadable_font_activity.xml │ │ ├── layout_facebook_share_activity.xml │ │ ├── layout_flavor_example_activity.xml │ │ ├── layout_fragment_result_api_activity.xml │ │ ├── layout_fragment_result_api_dialog_fragment.xml │ │ ├── layout_fragment_result_api_fragment_a.xml │ │ ├── layout_fragment_result_api_fragment_b.xml │ │ ├── layout_full_screen_activity.xml │ │ ├── layout_full_screen_example_activity.xml │ │ ├── layout_gaid_activity.xml │ │ ├── layout_gesture_detector_activity.xml │ │ ├── layout_gps_signal_activity.xml │ │ ├── layout_home_activity.xml │ │ ├── layout_immersion_activity.xml │ │ ├── layout_motion_layout_example_activity.xml │ │ ├── layout_options_child_item.xml │ │ ├── layout_options_parent_item.xml │ │ ├── layout_result_api_activity.xml │ │ ├── layout_search_activity.xml │ │ ├── layout_search_example_activity.xml │ │ ├── layout_setting_activity.xml │ │ ├── layout_share_activity.xml │ │ ├── layout_shortcuts_activity.xml │ │ ├── layout_system_share_activity.xml │ │ ├── layout_text_content_item.xml │ │ ├── layout_time_change_example_activity.xml │ │ ├── layout_title.xml │ │ ├── layout_toolbar_activity.xml │ │ ├── layout_traffic_stats_activity.xml │ │ ├── layout_tripartite_login_activity.xml │ │ ├── layout_volume_contoller_dialog.xml │ │ ├── layout_web_view_activity.xml │ │ ├── layout_wifi_example_activity.xml │ │ ├── layout_wifi_input_password_dialog.xml │ │ └── layout_wifi_item.xml │ │ ├── menu │ │ ├── example_menu.xml │ │ └── example_seach_menu.xml │ │ ├── mipmap-hdpi │ │ └── icon_back.webp │ │ ├── mipmap-mdpi │ │ └── icon_back.webp │ │ ├── mipmap-xhdpi │ │ └── icon_back.webp │ │ ├── mipmap-xxhdpi │ │ └── icon_back.webp │ │ ├── mipmap-xxxhdpi │ │ └── icon_back.webp │ │ ├── values-night │ │ └── themes.xml │ │ ├── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── font_certs.xml │ │ ├── preloaded_fonts.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── data_extraction_rules.xml │ │ ├── example_motion_scene.xml │ │ ├── example_setting.xml │ │ ├── example_user_info.xml │ │ ├── file_path.xml │ │ ├── full_backup_content.xml │ │ ├── searchable.xml │ │ └── shortcuts.xml │ └── test │ └── java │ └── com │ └── chenyihong │ └── exampledemo │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .cxx 10 | local.properties 11 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/ExampleDemo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/ExampleDemo -------------------------------------------------------------------------------- /app/ExampleDemoFlavor.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/ExampleDemoFlavor.jks -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "905315689902", 4 | "project_id": "exampledemo-1651736171734", 5 | "storage_bucket": "exampledemo-1651736171734.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:905315689902:android:08286b58e58c8c484ad43f", 11 | "android_client_info": { 12 | "package_name": "com.chenyihong.exampledemo" 13 | } 14 | }, 15 | "oauth_client": [ 16 | { 17 | "client_id": "905315689902-lpgfq29mikifeuoodaa0hm36p5quqr5h.apps.googleusercontent.com", 18 | "client_type": 1, 19 | "android_info": { 20 | "package_name": "com.chenyihong.exampledemo", 21 | "certificate_hash": "4a185aa09bd5bbb5a684b75b51477fb334f92897" 22 | } 23 | }, 24 | { 25 | "client_id": "905315689902-hvgsu7564tllr1kaq9k2pecibvno97kq.apps.googleusercontent.com", 26 | "client_type": 3 27 | } 28 | ], 29 | "api_key": [ 30 | { 31 | "current_key": "AIzaSyB7QFJ6Pe0f9ndgH1pBtBxL7X7-QkBJzQg" 32 | } 33 | ], 34 | "services": { 35 | "appinvite_service": { 36 | "other_platform_oauth_client": [ 37 | { 38 | "client_id": "905315689902-hvgsu7564tllr1kaq9k2pecibvno97kq.apps.googleusercontent.com", 39 | "client_type": 3 40 | } 41 | ] 42 | } 43 | } 44 | } 45 | ], 46 | "configuration_version": "1" 47 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/chenyihong/exampledemo/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.chenyihong.exampledemo", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/exampleflavor/assets/flavor_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "flavor_name": "example_flavor" 3 | } -------------------------------------------------------------------------------- /app/src/exampleflavor/res/drawable/icon_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/exampleflavor/res/drawable/icon_android.png -------------------------------------------------------------------------------- /app/src/exampleflavor/res/layout/layout_flavor_example_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 12 | 13 | 22 | 23 | 32 | 33 | 42 | 43 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/exampleflavor/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | FlavorExampleDemo 3 | -------------------------------------------------------------------------------- /app/src/main/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test 6 | 27 | 28 | 29 |
30 |

receive:

31 | 35 | 39 |
40 |
41 | 45 |
46 | 47 | -------------------------------------------------------------------------------- /app/src/main/assets/index_intercept_request.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test 6 | 7 | 8 |
9 | 10 |
11 | 12 | -------------------------------------------------------------------------------- /app/src/main/assets/index_new_tab.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test 6 | 15 | 16 | 17 |
18 |

receive:

19 | 23 |
24 | 25 | -------------------------------------------------------------------------------- /app/src/main/assets/index_open_tab.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test 6 | 15 | 16 | 17 |
18 |

receive:

19 | use a tag 20 | 24 |
25 | 26 | -------------------------------------------------------------------------------- /app/src/main/assets/test_icon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/assets/test_icon.jpg -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/adapter/TestFunctionAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.adapter 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.appcompat.widget.AppCompatTextView 7 | import androidx.recyclerview.widget.RecyclerView 8 | import com.chenyihong.exampledemo.R 9 | import com.chenyihong.exampledemo.entity.OptionsChildEntity 10 | 11 | class TestFunctionAdapter : RecyclerView.Adapter() { 12 | 13 | private val testFunctions = ArrayList() 14 | 15 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TestFunctionViewHolder { 16 | return TestFunctionViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_options_child_item, parent, false)) 17 | } 18 | 19 | override fun onBindViewHolder(holder: TestFunctionViewHolder, position: Int) { 20 | val functionEntity = testFunctions[position] 21 | holder.tvFunctionName.text = functionEntity.testFunctionName 22 | holder.vDividerBottom.visibility = if (position == itemCount - 1) View.GONE else View.VISIBLE 23 | holder.itemView.setOnClickListener { 24 | functionEntity.testFunction.invoke() 25 | } 26 | } 27 | 28 | override fun getItemCount(): Int { 29 | return testFunctions.size 30 | } 31 | 32 | fun setNewData(testFunctions: ArrayList?) { 33 | val currentItemCount = itemCount 34 | if (currentItemCount != 0) { 35 | this.testFunctions.clear() 36 | notifyItemRangeRemoved(0, currentItemCount) 37 | } 38 | if (!testFunctions.isNullOrEmpty()) { 39 | this.testFunctions.addAll(testFunctions) 40 | notifyItemRangeChanged(0, itemCount) 41 | } 42 | } 43 | 44 | class TestFunctionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 45 | val vDividerBottom: View = itemView.findViewById(R.id.v_divider_bottom) 46 | val tvFunctionName: AppCompatTextView = itemView.findViewById(R.id.tv_test_function_name) 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/adapter/TestFunctionGroupAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.adapter 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.appcompat.widget.AppCompatTextView 7 | import androidx.recyclerview.widget.RecyclerView 8 | import androidx.recyclerview.widget.SimpleItemAnimator 9 | import com.chenyihong.exampledemo.R 10 | 11 | import com.minigame.testapp.ui.entity.OptionsEntity 12 | 13 | class TestFunctionGroupAdapter : RecyclerView.Adapter() { 14 | 15 | private val functionGroup = ArrayList() 16 | 17 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TestFunctionGroupViewHolder { 18 | return TestFunctionGroupViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_options_parent_item, parent, false)) 19 | } 20 | 21 | override fun onBindViewHolder(holder: TestFunctionGroupViewHolder, position: Int) { 22 | val functionGroupEntity = functionGroup[position] 23 | holder.vDividerTop.visibility = if (position == 0) View.VISIBLE else View.GONE 24 | holder.tvFunctionGroupName.text = functionGroupEntity.moduleName 25 | holder.tvFunctionGroupName.setOnClickListener { 26 | functionGroupEntity.expanded = !functionGroupEntity.expanded 27 | notifyItemChanged(position) 28 | } 29 | holder.rvTestFunction.visibility = if (functionGroupEntity.expanded) View.VISIBLE else View.GONE 30 | holder.vDividerMiddle.visibility = if (functionGroupEntity.expanded) View.VISIBLE else View.GONE 31 | holder.testFunctionAdapter?.setNewData(functionGroupEntity.containerTest) 32 | } 33 | 34 | override fun getItemCount(): Int { 35 | return functionGroup.size 36 | } 37 | 38 | fun setNewData(functionGroup: ArrayList?) { 39 | val currentItemCount = itemCount 40 | if (currentItemCount != 0) { 41 | this.functionGroup.clear() 42 | notifyItemRangeRemoved(0, currentItemCount) 43 | } 44 | if (!functionGroup.isNullOrEmpty()) { 45 | this.functionGroup.addAll(functionGroup) 46 | notifyItemRangeChanged(0, itemCount) 47 | } 48 | } 49 | 50 | class TestFunctionGroupViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 51 | val vDividerTop: View = itemView.findViewById(R.id.v_divider_top) 52 | val vDividerMiddle: View = itemView.findViewById(R.id.v_divider_middle) 53 | val tvFunctionGroupName: AppCompatTextView = itemView.findViewById(R.id.tv_group_name) 54 | val rvTestFunction: RecyclerView = itemView.findViewById(R.id.rv_test_function) 55 | var testFunctionAdapter: TestFunctionAdapter? = null 56 | 57 | init { 58 | testFunctionAdapter = TestFunctionAdapter() 59 | rvTestFunction.adapter = testFunctionAdapter 60 | val itemAnimator = rvTestFunction.itemAnimator 61 | if (itemAnimator != null) { 62 | (itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false 63 | } 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/adapter/TextDataAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.adapter 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.appcompat.widget.AppCompatTextView 7 | import androidx.recyclerview.widget.RecyclerView 8 | import com.chenyihong.exampledemo.R 9 | 10 | class TextDataAdapter : RecyclerView.Adapter() { 11 | 12 | private val textData = ArrayList() 13 | 14 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextDataViewHolder { 15 | return TextDataViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_text_content_item, parent, false)) 16 | } 17 | 18 | override fun onBindViewHolder(holder: TextDataViewHolder, position: Int) { 19 | holder.tvTextDataContent.text = textData[position] 20 | } 21 | 22 | override fun getItemCount(): Int { 23 | return textData.size 24 | } 25 | 26 | fun setNewData(searchData: ArrayList?) { 27 | val lastItemCount = itemCount 28 | if (lastItemCount != 0) { 29 | this.textData.clear() 30 | notifyItemRangeRemoved(0, lastItemCount) 31 | } 32 | searchData?.let { this.textData.addAll(it) } 33 | notifyItemChanged(0, itemCount) 34 | } 35 | 36 | class TextDataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 37 | val tvTextDataContent: AppCompatTextView = itemView.findViewById(R.id.tv_content) 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/adapter/ViewPager2Adapter.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.adapter 2 | 3 | import androidx.fragment.app.Fragment 4 | import androidx.fragment.app.FragmentActivity 5 | import androidx.viewpager2.adapter.FragmentStateAdapter 6 | 7 | class ViewPager2Adapter : FragmentStateAdapter { 8 | 9 | private val fragments: ArrayList> 10 | 11 | constructor(fragment: Fragment, fragments: ArrayList>) : super(fragment) { 12 | this.fragments = fragments 13 | } 14 | 15 | constructor(fragmentActivity: FragmentActivity, fragments: ArrayList>) : super(fragmentActivity) { 16 | this.fragments = fragments 17 | } 18 | 19 | override fun getItemCount(): Int { 20 | return fragments.size 21 | } 22 | 23 | override fun createFragment(position: Int): Fragment { 24 | return fragments[position].newInstance()!! 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/autofill/AutofillExampleActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.autofill 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.net.Uri 6 | import android.os.Build 7 | import android.os.Bundle 8 | import android.provider.Settings 9 | import android.util.Log 10 | import android.view.autofill.AutofillManager 11 | import androidx.activity.result.contract.ActivityResultContracts 12 | import androidx.core.widget.addTextChangedListener 13 | import androidx.databinding.DataBindingUtil 14 | import com.chenyihong.exampledemo.R 15 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 16 | import com.chenyihong.exampledemo.databinding.LayoutAutofillExampleActivityBinding 17 | 18 | const val TAG = "AutofillExampleTag" 19 | 20 | class AutoFillExampleActivity : BaseGestureDetectorActivity() { 21 | 22 | private val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { 23 | if (it.resultCode == Activity.RESULT_OK) { 24 | Log.i(TAG, "result ok") 25 | } 26 | } 27 | 28 | override fun onCreate(savedInstanceState: Bundle?) { 29 | super.onCreate(savedInstanceState) 30 | val binding = DataBindingUtil.setContentView(this, R.layout.layout_autofill_example_activity) 31 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 32 | val autofillManager = getSystemService(AutofillManager::class.java) 33 | binding.etAccount.addTextChangedListener { 34 | it?.run { 35 | binding.etPassword.text?.let { passwordText -> 36 | binding.btnCommit.isEnabled = isNotEmpty() && passwordText.isNotEmpty() 37 | } 38 | } 39 | } 40 | binding.etPassword.addTextChangedListener { 41 | it?.run { 42 | binding.etAccount.text?.let { accountText -> 43 | binding.btnCommit.isEnabled = isNotEmpty() && accountText.isNotEmpty() 44 | } 45 | } 46 | } 47 | binding.btnCommit.setOnClickListener { 48 | binding.etAccount.clearFocus() 49 | binding.etPassword.clearFocus() 50 | autofillManager.commit() 51 | } 52 | binding.btnChangeAutofillService.setOnClickListener { 53 | // isAutofillSupported判断设备是否支持自动填充服务 54 | // hasEnabledAutofillServices判断当前使用的自动填充服务是否是我们自定义的 55 | if (autofillManager.isAutofillSupported && !autofillManager.hasEnabledAutofillServices()) { 56 | launcher.launch(Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE).apply { 57 | data = Uri.parse("package:com.chenyihong.exampledemo") 58 | }) 59 | } 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/backpress/BackPressApiActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.backpress 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.util.Log 6 | import androidx.activity.OnBackPressedCallback 7 | import androidx.databinding.DataBindingUtil 8 | import androidx.fragment.app.Fragment 9 | import com.chenyihong.exampledemo.R 10 | import com.chenyihong.exampledemo.adapter.ViewPager2Adapter 11 | import com.chenyihong.exampledemo.databinding.LayoutBackPressApiActivityBinding 12 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 13 | 14 | const val TAG = "BackPressApi" 15 | 16 | class BackPressApiActivity : BaseGestureDetectorActivity() { 17 | 18 | private val canonicalName = this::class.java.canonicalName!! 19 | 20 | @SuppressLint("SetTextI18n") 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | val binding = DataBindingUtil.setContentView(this, R.layout.layout_back_press_api_activity) 24 | supportFragmentManager.setFragmentResultListener(canonicalName, this) { requestKey, result -> 25 | Log.i(com.chenyihong.exampledemo.androidapi.fragmentresultapi.TAG, "Activity receive result requestKey:$requestKey ,result:$result") 26 | if (requestKey == canonicalName) { 27 | val resultIndex = result.getInt("result", -1) 28 | if (resultIndex != -1) { 29 | binding.vpContainer.currentItem = resultIndex 30 | } 31 | } 32 | } 33 | onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) { 34 | override fun handleOnBackPressed() { 35 | Log.i(TAG, "BackPressApiActivity OnBackPressedCallback handleOnBackPressed function invoke") 36 | finish() 37 | } 38 | }) 39 | binding.run { 40 | includeTitle.tvTitle.text = "BackPress Api" 41 | btnAFragment.setOnClickListener { 42 | vpContainer.currentItem = 0 43 | } 44 | btnBFragment.setOnClickListener { 45 | vpContainer.currentItem = 1 46 | } 47 | 48 | val fragments = ArrayList>() 49 | fragments.add(FragmentA::class.java) 50 | fragments.add(FragmentB::class.java) 51 | 52 | vpContainer.adapter = ViewPager2Adapter(this@BackPressApiActivity, fragments) 53 | vpContainer.isUserInputEnabled = false 54 | 55 | vpContainer.currentItem = 0 56 | } 57 | } 58 | 59 | override fun onDestroy() { 60 | super.onDestroy() 61 | supportFragmentManager.clearFragmentResultListener(canonicalName) 62 | } 63 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/backpress/FragmentA.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.backpress 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.util.Log 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import androidx.activity.OnBackPressedCallback 10 | import androidx.databinding.DataBindingUtil 11 | import androidx.fragment.app.Fragment 12 | import com.chenyihong.exampledemo.R 13 | import com.chenyihong.exampledemo.databinding.LayoutBackPressApiFragmentBinding 14 | 15 | class FragmentA : Fragment() { 16 | 17 | lateinit var binding: LayoutBackPressApiFragmentBinding 18 | 19 | private val onBackPressedCallback = object : OnBackPressedCallback(true) { 20 | override fun handleOnBackPressed() { 21 | Log.i(TAG, "FragmentA OnBackPressedCallback handleOnBackPressed function invoke") 22 | isEnabled = false 23 | requireActivity().onBackPressedDispatcher.onBackPressed() 24 | } 25 | } 26 | 27 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { 28 | binding = DataBindingUtil.inflate(inflater, R.layout.layout_back_press_api_fragment, container, false) 29 | return binding.root 30 | } 31 | 32 | @SuppressLint("SetTextI18n") 33 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 34 | super.onViewCreated(view, savedInstanceState) 35 | requireActivity().onBackPressedDispatcher.addCallback(onBackPressedCallback) 36 | binding.includeTitle.tvTitle.text = "BackPressFragmentA" 37 | binding.btnBackPress.setOnClickListener { 38 | requireActivity().onBackPressedDispatcher.onBackPressed() 39 | } 40 | } 41 | 42 | override fun onResume() { 43 | super.onResume() 44 | onBackPressedCallback.isEnabled = true 45 | } 46 | 47 | override fun onPause() { 48 | super.onPause() 49 | onBackPressedCallback.isEnabled = false 50 | } 51 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/backpress/FragmentB.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.backpress 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.util.Log 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import androidx.activity.OnBackPressedCallback 10 | import androidx.databinding.DataBindingUtil 11 | import androidx.fragment.app.Fragment 12 | import com.chenyihong.exampledemo.R 13 | import com.chenyihong.exampledemo.databinding.LayoutBackPressApiFragmentBinding 14 | 15 | class FragmentB : Fragment() { 16 | 17 | lateinit var binding: LayoutBackPressApiFragmentBinding 18 | 19 | private val onBackPressedCallback = object : OnBackPressedCallback(true) { 20 | override fun handleOnBackPressed() { 21 | Log.i(TAG, "FragmentB OnBackPressedCallback handleOnBackPressed function invoke") 22 | parentFragmentManager.setFragmentResult(BackPressApiActivity::class.java.canonicalName!!, Bundle().apply { putInt("result", 0) }) 23 | } 24 | } 25 | 26 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { 27 | binding = DataBindingUtil.inflate(inflater, R.layout.layout_back_press_api_fragment, container, false) 28 | return binding.root 29 | } 30 | 31 | @SuppressLint("SetTextI18n") 32 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 33 | super.onViewCreated(view, savedInstanceState) 34 | requireActivity().onBackPressedDispatcher.addCallback(onBackPressedCallback) 35 | binding.includeTitle.tvTitle.text = "BackPressFragmentB" 36 | binding.btnBackPress.setOnClickListener { 37 | requireActivity().onBackPressedDispatcher.onBackPressed() 38 | } 39 | } 40 | 41 | override fun onResume() { 42 | super.onResume() 43 | onBackPressedCallback.isEnabled = true 44 | } 45 | 46 | override fun onPause() { 47 | super.onPause() 48 | onBackPressedCallback.isEnabled = false 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/camerax/CameraLifecycle.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.camerax 2 | 3 | import androidx.lifecycle.Lifecycle 4 | import androidx.lifecycle.LifecycleOwner 5 | import androidx.lifecycle.LifecycleRegistry 6 | 7 | class CameraLifecycle : LifecycleOwner { 8 | 9 | private var lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this) 10 | 11 | fun cameraOnCreate() { 12 | lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) 13 | } 14 | 15 | fun cameraOnStart() { 16 | lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START) 17 | } 18 | 19 | fun cameraOnResume() { 20 | lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) 21 | } 22 | 23 | fun cameraOnPause() { 24 | lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE) 25 | } 26 | 27 | fun cameraOnStop() { 28 | lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP) 29 | } 30 | 31 | fun cameraOnDestroyed() { 32 | lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) 33 | } 34 | 35 | override fun getLifecycle(): Lifecycle { 36 | return lifecycleRegistry 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/downloadablefont/DownloadableFontActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.downloadablefont 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import androidx.databinding.DataBindingUtil 6 | import com.chenyihong.exampledemo.R 7 | import com.chenyihong.exampledemo.databinding.LayoutDownloadableFontActivityBinding 8 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 9 | 10 | class DownloadableFontActivity : BaseGestureDetectorActivity() { 11 | 12 | @SuppressLint("SetTextI18n") 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | val binding: LayoutDownloadableFontActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_downloadable_font_activity) 16 | binding.includeTitle.tvTitle.text = "DownloadAbleFont" 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/fragmentresultapi/DialogFragment.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.fragmentresultapi 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.util.Log 6 | import android.view.* 7 | import androidx.core.content.ContextCompat 8 | import androidx.databinding.DataBindingUtil 9 | import androidx.fragment.app.DialogFragment 10 | import androidx.fragment.app.Fragment 11 | import com.chenyihong.exampledemo.R 12 | import com.chenyihong.exampledemo.databinding.LayoutFragmentResultApiDialogFragmentBinding 13 | import com.chenyihong.exampledemo.adapter.ViewPager2Adapter 14 | 15 | class DialogFragment : DialogFragment() { 16 | 17 | private var binding: LayoutFragmentResultApiDialogFragmentBinding? = null 18 | 19 | private val canonicalName = this::class.java.canonicalName!! 20 | 21 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 22 | dialog?.window?.run { 23 | setBackgroundDrawable(ContextCompat.getDrawable(requireContext(), android.R.color.transparent)) 24 | decorView.setBackgroundResource(android.R.color.transparent) 25 | 26 | val layoutParams = attributes 27 | layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT 28 | layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT 29 | layoutParams.gravity = Gravity.CENTER 30 | attributes = layoutParams 31 | } 32 | binding = DataBindingUtil.inflate(inflater, R.layout.layout_fragment_result_api_dialog_fragment, container, false) 33 | return binding?.root 34 | } 35 | 36 | @SuppressLint("SetTextI18n") 37 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 38 | super.onViewCreated(view, savedInstanceState) 39 | childFragmentManager.setFragmentResultListener(canonicalName, this) { requestKey, result -> 40 | Log.i(TAG, "Dialog Fragment receive result requestKey:$requestKey ,result:$result") 41 | binding?.tvReceiver?.text = "Dialog Fragment receive: requestKey = $requestKey ,result = $result" 42 | val bundle = Bundle() 43 | bundle.putString("result", "DialogFragment transit ${result.getString("result", "")}") 44 | parentFragmentManager.setFragmentResult(FragmentResultApiActivity::class.java.canonicalName!!, bundle) 45 | } 46 | binding?.run { 47 | btnAFragment.setOnClickListener { 48 | vpContainer.currentItem = 0 49 | } 50 | btnBFragment.setOnClickListener { 51 | vpContainer.currentItem = 1 52 | } 53 | 54 | val fragments = ArrayList>() 55 | fragments.add(FragmentA::class.java) 56 | fragments.add(FragmentB::class.java) 57 | 58 | vpContainer.adapter = ViewPager2Adapter(this@DialogFragment, fragments) 59 | vpContainer.isUserInputEnabled = false 60 | 61 | vpContainer.currentItem = 0 62 | } 63 | } 64 | 65 | override fun onDestroyView() { 66 | binding?.unbind() 67 | childFragmentManager.clearFragmentResultListener(canonicalName) 68 | super.onDestroyView() 69 | } 70 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/fragmentresultapi/FragmentA.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.fragmentresultapi 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.util.Log 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import androidx.databinding.DataBindingUtil 10 | import androidx.fragment.app.Fragment 11 | import com.chenyihong.exampledemo.R 12 | import com.chenyihong.exampledemo.databinding.LayoutFragmentResultApiFragmentABinding 13 | 14 | class FragmentA : Fragment() { 15 | 16 | lateinit var binding: LayoutFragmentResultApiFragmentABinding 17 | 18 | private val canonicalName = this::class.java.canonicalName!! 19 | 20 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { 21 | binding = DataBindingUtil.inflate(inflater, R.layout.layout_fragment_result_api_fragment_a, container, false) 22 | return binding.root 23 | } 24 | 25 | @SuppressLint("SetTextI18n") 26 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 27 | super.onViewCreated(view, savedInstanceState) 28 | parentFragmentManager.setFragmentResultListener(canonicalName, this) { requestKey, result -> 29 | Log.i(TAG, "A Fragment receive result requestKey:$requestKey ,result:$result") 30 | binding.tvReceiver.text = "A Fragment receive: requestKey = $requestKey ,result = $result" 31 | } 32 | binding.includeTitle.tvTitle.text = "Fragment A" 33 | binding.btnSendParent.setOnClickListener { 34 | val bundle = Bundle() 35 | bundle.putString("result", "a result from Fragment A") 36 | parentFragmentManager.setFragmentResult(DialogFragment::class.java.canonicalName!!, bundle) 37 | } 38 | binding.btnSendToB.setOnClickListener { 39 | val bundle = Bundle() 40 | bundle.putString("result", "a result from Fragment A") 41 | parentFragmentManager.setFragmentResult(FragmentB::class.java.canonicalName!!, bundle) 42 | } 43 | } 44 | 45 | override fun onDestroyView() { 46 | super.onDestroyView() 47 | parentFragmentManager.clearFragmentResultListener(canonicalName) 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/fragmentresultapi/FragmentB.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.fragmentresultapi 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.util.Log 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import androidx.databinding.DataBindingUtil 10 | import androidx.fragment.app.Fragment 11 | import com.chenyihong.exampledemo.R 12 | import com.chenyihong.exampledemo.databinding.LayoutFragmentResultApiFragmentBBinding 13 | 14 | class FragmentB : Fragment() { 15 | 16 | lateinit var binding: LayoutFragmentResultApiFragmentBBinding 17 | 18 | private val canonicalName = this::class.java.canonicalName!! 19 | 20 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { 21 | binding = DataBindingUtil.inflate(inflater, R.layout.layout_fragment_result_api_fragment_b, container, false) 22 | return binding.root 23 | } 24 | 25 | @SuppressLint("SetTextI18n") 26 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 27 | super.onViewCreated(view, savedInstanceState) 28 | parentFragmentManager.setFragmentResultListener(canonicalName, this) { requestKey, result -> 29 | Log.i(TAG, "B Fragment receive result requestKey:$requestKey ,result:$result") 30 | binding.tvReceiver.text = "B Fragment receive: requestKey = $requestKey ,result = $result" 31 | } 32 | binding.includeTitle.tvTitle.text="Fragment B" 33 | binding.btnSendToA.setOnClickListener { 34 | val bundle = Bundle() 35 | bundle.putString("result", "a result from Fragment B") 36 | parentFragmentManager.setFragmentResult(FragmentA::class.java.canonicalName!!, bundle) 37 | } 38 | } 39 | 40 | override fun onDestroyView() { 41 | super.onDestroyView() 42 | parentFragmentManager.clearFragmentResultListener(canonicalName) 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/fragmentresultapi/FragmentResultApiActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.fragmentresultapi 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.util.Log 6 | import androidx.databinding.DataBindingUtil 7 | import com.chenyihong.exampledemo.R 8 | import com.chenyihong.exampledemo.databinding.LayoutFragmentResultApiActivityBinding 9 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 10 | 11 | const val TAG = "FragmentResultAPI" 12 | 13 | class FragmentResultApiActivity : BaseGestureDetectorActivity() { 14 | 15 | private val canonicalName = this::class.java.canonicalName!! 16 | 17 | @SuppressLint("SetTextI18n") 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | val binding = DataBindingUtil.setContentView(this, R.layout.layout_fragment_result_api_activity) 21 | 22 | binding.includeTitle.tvTitle.text = "Fragment Result Api" 23 | supportFragmentManager.setFragmentResultListener(canonicalName, this) { requestKey, result -> 24 | Log.i(TAG, "Activity receive result requestKey:$requestKey ,result:$result") 25 | binding.tvReceiver.text = "Activity receive: requestKey = $requestKey ,result = $result" 26 | } 27 | 28 | binding.btnShowDialog.setOnClickListener { 29 | DialogFragment().show(supportFragmentManager, null) 30 | } 31 | } 32 | 33 | override fun onDestroy() { 34 | super.onDestroy() 35 | supportFragmentManager.clearFragmentResultListener(canonicalName) 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/fullscreen/FullScreenActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.fullscreen 2 | 3 | import android.os.Bundle 4 | import androidx.core.view.* 5 | import androidx.databinding.DataBindingUtil 6 | import com.chenyihong.exampledemo.R 7 | import com.chenyihong.exampledemo.databinding.LayoutFullScreenActivityBinding 8 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 9 | 10 | class FullScreenActivity : BaseGestureDetectorActivity() { 11 | 12 | lateinit var binding: LayoutFullScreenActivityBinding 13 | 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | binding = DataBindingUtil.setContentView(this, R.layout.layout_full_screen_activity) 17 | val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView) 18 | windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE 19 | windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/fullscreen/FullScreenExampleActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.fullscreen 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.databinding.DataBindingUtil 7 | import com.chenyihong.exampledemo.R 8 | import com.chenyihong.exampledemo.databinding.LayoutFullScreenExampleActivityBinding 9 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 10 | 11 | class FullScreenExampleActivity : BaseGestureDetectorActivity() { 12 | 13 | @SuppressLint("SetTextI18n") 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | val binding = DataBindingUtil.setContentView(this, R.layout.layout_full_screen_example_activity) 17 | 18 | binding.includeTitle.tvTitle.text = "FullScreen Api" 19 | binding.btnFullScreen.setOnClickListener { 20 | startActivity(Intent(this, FullScreenActivity::class.java)) 21 | } 22 | 23 | binding.btnImmersion.setOnClickListener { 24 | startActivity(Intent(this, ImmersionActivity::class.java)) 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/fullscreen/ImmersionActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.fullscreen 2 | 3 | import android.os.Bundle 4 | import androidx.constraintlayout.widget.ConstraintLayout 5 | import androidx.core.content.ContextCompat 6 | import androidx.core.view.* 7 | import androidx.databinding.DataBindingUtil 8 | import com.chenyihong.exampledemo.R 9 | import com.chenyihong.exampledemo.databinding.LayoutImmersionActivityBinding 10 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 11 | 12 | class ImmersionActivity : BaseGestureDetectorActivity() { 13 | 14 | private lateinit var windowInsetsController: WindowInsetsControllerCompat 15 | 16 | lateinit var binding: LayoutImmersionActivityBinding 17 | 18 | private var hadChange = false 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | binding = DataBindingUtil.setContentView(this, R.layout.layout_immersion_activity) 23 | 24 | WindowCompat.setDecorFitsSystemWindows(window, false) 25 | windowInsetsController = WindowCompat.getInsetsController(window, window.decorView) 26 | //透明的导航栏 27 | windowInsetsController.isAppearanceLightNavigationBars = false 28 | 29 | ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets -> 30 | if (!hadChange) { 31 | hadChange = true 32 | val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 33 | //状态栏高度 34 | val statusBarHeight = insets.top 35 | //调整顶部控件的高度 36 | binding.topView.run { 37 | updateLayoutParams { 38 | height += statusBarHeight 39 | } 40 | updatePadding(top = paddingTop + statusBarHeight) 41 | } 42 | binding.tvTitle.run { 43 | updateLayoutParams { 44 | topMargin += statusBarHeight 45 | } 46 | } 47 | 48 | //导航栏高度 49 | val navigationBarHeight = insets.bottom 50 | //调整圆点控件不被导航栏遮挡 51 | binding.bottomView.run { 52 | updateLayoutParams { 53 | bottomMargin += navigationBarHeight 54 | } 55 | } 56 | } 57 | WindowInsetsCompat.CONSUMED 58 | } 59 | 60 | binding.btnChangeToLightBar.setOnClickListener { 61 | lightBar() 62 | } 63 | 64 | binding.btnChangeToDarkBar.setOnClickListener { 65 | darkBar() 66 | } 67 | } 68 | 69 | private fun lightBar() { 70 | binding.topView.setBackgroundColor(ContextCompat.getColor(this, R.color.white)) 71 | binding.tvTitle.setTextColor(ContextCompat.getColor(this, R.color.black)) 72 | setBarStatus(true) 73 | } 74 | 75 | private fun darkBar() { 76 | binding.topView.setBackgroundColor(ContextCompat.getColor(this, R.color.color_23242a)) 77 | binding.tvTitle.setTextColor(ContextCompat.getColor(this, R.color.white)) 78 | setBarStatus(false) 79 | } 80 | 81 | private fun setBarStatus(light: Boolean) { 82 | windowInsetsController.isAppearanceLightStatusBars = light 83 | } 84 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/gesturedetector/GestureDetectorAActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.gesturedetector 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.databinding.DataBindingUtil 7 | import com.chenyihong.exampledemo.R 8 | import com.chenyihong.exampledemo.databinding.LayoutGestureDetectorActivityBinding 9 | 10 | class GestureDetectorAActivity : BaseGestureDetectorActivity() { 11 | 12 | @SuppressLint("SetTextI18n") 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | val binding = DataBindingUtil.setContentView(this, R.layout.layout_gesture_detector_activity) 16 | binding.tvTitle.text = "Gesture Detector Api" 17 | binding.btnEntrance.setOnClickListener { 18 | startActivity(Intent(this, GestureDetectorBActivity::class.java)) 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/gesturedetector/GestureDetectorBActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.gesturedetector 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.view.View 6 | import androidx.databinding.DataBindingUtil 7 | import com.chenyihong.exampledemo.R 8 | import com.chenyihong.exampledemo.databinding.LayoutGestureDetectorActivityBinding 9 | 10 | class GestureDetectorBActivity : BaseGestureDetectorActivity() { 11 | 12 | @SuppressLint("SetTextI18n") 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | val binding = DataBindingUtil.setContentView(this, R.layout.layout_gesture_detector_activity) 16 | binding.tvTitle.text = "Gesture Detector B" 17 | binding.btnEntrance.visibility = View.GONE 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/motionlayout/MotionLayoutExampleActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.motionlayout 2 | 3 | import android.os.Bundle 4 | import android.util.Log 5 | import android.view.View 6 | import androidx.constraintlayout.motion.widget.MotionLayout 7 | import androidx.databinding.DataBindingUtil 8 | import com.chenyihong.exampledemo.R 9 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 10 | import com.chenyihong.exampledemo.databinding.LayoutMotionLayoutExampleActivityBinding 11 | 12 | const val TAG = "MotionLayoutExampleTag" 13 | 14 | class MotionLayoutExampleActivity : BaseGestureDetectorActivity() { 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | val binding: LayoutMotionLayoutExampleActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_motion_layout_example_activity) 19 | binding.motionLayout.setTransitionListener(object : MotionLayout.TransitionListener { 20 | override fun onTransitionStarted(motionLayout: MotionLayout?, startId: Int, endId: Int) { 21 | Log.i(TAG, "onTransitionStarted startId:$startId, endId:$endId") 22 | // 动画开始 23 | // 把发散的按钮显示出来 24 | binding.ivThumbUp1.visibility = View.VISIBLE 25 | binding.ivThumbUp2.visibility = View.VISIBLE 26 | binding.ivThumbUp3.visibility = View.VISIBLE 27 | binding.ivThumbUp4.visibility = View.VISIBLE 28 | binding.ivThumbUp5.visibility = View.VISIBLE 29 | } 30 | 31 | override fun onTransitionChange(motionLayout: MotionLayout?, startId: Int, endId: Int, progress: Float) { 32 | Log.i(TAG, "onTransitionChange startId:$startId, endId:$endId, progress:$progress") 33 | // 动画进行中 34 | } 35 | 36 | override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) { 37 | Log.i(TAG, "onTransitionCompleted currentId:$currentId") 38 | // 动画完成 39 | // 隐藏发散的按钮,将状态还原 40 | binding.root.postDelayed({ 41 | binding.ivThumbUp1.visibility = View.GONE 42 | binding.ivThumbUp2.visibility = View.GONE 43 | binding.ivThumbUp3.visibility = View.GONE 44 | binding.ivThumbUp4.visibility = View.GONE 45 | binding.ivThumbUp5.visibility = View.GONE 46 | binding.motionLayout.progress = 0f 47 | }, 200) 48 | } 49 | 50 | override fun onTransitionTrigger(motionLayout: MotionLayout?, triggerId: Int, positive: Boolean, progress: Float) { 51 | Log.i(TAG, "onTransitionTrigger triggerId:$triggerId, positive:$positive, progress:$progress") 52 | } 53 | }) 54 | } 55 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/resultapi/custom/MultipleLauncherOptions.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.resultapi.custom 2 | 3 | data class MultipleLauncherOptions(val mimeType: String?, val maxCount: Int) -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/resultapi/custom/PickMultipleMediumContract.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.resultapi.custom 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.net.Uri 7 | import android.os.Build 8 | import android.provider.MediaStore 9 | import androidx.activity.result.contract.ActivityResultContract 10 | import com.chenyihong.exampledemo.base.MimeType 11 | 12 | class PickMultipleMediumContract : ActivityResultContract>() { 13 | 14 | override fun createIntent(context: Context, input: MultipleLauncherOptions?): Intent { 15 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { 16 | val maxLimit = MediaStore.getPickImagesMaxLimit() 17 | val inputMaxCount = input?.maxCount ?: 0 18 | val finalMaxCount = if (inputMaxCount != 0 && inputMaxCount < maxLimit) inputMaxCount else maxLimit 19 | Intent(MediaStore.ACTION_PICK_IMAGES) 20 | .setType(if (input?.mimeType.isNullOrEmpty() || input?.mimeType.isNullOrBlank()) MimeType.ALL else input?.mimeType) 21 | .putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, finalMaxCount) 22 | } else { 23 | Intent(Intent.ACTION_PICK) 24 | .setType(if (input?.mimeType.isNullOrEmpty() || input?.mimeType.isNullOrBlank()) MimeType.ALL else input?.mimeType) 25 | .putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) 26 | } 27 | } 28 | 29 | override fun parseResult(resultCode: Int, intent: Intent?): List { 30 | return if (intent == null || resultCode != Activity.RESULT_OK) { 31 | emptyList() 32 | } else { 33 | getClipDataUris(intent) 34 | } 35 | } 36 | 37 | private fun getClipDataUris(intent: Intent): List { 38 | val resultSet = LinkedHashSet() 39 | intent.data?.let { resultSet.add(it) } 40 | val clipData = intent.clipData 41 | if (clipData == null && resultSet.isEmpty()) { 42 | return emptyList() 43 | } else if (clipData != null) { 44 | for (i in 0 until clipData.itemCount) { 45 | val uri = clipData.getItemAt(i).uri 46 | if (uri != null) { 47 | resultSet.add(uri) 48 | } 49 | } 50 | } 51 | return ArrayList(resultSet) 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/resultapi/custom/PickSingleMediumContract.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.resultapi.custom 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.net.Uri 7 | import android.os.Build 8 | import android.provider.MediaStore 9 | import androidx.activity.result.contract.ActivityResultContract 10 | import com.chenyihong.exampledemo.base.MimeType 11 | 12 | class PickSingleMediumContract : ActivityResultContract() { 13 | 14 | override fun createIntent(context: Context, input: String?): Intent { 15 | return Intent(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) MediaStore.ACTION_PICK_IMAGES else Intent.ACTION_PICK) 16 | .setType(if (input.isNullOrEmpty() || input.isBlank()) MimeType.ALL else input) 17 | } 18 | 19 | override fun parseResult(resultCode: Int, intent: Intent?): Uri? { 20 | return if (intent == null || resultCode != Activity.RESULT_OK) null else intent.data 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/search/RecentSearchProvider.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.search 2 | 3 | import android.content.SearchRecentSuggestionsProvider 4 | 5 | class RecentSearchProvider : SearchRecentSuggestionsProvider() { 6 | 7 | companion object { 8 | const val AUTHORITY = "com.chenyihong.exampledemo.androidapi.search.RecentSearchProvider" 9 | const val MODE: Int = DATABASE_MODE_QUERIES or DATABASE_MODE_2LINES 10 | } 11 | 12 | init { 13 | setupSuggestions(AUTHORITY, MODE) 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/search/SearchExampleActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.search 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.SearchManager 5 | import android.content.Context 6 | import android.content.Intent 7 | import android.os.Bundle 8 | import androidx.databinding.DataBindingUtil 9 | import com.chenyihong.exampledemo.R 10 | import com.chenyihong.exampledemo.databinding.LayoutSearchExampleActivityBinding 11 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 12 | 13 | class SearchExampleActivity : BaseGestureDetectorActivity() { 14 | 15 | override fun onSearchRequested(): Boolean { 16 | val appData = Bundle() 17 | appData.putString("gender", "male") 18 | appData.putInt("age", 24) 19 | startSearch(null, false, appData, false) 20 | return true 21 | } 22 | 23 | @SuppressLint("SetTextI18n") 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | val binding: LayoutSearchExampleActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_search_example_activity) 27 | binding.includeTitle.tvTitle.text = "Search Api" 28 | binding.btnSearchView.setOnClickListener { startActivity(Intent(this, SearchActivity::class.java)) } 29 | binding.btnSearchDialog.setOnClickListener { onSearchRequested() } 30 | val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager 31 | searchManager.setOnDismissListener { 32 | showToast("Search Dialog dismiss") 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/setting/HelperFragment.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.setting 2 | 3 | import android.os.Bundle 4 | import android.widget.Toast 5 | import androidx.preference.Preference 6 | import androidx.preference.PreferenceCategory 7 | import androidx.preference.PreferenceFragmentCompat 8 | 9 | class HelperFragment : PreferenceFragmentCompat() { 10 | 11 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 12 | val context = preferenceManager.context 13 | val screen = preferenceManager.createPreferenceScreen(context) 14 | val qaPreferenceCategory = PreferenceCategory(context) 15 | qaPreferenceCategory.key = "qa" 16 | qaPreferenceCategory.title = "QA" 17 | val qa1Preference = Preference(context) 18 | qa1Preference.key = "qa1" 19 | qa1Preference.title = "How to open Notification" 20 | qa1Preference.summary = "Open system setting" 21 | val qa2Preference = Preference(context) 22 | qa2Preference.key = "qa2" 23 | qa2Preference.title = "How to bind google account" 24 | qa2Preference.summary = "oOpen settings, bind Google login" 25 | screen.addPreference(qaPreferenceCategory) 26 | qaPreferenceCategory.addPreference(qa1Preference) 27 | qaPreferenceCategory.addPreference(qa2Preference) 28 | val contactPreferenceCategory = PreferenceCategory(context) 29 | contactPreferenceCategory.key = "contact" 30 | contactPreferenceCategory.title = "Contact" 31 | val onlineContactPreference = Preference(context) 32 | onlineContactPreference.key = "online_customer" 33 | onlineContactPreference.title = "Online customer" 34 | onlineContactPreference.summary = "Contact online customer service to solve your problem" 35 | onlineContactPreference.setOnPreferenceClickListener { 36 | requireActivity().runOnUiThread { Toast.makeText(requireContext(), "Click online customer", Toast.LENGTH_SHORT).show() } 37 | true 38 | } 39 | val telephoneContactPreference = Preference(context) 40 | telephoneContactPreference.key = "telephone_customer" 41 | telephoneContactPreference.title = "Telephone customer" 42 | telephoneContactPreference.summary = "Contact telephone_contact customer service to solve your problem" 43 | telephoneContactPreference.setOnPreferenceClickListener { 44 | requireActivity().runOnUiThread { Toast.makeText(requireContext(), "Click Telephone customer", Toast.LENGTH_SHORT).show() } 45 | true 46 | } 47 | screen.addPreference(contactPreferenceCategory) 48 | contactPreferenceCategory.addPreference(onlineContactPreference) 49 | contactPreferenceCategory.addPreference(telephoneContactPreference) 50 | preferenceScreen = screen 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/setting/SettingActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.setting 2 | 3 | import android.os.Bundle 4 | import androidx.databinding.DataBindingUtil 5 | import androidx.lifecycle.lifecycleScope 6 | import androidx.preference.Preference 7 | import androidx.preference.PreferenceFragmentCompat 8 | import com.chenyihong.exampledemo.R 9 | import com.chenyihong.exampledemo.databinding.LayoutSettingActivityBinding 10 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 11 | 12 | const val TAG = "PreferenceApi" 13 | 14 | class SettingActivity : BaseGestureDetectorActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { 15 | 16 | private lateinit var binding: LayoutSettingActivityBinding 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | binding = DataBindingUtil.setContentView(this, R.layout.layout_setting_activity) 21 | ExampleDataStore.coroutineScope = lifecycleScope 22 | supportFragmentManager 23 | .beginTransaction() 24 | .replace(R.id.ct_setting_container, SettingFragment()) 25 | .commitAllowingStateLoss() 26 | } 27 | 28 | override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference): Boolean { 29 | pref.fragment?.let { 30 | val fragment = supportFragmentManager.fragmentFactory.instantiate(classLoader, it) 31 | supportFragmentManager.beginTransaction() 32 | .replace(R.id.ct_setting_container, fragment) 33 | .addToBackStack(null) 34 | .commitAllowingStateLoss() 35 | } 36 | return true 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/setting/SettingFragment.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.setting 2 | 3 | import android.content.Intent 4 | import android.net.Uri 5 | import android.os.Bundle 6 | import android.provider.Settings 7 | import androidx.preference.Preference 8 | import androidx.preference.Preference.OnPreferenceChangeListener 9 | import androidx.preference.PreferenceFragmentCompat 10 | import androidx.preference.SwitchPreferenceCompat 11 | import com.chenyihong.exampledemo.R 12 | 13 | class SettingFragment : PreferenceFragmentCompat() { 14 | 15 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 16 | setPreferencesFromResource(R.xml.example_setting, rootKey) 17 | preferenceManager.preferenceDataStore = ExampleDataStore 18 | val notificationOpenStatus = findPreference("notifications_open_status") 19 | val autoLoginStatus = findPreference("auto_login_enable") 20 | val googleAccountStatus = findPreference("google_account_bind_status") 21 | val facebookAccountStatus = findPreference("facebook_account_bind_status") 22 | findPreference("system_system")?.setOnPreferenceClickListener { 23 | try { 24 | val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) 25 | val uri: Uri = Uri.fromParts("package", requireActivity().packageName, null) 26 | intent.data = uri 27 | startActivity(intent) 28 | } catch (e: Exception) { 29 | e.printStackTrace() 30 | } 31 | true 32 | } 33 | 34 | val notificationOpenStatusValue = ExampleDataStore.getBoolean("notifications_open_status", false) 35 | val autoLoginStatusValue = ExampleDataStore.getBoolean("auto_login_enable", false) 36 | val googleAccountStatusValue = ExampleDataStore.getBoolean("google_account_bind_status", false) 37 | val facebookAccountStatusValue = ExampleDataStore.getBoolean("facebook_account_bind_status", false) 38 | 39 | notificationOpenStatus?.isChecked = notificationOpenStatusValue 40 | autoLoginStatus?.isChecked = autoLoginStatusValue 41 | googleAccountStatus?.run { 42 | isChecked = googleAccountStatusValue 43 | onPreferenceChangeListener = OnPreferenceChangeListener { preference, newValue -> 44 | googleAccountStatus.summaryOn = "xxxxx@gmail.com" 45 | true 46 | } 47 | } 48 | facebookAccountStatus?.run { 49 | isChecked = facebookAccountStatusValue 50 | onPreferenceChangeListener = OnPreferenceChangeListener { preference, newValue -> 51 | facebookAccountStatus.summaryOn = "xxxxxxfbaccount" 52 | true 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/setting/UserInfoFragment.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.setting 2 | 3 | import android.os.Bundle 4 | import android.text.InputType 5 | import androidx.preference.EditTextPreference 6 | import androidx.preference.Preference 7 | import androidx.preference.PreferenceFragmentCompat 8 | import com.chenyihong.exampledemo.R 9 | 10 | class UserInfoFragment : PreferenceFragmentCompat() { 11 | 12 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 13 | setPreferencesFromResource(R.xml.example_user_info, rootKey) 14 | findPreference("user_info_nick_name")?.summaryProvider = Preference.SummaryProvider { preference -> 15 | preference.text ?: "Please enter a nickname" 16 | } 17 | findPreference("user_info_real_name")?.summaryProvider = Preference.SummaryProvider { preference -> 18 | preference.text ?: "Please enter real name" 19 | } 20 | findPreference("user_info_age")?.run { 21 | summaryProvider = Preference.SummaryProvider { preference -> 22 | preference.text ?: "Please enter your age" 23 | } 24 | setOnBindEditTextListener { it.inputType = InputType.TYPE_CLASS_NUMBER } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/shortcuts/CreateCameraShortcutActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.shortcuts 2 | 3 | import android.content.ComponentName 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AppCompatActivity 7 | import androidx.core.content.pm.ShortcutInfoCompat 8 | import androidx.core.content.pm.ShortcutManagerCompat 9 | import androidx.core.graphics.drawable.IconCompat 10 | import androidx.databinding.DataBindingUtil 11 | import com.chenyihong.exampledemo.R 12 | import com.chenyihong.exampledemo.androidapi.camerax.CameraActivity 13 | import com.chenyihong.exampledemo.androidapi.gps.GpsSignalActivity 14 | import com.chenyihong.exampledemo.databinding.LayoutCreateShortcutsActivityBinding 15 | 16 | class CreateCameraShortcutActivity : AppCompatActivity() { 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | val binding: LayoutCreateShortcutsActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_create_shortcuts_activity) 21 | binding.tvTips.text = "Do you want to add the Camera Launcher icon to your home screen?" 22 | binding.btnAddShortcut.setOnClickListener { 23 | createPinShortcuts() 24 | } 25 | binding.btnReject.setOnClickListener { 26 | finish() 27 | } 28 | } 29 | 30 | private fun createPinShortcuts() { 31 | if (ShortcutManagerCompat.isRequestPinShortcutSupported(this)) { 32 | val pinShortcutInfo = ShortcutInfoCompat.Builder(this, "camera") 33 | .setShortLabel(getString(R.string.camera_shortcuts_short_label)) 34 | .setLongLabel(getString(R.string.camera_shortcuts_long_label)) 35 | .setDisabledMessage(getString(R.string.shortcuts_disable_message)) 36 | .setIcon(IconCompat.createWithResource(this, R.drawable.icon_camera)) 37 | .setIntent(Intent(Intent.ACTION_VIEW).apply { 38 | component = ComponentName(packageName, CameraActivity::class.java.name) 39 | }) 40 | .build() 41 | val pinnedShortcutCallbackIntent = ShortcutManagerCompat.createShortcutResultIntent(this, pinShortcutInfo) 42 | setResult(RESULT_OK, pinnedShortcutCallbackIntent) 43 | finish() 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/shortcuts/CreateLocationShortcutActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.shortcuts 2 | 3 | import android.content.ComponentName 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AppCompatActivity 7 | import androidx.core.content.pm.ShortcutInfoCompat 8 | import androidx.core.content.pm.ShortcutManagerCompat 9 | import androidx.core.graphics.drawable.IconCompat 10 | import androidx.databinding.DataBindingUtil 11 | import com.chenyihong.exampledemo.R 12 | import com.chenyihong.exampledemo.androidapi.gps.GpsSignalActivity 13 | import com.chenyihong.exampledemo.databinding.LayoutCreateShortcutsActivityBinding 14 | 15 | class CreateLocationShortcutActivity : AppCompatActivity() { 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | val binding: LayoutCreateShortcutsActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_create_shortcuts_activity) 20 | binding.tvTips.text = "Do you want to add the Location Launcher icon to your home screen?" 21 | binding.btnAddShortcut.setOnClickListener { 22 | createPinShortcuts() 23 | } 24 | binding.btnReject.setOnClickListener { 25 | finish() 26 | } 27 | } 28 | 29 | private fun createPinShortcuts() { 30 | if (ShortcutManagerCompat.isRequestPinShortcutSupported(this)) { 31 | val pinShortcutInfo = ShortcutInfoCompat.Builder(this, "location") 32 | .setShortLabel(getString(R.string.location_shortcuts_short_label)) 33 | .setLongLabel(getString(R.string.location_shortcuts_long_label)) 34 | .setDisabledMessage(getString(R.string.shortcuts_disable_message)) 35 | .setIcon(IconCompat.createWithResource(this, R.drawable.icon_location)) 36 | .setIntent(Intent(Intent.ACTION_VIEW).apply { 37 | component = ComponentName(packageName, GpsSignalActivity::class.java.name) 38 | }) 39 | .build() 40 | val pinnedShortcutCallbackIntent = ShortcutManagerCompat.createShortcutResultIntent(this, pinShortcutInfo) 41 | setResult(RESULT_OK, pinnedShortcutCallbackIntent) 42 | finish() 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/toolbar/ToolbarActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.toolbar 2 | 3 | import android.os.Bundle 4 | import android.view.Menu 5 | import android.view.MenuItem 6 | import androidx.databinding.DataBindingUtil 7 | import com.chenyihong.exampledemo.R 8 | import com.chenyihong.exampledemo.databinding.LayoutToolbarActivityBinding 9 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 10 | 11 | const val TAG = "ToolBalSimpleTag" 12 | 13 | class ToolbarActivity : BaseGestureDetectorActivity() { 14 | 15 | override fun onCreateOptionsMenu(menu: Menu?): Boolean { 16 | menuInflater.inflate(R.menu.example_menu, menu) 17 | return true 18 | } 19 | 20 | override fun onPrepareOptionsMenu(menu: Menu?): Boolean { 21 | // 如果需要在运行时对菜单进行调整(删除或增加),在此处理 22 | return super.onPrepareOptionsMenu(menu) 23 | } 24 | 25 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 26 | // 在此处理菜单项的点击事件 27 | when (item.itemId) { 28 | R.id.action_search -> { 29 | showToast("click search menu") 30 | } 31 | R.id.action_scan -> { 32 | showToast("click scan menu") 33 | } 34 | R.id.action_setting -> { 35 | showToast("click setting menu") 36 | } 37 | } 38 | return super.onOptionsItemSelected(item) 39 | } 40 | 41 | override fun onCreate(savedInstanceState: Bundle?) { 42 | super.onCreate(savedInstanceState) 43 | val binding: LayoutToolbarActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_toolbar_activity) 44 | setSupportActionBar(binding.toolbar) 45 | supportActionBar?.run { 46 | setHomeAsUpIndicator(R.drawable.icon_back) 47 | setDisplayHomeAsUpEnabled(true) 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/trafficstats/NetSpeedUtils.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.trafficstats 2 | 3 | import android.net.TrafficStats 4 | import com.chenyihong.exampledemo.base.ExampleApplication 5 | import java.util.Timer 6 | import java.util.TimerTask 7 | 8 | object NetSpeedUtils { 9 | 10 | var netSpeedCallback: NetSpeedCallback? = null 11 | 12 | private var timer: Timer? = null 13 | private var timerTask: TimerTask? = null 14 | 15 | private var lastTotalReceiveBytes: Long = 0 16 | private var lastTotalTransferBytes: Long = 0 17 | 18 | /** 19 | * 根据应用uid获取设备启动以来,该应用接收到的总字节数 20 | */ 21 | fun getTotalReceiveBytes(): Long { 22 | var receiveBytes: Long = TrafficStats.UNSUPPORTED.toLong() 23 | ExampleApplication.exampleContext?.run { 24 | receiveBytes = TrafficStats.getUidRxBytes(applicationInfo.uid) 25 | } 26 | return if (receiveBytes == TrafficStats.UNSUPPORTED.toLong()) 0 else receiveBytes / 1024 27 | } 28 | 29 | /** 30 | * 根据应用uid获取设备启动以来,该应用传输的总字节数 31 | */ 32 | fun getTotalTransferBytes(): Long { 33 | var transferBytes: Long = TrafficStats.UNSUPPORTED.toLong() 34 | ExampleApplication.exampleContext?.run { 35 | transferBytes = TrafficStats.getUidTxBytes(applicationInfo.uid) 36 | } 37 | return if (transferBytes == TrafficStats.UNSUPPORTED.toLong()) 0 else transferBytes / 1024 38 | } 39 | 40 | private fun calculateNetSpeed() { 41 | val nowTotalReceiveBytes = getTotalReceiveBytes() 42 | val nowTotalTransferBytes = getTotalTransferBytes() 43 | 44 | val downloadSpeed = nowTotalReceiveBytes - lastTotalReceiveBytes 45 | val uploadSpeed = nowTotalTransferBytes - lastTotalTransferBytes 46 | 47 | lastTotalReceiveBytes = nowTotalReceiveBytes 48 | lastTotalTransferBytes = nowTotalTransferBytes 49 | 50 | netSpeedCallback?.onNetSpeedChange("$downloadSpeed kb/s", "$uploadSpeed kb/s") 51 | } 52 | 53 | fun startMeasuringNetSpeed() { 54 | if (timer == null && timerTask == null) { 55 | timer = Timer() 56 | timerTask = object : TimerTask() { 57 | override fun run() { 58 | calculateNetSpeed() 59 | } 60 | } 61 | timer?.run { timerTask?.let { schedule(it, 0L, 1000L) } } 62 | } 63 | } 64 | 65 | fun stopMeasuringNetSpeed() { 66 | timerTask?.cancel() 67 | timerTask = null 68 | timer?.cancel() 69 | timer = null 70 | } 71 | 72 | interface NetSpeedCallback { 73 | fun onNetSpeedChange(downloadSpeed: String, uploadSpeed: String) 74 | } 75 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/trafficstats/TrafficStatsActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.trafficstats 2 | 3 | import android.annotation.SuppressLint 4 | import android.graphics.Bitmap 5 | import android.os.Bundle 6 | import android.util.Log 7 | import android.view.ViewGroup 8 | import android.webkit.* 9 | import androidx.databinding.DataBindingUtil 10 | import com.chenyihong.exampledemo.R 11 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 12 | import com.chenyihong.exampledemo.databinding.LayoutTrafficStatsActivityBinding 13 | 14 | const val TAG = "TrafficStatsTag" 15 | 16 | class TrafficStatsActivity : BaseGestureDetectorActivity() { 17 | 18 | private lateinit var binding: LayoutTrafficStatsActivityBinding 19 | 20 | @SuppressLint("SetTextI18n") 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | binding = DataBindingUtil.setContentView(this, R.layout.layout_traffic_stats_activity) 24 | binding.includeTitle.tvTitle.text = "TrafficStatsExample" 25 | NetSpeedUtils.netSpeedCallback = object : NetSpeedUtils.NetSpeedCallback { 26 | override fun onNetSpeedChange(downloadSpeed: String, uploadSpeed: String) { 27 | binding.tvNetSpeed.run { post { text = "downloadSpeed:$downloadSpeed , uploadSpeed:$uploadSpeed" } } 28 | } 29 | } 30 | binding.btnStartMeasureNetSpeed.setOnClickListener { 31 | NetSpeedUtils.startMeasuringNetSpeed() 32 | } 33 | binding.btnStopMeasureNetSpeed.setOnClickListener { 34 | NetSpeedUtils.stopMeasuringNetSpeed() 35 | } 36 | initWebViewSetting(binding.webView) 37 | 38 | binding.webView.loadUrl("https://go.minigame.vip/") 39 | } 40 | 41 | @SuppressLint("JavascriptInterface", "SetJavaScriptEnabled") 42 | private fun initWebViewSetting(webView: WebView?) { 43 | webView?.run { 44 | settings.cacheMode = WebSettings.LOAD_DEFAULT 45 | settings.domStorageEnabled = true 46 | settings.allowContentAccess = true 47 | settings.allowFileAccess = true 48 | settings.useWideViewPort = true 49 | settings.loadWithOverviewMode = true 50 | settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW 51 | settings.javaScriptEnabled = true 52 | settings.javaScriptCanOpenWindowsAutomatically = true 53 | settings.setSupportMultipleWindows(true) 54 | 55 | webViewClient = object : WebViewClient() { 56 | override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { 57 | super.onPageStarted(view, url, favicon) 58 | Log.i(TAG, "WebViewActivity onPageStarted url:$url") 59 | } 60 | 61 | override fun onPageFinished(view: WebView?, url: String?) { 62 | super.onPageFinished(view, url) 63 | Log.i(TAG, "WebViewActivity onPageFinished view:$view url:$url") 64 | } 65 | } 66 | } 67 | } 68 | 69 | override fun onDestroy() { 70 | super.onDestroy() 71 | binding.webView.clearHistory() 72 | binding.webView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null) 73 | binding.root.run { 74 | if (this is ViewGroup) { 75 | this.removeView(binding.webView) 76 | } 77 | } 78 | binding.webView.destroy() 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/wifi/WIFIAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.wifi 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.appcompat.widget.AppCompatImageView 7 | import androidx.appcompat.widget.AppCompatTextView 8 | import androidx.recyclerview.widget.RecyclerView 9 | import com.chenyihong.exampledemo.R 10 | 11 | class WIFIAdapter : RecyclerView.Adapter() { 12 | 13 | private val wifiData = ArrayList() 14 | 15 | var itemClickListener: ItemClickListener? = null 16 | 17 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WIFIViewHolder { 18 | return WIFIViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_wifi_item, parent, false)) 19 | } 20 | 21 | override fun onBindViewHolder(holder: WIFIViewHolder, position: Int) { 22 | wifiData[position].run { 23 | holder.tvWifiName.text = wifiSSID 24 | holder.tvWifiSSID.text = wifiBSSID 25 | holder.ivWifiStrength.setImageResource(getStrengthIcon(wifiStrength)) 26 | holder.ivNeedPassword.setImageResource(if (needPassword) R.drawable.icon_lock else R.drawable.icon_unlock) 27 | } 28 | holder.itemView.setOnClickListener { 29 | itemClickListener?.onItemClick(wifiData[position]) 30 | } 31 | } 32 | 33 | override fun getItemCount(): Int { 34 | return wifiData.size 35 | } 36 | 37 | fun setNewData(wifiData: ArrayList?) { 38 | val lastItemCount = itemCount 39 | if (lastItemCount != 0) { 40 | this.wifiData.clear() 41 | notifyItemRangeRemoved(0, lastItemCount) 42 | } 43 | wifiData?.let { this.wifiData.addAll(it) } 44 | notifyItemChanged(0, itemCount) 45 | } 46 | 47 | private fun getStrengthIcon(wifiStrength: Int): Int { 48 | return when (wifiStrength) { 49 | 0 -> R.drawable.wifi_strength_0 50 | 1 -> R.drawable.wifi_strength_1 51 | 2 -> R.drawable.wifi_strength_2 52 | else -> R.drawable.wifi_strength_3 53 | } 54 | } 55 | 56 | interface ItemClickListener { 57 | fun onItemClick(wifiInfo: WIFIEntity) 58 | } 59 | 60 | class WIFIViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 61 | val tvWifiName: AppCompatTextView = itemView.findViewById(R.id.tv_wifi_name) 62 | val tvWifiSSID: AppCompatTextView = itemView.findViewById(R.id.tv_wifi_ssid) 63 | val ivNeedPassword: AppCompatImageView = itemView.findViewById(R.id.iv_need_password) 64 | val ivWifiStrength: AppCompatImageView = itemView.findViewById(R.id.iv_wifi_strength) 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/androidapi/wifi/WIFIEntity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.androidapi.wifi 2 | 3 | data class WIFIEntity( 4 | val wifiSSID: String, 5 | val wifiBSSID: String, 6 | val needPassword: Boolean, 7 | val capabilities: String, 8 | val wifiStrength: Int 9 | ) { 10 | 11 | override fun toString(): String { 12 | return "WIFIEntity(wifiSSID='$wifiSSID', wifiBSSID='$wifiBSSID', needPassword=$needPassword, capabilities='$capabilities', wifiStrength=$wifiStrength)" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/base/MimeType.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.base 2 | 3 | object MimeType { 4 | 5 | const val TEXT_PLAIN = "text/plain" 6 | const val TEXT_RTF = "text/rtf" 7 | const val TEXT_HTML = "text/html" 8 | const val TEXT_JSON = "text/json" 9 | 10 | const val IMAGE_HEAD = "image/" 11 | const val IMAGE_JPEG = "image/jpeg" 12 | const val IMAGE_PNG = "image/png" 13 | const val IMAGE_GIT = "image/gif" 14 | const val IMAGE_ALL = "image/*" 15 | 16 | const val VIDEO_HEAD = "video/" 17 | const val VIDEO_MP4 = "video/mp4" 18 | const val VIDEO_3GP = "video/3gp" 19 | const val VIDEO_All = "video/*" 20 | 21 | const val ALL = "*/*" 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/customview/CustomChartViewActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.customview 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import androidx.databinding.DataBindingUtil 6 | import com.chenyihong.exampledemo.R 7 | import com.chenyihong.exampledemo.databinding.LayoutCustomChartViewActivityBinding 8 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 9 | 10 | class CustomChartViewActivity : BaseGestureDetectorActivity() { 11 | 12 | @SuppressLint("SetTextI18n") 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | val binding: LayoutCustomChartViewActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_custom_chart_view_activity) 16 | binding.includeTitle.tvTitle.text = "Custom Chart View" 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/entity/LineEntity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.entity 2 | 3 | data class LineEntity( 4 | val xValue: Float, 5 | val yValue: Float 6 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/entity/OptionsChildEntity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.entity 2 | 3 | data class OptionsChildEntity(val testFunctionName: String, val testFunction: () -> Unit) { 4 | 5 | override fun toString(): String { 6 | return "OptionsChildEntity(testFunctionName=$testFunctionName, testFunction=$testFunction)" 7 | } 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/entity/OptionsEntity.kt: -------------------------------------------------------------------------------- 1 | package com.minigame.testapp.ui.entity 2 | 3 | import com.chenyihong.exampledemo.entity.OptionsChildEntity 4 | 5 | data class OptionsEntity(val moduleName: String, var expanded: Boolean = false, val containerTest: ArrayList) {} -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/entity/PersonEntity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.entity 2 | 3 | import android.os.Parcelable 4 | import kotlinx.parcelize.Parcelize 5 | 6 | @Parcelize 7 | data class PersonEntity( 8 | val name: String, 9 | val age: Int, 10 | val gender: Int, 11 | val weight: Float, 12 | val height: Float 13 | ) : Parcelable { 14 | 15 | override fun toString(): String { 16 | return "PersonEntity(name='$name', age=$age, gender=$gender, weight=$weight, height=$height)" 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/flavor/FlavorExampleActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.flavor 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import androidx.databinding.DataBindingUtil 6 | import com.chenyihong.exampledemo.BuildConfig 7 | import com.chenyihong.exampledemo.R 8 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 9 | import com.chenyihong.exampledemo.databinding.LayoutFlavorExampleActivityBinding 10 | 11 | class FlavorExampleActivity : BaseGestureDetectorActivity() { 12 | 13 | @SuppressLint("SetTextI18n") 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | 17 | val binding = DataBindingUtil.setContentView(this, R.layout.layout_flavor_example_activity) 18 | binding.includeTitle.tvTitle.text = "Flavor ${BuildConfig.FLAVOR}" 19 | binding.tvFlavorBuildConfigValue.text = BuildConfig.example_value 20 | binding.tvFlavorResValue.text = getString(R.string.example_value) 21 | binding.tvVersionInfo.text = "VersionCode:${BuildConfig.VERSION_CODE} VersionName:${BuildConfig.VERSION_NAME}" 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/tripartite/admob/AppOpenAdActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.tripartite.admob 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.os.Handler 6 | import android.os.Looper 7 | import androidx.appcompat.app.AppCompatActivity 8 | import com.chenyihong.exampledemo.R 9 | import com.chenyihong.exampledemo.base.ExampleApplication 10 | import com.chenyihong.exampledemo.home.HomeActivity 11 | 12 | class AppOpenAdActivity : AppCompatActivity() { 13 | 14 | private val handler = Handler(Looper.myLooper() ?: Looper.getMainLooper()) 15 | private val enterRunnable = Runnable { 16 | // 停止自动显示,避免进入主页后自动展示广告打断用户行为 17 | (application as ExampleApplication).appOpenAdManager?.stopAutoShow() 18 | enterHomePage() 19 | } 20 | 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | setContentView(R.layout.layout_app_open_activity) 24 | (application as ExampleApplication).appOpenAdManager?.showAppOpenAd(this, object : AppOpenAdManager.AppOpenAdShowCallback { 25 | override fun onAppOpenAdShow() { 26 | // 开屏广告已显示,停止计时线程 27 | handler.removeCallbacks(enterRunnable) 28 | } 29 | 30 | override fun onAppOpenAdShowComplete() { 31 | // 开屏广告播放完毕(成功或失败),停止计时线程并进入主页 32 | handler.removeCallbacks(enterRunnable) 33 | enterHomePage() 34 | } 35 | }, true) 36 | // 三秒内没有显示出广告,自动进入主页 37 | handler.postDelayed(enterRunnable, 3000) 38 | } 39 | 40 | private fun enterHomePage() { 41 | startActivity(Intent(this, HomeActivity::class.java)) 42 | finish() 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/tripartite/share/TripartiteShareActivity.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.tripartite.share 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.databinding.DataBindingUtil 7 | import com.chenyihong.exampledemo.R 8 | import com.chenyihong.exampledemo.databinding.LayoutShareActivityBinding 9 | import com.chenyihong.exampledemo.androidapi.gesturedetector.BaseGestureDetectorActivity 10 | 11 | class TripartiteShareActivity : BaseGestureDetectorActivity() { 12 | 13 | @SuppressLint("SetTextI18n") 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | val binding = DataBindingUtil.setContentView(this, R.layout.layout_share_activity) 17 | 18 | binding.includeTitle.tvTitle.text = "Tripartite Share" 19 | binding.btnFacebookShare.setOnClickListener { 20 | startActivity(Intent(this, FacebookShareActivity::class.java)) 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/utils/DensityUtil.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.utils 2 | 3 | import android.content.res.Resources 4 | import android.util.TypedValue 5 | 6 | object DensityUtil { 7 | 8 | /** 9 | * dp convert to px 10 | * 11 | * @param dpValue dp 12 | */ 13 | @JvmStatic 14 | fun dp2Px(dpValue: Int): Int { 15 | return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue.toFloat(), Resources.getSystem().displayMetrics).toInt() 16 | } 17 | 18 | /** 19 | * px convert to dp 20 | * 21 | * @param pxValue px 22 | */ 23 | @JvmStatic 24 | fun px2Dp(pxValue: Int): Int { 25 | return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, pxValue.toFloat(), Resources.getSystem().displayMetrics).toInt() 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/utils/ShapeDrawableUtils.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.utils 2 | 3 | import android.graphics.drawable.GradientDrawable 4 | import java.util.ArrayList 5 | 6 | object ShapeDrawableUtils { 7 | 8 | /** 9 | * get shape 10 | * 11 | * @param radius corner radius 12 | * @param backgroundColor background color 13 | */ 14 | @JvmStatic 15 | fun getRectAngleGradientDrawable(radius: Float, backgroundColor: Int): GradientDrawable { 16 | return getRectAngleGradientDrawable(radius, backgroundColor, 0, 0, true, needRightTopCorner = true, needRightBottomCorner = true, needLeftBottomCorner = true) 17 | } 18 | 19 | /** 20 | * get shape 21 | * 22 | * @param radius corner radius 23 | * @param backgroundColor background color 24 | * @param width view width 25 | * @param height view height 26 | * @param needLeftCorner set left corner or not 27 | * @param needRightCorner set right corner or not 28 | */ 29 | @JvmStatic 30 | fun getRectAngleGradientDrawable(radius: Float, backgroundColor: Int, width: Int, height: Int, needLeftCorner: Boolean, needRightCorner: Boolean): GradientDrawable { 31 | return getRectAngleGradientDrawable(radius, backgroundColor, width, height, needLeftCorner, needRightCorner, needRightCorner, needLeftCorner) 32 | } 33 | 34 | /** 35 | * get shape 36 | * 37 | * @param radius corner radius 38 | * @param backgroundColor background color 39 | * @param width view width 40 | * @param height view height 41 | * @param needLeftTopCorner set left top corner or not 42 | * @param needRightTopCorner set right top corner or not 43 | * @param needRightBottomCorner set right bottom corner or not 44 | * @param needLeftBottomCorner set left bottom corner or not 45 | */ 46 | @JvmStatic 47 | fun getRectAngleGradientDrawable(radius: Float, backgroundColor: Int, width: Int, height: Int, 48 | needLeftTopCorner: Boolean, needRightTopCorner: Boolean, 49 | needRightBottomCorner: Boolean, needLeftBottomCorner: Boolean): GradientDrawable { 50 | val drawable = GradientDrawable() 51 | drawable.shape = GradientDrawable.RECTANGLE 52 | val radiusArray = ArrayList() 53 | if (needLeftTopCorner) { 54 | radiusArray.add(radius) 55 | radiusArray.add(radius) 56 | } else { 57 | radiusArray.add(0f) 58 | radiusArray.add(0f) 59 | } 60 | if (needRightTopCorner) { 61 | radiusArray.add(radius) 62 | radiusArray.add(radius) 63 | } else { 64 | radiusArray.add(0f) 65 | radiusArray.add(0f) 66 | } 67 | if (needRightBottomCorner) { 68 | radiusArray.add(radius) 69 | radiusArray.add(radius) 70 | } else { 71 | radiusArray.add(0f) 72 | radiusArray.add(0f) 73 | } 74 | if (needLeftBottomCorner) { 75 | radiusArray.add(radius) 76 | radiusArray.add(radius) 77 | } else { 78 | radiusArray.add(0f) 79 | radiusArray.add(0f) 80 | } 81 | val radii = FloatArray(radiusArray.size) 82 | for (i in radiusArray.indices) { 83 | radii[i] = radiusArray[i] 84 | } 85 | drawable.cornerRadii = radii 86 | if (width != 0 && height != 0) { 87 | drawable.setSize(width, height) 88 | } 89 | drawable.setColor(backgroundColor) 90 | return drawable 91 | } 92 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chenyihong/exampledemo/web/JsInteractive.kt: -------------------------------------------------------------------------------- 1 | package com.chenyihong.exampledemo.web 2 | 3 | interface JsInteractive { 4 | 5 | fun jsCallAndroid() 6 | 7 | fun jsCallAndroidWithParams(params: String) 8 | 9 | fun getPersonJsonArray() 10 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/facebook.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/facebook.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/google.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/google.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_android.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_back.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_back.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_biometrics.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_biometrics.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_camera.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_camera.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_juejin.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_juejin.jpeg -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_location.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_location.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_lock.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_lock.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_scan.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_scan.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_scan_32_black.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_scan_32_black.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_search.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_search.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_search_48.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_search_48.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_setting.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_setting.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_thumb_up.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_thumb_up.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_unlock.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/icon_unlock.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/layer_progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/login.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/login.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/notification.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/notification.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_float_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_float_bg1.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_oval.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_red_oval.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_vollume_controller.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/wifi_strength_0.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/wifi_strength_0.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/wifi_strength_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/wifi_strength_1.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/wifi_strength_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/wifi_strength_2.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/wifi_strength_3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/drawable/wifi_strength_3.webp -------------------------------------------------------------------------------- /app/src/main/res/font/noto_sans.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/font/noto_sans_bold.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/font/noto_sanssc_bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/font/noto_sanssc_bold.otf -------------------------------------------------------------------------------- /app/src/main/res/font/noto_sanssc_regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiHong930921/example-demo/465a7b95acf856a0be0b1611dba8ede5b49285ea/app/src/main/res/font/noto_sanssc_regular.otf -------------------------------------------------------------------------------- /app/src/main/res/font/noto_serif.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/font/noto_serif_bold.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_admob_example_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 11 | 12 |