├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── yang │ │ └── keyboard_example │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── emoticons │ │ │ ├── list │ │ │ ├── tusiji │ │ │ ├── config.xml │ │ │ ├── icon_002_cover.png │ │ │ ├── icon_007_cover.png │ │ │ ├── icon_010_cover.png │ │ │ ├── icon_012_cover.png │ │ │ ├── icon_013_cover.png │ │ │ ├── icon_018_cover.png │ │ │ ├── icon_019_cover.png │ │ │ ├── icon_020_cover.png │ │ │ ├── icon_021_cover.png │ │ │ ├── icon_022_cover.png │ │ │ ├── icon_024_cover.png │ │ │ ├── icon_027_cover.png │ │ │ ├── icon_029_cover.png │ │ │ ├── icon_030_cover.png │ │ │ ├── icon_035_cover.png │ │ │ └── icon_040_cover.png │ │ │ └── xhs │ │ │ ├── config.xml │ │ │ ├── xhsemoji_1.png │ │ │ ├── xhsemoji_10.png │ │ │ ├── xhsemoji_11.png │ │ │ ├── xhsemoji_12.png │ │ │ ├── xhsemoji_13.png │ │ │ ├── xhsemoji_14.png │ │ │ ├── xhsemoji_15.png │ │ │ ├── xhsemoji_16.png │ │ │ ├── xhsemoji_17.png │ │ │ ├── xhsemoji_18.png │ │ │ ├── xhsemoji_19.png │ │ │ ├── xhsemoji_2.png │ │ │ ├── xhsemoji_20.png │ │ │ ├── xhsemoji_21.png │ │ │ ├── xhsemoji_3.png │ │ │ ├── xhsemoji_4.png │ │ │ ├── xhsemoji_5.png │ │ │ ├── xhsemoji_6.png │ │ │ ├── xhsemoji_7.png │ │ │ ├── xhsemoji_8.png │ │ │ └── xhsemoji_9.png │ ├── java │ │ └── com │ │ │ └── yang │ │ │ └── keyboard_example │ │ │ ├── ChatBean.java │ │ │ ├── MainActivity.java │ │ │ ├── MainApplication.java │ │ │ ├── UserFragment.java │ │ │ └── models │ │ │ ├── DefaultUser.java │ │ │ └── MyMessage.java │ └── res │ │ ├── drawable-hdpi │ │ ├── deadpool.png │ │ ├── ironman.png │ │ ├── pic_select_n.png │ │ └── qbi.png │ │ ├── drawable │ │ ├── icon_camera.png │ │ ├── icon_photo.png │ │ └── send_button_bg.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_main2.xml │ │ ├── item_app.xml │ │ ├── item_list.xml │ │ └── simple_fragment_keybord_layouts.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ ├── arrays.xml │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── yang │ └── keyboard_example │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keyboard ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── yang │ │ └── keyboard │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── yang │ │ └── keyboard │ │ ├── ChatKeyboardLayout.java │ │ ├── KeyboardFragment.java │ │ ├── audio │ │ └── AudioManger.java │ │ ├── emoticon │ │ ├── EmoticonBean.java │ │ ├── EmoticonSetBean.java │ │ ├── bean │ │ │ ├── EmoticonEntity.java │ │ │ ├── EmoticonLayout.java │ │ │ ├── EmoticonsAdapter.java │ │ │ ├── EmoticonsPageView.java │ │ │ ├── EmoticonsToolBarView.java │ │ │ └── IView.java │ │ ├── db │ │ │ ├── EmoticonDBHelper.java │ │ │ └── TableColumns.java │ │ └── util │ │ │ ├── DefEmoticons.java │ │ │ ├── EmoticonHandler.java │ │ │ └── EmoticonsKeyboardBuilder.java │ │ ├── media │ │ ├── MediaBean.java │ │ ├── MediaGridAdapter.java │ │ ├── MediaLayout.java │ │ ├── MediaListener.java │ │ └── MediaPagerAdapter.java │ │ ├── utils │ │ ├── EmoticonBase.java │ │ ├── EmoticonLoader.java │ │ ├── FileUtils.java │ │ ├── HadLog.java │ │ ├── OnKeyBoardLister.java │ │ └── Utils.java │ │ └── view │ │ ├── AudioRecordButton.java │ │ ├── ChatTextView.java │ │ ├── HadEditText.java │ │ ├── IndicatorView.java │ │ ├── RecordingLayout.java │ │ ├── SoftHandleLayout.java │ │ ├── SoftListenLayout.java │ │ └── VerticalImageSpan.java │ └── res │ ├── color │ └── text_touch_selector.xml │ ├── drawable-xhdpi │ ├── cross_icon.png │ ├── ic_launcher.png │ ├── icon_face_nomal.png │ ├── icon_face_pop.png │ ├── input_bg_gray.9.png │ ├── input_bg_green.9.png │ ├── keyboard_icon.png │ ├── recording_cancel.png │ ├── recording_icon.png │ ├── recording_level_1.png │ ├── recording_level_2.png │ ├── recording_level_3.png │ ├── recording_level_4.png │ ├── recording_level_5.png │ ├── recording_level_6.png │ ├── recording_level_7.png │ └── recording_mic.png │ ├── drawable-xxhdpi │ └── icon_photo.png │ ├── drawable │ ├── circle_button_bg.xml │ ├── emoticon_bg.xml │ ├── recording_bg.xml │ ├── recording_n.xml │ ├── recording_p.xml │ ├── recording_text_bg.xml │ ├── send_button_bg.xml │ └── transparent_bg.xml │ ├── layout │ ├── emoticons_item.xml │ ├── emoticonstoolbar_item.xml │ ├── emoticonstoolbar_view.xml │ ├── had_recording_view.xml │ ├── keyboard_bottom_emoticons.xml │ ├── keyboard_bottom_media.xml │ ├── media_item.xml │ ├── media_page.xml │ ├── simple_fragment_keybord_layout.xml │ └── view_keyboardbar.xml │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── ids.xml │ ├── strings.xml │ └── styles.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea 4 | .DS_Store 5 | /build 6 | /captures 7 | .idea 8 | *.iml 9 | /app/*.iml 10 | /keyboard/*.iml 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | android: 4 | components: 5 | - build-tools-23.0.1 6 | - android-23 7 | - extra-google-m2repository 8 | - extra-android-m2repository 9 | licenses: 10 | - 'android-sdk-license.*' 11 | 12 | branches: 13 | only: 14 | - master 15 | 16 | notifications: 17 | email: false 18 | 19 | script: 20 | - ./gradlew build clean 21 | 22 | before_install: 23 | - chmod +x gradlew -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Chris 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of ChatKeyboard nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # ChatKeyboard 4 | 5 | [](https://github.com/yangchaojiang/ChatKeyboard-master) 6 | 7 | A powerful and easy using keyboard lib includes emoticons, audio recording, multi media keyboard, etc. 8 | 9 | 10 | ###Import 11 | 12 | use import dependency in gradle 13 | 14 | ``` 15 | dependencies { 16 | compile 'ycjiang:keyboard:1.0.6' 17 | } 18 | Maven 19 | dependency> 20 | ycjiang 21 | videolibrary 22 | 1.0.6 23 | pom 24 | 25 | ``` 26 | 27 | 28 | dependency 29 | ``` 30 | compile 'com.android.support:appcompat-v7:25.3.1' 31 | ``` 32 | 33 | ###How to use 34 | 35 | 1, Use ChatKeyboardLayout make your layout contains keyboard. 36 | 用你 Framgment extends KeyboardFragment 37 | 38 | ``` 39 | FragmentTransaction sss = getSupportFragmentManager().beginTransaction(); 40 | UserFragment keyboardFragment = new UserFragment(); 41 | sss.add(R.id.sssssssss, keyboardFragment); 42 | sss.commit(); 43 | keyboardFragment.setKeyBoardLister(this); 44 | ``` 45 | perhaps 46 | ``` 47 | 52 | ...your layout 53 | 54 | ``` 55 | 56 | **Notice: ChatKeyboardLayout can only include one child.** 57 | 2, custom your emoticon and stick keyboard 58 | ``` 59 | if ( !ChatKeyboardLayout.isEmoticonInitSuccess(this) ) { 60 | List entities = new ArrayList<>(); 61 | entities.add(new EmoticonEntity("emoticons/xhs", EmoticonBase.Scheme.ASSETS)); 62 | entities.add(new EmoticonEntity("emoticons/tusiji", EmoticonBase.Scheme.ASSETS)); 63 | ChatKeyboardLayout.initEmoticonsDB(this, true, entities); 64 | } 65 | ``` 66 | **Notice: Add the code above before the ChatKeyboardLayout used, better in onCreate of Application** 67 | 68 | other usage 69 | please refer to the demo code 70 | 71 | Thanks for [xhsEmoticonsKeyboard](https://github.com/w446108264/XhsEmoticonsKeyboard) powered by w446108264. 72 | Thanks to Chris for ideas [](https://github.com/CPPAlien) email creaspan@gmail.com 73 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion project.ext.compileSdkVersion 5 | buildToolsVersion project.ext.buildToolsVersion 6 | defaultConfig { 7 | minSdkVersion project.ext.minSdkVersion 8 | targetSdkVersion project.ext.targetSdkVersion 9 | applicationId "cn.hadcn.keyboard_example" 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | lintOptions { 20 | abortOnError false 21 | } 22 | 23 | } 24 | 25 | dependencies { 26 | compile fileTree(include: ['*.jar'], dir: 'libs') 27 | testCompile 'junit:junit:4.12' 28 | compile 'cn.jiguang.imui:messagelist:0.4.9' 29 | compile project(':keyboard') 30 | compile 'com.github.bumptech.glide:glide:3.7.0' 31 | } 32 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Coding\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/yang/keyboard_example/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard_example; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/list: -------------------------------------------------------------------------------- 1 | ["qbi"] -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | tusiji 4 | 2 5 | 4 6 | 1 7 | icon_030_cover.png 8 | 0 9 | 30 10 | 0 11 | 0 12 | 13 | 14 | 2 15 | icon_002_cover.png 16 | 17 | tusiji_cry 18 | 19 | 20 | 2 21 | icon_007_cover.png 22 | 嘚瑟 23 | tusiji_dese 24 | 25 | 26 | 2 27 | icon_010_cover.png 28 | 手舞足蹈 29 | tusiji_dance 30 | 31 | 32 | 2 33 | icon_012_cover.png 34 | 叮铃 35 | tusiji_dingling 36 | 37 | 38 | 2 39 | icon_013_cover.png 40 | 拜拜 41 | tusiji_bye 42 | 43 | 44 | 2 45 | icon_018_cover.png 46 | 闪亮 47 | tusiji_shining 48 | 49 | 50 | 2 51 | icon_019_cover.png 52 | 抱奶瓶 53 | tusiji_milk 54 | 55 | 56 | 2 57 | icon_020_cover.png 58 | 晚安 59 | tusiji_goodnight 60 | 61 | 62 | 2 63 | icon_021_cover.png 64 | 飞吻 65 | tusiji_kiss 66 | 67 | 68 | 2 69 | icon_022_cover.png 70 | 71 | tusiji_qie 72 | 73 | 74 | 2 75 | icon_024_cover.png 76 | 使劲摇 77 | tusiji_shake 78 | 79 | 80 | 2 81 | icon_027_cover.png 82 | 生日快乐 83 | tusiji_happybirthday 84 | 85 | 86 | 2 87 | icon_029_cover.png 88 | 我最帅 89 | tusiji_handsome 90 | 91 | 92 | 2 93 | icon_030_cover.png 94 | 抓墙 95 | tusiji_zhuaqiang 96 | 97 | 98 | 2 99 | icon_035_cover.png 100 | 扭屁股 101 | tusiji_niupigu 102 | 103 | 104 | 2 105 | icon_040_cover.png 106 | 印度舞 107 | tusiji_india 108 | 109 | 110 | -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_002_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_002_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_007_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_007_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_010_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_010_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_012_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_012_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_013_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_013_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_018_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_018_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_019_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_019_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_020_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_020_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_021_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_021_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_022_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_022_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_024_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_024_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_027_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_027_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_029_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_029_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_030_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_030_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_035_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_035_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/tusiji/icon_040_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/tusiji/icon_040_cover.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/config.xml: -------------------------------------------------------------------------------- 1 | 2 | xhs 3 | 3 4 | 7 5 | xhsemoji_19.png 6 | 0 7 | 1 8 | 20 9 | 0 10 | 0 11 | 12 | 13 | 0 14 | xhsemoji_1.png 15 | 生气 16 | [生气] 17 | 18 | 19 | 0 20 | xhsemoji_2.png 21 | 生气 22 | [生气] 23 | 24 | 25 | 0 26 | xhsemoji_3.png 27 | 28 | [晕] 29 | 30 | 31 | 0 32 | xhsemoji_4.png 33 | 34 | [酷] 35 | 36 | 37 | 0 38 | xhsemoji_5.png 39 | 40 | [哭] 41 | 42 | 43 | 0 44 | xhsemoji_6.png 45 | 可爱 46 | [可爱] 47 | 48 | 49 | 0 50 | xhsemoji_7.png 51 | 抠鼻 52 | [抠鼻] 53 | 54 | 55 | 0 56 | xhsemoji_8.png 57 | 昏掉 58 | [昏掉] 59 | 60 | 61 | 0 62 | xhsemoji_9.png 63 | 寒冷 64 | [寒冷] 65 | 66 | 67 | 0 68 | xhsemoji_10.png 69 | 哈哈 70 | [哈哈] 71 | 72 | 73 | 0 74 | xhsemoji_11.png 75 | 无语 76 | [无语] 77 | 78 | 79 | 0 80 | xhsemoji_12.png 81 | 亲亲 82 | [亲亲] 83 | 84 | 85 | 0 86 | xhsemoji_13.png 87 | 闪亮 88 | [闪亮] 89 | 90 | 91 | 0 92 | xhsemoji_14.png 93 | 爆炸 94 | [爆炸] 95 | 96 | 97 | 0 98 | xhsemoji_15.png 99 | 问号 100 | [问号] 101 | 102 | 103 | 0 104 | xhsemoji_16.png 105 | 绅士 106 | [绅士] 107 | 108 | 109 | 0 110 | xhsemoji_17.png 111 | 啊啊 112 | [啊啊] 113 | 114 | 115 | 0 116 | xhsemoji_18.png 117 | 闭嘴 118 | [闭嘴] 119 | 120 | 121 | 0 122 | xhsemoji_19.png 123 | 爱心 124 | [爱心] 125 | 126 | 127 | 0 128 | xhsemoji_20.png 129 | 窃喜 130 | [窃喜] 131 | 132 | 133 | 0 134 | xhsemoji_21.png 135 | 大笑 136 | [大笑] 137 | 138 | 139 | -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_1.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_10.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_11.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_12.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_13.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_14.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_15.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_16.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_17.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_18.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_19.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_2.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_20.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_21.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_3.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_4.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_5.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_6.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_7.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_8.png -------------------------------------------------------------------------------- /app/src/main/assets/emoticons/xhs/xhsemoji_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/assets/emoticons/xhs/xhsemoji_9.png -------------------------------------------------------------------------------- /app/src/main/java/com/yang/keyboard_example/ChatBean.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard_example; 2 | 3 | /** 4 | * ChatBean 5 | * Created by 90Chris on 2015/11/24. 6 | */ 7 | public class ChatBean { 8 | private String tag; 9 | private String textMsg; 10 | 11 | public ChatBean(String tag, String textMsg) { 12 | this.tag = tag; 13 | this.textMsg = textMsg; 14 | } 15 | 16 | public String getTag() { 17 | return tag; 18 | } 19 | 20 | public String getTextMsg() { 21 | return textMsg; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/yang/keyboard_example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard_example; 2 | 3 | import android.content.res.Resources; 4 | import android.os.Bundle; 5 | import android.support.v4.app.FragmentActivity; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | 11 | import com.bumptech.glide.Glide; 12 | import com.bumptech.glide.request.target.Target; 13 | import com.yang.keyboard.utils.OnKeyBoardLister; 14 | import com.yang.keyboard_example.models.DefaultUser; 15 | import com.yang.keyboard_example.models.MyMessage; 16 | 17 | import java.text.SimpleDateFormat; 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.Date; 21 | import java.util.List; 22 | import java.util.Locale; 23 | 24 | import cn.jiguang.imui.commons.ImageLoader; 25 | import cn.jiguang.imui.commons.models.IMessage; 26 | import cn.jiguang.imui.messages.MessageList; 27 | import cn.jiguang.imui.messages.MsgListAdapter; 28 | 29 | public class MainActivity extends AppCompatActivity implements OnKeyBoardLister { 30 | UserFragment userFragment; 31 | MessageList messageList; 32 | MsgListAdapter adapter; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.activity_main2); 38 | userFragment = (UserFragment) getSupportFragmentManager().findFragmentById(R.id.text); 39 | userFragment.setKeyBoardLister(this); 40 | findViewById(R.id.textView).setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | userFragment.getChatKeyboardLayout().hideKeyboard(); 44 | } 45 | }); 46 | messageList = (MessageList) findViewById(R.id.msg_list); 47 | userFragment.getView().setOnTouchListener(new View.OnTouchListener() { 48 | @Override 49 | public boolean onTouch(View v, MotionEvent event) { 50 | userFragment.getChatKeyboardLayout().hideKeyboard(); 51 | return false; 52 | } 53 | }); 54 | ImageLoader imageLoader = new ImageLoader() { 55 | @Override 56 | public void loadAvatarImage(ImageView avatarImageView, String string) { 57 | if (string.contains("R.drawable")) { 58 | Integer resId = getResources().getIdentifier(string.replace("R.drawable.", ""), 59 | "drawable", getPackageName()); 60 | 61 | avatarImageView.setImageResource(resId); 62 | } else { 63 | Glide.with(getApplicationContext()) 64 | .load(string) 65 | .placeholder(R.drawable.aurora_headicon_default) 66 | .into(avatarImageView); 67 | } 68 | } 69 | 70 | @Override 71 | public void loadImage(ImageView imageView, String string) { 72 | Glide.with(getApplicationContext()) 73 | .load(string) 74 | .fitCenter() 75 | .placeholder(R.drawable.aurora_picture_not_found) 76 | .override(400, Target.SIZE_ORIGINAL) 77 | .into(imageView); 78 | } 79 | }; 80 | 81 | adapter = new MsgListAdapter("1", imageLoader); 82 | adapter.addToEnd(getMessages()); 83 | messageList.setAdapter(adapter); 84 | messageList.postDelayed(new Runnable() { 85 | @Override 86 | public void run() { 87 | messageList.scrollToPosition(0); 88 | } 89 | }, 300); 90 | 91 | 92 | } 93 | 94 | @Override 95 | public boolean onTouchEvent(MotionEvent event) { 96 | return super.onTouchEvent(event); 97 | } 98 | 99 | @Override 100 | public void sendText(String text) { 101 | MyMessage message = new MyMessage(text, IMessage.MessageType.SEND_TEXT); 102 | message.setUserInfo(new DefaultUser("1", "Ironman", "R.drawable.ironman")); 103 | message.setTimeString(new SimpleDateFormat("HH:mm", Locale.getDefault()).format(new Date())); 104 | adapter.addToStart(message, true); 105 | } 106 | 107 | @Override 108 | public void sendUserDefEmoticon(String tag, String uri) { 109 | 110 | } 111 | 112 | @Override 113 | public void sendAudio(String path, int time) { 114 | MyMessage message = new MyMessage(null, IMessage.MessageType.SEND_VOICE); 115 | message.setUserInfo(new DefaultUser("1", "Ironman", "R.drawable.ironman")); 116 | message.setMediaFilePath(path); 117 | message.setDuration(time); 118 | message.setTimeString(new SimpleDateFormat("HH:mm", Locale.getDefault()).format(new Date())); 119 | adapter.addToStart(message, true); 120 | } 121 | 122 | @Override 123 | public void sendMedia(int ids) { 124 | 125 | } 126 | 127 | @Override 128 | public void clickAddBtn(View view) { 129 | messageList.scrollToPosition(0); 130 | 131 | } 132 | 133 | private List getMessages() { 134 | List list = new ArrayList<>(); 135 | Resources res = getResources(); 136 | String[] messages = res.getStringArray(R.array.messages_array); 137 | for (int i = 0; i < messages.length; i++) { 138 | MyMessage message; 139 | if (i % 2 == 0) { 140 | message = new MyMessage(messages[i], IMessage.MessageType.RECEIVE_TEXT); 141 | message.setUserInfo(new DefaultUser("0", "DeadPool", "R.drawable.deadpool")); 142 | } else { 143 | message = new MyMessage(messages[i], IMessage.MessageType.SEND_TEXT); 144 | message.setUserInfo(new DefaultUser("1", "IronMan", "R.drawable.ironman")); 145 | } 146 | message.setTimeString(new SimpleDateFormat("HH:mm", Locale.getDefault()).format(new Date())); 147 | list.add(message); 148 | } 149 | Collections.reverse(list); 150 | return list; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /app/src/main/java/com/yang/keyboard_example/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard_example; 2 | 3 | import android.app.Application; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import com.yang.keyboard.emoticon.bean.EmoticonEntity; 9 | import com.yang.keyboard.emoticon.util.EmoticonHandler; 10 | import com.yang.keyboard.utils.EmoticonBase; 11 | 12 | /** 13 | * MainApplication 14 | * Created by 90Chris on 2015/10/8. 15 | */ 16 | public class MainApplication extends Application { 17 | @Override 18 | public void onCreate() { 19 | super.onCreate(); 20 | if ( !EmoticonHandler.isEmoticonInitSuccess(this) ) { 21 | List entities = new ArrayList<>(); 22 | entities.add(new EmoticonEntity("emoticons/xhs", EmoticonBase.Scheme.ASSETS)); 23 | entities.add(new EmoticonEntity("emoticons/tusiji", EmoticonBase.Scheme.ASSETS)); 24 | EmoticonHandler.initEmoticonsDB(this, false, entities); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yang/keyboard_example/UserFragment.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard_example; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.yang.keyboard.ChatKeyboardLayout; 10 | import com.yang.keyboard.KeyboardFragment; 11 | import com.yang.keyboard.view.RecordingLayout; 12 | import com.yang.keyboard.media.MediaBean; 13 | 14 | import java.util.ArrayList; 15 | 16 | /** 17 | * Created by yangc on 2017/3/15. 18 | * E-Mail:1007181167@qq.com 19 | * Description: 20 | */ 21 | 22 | public class UserFragment extends KeyboardFragment { 23 | 24 | @Override 25 | protected ArrayList intiData() { 26 | ArrayList popupModels = new ArrayList<>(); 27 | popupModels.add(new MediaBean(0, com.yang.keyboard.R.drawable.icon_photo, "拍照", this)); 28 | popupModels.add(new MediaBean(1, com.yang.keyboard.R.drawable.icon_photo, "照片", this)); 29 | 30 | return popupModels; 31 | } 32 | @Nullable 33 | @Override 34 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 35 | return inflater.inflate(R.layout.simple_fragment_keybord_layouts, container, false); 36 | } 37 | 38 | 39 | @Override 40 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 41 | keyboardLayout = (ChatKeyboardLayout) view.findViewById(com.yang.keyboard.R.id.kv_bar); 42 | rlRecordArea = (RecordingLayout) view.findViewById(com.yang.keyboard.R.id.recording_area); 43 | ArrayList popupModels = intiData(); 44 | keyboardLayout.showMedias(popupModels); 45 | keyboardLayout.showEmoBtn(false); 46 | keyboardLayout.setOnKeyBoardBarListener(this); 47 | } 48 | ChatKeyboardLayout getChatKeyboardLayout() { 49 | return keyboardLayout; 50 | } 51 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yang/keyboard_example/models/DefaultUser.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard_example.models; 2 | 3 | import cn.jiguang.imui.commons.models.IUser; 4 | 5 | 6 | public class DefaultUser implements IUser { 7 | 8 | private String id; 9 | private String displayName; 10 | private String avatar; 11 | 12 | public DefaultUser(String id, String displayName, String avatar) { 13 | this.id = id; 14 | this.displayName = displayName; 15 | this.avatar = avatar; 16 | } 17 | 18 | @Override 19 | public String getId() { 20 | return id; 21 | } 22 | 23 | @Override 24 | public String getDisplayName() { 25 | return displayName; 26 | } 27 | 28 | @Override 29 | public String getAvatarFilePath() { 30 | return avatar; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/yang/keyboard_example/models/MyMessage.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard_example.models; 2 | 3 | import java.util.UUID; 4 | 5 | import cn.jiguang.imui.commons.models.IMessage; 6 | import cn.jiguang.imui.commons.models.IUser; 7 | 8 | 9 | public class MyMessage implements IMessage { 10 | 11 | private long id; 12 | private String text; 13 | private String timeString; 14 | private MessageType type; 15 | private IUser user; 16 | private String mediaFilePath; 17 | private long duration; 18 | private String progress; 19 | 20 | public MyMessage(String text, MessageType type) { 21 | this.text = text; 22 | this.type = type; 23 | this.id = UUID.randomUUID().getLeastSignificantBits(); 24 | } 25 | 26 | @Override 27 | public String getMsgId() { 28 | return String.valueOf(id); 29 | } 30 | 31 | @Override 32 | public IUser getFromUser() { 33 | if (user == null) { 34 | return new DefaultUser("0", "user1", null); 35 | } 36 | return user; 37 | } 38 | 39 | public void setUserInfo(IUser user) { 40 | this.user = user; 41 | } 42 | 43 | public void setMediaFilePath(String path) { 44 | this.mediaFilePath = path; 45 | } 46 | 47 | public void setDuration(long duration) { 48 | this.duration = duration; 49 | } 50 | 51 | @Override 52 | public long getDuration() { 53 | return duration; 54 | } 55 | 56 | public void setProgress(String progress) { 57 | this.progress = progress; 58 | } 59 | 60 | @Override 61 | public String getProgress() { 62 | return progress; 63 | } 64 | 65 | public void setTimeString(String timeString) { 66 | this.timeString = timeString; 67 | } 68 | 69 | @Override 70 | public String getTimeString() { 71 | return timeString; 72 | } 73 | 74 | @Override 75 | public MessageType getType() { 76 | return type; 77 | } 78 | 79 | @Override 80 | public MessageStatus getMessageStatus() { 81 | return MessageStatus.SEND_SUCCEED; 82 | } 83 | 84 | @Override 85 | public String getText() { 86 | return text; 87 | } 88 | 89 | @Override 90 | public String getMediaFilePath() { 91 | return mediaFilePath; 92 | } 93 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/deadpool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/res/drawable-hdpi/deadpool.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ironman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/res/drawable-hdpi/ironman.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/pic_select_n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/res/drawable-hdpi/pic_select_n.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/qbi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/res/drawable-hdpi/qbi.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/res/drawable/icon_camera.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/res/drawable/icon_photo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/send_button_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 16 | 17 | 18 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main2.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 12 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_app.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 14 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/simple_fragment_keybord_layouts.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 34 | 35 | 36 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 图片 5 | 拍照 6 | 7 | 8 | 9 | icon_photo 10 | icon_camera 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ChatKeyboard 3 | 4 | Hello world! 5 | Settings 6 | 7 | How are you 8 | Fine. And you? 9 | Me, too. Is there any news today? 10 | Yep! I got a news here: boom! Tomorrow is the end of The Walking Dead! 11 | Are you kidding me? 12 | Absolutely not! 13 | Jesus, that\'s crazy 14 | I thought no one would gonna to make it 15 | That\'s cruel, I don\'t like it, maybe there is a favourable turn 16 | Hope so 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/test/java/com/yang/keyboard_example/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard_example; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | google() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.0.0' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | classpath 'com.novoda:bintray-release:0.6.1' 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | jcenter() 19 | google() 20 | } 21 | project.ext { 22 | buildToolsVersion="26.0.3" 23 | minSdkVersion=16 24 | compileSdkVersion = 25 25 | targetSdkVersion = 25 26 | versionCode=1 27 | versionName="1.0" 28 | } 29 | tasks.withType(Javadoc) { 30 | options{ 31 | encoding "UTF-8" 32 | charSet 'UTF-8' 33 | links "http://docs.oracle.com/javase/7/docs/api" 34 | } 35 | } 36 | } 37 | 38 | task clean(type: Delete) { 39 | delete rootProject.buildDir 40 | } 41 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Wed Mar 30 11:07:57 CST 2016 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Nov 14 11:32:24 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /keyboard/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /keyboard/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion project.ext.compileSdkVersion 5 | buildToolsVersion project.ext.buildToolsVersion 6 | defaultConfig { 7 | minSdkVersion project.ext.minSdkVersion 8 | targetSdkVersion project.ext.targetSdkVersion 9 | } 10 | buildTypes { 11 | release { 12 | minifyEnabled false 13 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 14 | } 15 | } 16 | lintOptions { 17 | abortOnError false 18 | } 19 | 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:25.3.1' 25 | } 26 | apply plugin: 'com.novoda.bintray-release' 27 | publish { 28 | userOrg = 'ycjiang' //bintray注册的用户名 29 | groupId = 'com.ycjiang' //compile引用时的第1部分groupId 30 | artifactId = 'keyboard' //compile引用时的第2部分项目名 31 | publishVersion = '1.0.6' //compile引用时的第3部分版本号 32 | desc = 'Custom keyboard support custom Emoticon and voice recording multimedia selector'//d项目描述 33 | repoName="yangjiang" //你的仓库名称,没有填写默认仓库是maven//这也是很多人上传仓库不对问题最多情况, 34 | website = 'git@github.com:yangchaojiang/ChatKeyboard-master.gitr' //github 托管地址 35 | } 36 | -------------------------------------------------------------------------------- /keyboard/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Coding\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /keyboard/src/androidTest/java/com/yang/keyboard/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /keyboard/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/KeyboardFragment.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.CallSuper; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.util.Log; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.Toast; 12 | 13 | import java.util.ArrayList; 14 | import com.yang.keyboard.audio.AudioManger; 15 | import com.yang.keyboard.media.MediaBean; 16 | import com.yang.keyboard.media.MediaListener; 17 | import com.yang.keyboard.utils.OnKeyBoardLister; 18 | import com.yang.keyboard.view.AudioRecordButton; 19 | import com.yang.keyboard.view.RecordingLayout; 20 | 21 | /** 22 | * Created by yangc on 2017/3/7. 23 | * E-Mail:1007181167@qq.com 24 | * Description:键盘封装展示 方便集成 25 | */ 26 | 27 | public class KeyboardFragment extends Fragment implements MediaListener, ChatKeyboardLayout.OnChatKeyBoardListener { 28 | 29 | protected String TAG = KeyboardFragment.class.getName(); 30 | protected ChatKeyboardLayout keyboardLayout = null; 31 | protected RecordingLayout rlRecordArea; 32 | protected OnKeyBoardLister keyBoardLister; 33 | 34 | @Nullable 35 | @Override 36 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 37 | return inflater.inflate(R.layout.simple_fragment_keybord_layout, container, false); 38 | } 39 | 40 | @Override 41 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 42 | super.onViewCreated(view, savedInstanceState); 43 | keyboardLayout = (ChatKeyboardLayout) view.findViewById(R.id.kv_bar); 44 | rlRecordArea = (RecordingLayout) view.findViewById(R.id.recording_area); 45 | } 46 | 47 | /**** 48 | * 重写实现选择器内容选择器 49 | * @return ArrayList 50 | * ******/ 51 | protected ArrayList intiData() { 52 | ArrayList popupModels = new ArrayList<>(); 53 | popupModels.add(new MediaBean(0, R.drawable.icon_photo, "拍照", this)); 54 | return popupModels; 55 | } 56 | 57 | @Override 58 | public void onMediaClick(int id) { 59 | if (keyBoardLister != null) { 60 | keyBoardLister.sendMedia(id); 61 | } 62 | } 63 | 64 | @Override 65 | public void onSendBtnClick(String msg) { 66 | if (keyBoardLister != null) { 67 | keyBoardLister.sendText(msg); 68 | } 69 | } 70 | @Override 71 | public void onRecordingAction(AudioRecordButton audioRecordButton, ChatKeyboardLayout.RecordingAction action) { 72 | switch (action) { 73 | case START: 74 | String mVoicePath = AudioManger.getInstance().generatePath(getActivity()); 75 | AudioManger.getInstance().start(mVoicePath, new AudioListener()); 76 | rlRecordArea.show(1); 77 | break; 78 | case RESTORE: 79 | rlRecordArea.show(1); 80 | break; 81 | case WILLCANCEL: 82 | rlRecordArea.show(0); 83 | break; 84 | case CANCELED: 85 | AudioManger.getInstance().cancel(); 86 | rlRecordArea.hide(); 87 | break; 88 | case COMPLETE: 89 | int time = AudioManger.getInstance().complete(); 90 | if (time < 0) { 91 | Toast.makeText(getActivity(), "time is too short", Toast.LENGTH_SHORT).show(); 92 | } else { 93 | if (keyBoardLister != null) { 94 | keyBoardLister.sendAudio(AudioManger.getInstance().getmPath(), time); 95 | } 96 | } 97 | Log.d(TAG, "time:" + time + "mVoicePath" + AudioManger.getInstance().getmPath()); 98 | rlRecordArea.hide(); 99 | break; 100 | } 101 | } 102 | 103 | @Override 104 | public void onUserDefEmoticonClicked(String tag, String uri) { 105 | if (keyBoardLister != null) { 106 | keyBoardLister.sendUserDefEmoticon(tag, uri); 107 | } 108 | } 109 | 110 | @Override 111 | public void clickAddBtn(View view) { 112 | if (keyBoardLister != null) { 113 | keyBoardLister.clickAddBtn(view); 114 | } 115 | } 116 | 117 | /*** 118 | * 语音音量的大小监听 119 | * ***/ 120 | private class AudioListener implements AudioManger.OnAudioListener { 121 | @Override 122 | public void onDbChange(double db) { 123 | int level = 0; 124 | Log.e("pengtao", "onDbChange db = " + db); 125 | if (db > 40) { 126 | level = ((int) db - 40) / 7; 127 | } 128 | Log.e("pengtao", "onDbChange level = " + level); 129 | rlRecordArea.setVoiceLevel(level); 130 | } 131 | } 132 | 133 | public void setKeyBoardLister(OnKeyBoardLister keyBoardLister) { 134 | this.keyBoardLister = keyBoardLister; 135 | } 136 | 137 | @CallSuper 138 | @Override 139 | public void onDestroy() { 140 | if (keyboardLayout!=null){ 141 | keyboardLayout.release(); 142 | } 143 | super.onDestroy(); 144 | 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/audio/AudioManger.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.audio; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageManager; 5 | import android.media.MediaPlayer; 6 | import android.media.MediaRecorder; 7 | import android.os.Environment; 8 | import android.os.Handler; 9 | import android.support.v4.content.ContextCompat; 10 | import android.support.v4.content.PermissionChecker; 11 | 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.util.Timer; 15 | import java.util.TimerTask; 16 | 17 | import com.yang.keyboard.utils.HadLog; 18 | 19 | 20 | /** 21 | * Created by yangjiang on 2017/04/07. 22 | * E-Mail:1007181167@qq.com 23 | * Description:[音频录音和播放管理器] 24 | **/ 25 | public class AudioManger { 26 | private final String TAG = getClass().getSimpleName(); 27 | private volatile static AudioManger instance = null; 28 | private MediaRecorder recorder; 29 | private String mPath;//音频路径 30 | private int mPeriod = 0;///隐音频的时长 31 | private static final int MIN_LENGTH = 2; 32 | 33 | public static AudioManger getInstance() { 34 | if (instance == null) { 35 | synchronized (AudioManger.class) { 36 | if (instance == null) { 37 | instance = new AudioManger(); 38 | } 39 | } 40 | } 41 | return instance; 42 | } 43 | 44 | public AudioManger() { 45 | new Timer().schedule(new AudioTimerTask(), 0, 1000); 46 | } 47 | 48 | private class AudioTimerTask extends TimerTask { 49 | 50 | @Override 51 | public void run() { 52 | ++mPeriod; 53 | } 54 | } 55 | 56 | public synchronized void start(String path, OnAudioListener listener) { 57 | HadLog.d(TAG, "start recording"); 58 | mPeriod = 0; 59 | mListener = listener; 60 | recorder = new MediaRecorder(); 61 | recorder.setOnInfoListener(new MediaRecorder.OnInfoListener() { 62 | @Override 63 | public void onInfo(MediaRecorder mr, int what, int extra) { 64 | 65 | } 66 | }); 67 | recorder.setAudioSource(MediaRecorder.AudioSource.MIC); 68 | // 设置文件音频的输出格式为aac 69 | recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); 70 | // 设置音频的编码格式为aac 71 | recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); 72 | // recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB); 73 | // recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); 74 | // .m4a 格式可以在 iOS 上直接播放 75 | //recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 76 | recorder.setOutputFile(path); 77 | try { 78 | recorder.prepare(); 79 | recorder.start(); 80 | updateMicStatus(); 81 | HadLog.d(TAG, "record start success"); 82 | } catch (IllegalStateException e) { 83 | e.printStackTrace(); 84 | HadLog.e(TAG, "IllegalStateException"); 85 | } catch (IOException e) { 86 | e.printStackTrace(); 87 | HadLog.e(TAG, "IOException:" + e.getMessage()); 88 | } 89 | 90 | mPath = path; 91 | 92 | } 93 | 94 | /** 95 | * cancel, not save the file 96 | * 97 | * @return true, cancel success, false, cancel failed 98 | */ 99 | public synchronized boolean cancel() { 100 | HadLog.d(TAG, "cancel recording"); 101 | if (recorder == null) { 102 | HadLog.e(TAG, "recorder is null "); 103 | return false; 104 | } 105 | try { 106 | stopRecord(); 107 | } catch (IllegalStateException e) { 108 | e.printStackTrace(); 109 | HadLog.e(TAG, "illegal state happened when cancel"); 110 | } 111 | 112 | File file = new File(mPath); 113 | return file.exists() && file.delete(); 114 | } 115 | 116 | 117 | /** 118 | * complete the recording 119 | * 120 | * @return recording last time 121 | */ 122 | public synchronized int complete() { 123 | HadLog.i(TAG, "complete recording"); 124 | if (recorder == null) { 125 | HadLog.e(TAG, "recorder is null "); 126 | return -1; 127 | } 128 | 129 | try { 130 | stopRecord(); 131 | } catch (IllegalStateException e) { 132 | e.printStackTrace(); 133 | HadLog.e(TAG, "illegal state happened when complete"); 134 | return -1; 135 | } 136 | 137 | if (mPeriod < MIN_LENGTH) { 138 | HadLog.i(TAG, "record time is too short"); 139 | return -1; 140 | } 141 | 142 | return mPeriod; 143 | } 144 | 145 | public String generatePath(Context context) { 146 | boolean isSuccess = true; 147 | final String CACHE_DIR_NAME = "audioCache"; 148 | final String cachePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + CACHE_DIR_NAME; 149 | File file = new File(cachePath); 150 | if (!file.exists()) { 151 | isSuccess = file.mkdirs(); 152 | } 153 | if (isSuccess) { 154 | return cachePath + File.separator + System.currentTimeMillis() + ".aac"; 155 | } else { 156 | return null; 157 | } 158 | } 159 | 160 | private synchronized void stopRecord() throws IllegalStateException { 161 | if (mHandler != null) { 162 | mHandler.removeCallbacks(mUpdateMicStatusTimer); 163 | } 164 | recorder.reset(); 165 | recorder.release(); 166 | recorder = null; 167 | } 168 | 169 | private final Handler mHandler = new Handler(); 170 | private Runnable mUpdateMicStatusTimer = new Runnable() { 171 | public void run() { 172 | updateMicStatus(); 173 | } 174 | }; 175 | 176 | private void updateMicStatus() { 177 | if (recorder != null) { 178 | double ratio = (double) recorder.getMaxAmplitude(); 179 | double db = 0; 180 | if (ratio > 1) 181 | db = 20 * Math.log10(ratio); 182 | if (mListener != null) { 183 | mListener.onDbChange(db); 184 | } 185 | mHandler.postDelayed(mUpdateMicStatusTimer, 500); 186 | } 187 | } 188 | 189 | private OnAudioListener mListener = null; 190 | 191 | public interface OnAudioListener { 192 | void onDbChange(double db); 193 | } 194 | 195 | private MediaPlayer mMediaPlayer = null; 196 | private String mCurrentPlayingAudioPath = null; 197 | private OnMediaPlayComplete mPlayListener = null; 198 | 199 | /** 200 | * play the audio 201 | * 202 | * @param path path of the audio file 203 | * @param listener 接口 204 | */ 205 | public synchronized void playAudio(String path, OnMediaPlayComplete listener) { 206 | mPlayListener = listener; 207 | if (mMediaPlayer != null) { 208 | stopPlay(); 209 | } 210 | mMediaPlayer = new MediaPlayer(); 211 | mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 212 | @Override 213 | public void onCompletion(MediaPlayer mp) { 214 | stopPlay(); 215 | if (mPlayListener != null) { 216 | mPlayListener.onPlayComplete(true); 217 | } 218 | } 219 | }); 220 | try { 221 | mMediaPlayer.setDataSource(path); 222 | mMediaPlayer.prepare(); 223 | } catch (IOException e) { 224 | e.printStackTrace(); 225 | mPlayListener.onPlayComplete(false); 226 | } 227 | 228 | mMediaPlayer.start(); 229 | 230 | mCurrentPlayingAudioPath = path; 231 | } 232 | 233 | public synchronized void stopPlay() { 234 | mMediaPlayer.stop(); 235 | mMediaPlayer.release(); 236 | mMediaPlayer = null; 237 | mCurrentPlayingAudioPath = null; 238 | } 239 | 240 | public boolean isPlaying(String path) { 241 | return (mMediaPlayer != null) && mMediaPlayer.isPlaying() && (path.equals(mCurrentPlayingAudioPath)); 242 | } 243 | 244 | public interface OnMediaPlayComplete { 245 | void onPlayComplete(boolean isSuccess); 246 | } 247 | 248 | public String getmPath() { 249 | return mPath; 250 | } 251 | 252 | private boolean voicePermission(Context context) { 253 | return (PackageManager.PERMISSION_GRANTED == ContextCompat. 254 | checkSelfPermission(context, android.Manifest.permission.RECORD_AUDIO)); 255 | } 256 | 257 | } 258 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/emoticon/EmoticonBean.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.emoticon; 2 | /** 3 | * Created by yangjiang on 2017/04/07. 4 | * E-Mail:1007181167@qq.com 5 | * Description:[表情item 实体类] 6 | **/ 7 | public class EmoticonBean { 8 | 9 | public final static int FACE_TYPE_NORMAL = 0; 10 | public final static int FACE_TYPE_DEL = 1; 11 | public final static int FACE_TYPE_USERDEF = 2; // user downloaded emoticons 12 | 13 | private long eventType; 14 | private String iconUri; 15 | private String msgUri; 16 | private String tag; 17 | private String name; 18 | 19 | public long getEventType() { return eventType; } 20 | 21 | public void setEventType(long eventType) { this.eventType = eventType; } 22 | 23 | public String getIconUri() { 24 | return iconUri; 25 | } 26 | 27 | public void setIconUri(String iconUri) { 28 | this.iconUri = iconUri; 29 | } 30 | 31 | public String getMsgUri() { 32 | return msgUri; 33 | } 34 | 35 | public void setMsgUri(String msgUri) { 36 | this.msgUri = msgUri; 37 | } 38 | 39 | public String getTag() { 40 | return tag; 41 | } 42 | 43 | public void setTag(String tag) { 44 | this.tag = tag; 45 | } 46 | 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | public void setName(String name) { 52 | this.name = name; 53 | } 54 | 55 | public static String fromChars(String chars) { return chars; } 56 | 57 | public static String fromChar(char ch) { return Character.toString(ch); } 58 | 59 | public static String fromCodePoint(int codePoint) { return newString(codePoint); } 60 | 61 | public static String newString(int codePoint) { 62 | if (Character.charCount(codePoint) == 1) { 63 | return String.valueOf(codePoint); 64 | } else { 65 | return new String(Character.toChars(codePoint)); 66 | } 67 | } 68 | 69 | public EmoticonBean(long eventType , String iconUri , String tag, String name){ 70 | this.eventType = eventType; 71 | this.iconUri = iconUri; 72 | this.tag = tag; 73 | this.name = name; 74 | } 75 | 76 | public EmoticonBean() { 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/emoticon/EmoticonSetBean.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.emoticon; 2 | 3 | import java.util.ArrayList; 4 | /** 5 | * Created by yangjiang on 2017/04/07. 6 | * E-Mail:1007181167@qq.com 7 | * Description:[表情选择卡 实体类] 8 | **/ 9 | public class EmoticonSetBean { 10 | /** 11 | * name of set 12 | */ 13 | private String name; 14 | /** 15 | * line number 16 | */ 17 | private int line; 18 | /** 19 | * row number 20 | */ 21 | private int row; 22 | /** 23 | * icon 24 | */ 25 | private String iconUri; 26 | /** 27 | * is show delete button 28 | */ 29 | private boolean isShowDelBtn; 30 | /** 31 | * item padding 32 | */ 33 | private int itemPadding; 34 | 35 | private int horizontalSpacing; 36 | 37 | private int verticalSpacing; 38 | 39 | private ArrayList emoticonList; 40 | 41 | private boolean isShownName; 42 | 43 | public EmoticonSetBean(){ 44 | } 45 | 46 | public EmoticonSetBean(String name , int line , int row){ 47 | this.name = name; 48 | this.line = line; 49 | this.row = row; 50 | } 51 | 52 | public EmoticonSetBean(String name , int line , int row , String iconUri, boolean isShowDelBtn , boolean isShownName, 53 | int itemPadding , int horizontalSpacing , int verticalSpacing , ArrayList emoticonList){ 54 | this.name = name; 55 | this.line = line; 56 | this.row = row; 57 | this.iconUri = iconUri; 58 | this.isShowDelBtn = isShowDelBtn; 59 | this.itemPadding = itemPadding; 60 | this.horizontalSpacing = horizontalSpacing; 61 | this.verticalSpacing = verticalSpacing; 62 | this.emoticonList = emoticonList; 63 | this.isShownName = isShownName; 64 | } 65 | 66 | public boolean isShownName() { 67 | return isShownName; 68 | } 69 | 70 | public void setIsShownName(boolean isShownName) { 71 | this.isShownName = isShownName; 72 | } 73 | 74 | public String getName() { 75 | return name; 76 | } 77 | 78 | public void setName(String name) { 79 | this.name = name; 80 | } 81 | 82 | public int getLine() { 83 | return line; 84 | } 85 | 86 | public void setLine(int line) { 87 | this.line = line; 88 | } 89 | 90 | public int getRow() { 91 | return row; 92 | } 93 | 94 | public void setRow(int row) { 95 | this.row = row; 96 | } 97 | 98 | public String getIconUri() { 99 | return iconUri; 100 | } 101 | 102 | public void setIconUri(String iconUri) { 103 | this.iconUri = iconUri; 104 | } 105 | 106 | public boolean isShowDelBtn() { 107 | return isShowDelBtn; 108 | } 109 | 110 | public void setShowDelBtn(boolean isShowDelBtn) { 111 | this.isShowDelBtn = isShowDelBtn; 112 | } 113 | 114 | public int getItemPadding() { 115 | return itemPadding; 116 | } 117 | 118 | public void setItemPadding(int itemPadding) { 119 | this.itemPadding = itemPadding; 120 | } 121 | 122 | public int getHorizontalSpacing() { 123 | return horizontalSpacing; 124 | } 125 | 126 | public void setHorizontalSpacing(int horizontalSpacing) { this.horizontalSpacing = horizontalSpacing; } 127 | 128 | public int getVerticalSpacing() { 129 | return verticalSpacing; 130 | } 131 | 132 | public void setVerticalSpacing(int verticalSpacing) { 133 | this.verticalSpacing = verticalSpacing; 134 | } 135 | 136 | public ArrayList getEmoticonList() { 137 | return emoticonList; 138 | } 139 | 140 | public void setEmoticonList(ArrayList emoticonList) { this.emoticonList = emoticonList; } 141 | } 142 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/emoticon/bean/EmoticonEntity.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.emoticon.bean; 2 | 3 | import com.yang.keyboard.utils.EmoticonBase; 4 | 5 | /** 6 | * Created by yangjiang on 2017/04/07. 7 | * E-Mail:1007181167@qq.com 8 | * Description:[表情父类] 9 | **/ 10 | public class EmoticonEntity { 11 | private String path; 12 | private EmoticonBase.Scheme scheme; 13 | 14 | public EmoticonEntity(String path, EmoticonBase.Scheme scheme) { 15 | this.path = path; 16 | this.scheme = scheme; 17 | } 18 | 19 | public String getPath() { 20 | return path; 21 | } 22 | 23 | public EmoticonBase.Scheme getScheme() { 24 | return scheme; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/emoticon/bean/EmoticonLayout.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.emoticon.bean; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.RelativeLayout; 8 | 9 | import com.yang.keyboard.R; 10 | import com.yang.keyboard.emoticon.EmoticonBean; 11 | import com.yang.keyboard.emoticon.util.EmoticonsKeyboardBuilder; 12 | import com.yang.keyboard.view.IndicatorView; 13 | 14 | /** 15 | * Created by yangjiang on 2017/04/07. 16 | * E-Mail:1007181167@qq.com 17 | * Description:[表情展示布局] 18 | **/ 19 | public class EmoticonLayout extends RelativeLayout implements EmoticonsPageView.OnEmoticonsPageViewListener { 20 | Context mContext; 21 | EmoticonsPageView epvContent; 22 | IndicatorView ivIndicator; 23 | EmoticonsToolBarView etvToolBar; 24 | 25 | public EmoticonLayout(Context context) { 26 | super(context); 27 | mContext = context; 28 | init(mContext); 29 | } 30 | 31 | public EmoticonLayout(Context context, AttributeSet attrs) { 32 | super(context, attrs); 33 | mContext = context; 34 | init(mContext); 35 | } 36 | 37 | public EmoticonLayout(Context context, AttributeSet attrs, int defStyleAttr) { 38 | super(context, attrs, defStyleAttr); 39 | mContext = context; 40 | init(mContext); 41 | } 42 | 43 | private void init(Context context) { 44 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 45 | inflater.inflate(R.layout.keyboard_bottom_emoticons, this); 46 | ivIndicator = (IndicatorView) findViewById(R.id.emoticon_indicator_view); 47 | epvContent = (EmoticonsPageView) findViewById(R.id.emoticon_page_view); 48 | etvToolBar = (EmoticonsToolBarView) findViewById(R.id.emoticon_page_toolbar); 49 | epvContent.setOnIndicatorListener(this); 50 | epvContent.setIViewListener(new IView() { 51 | @Override 52 | public void onItemClick(EmoticonBean bean) { 53 | mListener.onEmoticonItemClicked(bean); 54 | } 55 | 56 | @Override 57 | public void onPageChangeTo(int position) { 58 | etvToolBar.setToolBtnSelect(position); 59 | } 60 | }); 61 | etvToolBar.setOnToolBarItemClickListener(new EmoticonsToolBarView.OnToolBarItemClickListener() { 62 | @Override 63 | public void onToolBarItemClick(int position) { 64 | epvContent.setPageSelect(position); 65 | } 66 | }); 67 | } 68 | 69 | OnEmoticonListener mListener = null; 70 | 71 | public interface OnEmoticonListener { 72 | void onEmoticonItemClicked(EmoticonBean bean); 73 | } 74 | 75 | @Override 76 | public void emoticonsPageViewCountChanged(int count) { 77 | ivIndicator.setIndicatorCount(count); 78 | } 79 | 80 | @Override 81 | public void moveTo(int position) { 82 | ivIndicator.moveTo(position); 83 | } 84 | 85 | @Override 86 | public void moveBy(int oldPosition, int newPosition) { 87 | ivIndicator.moveTo(newPosition); 88 | } 89 | 90 | public void addToolView(int icon) { 91 | if (etvToolBar != null && icon > 0) { 92 | etvToolBar.addData(icon); 93 | } 94 | } 95 | 96 | public void addFixedView(View view, boolean isRight) { 97 | if (etvToolBar != null) { 98 | etvToolBar.addFixedView(view, isRight); 99 | } 100 | } 101 | 102 | public void setContents(EmoticonsKeyboardBuilder builder, OnEmoticonListener listener) { 103 | epvContent.setEmoticonContents(builder); 104 | etvToolBar.setEmoticonContents(builder); 105 | mListener = listener; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/emoticon/bean/EmoticonsAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.emoticon.bean; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.AbsListView; 8 | import android.widget.BaseAdapter; 9 | import android.widget.ImageView; 10 | import android.widget.LinearLayout; 11 | import android.widget.RelativeLayout; 12 | import android.widget.TextView; 13 | 14 | import java.util.List; 15 | 16 | import com.yang.keyboard.R; 17 | import com.yang.keyboard.emoticon.EmoticonBean; 18 | import com.yang.keyboard.utils.EmoticonLoader; 19 | 20 | /** 21 | * Created by yangjiang on 2017/04/07. 22 | * E-Mail:1007181167@qq.com 23 | * Description:[表情展示适配器] 24 | **/ 25 | public class EmoticonsAdapter extends BaseAdapter { 26 | private Context mContext; 27 | 28 | private List data; 29 | private int mItemHeight = 0; 30 | private int mImgHeight = 0; 31 | private boolean isDisplayName = false; 32 | 33 | public EmoticonsAdapter(Context context, List list, boolean isDisplayName) { 34 | this.mContext = context; 35 | this.data = list; 36 | this.isDisplayName = isDisplayName; 37 | } 38 | 39 | @Override 40 | public int getCount() { 41 | return data.size(); 42 | } 43 | 44 | @Override 45 | public EmoticonBean getItem(int position) { 46 | return data.get(position); 47 | } 48 | 49 | @Override 50 | public long getItemId(int position) { 51 | return position; 52 | } 53 | 54 | @Override 55 | public View getView(int position, View convertView, ViewGroup parent) { 56 | ViewHolder viewHolder; 57 | if (convertView == null) { 58 | convertView = LayoutInflater.from(mContext).inflate(R.layout.emoticons_item, parent, false); 59 | convertView.setLayoutParams(new AbsListView.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, mItemHeight)); 60 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mImgHeight, mImgHeight); 61 | //params.addRule(RelativeLayout.CENTER_HORIZONTAL); 62 | viewHolder = new ViewHolder(convertView); 63 | viewHolder.ivEmoticon.setLayoutParams(params); 64 | convertView.setTag(viewHolder); 65 | } else { 66 | viewHolder = (ViewHolder) convertView.getTag(); 67 | } 68 | 69 | final EmoticonBean emoticonBean = getItem(position); 70 | if ( emoticonBean != null ) { // exists some empty block 71 | viewHolder.ivEmoticon.setBackgroundResource(R.drawable.emoticon_bg); 72 | if ( isDisplayName ) { 73 | viewHolder.tvName.setVisibility(View.VISIBLE); 74 | viewHolder.tvName.setText(getItem(position).getName()); 75 | } else { 76 | viewHolder.tvName.setVisibility(View.GONE); 77 | } 78 | viewHolder.ivEmoticon.setImageDrawable(EmoticonLoader.getInstance(mContext).getDrawable(emoticonBean.getIconUri())); 79 | 80 | convertView.setOnClickListener(new View.OnClickListener() { 81 | @Override 82 | public void onClick(View v) { 83 | if (mOnItemListener != null) { 84 | mOnItemListener.onItemClick(emoticonBean); 85 | } 86 | } 87 | }); 88 | } 89 | 90 | return convertView; 91 | } 92 | 93 | static class ViewHolder { 94 | public ImageView ivEmoticon; 95 | public TextView tvName; 96 | 97 | public ViewHolder(View view) { 98 | ivEmoticon = (ImageView)view.findViewById(R.id.emoticon_item_image); 99 | tvName = (TextView)view.findViewById(R.id.emoticon_item_text); 100 | } 101 | } 102 | 103 | public void setHeight(int height, int padding) { 104 | mItemHeight = height; 105 | mImgHeight = mItemHeight - padding; 106 | notifyDataSetChanged(); 107 | } 108 | 109 | IView mOnItemListener; 110 | public void setOnItemListener(IView listener) { 111 | this.mOnItemListener = listener; 112 | } 113 | } -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/emoticon/bean/EmoticonsToolBarView.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.emoticon.bean; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.HorizontalScrollView; 8 | import android.widget.ImageView; 9 | import android.widget.LinearLayout; 10 | import android.widget.RelativeLayout; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.Random; 15 | 16 | import com.yang.keyboard.R; 17 | import com.yang.keyboard.emoticon.EmoticonSetBean; 18 | import com.yang.keyboard.emoticon.util.EmoticonsKeyboardBuilder; 19 | import com.yang.keyboard.utils.Utils; 20 | import com.yang.keyboard.utils.EmoticonLoader; 21 | /** 22 | * Created by yangjiang on 2017/04/07. 23 | * E-Mail:1007181167@qq.com 24 | * Description:[表情类别 选择指示器] 25 | **/ 26 | public class EmoticonsToolBarView extends RelativeLayout { 27 | 28 | private Context mContext; 29 | private HorizontalScrollView hsv_toolbar; 30 | private LinearLayout ly_tool; 31 | 32 | private List mEmoticonSetBeanList; 33 | private ArrayList mToolBtnList = new ArrayList<>(); 34 | private int mBtnWidth = 60; 35 | 36 | public EmoticonsToolBarView(Context context) { 37 | this(context, null); 38 | } 39 | 40 | public EmoticonsToolBarView(Context context, AttributeSet attrs) { 41 | super(context, attrs); 42 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 43 | inflater.inflate(R.layout.emoticonstoolbar_view, this); 44 | this.mContext = context; 45 | findView(); 46 | } 47 | 48 | private void findView() { 49 | hsv_toolbar = (HorizontalScrollView) findViewById(R.id.hsv_toolbar); 50 | ly_tool = (LinearLayout) findViewById(R.id.ly_tool); 51 | } 52 | 53 | private void scrollToBtnPosition(final int position) { 54 | int childCount = ly_tool.getChildCount(); 55 | if (position < childCount) { 56 | hsv_toolbar.post(new Runnable() { 57 | @Override 58 | public void run() { 59 | int mScrollX = hsv_toolbar.getScrollX(); 60 | 61 | //todo test adding many views 62 | int childX = ly_tool.getChildAt(position).getLeft(); 63 | if (childX < mScrollX) { 64 | hsv_toolbar.scrollTo(childX, 0); 65 | return; 66 | } 67 | 68 | int childWidth = (int) ly_tool.getChildAt(position).getWidth(); 69 | int hsvWidth = hsv_toolbar.getWidth(); 70 | int childRight = childX + childWidth; 71 | int scrollRight = mScrollX + hsvWidth; 72 | 73 | if (childRight > scrollRight) { 74 | hsv_toolbar.scrollTo(childRight - scrollRight, 0); 75 | } 76 | } 77 | }); 78 | } 79 | } 80 | 81 | public void setToolBtnSelect(int select) { 82 | scrollToBtnPosition(select); 83 | for (int i = 0; i < mToolBtnList.size(); i++) { 84 | if (select == i) { 85 | mToolBtnList.get(i).setBackgroundColor(getResources().getColor(R.color.toolbar_btn_select)); 86 | } else { 87 | mToolBtnList.get(i).setBackgroundColor(getResources().getColor(R.color.toolbar_btn_nomal)); 88 | } 89 | } 90 | } 91 | 92 | public void setBtnWidth(int width) { 93 | mBtnWidth = width; 94 | } 95 | 96 | public void addData(int rec) { 97 | if (ly_tool != null) { 98 | View toolBtnView = inflate(mContext, R.layout.emoticonstoolbar_item, null); 99 | ImageView iv_icon = (ImageView) toolBtnView.findViewById(R.id.iv_icon); 100 | iv_icon.setImageResource(rec); 101 | LinearLayout.LayoutParams imgParams = new LinearLayout.LayoutParams(Utils.dip2px(mContext, mBtnWidth), LayoutParams.MATCH_PARENT); 102 | iv_icon.setLayoutParams(imgParams); 103 | ly_tool.addView(toolBtnView); 104 | final int position = mToolBtnList.size(); 105 | mToolBtnList.add(iv_icon); 106 | iv_icon.setOnClickListener(new OnClickListener() { 107 | @Override 108 | public void onClick(View view) { 109 | if (mItemClickListeners != null && !mItemClickListeners.isEmpty()) { 110 | for (OnToolBarItemClickListener listener : mItemClickListeners) { 111 | listener.onToolBarItemClick(position); 112 | } 113 | } 114 | } 115 | }); 116 | } 117 | } 118 | 119 | private int getIdValue() { 120 | int childCount = getChildCount(); 121 | int id = 1; 122 | if (childCount == 0) { 123 | return id; 124 | } 125 | boolean isKeep = true; 126 | while (isKeep) { 127 | isKeep = false; 128 | Random random = new Random(); 129 | id = random.nextInt(100); 130 | for (int i = 0; i < childCount; i++) { 131 | if (getChildAt(i).getId() == id) { 132 | isKeep = true; 133 | break; 134 | } 135 | } 136 | } 137 | return id; 138 | } 139 | 140 | public void addFixedView(View view, boolean isRight) { 141 | LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); 142 | LayoutParams hsvParams = (LayoutParams) hsv_toolbar.getLayoutParams(); 143 | if (view.getId() <= 0) { 144 | view.setId(getIdValue()); 145 | } 146 | if (isRight) { 147 | params.addRule(ALIGN_PARENT_RIGHT); 148 | hsvParams.addRule(LEFT_OF, view.getId()); 149 | } else { 150 | params.addRule(ALIGN_PARENT_LEFT); 151 | hsvParams.addRule(RIGHT_OF, view.getId()); 152 | } 153 | addView(view, params); 154 | hsv_toolbar.setLayoutParams(hsvParams); 155 | } 156 | 157 | public void setEmoticonContents(EmoticonsKeyboardBuilder builder) { 158 | mEmoticonSetBeanList = builder.builder == null ? null : builder.builder.getEmoticonSetBeanList(); 159 | if (mEmoticonSetBeanList == null) { 160 | return; 161 | } 162 | 163 | int i = 0; 164 | for (EmoticonSetBean bean : mEmoticonSetBeanList) { 165 | View toolBtnView = inflate(mContext, R.layout.emoticonstoolbar_item, null); 166 | ImageView iv_icon = (ImageView) toolBtnView.findViewById(R.id.iv_icon); 167 | LinearLayout.LayoutParams imgParams = new LinearLayout.LayoutParams(Utils.dip2px(mContext, mBtnWidth), LayoutParams.MATCH_PARENT); 168 | iv_icon.setLayoutParams(imgParams); 169 | ly_tool.addView(toolBtnView); 170 | 171 | iv_icon.setImageDrawable(EmoticonLoader.getInstance(mContext).getDrawable(bean.getIconUri())); 172 | 173 | mToolBtnList.add(iv_icon); 174 | 175 | final int finalI = i; 176 | iv_icon.setOnClickListener(new OnClickListener() { 177 | @Override 178 | public void onClick(View view) { 179 | if (mItemClickListeners != null && !mItemClickListeners.isEmpty()) { 180 | for (OnToolBarItemClickListener listener : mItemClickListeners) { 181 | listener.onToolBarItemClick(finalI); 182 | } 183 | } 184 | } 185 | }); 186 | i++; 187 | } 188 | setToolBtnSelect(0); 189 | } 190 | 191 | private List mItemClickListeners; 192 | 193 | public interface OnToolBarItemClickListener { 194 | void onToolBarItemClick(int position); 195 | } 196 | 197 | public void addOnToolBarItemClickListener(OnToolBarItemClickListener listener) { 198 | if (mItemClickListeners == null) { 199 | mItemClickListeners = new ArrayList(); 200 | } 201 | mItemClickListeners.add(listener); 202 | } 203 | 204 | public void setOnToolBarItemClickListener(OnToolBarItemClickListener listener) { 205 | addOnToolBarItemClickListener(listener); 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/emoticon/bean/IView.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.emoticon.bean; 2 | 3 | import com.yang.keyboard.emoticon.EmoticonBean; 4 | /** 5 | * Created by yangjiang on 2017/04/07. 6 | * E-Mail:1007181167@qq.com 7 | * Description:[每页的表情item 点击接口] 8 | **/ 9 | public interface IView { 10 | void onItemClick(EmoticonBean bean); 11 | void onPageChangeTo(int position); 12 | } 13 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/emoticon/db/TableColumns.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.emoticon.db; 2 | 3 | import android.provider.BaseColumns; 4 | /** 5 | * Created by yangjiang on 2017/04/07. 6 | * E-Mail:1007181167@qq.com 7 | * Description:[表情数据库表名] 8 | **/ 9 | public final class TableColumns { 10 | 11 | public interface EmoticonColumns extends BaseColumns { 12 | String EVENT_TYPE = "eventtype"; //1, for send in input area; 2, for sent in chat area directly 13 | String TAG = "tag"; //for matching, should be unique 14 | String NAME = "name"; //for displaying 15 | String ICON_URI = "icon_uri"; //uri for displaying in grid 16 | String MSG_URI = "msg_uri"; //for being sent in chat 17 | String EMOTICON_SET_NAME = "emoticon_set_name"; //emoticonset name 18 | } 19 | 20 | public interface EmoticonSetColumns extends BaseColumns { 21 | String NAME = "name"; 22 | String LINE = "line"; 23 | String ROW = "row"; 24 | String ICON_URI = "iconuri"; 25 | String IS_SHOW_DEL_BTN = "isshowdelbtn"; 26 | String ITEM_PADDING = "itempadding"; 27 | String HORIZONTAL_SPACING = "horizontalspacing"; 28 | String VERTICAL_SPACING = "verticalspacing"; 29 | String IS_SHOWN_NAME = "isshownname"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/emoticon/util/DefEmoticons.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.emoticon.util; 2 | 3 | import com.yang.keyboard.emoticon.EmoticonBean; 4 | 5 | /** 6 | * Created by yangjiang on 2017/04/07. 7 | * E-Mail:1007181167@qq.com 8 | * Description:[默认表情] 9 | **/ 10 | public class DefEmoticons { 11 | /** 12 | * emoji 13 | */ 14 | public static final String[] emojiArray = { 15 | "emoji_0x1f604.png," + EmoticonBean.fromCodePoint(0x1f604), 16 | "emoji_0x1f603.png," + EmoticonBean.fromCodePoint(0x1f603), 17 | "emoji_0x1f60a.png," + EmoticonBean.fromCodePoint(0x1f60a), 18 | "emoji_0x1f609.png," + EmoticonBean.fromCodePoint(0x1f609), 19 | "emoji_0x1f60d.png," + EmoticonBean.fromCodePoint(0x1f60d), 20 | "emoji_0x1f618.png," + EmoticonBean.fromCodePoint(0x1f618), 21 | "emoji_0x1f61a.png," + EmoticonBean.fromCodePoint(0x1f61a), 22 | "emoji_0x1f61c.png," + EmoticonBean.fromCodePoint(0x1f61c), 23 | "emoji_0x1f61d.png," + EmoticonBean.fromCodePoint(0x1f61d), 24 | "emoji_0x1f633.png," + EmoticonBean.fromCodePoint(0x1f633), 25 | "emoji_0x1f601.png," + EmoticonBean.fromCodePoint(0x1f601), 26 | "emoji_0x1f614.png," + EmoticonBean.fromCodePoint(0x1f614), 27 | "emoji_0x1f60c.png," + EmoticonBean.fromCodePoint(0x1f60c), 28 | "emoji_0x1f612.png," + EmoticonBean.fromCodePoint(0x1f612), 29 | "emoji_0x1f61e.png," + EmoticonBean.fromCodePoint(0x1f61e), 30 | "emoji_0x1f623.png," + EmoticonBean.fromCodePoint(0x1f623), 31 | "emoji_0x1f622.png," + EmoticonBean.fromCodePoint(0x1f622), 32 | "emoji_0x1f602.png," + EmoticonBean.fromCodePoint(0x1f602), 33 | "emoji_0x1f62d.png," + EmoticonBean.fromCodePoint(0x1f62d), 34 | "emoji_0x1f62a.png," + EmoticonBean.fromCodePoint(0x1f62a), 35 | "emoji_0x1f625.png," + EmoticonBean.fromCodePoint(0x1f625), 36 | "emoji_0x1f630.png," + EmoticonBean.fromCodePoint(0x1f630), 37 | "emoji_0x1f613.png," + EmoticonBean.fromCodePoint(0x1f613), 38 | "emoji_0x1f628.png," + EmoticonBean.fromCodePoint(0x1f628), 39 | "emoji_0x1f631.png," + EmoticonBean.fromCodePoint(0x1f631), 40 | "emoji_0x1f620.png," + EmoticonBean.fromCodePoint(0x1f620), 41 | "emoji_0x1f621.png," + EmoticonBean.fromCodePoint(0x1f621), 42 | "emoji_0x1f616.png," + EmoticonBean.fromCodePoint(0x1f616), 43 | "emoji_0x1f637.png," + EmoticonBean.fromCodePoint(0x1f637), 44 | "emoji_0x1f632.png," + EmoticonBean.fromCodePoint(0x1f632), 45 | "emoji_0x1f47f.png," + EmoticonBean.fromCodePoint(0x1f47f), 46 | "emoji_0x1f60f.png," + EmoticonBean.fromCodePoint(0x1f60f), 47 | "emoji_0x1f466.png," + EmoticonBean.fromCodePoint(0x1f466), 48 | "emoji_0x1f467.png," + EmoticonBean.fromCodePoint(0x1f467), 49 | "emoji_0x1f468.png," + EmoticonBean.fromCodePoint(0x1f468), 50 | "emoji_0x1f469.png," + EmoticonBean.fromCodePoint(0x1f469), 51 | "emoji_0x1f31f.png," + EmoticonBean.fromCodePoint(0x1f31f), 52 | "emoji_0x1f444.png," + EmoticonBean.fromCodePoint(0x1f444), 53 | "emoji_0x1f44d.png," + EmoticonBean.fromCodePoint(0x1f44d), 54 | "emoji_0x1f44e.png," + EmoticonBean.fromCodePoint(0x1f44e), 55 | "emoji_0x1f44c.png," + EmoticonBean.fromCodePoint(0x1f44c), 56 | "emoji_0x1f44a.png," + EmoticonBean.fromCodePoint(0x1f44a), 57 | "emoji_0x270a.png," + EmoticonBean.fromChar((char) 0x270a), 58 | "emoji_0x270c.png," + EmoticonBean.fromChar((char) 0x270c), 59 | "emoji_0x1f446.png," + EmoticonBean.fromCodePoint(0x1f446), 60 | "emoji_0x1f447.png," + EmoticonBean.fromCodePoint(0x1f447), 61 | "emoji_0x1f449.png," + EmoticonBean.fromCodePoint(0x1f449), 62 | "emoji_0x1f448.png," + EmoticonBean.fromCodePoint(0x1f448), 63 | "emoji_0x1f64f.png," + EmoticonBean.fromCodePoint(0x1f64f), 64 | "emoji_0x1f44f.png," + EmoticonBean.fromCodePoint(0x1f44f), 65 | "emoji_0x1f4aa.png," + EmoticonBean.fromCodePoint(0x1f4aa), 66 | "emoji_0x1f457.png," + EmoticonBean.fromCodePoint(0x1f457), 67 | "emoji_0x1f380.png," + EmoticonBean.fromCodePoint(0x1f380), 68 | "emoji_0x2764.png," + EmoticonBean.fromChar((char) 0x2764), 69 | "emoji_0x1f494.png," + EmoticonBean.fromCodePoint(0x1f494), 70 | "emoji_0x1f48e.png," + EmoticonBean.fromCodePoint(0x1f48e), 71 | "emoji_0x1f436.png," + EmoticonBean.fromCodePoint(0x1f436), 72 | "emoji_0x1f431.png," + EmoticonBean.fromCodePoint(0x1f431), 73 | "emoji_0x1f339.png," + EmoticonBean.fromCodePoint(0x1f339), 74 | "emoji_0x1f33b.png," + EmoticonBean.fromCodePoint(0x1f33b), 75 | "emoji_0x1f341.png," + EmoticonBean.fromCodePoint(0x1f341), 76 | "emoji_0x1f343.png," + EmoticonBean.fromCodePoint(0x1f343), 77 | "emoji_0x1f319.png," + EmoticonBean.fromCodePoint(0x1f319), 78 | "emoji_0x2600.png," + EmoticonBean.fromChar((char) 0x2600), 79 | "emoji_0x2601.png," + EmoticonBean.fromChar((char) 0x2601), 80 | "emoji_0x26a1.png," + EmoticonBean.fromChar((char) 0x26a1), 81 | "emoji_0x2614.png," + EmoticonBean.fromChar((char) 0x2614), 82 | "emoji_0x1f47b.png," + EmoticonBean.fromCodePoint(0x1f47b), 83 | "emoji_0x1f385.png," + EmoticonBean.fromCodePoint(0x1f385), 84 | "emoji_0x1f381.png," + EmoticonBean.fromCodePoint(0x1f381), 85 | "emoji_0x1f4f1.png," + EmoticonBean.fromCodePoint(0x1f4f1), 86 | "emoji_0x1f50d.png," + EmoticonBean.fromCodePoint(0x1f50d), 87 | "emoji_0x1f4a3.png," + EmoticonBean.fromCodePoint(0x1f4a3), 88 | "emoji_0x26bd.png," + EmoticonBean.fromChar((char) 0x26bd), 89 | "emoji_0x2615.png," + EmoticonBean.fromChar((char) 0x2615), 90 | "emoji_0x1f37a.png," + EmoticonBean.fromCodePoint(0x1f37a), 91 | "emoji_0x1f382.png," + EmoticonBean.fromCodePoint(0x1f382), 92 | "emoji_0x1f3e0.png," + EmoticonBean.fromCodePoint(0x1f3e0), 93 | "emoji_0x1f697.png," + EmoticonBean.fromCodePoint(0x1f697), 94 | "emoji_0x1f559.png," + EmoticonBean.fromCodePoint(0x1f559), 95 | }; 96 | } -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/emoticon/util/EmoticonHandler.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.emoticon.util; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.support.annotation.NonNull; 6 | import android.text.Spannable; 7 | 8 | import java.io.IOException; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import com.yang.keyboard.emoticon.bean.EmoticonEntity; 13 | import com.yang.keyboard.emoticon.EmoticonSetBean; 14 | import com.yang.keyboard.emoticon.db.EmoticonDBHelper; 15 | import com.yang.keyboard.emoticon.EmoticonBean; 16 | import com.yang.keyboard.utils.EmoticonBase; 17 | import com.yang.keyboard.utils.EmoticonLoader; 18 | import com.yang.keyboard.utils.HadLog; 19 | import com.yang.keyboard.utils.Utils; 20 | import com.yang.keyboard.view.VerticalImageSpan; 21 | 22 | import org.xmlpull.v1.XmlPullParserException; 23 | 24 | /** 25 | * Created by yangjiang on 2017/04/07. 26 | * E-Mail:1007181167@qq.com 27 | * Description:[表情数据库操作帮助类] 28 | **/ 29 | public class EmoticonHandler { 30 | private static ArrayList mEmoticonBeans = new ArrayList<>(); 31 | private static EmoticonHandler sEmoticonHandler = null; 32 | private Context mContext; 33 | private EmoticonDBHelper emoticonDbHelper = null; 34 | 35 | public void release() { 36 | mEmoticonBeans.clear(); 37 | if (emoticonDbHelper != null) { 38 | emoticonDbHelper.cleanup(); 39 | } 40 | sEmoticonHandler=null; 41 | } 42 | 43 | public static EmoticonHandler getInstance(@NonNull Context context) { 44 | if (sEmoticonHandler == null) { 45 | sEmoticonHandler = new EmoticonHandler(context); 46 | } 47 | return sEmoticonHandler; 48 | } 49 | 50 | private EmoticonHandler(Context context) { 51 | mContext = context; 52 | emoticonDbHelper = new EmoticonDBHelper(context); 53 | } 54 | 55 | public EmoticonDBHelper getEmoticonDbHelper() { 56 | if (emoticonDbHelper == null) { 57 | emoticonDbHelper = new EmoticonDBHelper(mContext); 58 | } 59 | return emoticonDbHelper; 60 | } 61 | 62 | public ArrayList loadEmoticonsToMemory() { 63 | mEmoticonBeans = emoticonDbHelper.queryAllEmoticonBeans(); 64 | emoticonDbHelper.cleanup(); 65 | 66 | return mEmoticonBeans; 67 | } 68 | 69 | public String getEmoticonUriByTag(String tag) { 70 | return emoticonDbHelper.getUriByTag(tag); 71 | } 72 | 73 | public void setTextFace(String content, Spannable spannable, int start, int size) { 74 | if (mEmoticonBeans == null) { 75 | mEmoticonBeans = emoticonDbHelper.queryAllEmoticonBeans(); 76 | emoticonDbHelper.cleanup(); 77 | } 78 | if (content.length() <= 0) { 79 | return; 80 | } 81 | int keyIndex = start; 82 | for (EmoticonBean bean : mEmoticonBeans) { 83 | String key = bean.getTag(); 84 | int keyLength = key.length(); 85 | while (keyIndex >= 0) { 86 | keyIndex = content.indexOf(key, keyIndex); //when do not find, get -1 87 | if (keyIndex < 0) { 88 | break; 89 | } 90 | Drawable drawable = EmoticonLoader.getInstance(mContext).getDrawable(bean.getIconUri()); 91 | drawable.setBounds(0, 0, size, size); 92 | VerticalImageSpan imageSpan = new VerticalImageSpan(drawable); 93 | spannable.setSpan(imageSpan, keyIndex, keyIndex + keyLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 94 | keyIndex += keyLength; 95 | } 96 | keyIndex = start; 97 | } 98 | } 99 | public static boolean isEmoticonInitSuccess(Context context) { 100 | return Utils.isInitDb(context); 101 | } 102 | public static void initEmoticonsDB(final Context context, final boolean isShowEmoji, final List emoticonEntities) { 103 | new Thread(new Runnable() { 104 | @Override 105 | public void run() { 106 | EmoticonDBHelper emoticonDbHelper = EmoticonHandler.getInstance(context).getEmoticonDbHelper(); 107 | if (isShowEmoji) { 108 | ArrayList emojiArray = Utils.ParseData(DefEmoticons.emojiArray, EmoticonBean.FACE_TYPE_NORMAL, EmoticonBase.Scheme.DRAWABLE); 109 | EmoticonSetBean emojiEmoticonSetBean = new EmoticonSetBean("emoji", 3, 7); 110 | emojiEmoticonSetBean.setIconUri("drawable://icon_emoji"); 111 | emojiEmoticonSetBean.setItemPadding(25); 112 | emojiEmoticonSetBean.setVerticalSpacing(10); 113 | emojiEmoticonSetBean.setShowDelBtn(true); 114 | emojiEmoticonSetBean.setEmoticonList(emojiArray); 115 | emoticonDbHelper.insertEmoticonSet(emojiEmoticonSetBean); 116 | } 117 | 118 | List emoticonSetBeans = new ArrayList<>(); 119 | for (EmoticonEntity entity : emoticonEntities) { 120 | try { 121 | EmoticonSetBean bean = Utils.ParseEmoticons(context, entity.getPath(), entity.getScheme()); 122 | emoticonSetBeans.add(bean); 123 | } catch (IOException e) { 124 | e.printStackTrace(); 125 | HadLog.e(String.format("read %s config.xml error", entity.getPath())); 126 | } catch (XmlPullParserException e) { 127 | e.printStackTrace(); 128 | HadLog.e(String.format("parse %s config.xml error", entity.getPath())); 129 | } 130 | } 131 | 132 | for (EmoticonSetBean setBean : emoticonSetBeans) { 133 | emoticonDbHelper.insertEmoticonSet(setBean); 134 | } 135 | emoticonDbHelper.cleanup(); 136 | 137 | if (emoticonSetBeans.size() == emoticonEntities.size()) { 138 | Utils.setIsInitDb(context, true); 139 | } 140 | } 141 | }).start(); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/emoticon/util/EmoticonsKeyboardBuilder.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.emoticon.util; 2 | 3 | 4 | import java.util.ArrayList; 5 | 6 | import com.yang.keyboard.emoticon.EmoticonSetBean; 7 | /** 8 | * Created by yangjiang on 2017/04/07. 9 | * E-Mail:1007181167@qq.com 10 | * Description:[表情点击初始化] 11 | **/ 12 | public class EmoticonsKeyboardBuilder { 13 | 14 | public Builder builder; 15 | 16 | public EmoticonsKeyboardBuilder(Builder builder){ 17 | this.builder = builder; 18 | } 19 | 20 | public static class Builder { 21 | 22 | ArrayList mEmoticonSetBeanList = new ArrayList(); 23 | 24 | public Builder(){ } 25 | 26 | public ArrayList getEmoticonSetBeanList() { return mEmoticonSetBeanList; } 27 | 28 | public Builder setEmoticonSetBeanList(ArrayList mEmoticonSetBeanList) { this.mEmoticonSetBeanList = mEmoticonSetBeanList; return this;} 29 | 30 | public EmoticonsKeyboardBuilder build() { return new EmoticonsKeyboardBuilder(this); } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/media/MediaBean.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.media; 2 | 3 | 4 | /** 5 | * Created by yangc on 2017/3/7. 6 | * E-Mail:1007181167@qq.com 7 | * deprecated 自定义选择实体类 8 | **/ 9 | public class MediaBean { 10 | private int id; 11 | private int drawableId; 12 | private String text; 13 | private MediaListener mediaListener; 14 | 15 | public MediaBean(int id, int drawableId, String text, MediaListener mediaListener) { 16 | this.id = id; 17 | this.drawableId = drawableId; 18 | this.text = text; 19 | this.mediaListener = mediaListener; 20 | } 21 | 22 | public int getId() { 23 | return id; 24 | } 25 | 26 | public int getDrawableId() { 27 | return drawableId; 28 | } 29 | 30 | public String getText() { 31 | return text; 32 | } 33 | 34 | public MediaListener getMediaListener() { 35 | return mediaListener; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/media/MediaGridAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.media; 2 | 3 | import android.content.Context; 4 | import android.support.v4.content.ContextCompat; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.View.OnClickListener; 8 | import android.view.ViewGroup; 9 | import android.widget.BaseAdapter; 10 | import android.widget.TextView; 11 | 12 | import java.util.ArrayList; 13 | 14 | import com.yang.keyboard.R; 15 | 16 | /** 17 | * Created by yangc on 2017/3/7. 18 | * E-Mail:1007181167@qq.com 19 | *

20 | * deprecated 自定义选择 适配器 21 | **/ 22 | public class MediaGridAdapter extends BaseAdapter { 23 | private ArrayList mediaModels; 24 | Context mContext; 25 | int mSize = 0; 26 | 27 | /** 28 | * MediaGridAdapter 29 | * 30 | * @param context context 31 | * @param mediaModels data 32 | */ 33 | public MediaGridAdapter(Context context, ArrayList mediaModels, int size) { 34 | this.mContext = context; 35 | this.mediaModels = mediaModels; 36 | mSize = size; 37 | } 38 | 39 | public void resizeItem(int size) { 40 | mSize = size; 41 | } 42 | 43 | public View getView(final int position, View convertView, ViewGroup parent) { 44 | ViewHolder viewHolder; 45 | if (convertView == null) { 46 | LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 47 | convertView = inflater.inflate(R.layout.media_item, parent, false); 48 | viewHolder = new ViewHolder(convertView); 49 | convertView.setTag(viewHolder); 50 | } else { 51 | viewHolder = (ViewHolder) convertView.getTag(); 52 | } 53 | viewHolder.tvText.setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(mContext, getItem(position).getDrawableId()), null, null); 54 | viewHolder.tvText.setText(getItem(position).getText()); 55 | 56 | convertView.setOnClickListener(new OnClickListener() { 57 | @Override 58 | public void onClick(View v) { 59 | getItem(position).getMediaListener().onMediaClick(getItem(position).getId()); 60 | } 61 | }); 62 | 63 | return convertView; 64 | } 65 | 66 | static class ViewHolder { 67 | public TextView tvText; 68 | 69 | public ViewHolder(View view) { 70 | tvText = (TextView) view.findViewById(R.id.media_item_text); 71 | } 72 | } 73 | 74 | @Override 75 | public int getCount() { 76 | return mediaModels.size(); 77 | } 78 | 79 | @Override 80 | public MediaBean getItem(int position) { 81 | return mediaModels.get(position); 82 | } 83 | 84 | @Override 85 | public long getItemId(int position) { 86 | return position; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/media/MediaLayout.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.media; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.ViewPager; 5 | import android.util.AttributeSet; 6 | import android.view.LayoutInflater; 7 | import android.widget.RelativeLayout; 8 | 9 | import java.util.List; 10 | 11 | import com.yang.keyboard.R; 12 | import com.yang.keyboard.view.IndicatorView; 13 | 14 | 15 | /** 16 | * Created by yangjiang on 2017/04/07. 17 | * E-Mail:1007181167@qq.com 18 | * Description:[自定义选择的布局] 19 | **/ 20 | public class MediaLayout extends RelativeLayout implements ViewPager.OnPageChangeListener { 21 | ViewPager vpContent; 22 | IndicatorView ivIndicator; 23 | Context mContext; 24 | 25 | public MediaLayout(Context context) { 26 | super(context); 27 | mContext = context; 28 | init(); 29 | } 30 | 31 | public MediaLayout(Context context, AttributeSet attrs) { 32 | super(context, attrs); 33 | mContext = context; 34 | init(); 35 | } 36 | 37 | public MediaLayout(Context context, AttributeSet attrs, int defStyleAttr) { 38 | super(context, attrs, defStyleAttr); 39 | mContext = context; 40 | init(); 41 | } 42 | 43 | private void init() { 44 | inflate(mContext, R.layout.keyboard_bottom_media, this); 45 | vpContent = (ViewPager) findViewById(R.id.popup_media_pager); 46 | ivIndicator = (IndicatorView) findViewById(R.id.popup_media_indicator); 47 | vpContent.addOnPageChangeListener(this); //compatible for android 22 48 | } 49 | 50 | public void setContents(List mediaContents) { 51 | int size = getResources().getDimensionPixelSize(R.dimen.media_item_size); 52 | MediaPagerAdapter adapter = new MediaPagerAdapter(mContext, mediaContents, size); 53 | vpContent.setAdapter(adapter); 54 | ivIndicator.setIndicatorCount(adapter.getPageNum()); 55 | if (adapter.getPageNum()<2){ 56 | ivIndicator.setVisibility(GONE); 57 | }else{ 58 | ivIndicator.setVisibility(VISIBLE); 59 | } 60 | } 61 | 62 | @Override 63 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 64 | 65 | } 66 | 67 | @Override 68 | public void onPageSelected(int position) { 69 | ivIndicator.moveTo(position); 70 | } 71 | 72 | @Override 73 | public void onPageScrollStateChanged(int state) { 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/media/MediaListener.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.media; 2 | 3 | /** 4 | * Created by yangc on 2017/3/7. 5 | * E-Mail:1007181167@qq.com 6 | * Description: 自自定义选择 7 | */ 8 | 9 | public interface MediaListener { 10 | void onMediaClick(int id); 11 | } 12 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/media/MediaPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.media; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.PagerAdapter; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.GridView; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import com.yang.keyboard.R; 14 | 15 | /** 16 | * Created by yangjiang on 2017/04/07. 17 | * E-Mail:1007181167@qq.com 18 | * Description:[自定义选择分页适配器] 19 | **/ 20 | public class MediaPagerAdapter extends PagerAdapter { 21 | private static final int MAX_NUM_PER_PAGE = 8; 22 | private Context mContext; 23 | private List gridAdapterList = new ArrayList<>(); 24 | private int mPageNum = 0; 25 | private int mColumnWidth = 0; 26 | 27 | /** 28 | * @param context context 29 | * @param mediaModels 数据 30 | * @param columnWidth 列 31 | ***/ 32 | public MediaPagerAdapter(Context context, List mediaModels, int columnWidth) { 33 | mContext = context; 34 | mColumnWidth = columnWidth; 35 | mPageNum = (int) Math.ceil((float) mediaModels.size() / MAX_NUM_PER_PAGE); 36 | for (int i = 0; i < mPageNum; ++i) { 37 | ArrayList mediaItems = new ArrayList<>(); 38 | for (int j = i * MAX_NUM_PER_PAGE; j < (i + 1) * MAX_NUM_PER_PAGE && j < mediaModels.size(); ++j) { 39 | mediaItems.add(mediaModels.get(j)); 40 | } 41 | MediaGridAdapter adapter = new MediaGridAdapter(mContext, mediaItems, mColumnWidth); 42 | gridAdapterList.add(adapter); 43 | } 44 | } 45 | 46 | public int getPageNum() { 47 | return mPageNum; 48 | } 49 | 50 | @Override 51 | public int getCount() { 52 | return gridAdapterList.size(); 53 | } 54 | 55 | @Override 56 | public Object instantiateItem(ViewGroup container, int position) { 57 | LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 58 | View layout = inflater.inflate(R.layout.media_page, container, false); 59 | 60 | GridView grid = (GridView) layout.findViewById(R.id.media_grid); 61 | grid.setColumnWidth(mColumnWidth); 62 | grid.setAdapter(gridAdapterList.get(position)); 63 | 64 | container.addView(layout); 65 | 66 | return layout; 67 | } 68 | 69 | @Override 70 | public void notifyDataSetChanged() { 71 | super.notifyDataSetChanged(); 72 | for (MediaGridAdapter adapter : gridAdapterList) { 73 | adapter.notifyDataSetChanged(); 74 | } 75 | } 76 | 77 | @Override 78 | public void destroyItem(ViewGroup container, int position, Object object) { 79 | container.removeAllViews(); 80 | } 81 | 82 | @Override 83 | public boolean isViewFromObject(View view, Object object) { 84 | return view == object; 85 | } 86 | } -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/utils/EmoticonBase.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.utils; 2 | 3 | import java.util.Locale; 4 | 5 | /** 6 | * Created by yangjiang on 2017/04/07. 7 | * E-Mail:1007181167@qq.com 8 | * Description:[表情自定义加载接口] 9 | **/ 10 | public interface EmoticonBase { 11 | enum Scheme { 12 | HTTP("http"), 13 | HTTPS("https"), 14 | FILE("file"), 15 | CONTENT("content"), 16 | ASSETS("assets"), 17 | DRAWABLE("drawable"), 18 | UNKNOWN(""); 19 | 20 | private String scheme; 21 | private String uriPrefix; 22 | 23 | Scheme(String scheme) { 24 | this.scheme = scheme; 25 | uriPrefix = scheme + "://"; 26 | } 27 | 28 | public static Scheme ofUri(String uri) { 29 | if (uri != null) { 30 | for (Scheme s : values()) { 31 | if (s.belongsTo(uri)) { 32 | return s; 33 | } 34 | } 35 | } 36 | return UNKNOWN; 37 | } 38 | 39 | public String crop(String uri) { 40 | if (!belongsTo(uri)) { 41 | throw new IllegalArgumentException(String.format("URI [%1$s] doesn't have expected scheme [%2$s]", uri, scheme)); 42 | } 43 | return uri.substring(uriPrefix.length()); 44 | } 45 | 46 | public String toUri(String path){ 47 | return uriPrefix + path; 48 | } 49 | 50 | private boolean belongsTo(String uri) { 51 | return uri.toLowerCase(Locale.US).startsWith(uriPrefix); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/utils/EmoticonLoader.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.drawable.BitmapDrawable; 7 | import android.graphics.drawable.Drawable; 8 | 9 | import java.io.File; 10 | import java.io.FileInputStream; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | 14 | import com.yang.keyboard.emoticon.util.EmoticonHandler; 15 | 16 | /** 17 | * Created by yangjiang on 2017/04/07. 18 | * E-Mail:1007181167@qq.com 19 | * Description:[表情自定义加载类] 20 | **/ 21 | public class EmoticonLoader implements EmoticonBase { 22 | protected final Context mContext; 23 | private volatile static EmoticonLoader instance; 24 | private final static String emoticonConfigFileName = "config.xml"; 25 | 26 | public static EmoticonLoader getInstance(Context context) { 27 | if (instance == null) { 28 | synchronized (EmoticonLoader.class) { 29 | if (instance == null) { 30 | instance = new EmoticonLoader(context); 31 | } 32 | } 33 | } 34 | return instance; 35 | } 36 | 37 | public EmoticonLoader(Context context) { 38 | this.mContext = context.getApplicationContext(); 39 | } 40 | 41 | /** 42 | * get the config file stream in emoticon directory, name of config 43 | * is config.xml 44 | * @param path path of directory 45 | * @param scheme scheme 46 | * @return file input stream 47 | */ 48 | public InputStream getConfigStream( String path, Scheme scheme ) { 49 | switch ( scheme ) { 50 | case FILE: 51 | try { 52 | File file = new File(path + "/" + emoticonConfigFileName); 53 | if (file.exists()) { 54 | return new FileInputStream(file); 55 | } 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | } 59 | return null; 60 | case ASSETS: 61 | try { 62 | return mContext.getAssets().open(path + "/" + emoticonConfigFileName); 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | return null; 66 | } 67 | } 68 | return null; 69 | } 70 | 71 | /** 72 | * get input stream of emoticon 73 | * @param imageUri emoticon uri 74 | * @return input stream 75 | */ 76 | private InputStream getInputStream( String imageUri ) { 77 | switch (Scheme.ofUri(imageUri)) { 78 | case FILE: 79 | String filePath = Scheme.FILE.crop(imageUri); 80 | try { 81 | File file = new File(filePath); 82 | if (file.exists()) { 83 | return new FileInputStream(file); 84 | } 85 | } catch (IOException e) { 86 | e.printStackTrace(); 87 | } 88 | return null; 89 | case ASSETS: 90 | String assetsPath = Scheme.ASSETS.crop(imageUri); 91 | try { 92 | return mContext.getAssets().open(assetsPath); 93 | } catch (Exception e) { 94 | e.printStackTrace(); 95 | return null; 96 | } 97 | } 98 | return null; 99 | } 100 | 101 | public InputStream getInputStreamByTag( String tag ) { 102 | String uri = EmoticonHandler.getInstance(mContext).getEmoticonUriByTag(tag); 103 | return getInputStream(uri); 104 | } 105 | 106 | public Drawable getDrawableByTag( String tag ) { 107 | String uri = EmoticonHandler.getInstance(mContext).getEmoticonUriByTag(tag); 108 | return getDrawable(uri); 109 | } 110 | 111 | public Drawable getDrawable(String imageUri){ 112 | switch (Scheme.ofUri(imageUri)) { 113 | case FILE: 114 | String filePath = Scheme.FILE.crop(imageUri); 115 | Bitmap fileBitmap; 116 | try { 117 | fileBitmap = BitmapFactory.decodeFile(filePath); 118 | return new BitmapDrawable(mContext.getResources(), fileBitmap); 119 | } catch (Exception e) { 120 | e.printStackTrace(); 121 | } 122 | return null; 123 | case CONTENT: 124 | return null; 125 | case ASSETS: 126 | String assetsPath = Scheme.ASSETS.crop(imageUri); 127 | Bitmap assetsBitmap; 128 | try { 129 | assetsBitmap = BitmapFactory.decodeStream(mContext.getAssets().open(assetsPath)); 130 | return new BitmapDrawable(mContext.getResources(), assetsBitmap); 131 | } catch (IOException e) { 132 | e.printStackTrace(); 133 | } 134 | return null; 135 | case DRAWABLE: 136 | String drawableIdString = Scheme.DRAWABLE.crop(imageUri); 137 | int resID = mContext.getResources().getIdentifier(drawableIdString, "drawable", mContext.getPackageName()); 138 | return mContext.getResources().getDrawable((int) resID); 139 | case UNKNOWN: 140 | default: 141 | return null; 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.util.zip.ZipEntry; 8 | import java.util.zip.ZipInputStream; 9 | /** 10 | * Created by yangjiang on 2017/04/07. 11 | * E-Mail:1007181167@qq.com 12 | * Description:[文件帮类] 13 | **/ 14 | public class FileUtils { 15 | public static void unzip(InputStream is, String dir) throws IOException { 16 | File dest = new File(dir); 17 | if (!dest.exists()) { 18 | dest.mkdirs(); 19 | } 20 | 21 | if (!dest.isDirectory()) 22 | throw new IOException("Invalid Unzip destination " + dest); 23 | if (null == is) { 24 | throw new IOException("InputStream is null"); 25 | } 26 | 27 | ZipInputStream zip = new ZipInputStream(is); 28 | 29 | ZipEntry ze; 30 | while ((ze = zip.getNextEntry()) != null) { 31 | final String path = dest.getAbsolutePath() 32 | + File.separator + ze.getName(); 33 | 34 | String zeName = ze.getName(); 35 | char cTail = zeName.charAt(zeName.length() - 1); 36 | if (cTail == File.separatorChar) { 37 | File file = new File(path); 38 | if (!file.exists()) { 39 | if (!file.mkdirs()) { 40 | throw new IOException("Unable to create folder " + file); 41 | } 42 | } 43 | continue; 44 | } 45 | 46 | FileOutputStream fout = new FileOutputStream(path); 47 | byte[] bytes = new byte[1024]; 48 | int c; 49 | while ((c = zip.read(bytes)) != -1) { 50 | fout.write(bytes, 0, c); 51 | } 52 | zip.closeEntry(); 53 | fout.close(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/utils/HadLog.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.utils; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Created by yangc on 2017/3/7. 7 | * E-Mail:1007181167@qq.com 8 | * Description: LogUtil 9 | * 10 | */ 11 | public class HadLog { 12 | public static String LOG_TAG = "HadKeyboard"; 13 | public static boolean enableLog = true;//true:enable log display 14 | 15 | private static final int RETURN_NOLOG = 99; 16 | 17 | @SuppressWarnings("unused") 18 | public static int d(String msg) { 19 | return enableLog ? Log.d(LOG_TAG + ":", msg) : RETURN_NOLOG; 20 | } 21 | 22 | @SuppressWarnings("unused") 23 | public static int e(String msg) { 24 | return enableLog ? Log.e(LOG_TAG + ":", msg) : RETURN_NOLOG; 25 | } 26 | 27 | @SuppressWarnings("unused") 28 | public static int i(String msg) { 29 | return enableLog ? Log.i(LOG_TAG + ":", msg) : RETURN_NOLOG; 30 | } 31 | 32 | @SuppressWarnings("unused") 33 | public static int w(String msg) { 34 | return enableLog ? Log.w(LOG_TAG + ":", msg) : RETURN_NOLOG; 35 | } 36 | 37 | @SuppressWarnings("unused") 38 | public static int d(String tag, String msg) { 39 | return enableLog ? Log.d(LOG_TAG + ":", msg) : RETURN_NOLOG; 40 | } 41 | 42 | @SuppressWarnings("unused") 43 | public static int e(String tag, String msg) { 44 | return enableLog ? Log.e(LOG_TAG + ":", msg) : RETURN_NOLOG; 45 | } 46 | 47 | @SuppressWarnings("unused") 48 | public static int i(String tag, String msg) { 49 | return enableLog ? Log.i(LOG_TAG + ":", msg) : RETURN_NOLOG; 50 | } 51 | 52 | @SuppressWarnings("unused") 53 | public static int w(String tag, String msg) { 54 | return enableLog ? Log.w(LOG_TAG + ":", msg) : RETURN_NOLOG; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/utils/OnKeyBoardLister.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.utils; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * Created by yangc on 2017/3/7. 7 | * E-Mail:1007181167@qq.com 8 | * Description:自定义键盘统一回调 9 | */ 10 | 11 | public interface OnKeyBoardLister { 12 | /** 13 | * @param text 发送文本 14 | **/ 15 | void sendText(String text); 16 | 17 | /** 18 | * @param tag 表情tag 19 | * @param uri 大表情路径 20 | **/ 21 | void sendUserDefEmoticon(String tag, String uri); 22 | 23 | /** 24 | * @param path 语音路径 25 | * @param time 语音时长 26 | **/ 27 | void sendAudio(String path, int time); 28 | 29 | /** 30 | * @param ids 自定义选择id 31 | **/ 32 | void sendMedia(int ids); 33 | 34 | /** 35 | * @param view 点击事件 36 | **/ 37 | void clickAddBtn(View view); 38 | } 39 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.SharedPreferences; 6 | import android.graphics.Paint; 7 | import android.preference.PreferenceManager; 8 | import android.text.TextUtils; 9 | import android.util.DisplayMetrics; 10 | import android.util.Xml; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.view.WindowManager; 14 | 15 | import org.xmlpull.v1.XmlPullParser; 16 | import org.xmlpull.v1.XmlPullParserException; 17 | 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | import java.util.ArrayList; 21 | 22 | import com.yang.keyboard.emoticon.EmoticonBean; 23 | import com.yang.keyboard.emoticon.EmoticonSetBean; 24 | 25 | /** 26 | * Created by yangc on 2017/3/7. 27 | * E-Mail:1007181167@qq.com 28 | * 29 | * @deprecated 帮助类 30 | **/ 31 | public class Utils { 32 | 33 | private static final String EXTRA_ISINITDB = "ISINITDB"; 34 | private static final String EXTRA_DEF_KEYBOARDHEIGHT = "DEF_KEYBOARDHEIGHT"; 35 | private static int sDefKeyboardHeight = 0; 36 | 37 | public static boolean isInitDb(Context context) { 38 | final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); 39 | return settings.getBoolean(EXTRA_ISINITDB, false); 40 | } 41 | 42 | public static void setIsInitDb(Context context, boolean b) { 43 | final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); 44 | settings.edit().putBoolean(EXTRA_ISINITDB, b).apply(); 45 | } 46 | 47 | public static int getDefKeyboardHeight(Context context) { 48 | if (sDefKeyboardHeight == 0) { //evaluate keyboard height 49 | sDefKeyboardHeight = getDisplayHeightPixels(context) * 3 / 7; 50 | } 51 | final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); 52 | int height = settings.getInt(EXTRA_DEF_KEYBOARDHEIGHT, 0); 53 | if (height > 0 && sDefKeyboardHeight != height) { 54 | Utils.setDefKeyboardHeight(context, height); 55 | } 56 | return sDefKeyboardHeight; 57 | } 58 | 59 | public static void setDefKeyboardHeight(Context context, int height) { 60 | if (sDefKeyboardHeight != height) { 61 | final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); 62 | settings.edit().putInt(EXTRA_DEF_KEYBOARDHEIGHT, height).apply(); 63 | } 64 | Utils.sDefKeyboardHeight = height; 65 | } 66 | 67 | private static int DisplayWidthPixels = 0; 68 | private static int DisplayHeightPixels = 0; 69 | 70 | private static void getDisplayMetrics(Context context) { 71 | WindowManager wm = (WindowManager) context. 72 | getSystemService(Context.WINDOW_SERVICE); 73 | DisplayMetrics dm = new DisplayMetrics(); 74 | wm.getDefaultDisplay().getMetrics(dm); 75 | DisplayWidthPixels = dm.widthPixels; 76 | DisplayHeightPixels = dm.heightPixels; 77 | } 78 | 79 | public static int getDisplayHeightPixels(Context context) { 80 | if (context == null) { 81 | return -1; 82 | } 83 | if (DisplayHeightPixels == 0) { 84 | getDisplayMetrics(context); 85 | } 86 | return DisplayHeightPixels; 87 | } 88 | 89 | public static int getDisplayWidthPixels(Context context) { 90 | if (context == null) { 91 | return -1; 92 | } 93 | if (DisplayWidthPixels == 0) { 94 | getDisplayMetrics(context); 95 | } 96 | return DisplayWidthPixels; 97 | } 98 | 99 | public static int dip2px(Context context, float dipValue) { 100 | final float scale = context.getResources().getDisplayMetrics().density; 101 | return (int) (dipValue * scale + 0.5f); 102 | } 103 | 104 | public static int px2dip(Context context, float pxValue) { 105 | final float scale = context.getResources().getDisplayMetrics().density; 106 | return (int) (pxValue / scale + 0.5f); 107 | } 108 | 109 | public static View getRootView(Activity context) { 110 | return ((ViewGroup) context.findViewById(android.R.id.content)).getChildAt(0); 111 | } 112 | 113 | public static ArrayList ParseData(String[] arry, long eventType, EmoticonBase.Scheme scheme) { 114 | try { 115 | ArrayList emojis = new ArrayList<>(); 116 | for (int i = 0; i < arry.length; i++) { 117 | if (!TextUtils.isEmpty(arry[i])) { 118 | String temp = arry[i].trim(); 119 | String[] text = temp.split(","); 120 | if (text.length == 2) { 121 | String fileName; 122 | if (scheme == EmoticonBase.Scheme.DRAWABLE) { 123 | if (text[0].contains(".")) { 124 | fileName = scheme.toUri(text[0].substring(0, text[0].lastIndexOf("."))); 125 | } else { 126 | fileName = scheme.toUri(text[0]); 127 | } 128 | } else { 129 | fileName = scheme.toUri(text[0]); 130 | } 131 | String content = text[1]; 132 | EmoticonBean bean = new EmoticonBean(eventType, fileName, content, content); 133 | emojis.add(bean); 134 | } 135 | } 136 | } 137 | return emojis; 138 | } catch (Exception e) { 139 | e.printStackTrace(); 140 | } 141 | 142 | return null; 143 | } 144 | 145 | public static EmoticonSetBean ParseEmoticons(Context context, String path, EmoticonBase.Scheme scheme) throws IOException, XmlPullParserException { 146 | String arrayParentKey = "EmoticonBean"; 147 | EmoticonSetBean emoticonSetBean = new EmoticonSetBean(); 148 | ArrayList emoticonList = new ArrayList<>(); 149 | emoticonSetBean.setEmoticonList(emoticonList); 150 | EmoticonBean emoticonBeanTemp = null; 151 | 152 | EmoticonLoader emoticonLoader = EmoticonLoader.getInstance(context); 153 | InputStream inStream = emoticonLoader.getConfigStream(path, scheme); 154 | if (inStream == null) { 155 | throw new IOException("Read config.xml in emoticon directory failed"); 156 | } 157 | 158 | boolean isChildCheck = false; 159 | XmlPullParser pullParser = Xml.newPullParser(); 160 | pullParser.setInput(inStream, "UTF-8"); 161 | int event = pullParser.getEventType(); 162 | 163 | while (event != XmlPullParser.END_DOCUMENT) { 164 | if (event == XmlPullParser.START_TAG) { 165 | String sKeyName = pullParser.getName(); 166 | if (isChildCheck) { 167 | switch (sKeyName) { 168 | case "eventType": { 169 | String value = pullParser.nextText(); 170 | emoticonBeanTemp.setEventType(Integer.parseInt(value)); 171 | break; 172 | } 173 | case "iconUri": { 174 | String value = pullParser.nextText(); 175 | emoticonBeanTemp.setIconUri(scheme.toUri(path + "/" + value)); 176 | break; 177 | } 178 | case "msgUri": { 179 | String value = pullParser.nextText(); 180 | emoticonBeanTemp.setMsgUri(scheme.toUri(path + "/" + value)); 181 | break; 182 | } 183 | case "tag": { 184 | String value = pullParser.nextText(); 185 | emoticonBeanTemp.setTag(value); 186 | break; 187 | } 188 | case "name": { 189 | String value = pullParser.nextText(); 190 | emoticonBeanTemp.setName(value); 191 | break; 192 | } 193 | } 194 | } else { 195 | switch (sKeyName) { 196 | case "name": { 197 | String value = pullParser.nextText(); 198 | emoticonSetBean.setName(value); 199 | break; 200 | } 201 | case "line": { 202 | String value = pullParser.nextText(); 203 | emoticonSetBean.setLine(Integer.parseInt(value)); 204 | break; 205 | } 206 | case "row": { 207 | String value = pullParser.nextText(); 208 | emoticonSetBean.setRow(Integer.parseInt(value)); 209 | break; 210 | } 211 | case "iconUri": { 212 | String value = pullParser.nextText(); 213 | emoticonSetBean.setIconUri(scheme.toUri(path + "/" + value)); 214 | break; 215 | } 216 | case "isShowDelBtn": { 217 | String value = pullParser.nextText(); 218 | emoticonSetBean.setShowDelBtn(Integer.parseInt(value) == 1); 219 | break; 220 | } 221 | case "itemPadding": { 222 | String value = pullParser.nextText(); 223 | emoticonSetBean.setItemPadding(Integer.parseInt(value)); 224 | break; 225 | } 226 | case "horizontalSpacing": { 227 | String value = pullParser.nextText(); 228 | emoticonSetBean.setHorizontalSpacing(Integer.parseInt(value)); 229 | break; 230 | } 231 | case "verticalSpacing": { 232 | String value = pullParser.nextText(); 233 | emoticonSetBean.setVerticalSpacing(Integer.parseInt(value)); 234 | break; 235 | } 236 | case "isShowName": { 237 | String value = pullParser.nextText(); 238 | emoticonSetBean.setIsShownName(Integer.parseInt(value) == 1); 239 | break; 240 | } 241 | } 242 | } 243 | 244 | if (sKeyName.equals(arrayParentKey)) { 245 | isChildCheck = true; 246 | emoticonBeanTemp = new EmoticonBean(); 247 | } 248 | } else if (event == XmlPullParser.END_TAG) { 249 | String ekeyName = pullParser.getName(); 250 | if (isChildCheck && ekeyName.equals(arrayParentKey)) { 251 | isChildCheck = false; 252 | emoticonList.add(emoticonBeanTemp); 253 | } 254 | } 255 | event = pullParser.next(); 256 | } 257 | return emoticonSetBean; 258 | } 259 | 260 | public static int getFontSize(float textSize) { 261 | Paint paint = new Paint(); 262 | paint.setTextSize(textSize); 263 | Paint.FontMetrics fm = paint.getFontMetrics(); 264 | return (int) (Math.ceil(fm.bottom - fm.top) + 0.5); 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/view/AudioRecordButton.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.MotionEvent; 6 | import android.view.View; 7 | 8 | import com.yang.keyboard.ChatKeyboardLayout; 9 | import com.yang.keyboard.R; 10 | import com.yang.keyboard.utils.Utils; 11 | 12 | /** 13 | * Created by yangc on 2017/3/7. 14 | * E-Mail:1007181167@qq.com 15 | * Description: 自定义音语音a按钮 16 | */ 17 | 18 | public class AudioRecordButton extends android.support.v7.widget.AppCompatButton { 19 | 20 | 21 | public AudioRecordButton(Context context) { 22 | super(context); 23 | initView(); 24 | } 25 | 26 | public AudioRecordButton(Context context, AttributeSet attrs) { 27 | super(context, attrs); 28 | initView(); 29 | } 30 | 31 | public AudioRecordButton(Context context, AttributeSet attrs, int defStyleAttr) { 32 | super(context, attrs, defStyleAttr); 33 | initView(); 34 | } 35 | private OnRecordingTouchListener onRecordingTouchListener; 36 | /**** 37 | * 初始化 38 | * ****/ 39 | private void initView() { 40 | setOnTouchListener(new RecordingTouchListener()); 41 | } 42 | 43 | 44 | /**** 45 | * 动作操作 46 | * **/ 47 | private class RecordingTouchListener implements OnTouchListener { 48 | float startY; 49 | float endY; 50 | boolean isCanceled = false; 51 | private long currentTimeMillis;//记录按下时间 52 | 53 | @Override 54 | public boolean onTouch(View view, MotionEvent motionEvent) { 55 | if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { 56 | if (currentTimeMillis != 0 && System.currentTimeMillis() - currentTimeMillis < 1000) { 57 | if (onRecordingTouchListener != null) { 58 | onRecordingTouchListener.onRecordingAction(AudioRecordButton.this,ChatKeyboardLayout.RecordingAction.CANCELED); 59 | } 60 | setText(getResources().getString(R.string.recording_start)); 61 | setBackgroundResource(R.drawable.recording_n); 62 | return false; 63 | } 64 | currentTimeMillis = System.currentTimeMillis(); 65 | startY = motionEvent.getRawY(); 66 | setText(getResources().getString(R.string.recording_end)); 67 | setBackgroundResource(R.drawable.recording_p); 68 | if (onRecordingTouchListener != null) { 69 | onRecordingTouchListener.onRecordingAction(AudioRecordButton.this,ChatKeyboardLayout.RecordingAction.START); 70 | } 71 | } else if (motionEvent.getAction() == MotionEvent.ACTION_UP) { 72 | setText(getResources().getString(R.string.recording_start)); 73 | setBackgroundResource(R.drawable.recording_n); 74 | if (onRecordingTouchListener != null && !isCanceled) { 75 | onRecordingTouchListener.onRecordingAction(AudioRecordButton.this,ChatKeyboardLayout.RecordingAction.COMPLETE); 76 | } else if (onRecordingTouchListener != null) { 77 | onRecordingTouchListener.onRecordingAction(AudioRecordButton.this,ChatKeyboardLayout.RecordingAction.CANCELED); 78 | } 79 | } else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) { 80 | //todo the num can be set by up layer 81 | endY = motionEvent.getRawY(); 82 | if (startY - endY > Utils.dip2px(getContext(), 50)) { 83 | setText(getResources().getString(R.string.recording_cancel)); 84 | isCanceled = true; 85 | if (onRecordingTouchListener != null) { 86 | onRecordingTouchListener.onRecordingAction(AudioRecordButton.this,ChatKeyboardLayout.RecordingAction.WILLCANCEL); 87 | } 88 | } else { 89 | if (onRecordingTouchListener != null) { 90 | onRecordingTouchListener.onRecordingAction(AudioRecordButton.this,ChatKeyboardLayout.RecordingAction.RESTORE); 91 | } 92 | setText(getResources().getString(R.string.recording_end)); 93 | isCanceled = false; 94 | } 95 | } 96 | return false; 97 | } 98 | } 99 | 100 | 101 | /**** 102 | * 动作回调借口 103 | * **/ 104 | public interface OnRecordingTouchListener { 105 | void onRecordingAction(AudioRecordButton button,ChatKeyboardLayout.RecordingAction action); 106 | } 107 | 108 | public void setOnRecordingTouchListener(OnRecordingTouchListener onRecordingTouchListener) { 109 | this.onRecordingTouchListener = onRecordingTouchListener; 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/view/ChatTextView.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.view; 2 | 3 | import android.content.Context; 4 | import android.text.SpannableStringBuilder; 5 | import android.text.TextUtils; 6 | import android.util.AttributeSet; 7 | import android.widget.TextView; 8 | import com.yang.keyboard.emoticon.util.EmoticonHandler; 9 | import com.yang.keyboard.utils.Utils; 10 | 11 | 12 | /** 13 | * Created by yangjiang on 2017/04/07. 14 | * E-Mail:1007181167@qq.com 15 | * Description:[展示自定义表情TextView] 16 | **/ 17 | public class ChatTextView extends TextView{ 18 | Context mContext; 19 | 20 | public ChatTextView(Context context) { 21 | super(context); 22 | init(context); 23 | } 24 | 25 | public ChatTextView(Context context, AttributeSet attrs) { 26 | super(context, attrs); 27 | init(context); 28 | } 29 | 30 | public ChatTextView(Context context, AttributeSet attrs, int defStyleAttr) { 31 | super(context, attrs, defStyleAttr); 32 | init(context); 33 | } 34 | 35 | private void init(Context context) { 36 | mContext = context; 37 | setText(getText()); 38 | } 39 | 40 | @Override 41 | public void setText(CharSequence text, BufferType type) { 42 | if (!TextUtils.isEmpty(text)) { 43 | SpannableStringBuilder builder = new SpannableStringBuilder(text); 44 | EmoticonHandler.getInstance(mContext).setTextFace(text.toString(), builder, 0, Utils.getFontSize(getTextSize()) ); 45 | text = builder; 46 | } 47 | super.setText(text, type); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/view/HadEditText.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | 6 | 7 | import com.yang.keyboard.emoticon.util.EmoticonHandler; 8 | import com.yang.keyboard.utils.Utils; 9 | 10 | /** 11 | * Created by yangc on 2017/3/7. 12 | * E-Mail:1007181167@qq.com 13 | * Description: 自定义输入 14 | */ 15 | public class HadEditText extends android.support.v7.widget.AppCompatEditText { 16 | private Context mContext; 17 | private OnTextChangedInterface onTextChangedInterface; 18 | public HadEditText(Context context, AttributeSet attrs, int defStyle) { 19 | super(context, attrs, defStyle); 20 | mContext = context; 21 | } 22 | 23 | public HadEditText(Context context) { 24 | super(context); 25 | mContext = context; 26 | } 27 | 28 | public HadEditText(Context context, AttributeSet attrs) { 29 | super(context, attrs); 30 | mContext = context; 31 | } 32 | 33 | @Override 34 | protected void onTextChanged(CharSequence arg0, int start, int lengthBefore, int after) { 35 | super.onTextChanged(arg0, start, lengthBefore, after); 36 | if (onTextChangedInterface != null) { 37 | onTextChangedInterface.onTextChanged(arg0); 38 | } 39 | String content = arg0.subSequence(0, start + after).toString(); 40 | EmoticonHandler.getInstance(mContext).setTextFace(content, getText(), start, Utils.getFontSize(getTextSize())); 41 | } 42 | 43 | public interface OnTextChangedInterface { 44 | void onTextChanged(CharSequence argo); 45 | } 46 | 47 | 48 | 49 | public void setOnTextChangedInterface(OnTextChangedInterface i) { 50 | onTextChangedInterface = i; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/view/IndicatorView.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.view; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorSet; 5 | import android.animation.ObjectAnimator; 6 | import android.content.Context; 7 | import android.graphics.drawable.Drawable; 8 | import android.support.v4.content.ContextCompat; 9 | import android.util.AttributeSet; 10 | import android.widget.ImageView; 11 | import android.widget.LinearLayout; 12 | import java.util.ArrayList; 13 | import com.yang.keyboard.R; 14 | 15 | 16 | /** 17 | * Created by yangjiang on 2017/04/07. 18 | * E-Mail:1007181167@qq.com 19 | * Description:[表情小圆点指示器] 20 | **/ 21 | public class IndicatorView extends LinearLayout { 22 | 23 | private Context mContext; 24 | private ArrayList mImageViews = new ArrayList<>(); 25 | private Drawable bmpSelect; 26 | private Drawable bmpNormal; 27 | private int mMargin = 0; 28 | private AnimatorSet mPlayToAnimatorSet; 29 | private AnimatorSet mPlayByInAnimatorSet; 30 | private AnimatorSet mPlayByOutAnimatorSet; 31 | 32 | public IndicatorView(Context context, AttributeSet attrs) { 33 | super(context, attrs); 34 | this.mContext = context; 35 | this.setOrientation(HORIZONTAL); 36 | 37 | bmpSelect = ContextCompat.getDrawable(mContext, android.R.drawable.presence_online); 38 | bmpNormal = ContextCompat.getDrawable(mContext, android.R.drawable.presence_invisible); 39 | mMargin = getResources().getDimensionPixelSize(R.dimen.indicator_margin); 40 | } 41 | 42 | public void setIndicatorCount(int count) { 43 | mImageViews.clear(); 44 | this.removeAllViews(); 45 | for (int i = 0; i < count; i++) { 46 | LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 47 | layoutParams.setMargins(mMargin, 0, mMargin, 0); 48 | ImageView imageView = new ImageView(mContext); 49 | if (i == 0) { 50 | imageView.setImageDrawable(bmpSelect); 51 | this.addView(imageView, layoutParams); 52 | } else { 53 | imageView.setImageDrawable(bmpNormal); 54 | this.addView(imageView, layoutParams); 55 | } 56 | mImageViews.add(imageView); 57 | } 58 | } 59 | 60 | public void moveTo(int position) { 61 | for (ImageView iv : mImageViews) { 62 | iv.setImageDrawable(bmpNormal); 63 | } 64 | mImageViews.get(position).setImageDrawable(bmpSelect); 65 | final ImageView imageViewStrat = mImageViews.get(position); 66 | ObjectAnimator animIn1 = ObjectAnimator.ofFloat(imageViewStrat, "scaleX", 0.25f, 1.0f); 67 | ObjectAnimator animIn2 = ObjectAnimator.ofFloat(imageViewStrat, "scaleY", 0.25f, 1.0f); 68 | if (mPlayToAnimatorSet != null && mPlayToAnimatorSet.isRunning()) { 69 | mPlayToAnimatorSet.cancel(); 70 | mPlayToAnimatorSet = null; 71 | } 72 | mPlayToAnimatorSet = new AnimatorSet(); 73 | mPlayToAnimatorSet.play(animIn1).with(animIn2); 74 | mPlayToAnimatorSet.setDuration(100); 75 | mPlayToAnimatorSet.start(); 76 | } 77 | 78 | 79 | /** 80 | * @param startPosition 开始 81 | * @param nextPosition 下一个位置 82 | ***/ 83 | public void playBy(int startPosition, int nextPosition) { 84 | boolean isShowInAnimOnly = false; 85 | if (startPosition < 0 || nextPosition < 0 || nextPosition == startPosition) { 86 | startPosition = nextPosition = 0; 87 | } 88 | if (startPosition < 0) { 89 | isShowInAnimOnly = true; 90 | startPosition = nextPosition = 0; 91 | } 92 | final ImageView imageViewStrat = mImageViews.get(startPosition); 93 | final ImageView imageViewNext = mImageViews.get(nextPosition); 94 | ObjectAnimator anim1 = ObjectAnimator.ofFloat(imageViewStrat, "scaleX", 1.0f, 0.25f); 95 | ObjectAnimator anim2 = ObjectAnimator.ofFloat(imageViewStrat, "scaleY", 1.0f, 0.25f); 96 | if (mPlayByOutAnimatorSet != null && mPlayByOutAnimatorSet.isRunning()) { 97 | mPlayByOutAnimatorSet.cancel(); 98 | mPlayByOutAnimatorSet = null; 99 | } 100 | mPlayByOutAnimatorSet = new AnimatorSet(); 101 | mPlayByOutAnimatorSet.play(anim1).with(anim2); 102 | mPlayByOutAnimatorSet.setDuration(100); 103 | 104 | ObjectAnimator animIn1 = ObjectAnimator.ofFloat(imageViewNext, "scaleX", 0.25f, 1.0f); 105 | ObjectAnimator animIn2 = ObjectAnimator.ofFloat(imageViewNext, "scaleY", 0.25f, 1.0f); 106 | 107 | if (mPlayByInAnimatorSet != null && mPlayByInAnimatorSet.isRunning()) { 108 | mPlayByInAnimatorSet.cancel(); 109 | mPlayByInAnimatorSet = null; 110 | } 111 | mPlayByInAnimatorSet = new AnimatorSet(); 112 | mPlayByInAnimatorSet.play(animIn1).with(animIn2); 113 | mPlayByInAnimatorSet.setDuration(100); 114 | 115 | if (isShowInAnimOnly) { 116 | mPlayByInAnimatorSet.start(); 117 | return; 118 | } 119 | 120 | anim1.addListener(new Animator.AnimatorListener() { 121 | @Override 122 | public void onAnimationStart(Animator animation) { 123 | } 124 | 125 | @Override 126 | public void onAnimationEnd(Animator animation) { 127 | if (imageViewStrat!=null) { 128 | imageViewStrat.setImageDrawable(bmpNormal); 129 | ObjectAnimator animFil1l = ObjectAnimator.ofFloat(imageViewStrat, "scaleX", 1.0f); 130 | ObjectAnimator animFill2 = ObjectAnimator.ofFloat(imageViewStrat, "scaleY", 1.0f); 131 | AnimatorSet mFillAnimatorSet = new AnimatorSet(); 132 | mFillAnimatorSet.play(animFil1l).with(animFill2); 133 | mFillAnimatorSet.start(); 134 | imageViewNext.setImageDrawable(bmpSelect); 135 | mPlayByInAnimatorSet.start(); 136 | } 137 | } 138 | 139 | @Override 140 | public void onAnimationCancel(Animator animation) { 141 | } 142 | 143 | @Override 144 | public void onAnimationRepeat(Animator animation) { 145 | } 146 | }); 147 | mPlayByOutAnimatorSet.start(); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/view/RecordingLayout.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.widget.ImageView; 7 | import android.widget.LinearLayout; 8 | import android.widget.ProgressBar; 9 | import android.widget.RelativeLayout; 10 | import android.widget.TextView; 11 | 12 | import com.yang.keyboard.R; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * Created by yangjiang on 2017/04/07. 19 | * E-Mail:1007181167@qq.com 20 | * Description:[录音对话框布局] 21 | **/ 22 | public class RecordingLayout extends RelativeLayout { 23 | LinearLayout llRecordingStart; 24 | ImageView ivRecordingCancel; 25 | ImageView ivVoiceLevel; 26 | ProgressBar pbLoading; 27 | TextView tvNotify; 28 | int mCurrentVoiceLevel = 0; 29 | List levelActions = new ArrayList<>(); 30 | 31 | public RecordingLayout(Context context) { 32 | super(context); 33 | init(context); 34 | } 35 | 36 | public RecordingLayout(Context context, AttributeSet attrs) { 37 | super(context, attrs); 38 | init(context); 39 | } 40 | 41 | public RecordingLayout(Context context, AttributeSet attrs, int defStyleAttr) { 42 | super(context, attrs, defStyleAttr); 43 | init(context); 44 | } 45 | 46 | private void init(Context context) { 47 | LayoutInflater.from(context).inflate(R.layout.had_recording_view, this); 48 | llRecordingStart = (LinearLayout) findViewById(R.id.had_recording_start); 49 | ivRecordingCancel = (ImageView) findViewById(R.id.had_recording_cancel); 50 | pbLoading = (ProgressBar) findViewById(R.id.had_recording_loading); 51 | tvNotify = (TextView) findViewById(R.id.had_recording_notify); 52 | ivVoiceLevel = (ImageView) findViewById(R.id.had_recording_level); 53 | } 54 | 55 | public void hide() { 56 | setVisibility(GONE); 57 | } 58 | 59 | /** 60 | * show recording area 61 | * 62 | * @param state 0 for canceling state, other for recording state 63 | */ 64 | public void show(int state) { 65 | setVisibility(VISIBLE); 66 | if (state == 0) { 67 | pbLoading.setVisibility(GONE); 68 | llRecordingStart.setVisibility(GONE); 69 | ivRecordingCancel.setVisibility(VISIBLE); 70 | tvNotify.setText(getResources().getString(R.string.recording_cancel)); 71 | tvNotify.setBackgroundResource(R.drawable.recording_text_bg); 72 | } else if (state == 1) { 73 | pbLoading.setVisibility(GONE); 74 | llRecordingStart.setVisibility(VISIBLE); 75 | ivRecordingCancel.setVisibility(GONE); 76 | tvNotify.setText(getResources().getString(R.string.recording_cancel_notice)); 77 | tvNotify.setBackgroundResource(R.drawable.transparent_bg); 78 | } else { 79 | pbLoading.setVisibility(VISIBLE); 80 | llRecordingStart.setVisibility(GONE); 81 | ivRecordingCancel.setVisibility(GONE); 82 | tvNotify.setText(getResources().getString(R.string.recording_cancel_notice)); 83 | tvNotify.setBackgroundResource(R.drawable.transparent_bg); 84 | } 85 | } 86 | 87 | public void setVoiceLevel(int level) { 88 | //if set voice again, cancel actions already in queue 89 | if (level == mCurrentVoiceLevel) { 90 | return; 91 | } 92 | for (Runnable r : levelActions) { 93 | removeCallbacks(r); 94 | } 95 | levelActions.clear(); 96 | 97 | if (mCurrentVoiceLevel > level) { 98 | for (int i = mCurrentVoiceLevel; i >= level; --i) { 99 | levelActions.add(new LevelAction(i)); 100 | } 101 | } else { 102 | for (int i = mCurrentVoiceLevel; i <= level; ++i) { 103 | levelActions.add(new LevelAction(i)); 104 | } 105 | } 106 | for (int i = 0; i < levelActions.size(); ++i) { 107 | postDelayed(levelActions.get(i), 10 * (i + 1)); 108 | } 109 | } 110 | 111 | private class LevelAction implements Runnable { 112 | int level; 113 | 114 | public LevelAction(int level) { 115 | this.level = level; 116 | } 117 | 118 | @Override 119 | public void run() { 120 | ivVoiceLevel.setImageResource(chooseLevelDrawable(level)); 121 | mCurrentVoiceLevel = level; 122 | } 123 | } 124 | 125 | private int chooseLevelDrawable(int level) { 126 | switch (level) { 127 | case 0: 128 | return R.drawable.recording_level_1; 129 | case 1: 130 | return R.drawable.recording_level_2; 131 | case 2: 132 | return R.drawable.recording_level_3; 133 | case 3: 134 | return R.drawable.recording_level_4; 135 | case 4: 136 | return R.drawable.recording_level_5; 137 | case 5: 138 | return R.drawable.recording_level_6; 139 | default: 140 | return R.drawable.recording_level_7; 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/view/SoftHandleLayout.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.view; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.view.inputmethod.InputMethodManager; 9 | import android.widget.EditText; 10 | import android.widget.LinearLayout; 11 | import android.widget.RelativeLayout; 12 | 13 | import com.yang.keyboard.R; 14 | import com.yang.keyboard.utils.Utils; 15 | 16 | 17 | public class SoftHandleLayout extends SoftListenLayout { 18 | public static final int KEYBOARD_STATE_NONE = 100; // no pop 19 | public static final int KEYBOARD_STATE_FUNC = 101; // only media or emoticon pop 20 | public static final int KEYBOARD_STATE_BOTH = 102; // keyboard and media or emoticon pop together 21 | protected Context mContext; 22 | protected int mAutoHeightLayoutId; 23 | protected int mAutoViewHeight; 24 | protected View mAutoHeightLayoutView; 25 | protected int mKeyboardState = KEYBOARD_STATE_NONE; 26 | private boolean isAutoViewNeedHide = true; //if soft keyboard close by itself, close auto view too. if not, just close keyboard 27 | public SoftHandleLayout(Context context, AttributeSet attrs) { 28 | super(context, attrs); 29 | this.mContext = context; 30 | mAutoViewHeight = Utils.getDefKeyboardHeight(mContext); 31 | } 32 | 33 | @Override 34 | public void addView(View child, int index, ViewGroup.LayoutParams params) { 35 | int childSum = getChildCount(); 36 | if (childSum > 1) { 37 | throw new IllegalStateException("can host only one direct child"); 38 | } 39 | super.addView(child, index, params); 40 | 41 | if (childSum == 0) { 42 | mAutoHeightLayoutId = child.getId(); 43 | if (mAutoHeightLayoutId < 0) { 44 | child.setId(R.id.main_view_id); 45 | mAutoHeightLayoutId = R.id.main_view_id; 46 | } 47 | LayoutParams paramsChild = (LayoutParams) child.getLayoutParams(); 48 | paramsChild.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); 49 | child.setLayoutParams(paramsChild); 50 | } else if (childSum == 1) { 51 | LayoutParams paramsChild = (LayoutParams) child.getLayoutParams(); 52 | paramsChild.addRule(RelativeLayout.ABOVE, mAutoHeightLayoutId); 53 | child.setLayoutParams(paramsChild); 54 | } 55 | } 56 | 57 | public void setAutoHeightLayoutView(View view) { 58 | mAutoHeightLayoutView = view; 59 | } 60 | 61 | public void setAutoViewHeight(final int height) { 62 | if ( height == 0 ) { 63 | mAutoHeightLayoutView.setVisibility(GONE); 64 | } else { 65 | mAutoHeightLayoutView.setVisibility(VISIBLE); 66 | LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mAutoHeightLayoutView.getLayoutParams(); 67 | params.height = height; 68 | mAutoHeightLayoutView.setLayoutParams(params); 69 | } 70 | } 71 | 72 | protected void hideAutoView(){ 73 | this.post(new Runnable() { 74 | @Override 75 | public void run() { 76 | setAutoViewHeight(0); 77 | } 78 | }); 79 | mKeyboardState = KEYBOARD_STATE_NONE; 80 | } 81 | 82 | protected void showAutoView() { 83 | post(new Runnable() { 84 | @Override 85 | public void run() { 86 | setAutoViewHeight( mAutoViewHeight ); 87 | } 88 | }); 89 | isAutoViewNeedHide = true; 90 | mKeyboardState = KEYBOARD_STATE_FUNC; 91 | } 92 | 93 | @Override 94 | public void OnSoftKeyboardPop( int height ) { 95 | if ( height > 0 && height != mAutoViewHeight ) { 96 | mAutoViewHeight = height; 97 | Utils.setDefKeyboardHeight(mContext, mAutoViewHeight); 98 | } 99 | 100 | //if soft keyboard popped, auto view must be visible, soft keyboard covers it 101 | if ( mKeyboardState != KEYBOARD_STATE_BOTH ) { 102 | showAutoView(); 103 | } 104 | mKeyboardState = KEYBOARD_STATE_BOTH; 105 | } 106 | 107 | @Override 108 | public void OnSoftKeyboardClose() { 109 | mKeyboardState = mKeyboardState == KEYBOARD_STATE_BOTH ? KEYBOARD_STATE_FUNC : KEYBOARD_STATE_NONE; 110 | 111 | // if keyboard closed isn't by calling close, but by pressing back button or keyboard hide, hide auto view 112 | if ( isAutoViewNeedHide ) { 113 | hideAutoView(); 114 | } 115 | isAutoViewNeedHide = true; 116 | } 117 | 118 | /** 119 | * display soft keyboard 120 | * @param et 打开 121 | */ 122 | protected void openSoftKeyboard( EditText et ) { 123 | InputMethodManager inputManager = (InputMethodManager) et.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 124 | inputManager.showSoftInput(et, 0); 125 | } 126 | 127 | /** 128 | * close soft keyboard 129 | * @param et view 130 | */ 131 | protected void closeSoftKeyboard( EditText et ) { 132 | InputMethodManager inputMethodManager = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); 133 | if (inputMethodManager != null && ((Activity) mContext).getCurrentFocus() != null) { 134 | inputMethodManager.hideSoftInputFromWindow(et.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); 135 | } 136 | isAutoViewNeedHide = false; //only if you close keyboard by calling method, auto view don't need hide 137 | } 138 | } -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/view/SoftListenLayout.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.util.DisplayMetrics; 6 | import android.view.WindowManager; 7 | import android.widget.RelativeLayout; 8 | 9 | import java.util.ArrayList; 10 | 11 | public abstract class SoftListenLayout extends RelativeLayout { 12 | private int mMaxParentHeight = 0; 13 | private ArrayList heightList = new ArrayList<>(); 14 | private int mOldHeight = 0; 15 | private int mMinLayoutHeight = 0; 16 | private int mMaxNavBarHeight = 0; 17 | 18 | public SoftListenLayout(Context context, AttributeSet attrs) { 19 | super(context, attrs); 20 | WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 21 | DisplayMetrics metrics = new DisplayMetrics(); 22 | manager.getDefaultDisplay().getMetrics(metrics); 23 | mMinLayoutHeight = metrics.heightPixels * 2 / 3; //the height of layout is at least 2/3 of screen height 24 | mMaxNavBarHeight = metrics.heightPixels / 6; // max height of navigation bar is 1/6 of height 25 | } 26 | 27 | /** 28 | * when keyboard hide, three onMeasure will be called 29 | * onMeasure measureHeight = 1533 30 | onMeasure measureHeight = 725 31 | onLayout top = 0, bottom = 1533 32 | onMeasure measureHeight = 725 33 | onLayout top = 0, bottom = 725 34 | */ 35 | @Override 36 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 37 | int measureHeight = measureHeight(heightMeasureSpec); 38 | 39 | if ( mMaxParentHeight != 0 && Math.abs(measureHeight - mOldHeight) < mMaxNavBarHeight ) { //for some devices whose the bottom navigation bar can be hiden or shown 40 | mMaxParentHeight += (measureHeight - mOldHeight); 41 | } else if ( mMaxParentHeight == 0 || measureHeight > mMinLayoutHeight ) { //ignore keyboard shown making height shorter 42 | mMaxParentHeight = measureHeight; 43 | } 44 | 45 | heightList.add(measureHeight); 46 | 47 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 48 | int expandSpec = MeasureSpec.makeMeasureSpec(mMaxParentHeight, heightMode); 49 | super.onMeasure(widthMeasureSpec, expandSpec); 50 | 51 | mOldHeight = measureHeight; 52 | } 53 | 54 | @Override 55 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 56 | super.onLayout(changed, l, t, r, mMaxParentHeight); 57 | if ( heightList.size() >= 2 ) { //keyboard hide or show, onMeasure will be called twice 58 | int oldh = heightList.get(0); 59 | int newh = heightList.get(heightList.size() - 1); 60 | 61 | int dividerHeight = Math.abs( newh - oldh ); 62 | if ( dividerHeight > mMaxNavBarHeight ) { //means keyboard hide or show 63 | if ( newh < oldh ) { 64 | OnSoftKeyboardPop(dividerHeight); 65 | } else { 66 | OnSoftKeyboardClose(); 67 | } 68 | } 69 | 70 | heightList.clear(); 71 | } else { 72 | heightList.clear(); 73 | } 74 | } 75 | 76 | private int measureHeight(int pHeightMeasureSpec) { 77 | int result = 0; 78 | int heightMode = MeasureSpec.getMode(pHeightMeasureSpec); 79 | int heightSize = MeasureSpec.getSize(pHeightMeasureSpec); 80 | 81 | switch (heightMode) { 82 | case MeasureSpec.AT_MOST: 83 | case MeasureSpec.EXACTLY: 84 | result = heightSize; 85 | break; 86 | } 87 | return result; 88 | } 89 | 90 | abstract void OnSoftKeyboardPop(int height); 91 | abstract void OnSoftKeyboardClose(); 92 | } -------------------------------------------------------------------------------- /keyboard/src/main/java/com/yang/keyboard/view/VerticalImageSpan.java: -------------------------------------------------------------------------------- 1 | package com.yang.keyboard.view; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Paint; 5 | import android.graphics.Rect; 6 | import android.graphics.drawable.Drawable; 7 | import android.text.style.ImageSpan; 8 | 9 | public class VerticalImageSpan extends ImageSpan { 10 | 11 | public VerticalImageSpan(Drawable drawable) { 12 | super(drawable, ImageSpan.ALIGN_BOTTOM); 13 | } 14 | 15 | @Override 16 | public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { 17 | Drawable drawable = getDrawable(); 18 | Rect rect = drawable.getBounds(); 19 | if (fm != null) { 20 | Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt(); 21 | int fontHeight = fmPaint.bottom - fmPaint.top; 22 | int drHeight = rect.bottom - rect.top; 23 | 24 | int top = drHeight / 2 - fontHeight / 4; 25 | int bottom = drHeight / 2 + fontHeight / 4; 26 | 27 | fm.ascent = -bottom; 28 | fm.top = -bottom; 29 | fm.bottom = top; 30 | fm.descent = top; 31 | } 32 | return rect.right; 33 | } 34 | 35 | @Override 36 | public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { 37 | Drawable drawable = getDrawable(); 38 | canvas.save(); 39 | int transY = ((bottom - top) - drawable.getBounds().bottom) / 2 + top; 40 | canvas.translate(x, transY); 41 | drawable.draw(canvas); 42 | canvas.restore(); 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /keyboard/src/main/res/color/text_touch_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/cross_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/cross_icon.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/icon_face_nomal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/icon_face_nomal.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/icon_face_pop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/icon_face_pop.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/input_bg_gray.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/input_bg_gray.9.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/input_bg_green.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/input_bg_green.9.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/keyboard_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/keyboard_icon.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/recording_cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/recording_cancel.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/recording_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/recording_icon.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/recording_level_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/recording_level_1.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/recording_level_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/recording_level_2.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/recording_level_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/recording_level_3.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/recording_level_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/recording_level_4.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/recording_level_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/recording_level_5.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/recording_level_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/recording_level_6.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/recording_level_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/recording_level_7.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xhdpi/recording_mic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xhdpi/recording_mic.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable-xxhdpi/icon_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchaojiang/ChatKeyboard-master/f8359434687a8f443ec7716221a506ae7c29fc8a/keyboard/src/main/res/drawable-xxhdpi/icon_photo.png -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable/circle_button_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable/emoticon_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable/recording_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable/recording_n.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 17 | 18 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable/recording_p.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable/recording_text_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable/send_button_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /keyboard/src/main/res/drawable/transparent_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /keyboard/src/main/res/layout/emoticons_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 15 | 22 | -------------------------------------------------------------------------------- /keyboard/src/main/res/layout/emoticonstoolbar_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 19 | 20 | -------------------------------------------------------------------------------- /keyboard/src/main/res/layout/emoticonstoolbar_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /keyboard/src/main/res/layout/had_recording_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 16 | 21 | 22 | 28 | 34 | 43 | -------------------------------------------------------------------------------- /keyboard/src/main/res/layout/keyboard_bottom_emoticons.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | 18 | 19 | 23 | 24 | 32 | 33 | 34 | 41 | -------------------------------------------------------------------------------- /keyboard/src/main/res/layout/keyboard_bottom_media.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 13 | 21 | 22 | -------------------------------------------------------------------------------- /keyboard/src/main/res/layout/media_item.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | -------------------------------------------------------------------------------- /keyboard/src/main/res/layout/media_page.xml: -------------------------------------------------------------------------------- 1 | 10 | 17 | -------------------------------------------------------------------------------- /keyboard/src/main/res/layout/simple_fragment_keybord_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | 24 | -------------------------------------------------------------------------------- /keyboard/src/main/res/layout/view_keyboardbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 15 | 16 | 22 | 23 | 32 | 33 | 45 | 46 | 47 | 57 | 58 | 74 | 75 | 76 | 84 | 85 | 86 | 94 | 95 | 103 |