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 |
113 |
114 |
115 |
116 |
123 |
124 |
--------------------------------------------------------------------------------
/keyboard/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/keyboard/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 | #CFCFCF
5 |
6 | #D9D9D9
7 | @color/white
8 |
--------------------------------------------------------------------------------
/keyboard/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 5dp
6 | 35dp
7 | 0.6dp
8 | 0.6dp
9 | 50dp
10 |
--------------------------------------------------------------------------------
/keyboard/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/keyboard/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 发送
4 | 按住 说话
5 | 松开 结束
6 | 松开手指,取消发送
7 | 手指上滑,取消发送
8 |
--------------------------------------------------------------------------------
/keyboard/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
13 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':keyboard'
2 |
--------------------------------------------------------------------------------