Full Code of GoBelieveIO/im_android for AI

master 2fd8eff6b0c6 cached
384 files
876.1 KB
212.7k tokens
1502 symbols
1 requests
Download .txt
Showing preview only (994K chars total). Download the full file or copy to clipboard to get everything.
Repository: GoBelieveIO/im_android
Branch: master
Commit: 2fd8eff6b0c6
Files: 384
Total size: 876.1 KB

Directory structure:
gitextract_tzm_poya/

├── .gitignore
├── README.md
├── app/
│   ├── .gitignore
│   ├── AndroidManifest.xml
│   ├── build.gradle
│   ├── res/
│   │   ├── anim/
│   │   │   ├── fade_in.xml
│   │   │   ├── fade_out.xml
│   │   │   ├── head_in.xml
│   │   │   ├── head_out.xml
│   │   │   ├── hold.xml
│   │   │   ├── push_bottom_in.xml
│   │   │   ├── push_bottom_out.xml
│   │   │   ├── push_top_in.xml
│   │   │   ├── push_top_in2.xml
│   │   │   ├── push_top_out.xml
│   │   │   ├── push_top_out2.xml
│   │   │   ├── slide_in_from_left.xml
│   │   │   ├── slide_in_from_right.xml
│   │   │   ├── slide_out_to_left.xml
│   │   │   └── slide_out_to_right.xml
│   │   ├── drawable/
│   │   │   └── btn_login_selector.xml
│   │   ├── layout/
│   │   │   ├── activity_conversation.xml
│   │   │   ├── activity_login.xml
│   │   │   └── conversation_message.xml
│   │   └── values/
│   │       ├── colors.xml
│   │       ├── dimen_font.xml
│   │       ├── dimens.xml
│   │       ├── strings.xml
│   │       └── styles.xml
│   └── src/
│       └── io/
│           └── gobelieve/
│               └── im/
│                   └── demo/
│                       ├── BaseActivity.java
│                       ├── ConversationView.java
│                       ├── IMDemoApplication.java
│                       ├── LoginActivity.java
│                       ├── MessageListActivity.java
│                       └── model/
│                           ├── Conversation.java
│                           ├── ConversationDB.java
│                           ├── MessageDatabaseHelper.java
│                           └── SQLCreator.java
├── asynctcp/
│   ├── .gitignore
│   ├── build.gradle
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── beetle/
│       │               └── asynctcp/
│       │                   └── ApplicationTest.java
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── beetle/
│           │           ├── AsyncSSLTCP.java
│           │           ├── AsyncTCP.java
│           │           ├── AsyncTCPInterface.java
│           │           ├── AsyncTCPTest.java
│           │           ├── TCPConnectCallback.java
│           │           └── TCPReadCallback.java
│           └── res/
│               └── values/
│                   └── strings.xml
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── imkit/
│   ├── build.gradle
│   ├── libs/
│   │   ├── AMap_Location_V5.1.0_20200708.jar
│   │   ├── AMap_Search_V7.3.0_20200331.jar
│   │   └── Amap_2DMap_V6.0.0_20191106.jar
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── assets/
│           │   └── emoticon
│           ├── java/
│           │   └── com/
│           │       └── beetle/
│           │           └── bauhinia/
│           │               ├── ChatItemQuickAction.java
│           │               ├── CustomerMessageActivity.java
│           │               ├── GroupMessageActivity.java
│           │               ├── MessageActivity.java
│           │               ├── MessageAudioActivity.java
│           │               ├── MessageBaseActivity.java
│           │               ├── PeerMessageActivity.java
│           │               ├── activity/
│           │               │   ├── CameraActivity.java
│           │               │   ├── LocationPickerActivity.java
│           │               │   ├── MapActivity.java
│           │               │   ├── MessageFileActivity.java
│           │               │   ├── OverlayActivity.java
│           │               │   ├── PhotoActivity.java
│           │               │   ├── PlayerActivity.java
│           │               │   └── WebActivity.java
│           │               ├── api/
│           │               │   ├── IMHttpAPI.java
│           │               │   ├── body/
│           │               │   │   └── PostDeviceToken.java
│           │               │   └── types/
│           │               │       ├── Audio.java
│           │               │       ├── File.java
│           │               │       ├── Image.java
│           │               │       ├── Media.java
│           │               │       └── Supporter.java
│           │               ├── handler/
│           │               │   ├── CustomerMessageHandler.java
│           │               │   ├── GroupMessageHandler.java
│           │               │   ├── PeerMessageHandler.java
│           │               │   └── SyncKeyHandler.java
│           │               ├── outbox/
│           │               │   ├── CustomerOutbox.java
│           │               │   ├── GroupOutbox.java
│           │               │   ├── Outbox.java
│           │               │   ├── OutboxObserver.java
│           │               │   └── PeerOutbox.java
│           │               ├── tools/
│           │               │   ├── AudioRecorder.java
│           │               │   ├── AudioUtil.java
│           │               │   ├── BinAscii.java
│           │               │   ├── DeviceUtil.java
│           │               │   ├── FileCache.java
│           │               │   ├── FileDownloader.java
│           │               │   ├── ImageMIME.java
│           │               │   ├── MapUtil.java
│           │               │   ├── TimeUtil.java
│           │               │   └── VideoUtil.java
│           │               └── view/
│           │                   ├── InMessageView.java
│           │                   ├── MessageRowView.java
│           │                   ├── MiddleMessageView.java
│           │                   ├── OutMessageView.java
│           │                   └── TagView.java
│           └── res/
│               ├── anim/
│               │   ├── fade_in.xml
│               │   ├── fade_out.xml
│               │   ├── head_in.xml
│               │   ├── head_out.xml
│               │   ├── hold.xml
│               │   ├── push_bottom_in.xml
│               │   ├── push_bottom_out.xml
│               │   ├── push_top_in.xml
│               │   ├── push_top_in2.xml
│               │   ├── push_top_out.xml
│               │   ├── push_top_out2.xml
│               │   ├── slide_in_from_left.xml
│               │   ├── slide_in_from_right.xml
│               │   ├── slide_out_to_left.xml
│               │   └── slide_out_to_right.xml
│               ├── drawable/
│               │   ├── chat_send_btn.xml
│               │   ├── chatting_setmode_msg_btn.xml
│               │   ├── chatting_setmode_voice_btn.xml
│               │   ├── conversation_recording_round.xml
│               │   ├── ease_chat_file_selector.xml
│               │   ├── ease_chat_image_selector.xml
│               │   ├── ease_chat_location_selector.xml
│               │   ├── ease_chat_press_speak_btn.xml
│               │   ├── ease_chat_send_btn_selector.xml
│               │   ├── ease_chat_takepic_selector.xml
│               │   ├── ease_chat_video_call_selector.xml
│               │   ├── ease_chatting_setmode_keyboard_btn.xml
│               │   ├── ease_chatting_setmode_voice_btn.xml
│               │   ├── ease_edit_text_bg.xml
│               │   ├── ease_recording_text_hint_bg.xml
│               │   ├── ease_type_select_btn.xml
│               │   └── ic_back.xml
│               ├── layout/
│               │   ├── activity_camera.xml
│               │   ├── activity_file.xml
│               │   ├── activity_overlay.xml
│               │   ├── activity_photo.xml
│               │   ├── activity_player.xml
│               │   ├── activity_web.xml
│               │   ├── chat.xml
│               │   ├── chat_container_center.xml
│               │   ├── chat_container_left.xml
│               │   ├── chat_container_right.xml
│               │   ├── chat_location.xml
│               │   ├── conversation_recording_dialog.xml
│               │   └── location_picker.xml
│               ├── menu/
│               │   ├── chat.xml
│               │   ├── location_picker.xml
│               │   └── menu_photo.xml
│               ├── values/
│               │   ├── colors.xml
│               │   ├── dimens.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               ├── values-zh/
│               │   └── strings.xml
│               └── xml/
│                   └── file_paths.xml
├── imlib/
│   ├── build.gradle
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── beetle/
│           │           └── bauhinia/
│           │               ├── activity/
│           │               │   └── BaseActivity.java
│           │               ├── db/
│           │               │   ├── ConversationIterator.java
│           │               │   ├── CustomerMessageDB.java
│           │               │   ├── CustomerPeerMessageDB.java
│           │               │   ├── EPeerMessageDB.java
│           │               │   ├── GroupMessageDB.java
│           │               │   ├── ICustomerMessage.java
│           │               │   ├── IMessage.java
│           │               │   ├── IMessageDB.java
│           │               │   ├── MessageFlag.java
│           │               │   ├── MessageIterator.java
│           │               │   ├── PeerMessageDB.java
│           │               │   ├── SQLCustomerMessageDB.java
│           │               │   ├── SQLGroupMessageDB.java
│           │               │   ├── SQLPeerMessageDB.java
│           │               │   └── message/
│           │               │       ├── ACK.java
│           │               │       ├── Attachment.java
│           │               │       ├── Audio.java
│           │               │       ├── Classroom.java
│           │               │       ├── Conference.java
│           │               │       ├── File.java
│           │               │       ├── GroupNotification.java
│           │               │       ├── GroupVOIP.java
│           │               │       ├── Headline.java
│           │               │       ├── Image.java
│           │               │       ├── Link.java
│           │               │       ├── Location.java
│           │               │       ├── MessageContent.java
│           │               │       ├── Notification.java
│           │               │       ├── P2PSession.java
│           │               │       ├── Readed.java
│           │               │       ├── Revoke.java
│           │               │       ├── Secret.java
│           │               │       ├── Tag.java
│           │               │       ├── Text.java
│           │               │       ├── TimeBase.java
│           │               │       ├── Unknown.java
│           │               │       ├── VOIP.java
│           │               │       └── Video.java
│           │               ├── gallery/
│           │               │   ├── GalleryImage.java
│           │               │   ├── tool/
│           │               │   │   ├── Closeables.java
│           │               │   │   ├── DisplayUtils.java
│           │               │   │   ├── FileUtils.java
│           │               │   │   ├── ImageUtils.java
│           │               │   │   ├── Md5FileNameUtils.java
│           │               │   │   └── StorageUtils.java
│           │               │   ├── ui/
│           │               │   │   ├── GalleryAdapter.java
│           │               │   │   ├── GalleryGridAdapter.java
│           │               │   │   ├── GalleryGridUI.java
│           │               │   │   ├── GalleryUI.java
│           │               │   │   └── PhotoActionPopup.java
│           │               │   └── view/
│           │               │       └── ScrollViewPager.java
│           │               ├── toolbar/
│           │               │   ├── Contact.java
│           │               │   ├── EaseChatExtendMenu.java
│           │               │   ├── EaseChatInputMenu.java
│           │               │   ├── EaseChatPrimaryMenu.java
│           │               │   ├── EaseExpandRecylerView.java
│           │               │   └── emoticon/
│           │               │       ├── Emoticon.java
│           │               │       ├── EmoticonAdapter.java
│           │               │       ├── EmoticonManager.java
│           │               │       ├── EmoticonPanel.java
│           │               │       ├── EmoticonUtils.java
│           │               │       └── ViewPagerAdapter.java
│           │               ├── tools/
│           │               │   └── DisplayUtils.java
│           │               └── view/
│           │                   ├── MessageAudioView.java
│           │                   ├── MessageClassroomView.java
│           │                   ├── MessageContentView.java
│           │                   ├── MessageFileView.java
│           │                   ├── MessageImageView.java
│           │                   ├── MessageLinkView.java
│           │                   ├── MessageLocationView.java
│           │                   ├── MessageNotificationView.java
│           │                   ├── MessageTextView.java
│           │                   ├── MessageUnknownView.java
│           │                   ├── MessageVOIPView.java
│           │                   └── MessageVideoView.java
│           └── res/
│               ├── drawable/
│               │   ├── bg_indicator_dot.xml
│               │   ├── bg_indicator_dot_disable.xml
│               │   ├── bg_indicator_dot_enable.xml
│               │   ├── chatfrom_bg.xml
│               │   ├── chatto_bg.xml
│               │   ├── circle_audio.xml
│               │   ├── gallery_watch_more_picture_background.xml
│               │   └── rounded_corner.xml
│               ├── drawable-mdpi/
│               │   ├── voice_from_icon.xml
│               │   └── voice_to_icon.xml
│               ├── layout/
│               │   ├── chat_content_audio.xml
│               │   ├── chat_content_file.xml
│               │   ├── chat_content_image.xml
│               │   ├── chat_content_link.xml
│               │   ├── chat_content_location.xml
│               │   ├── chat_content_small_text.xml
│               │   ├── chat_content_text.xml
│               │   ├── chat_content_video.xml
│               │   ├── chat_content_voip.xml
│               │   ├── ease_chat_menu_item.xml
│               │   ├── ease_row_expression.xml
│               │   ├── ease_widget_chat_input_menu.xml
│               │   ├── ease_widget_chat_primary_menu.xml
│               │   ├── ease_widget_emojicon.xml
│               │   ├── emoticon_view.xml
│               │   ├── gallery_activity_gallery.xml
│               │   ├── gallery_activity_gallery_grid.xml
│               │   ├── gallery_activity_gallery_grid_item.xml
│               │   ├── gallery_select_dialog_item.xml
│               │   ├── item_emoticon.xml
│               │   └── item_emoticon_page.xml
│               ├── values/
│               │   ├── attrs.xml
│               │   ├── colors.xml
│               │   └── strings.xml
│               └── values-zh/
│                   └── strings.xml
├── imsdk/
│   ├── build.gradle
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── beetle/
│       │               └── im/
│       │                   └── ApplicationTest.java
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── beetle/
│           │           └── im/
│           │               ├── BytePacket.java
│           │               ├── CustomerMessage.java
│           │               ├── CustomerMessageHandler.java
│           │               ├── CustomerMessageObserver.java
│           │               ├── GroupMessageHandler.java
│           │               ├── GroupMessageObserver.java
│           │               ├── IMMessage.java
│           │               ├── IMService.java
│           │               ├── IMServiceObserver.java
│           │               ├── Message.java
│           │               ├── MessageACK.java
│           │               ├── PeerMessageHandler.java
│           │               ├── PeerMessageObserver.java
│           │               ├── RTMessage.java
│           │               ├── RTMessageObserver.java
│           │               ├── RoomMessage.java
│           │               ├── RoomMessageObserver.java
│           │               ├── SyncKeyHandler.java
│           │               ├── SystemMessageObserver.java
│           │               └── Timer.java
│           └── res/
│               └── values/
│                   └── strings.xml
├── push_demo/
│   ├── .gitignore
│   ├── AndroidManifest.xml
│   ├── build.gradle
│   ├── libs/
│   │   ├── HwPush_SDK_V2559.jar
│   │   ├── MiPush_SDK_Client_2_2_16.jar
│   │   ├── Xg_sdk_v2.38_20150405_2046.jar
│   │   ├── jg_filter_sdk_1.1.jar
│   │   ├── mid-sdk-2.10.jar
│   │   └── wup-1.0.0-SNAPSHOT.jar
│   ├── proguard-rules.txt
│   ├── res/
│   │   ├── anim/
│   │   │   ├── fade_in.xml
│   │   │   ├── fade_out.xml
│   │   │   ├── head_in.xml
│   │   │   ├── head_out.xml
│   │   │   ├── hold.xml
│   │   │   ├── push_bottom_in.xml
│   │   │   ├── push_bottom_out.xml
│   │   │   ├── push_top_in.xml
│   │   │   ├── push_top_in2.xml
│   │   │   ├── push_top_out.xml
│   │   │   ├── push_top_out2.xml
│   │   │   ├── slide_in_from_left.xml
│   │   │   ├── slide_in_from_right.xml
│   │   │   ├── slide_out_to_left.xml
│   │   │   └── slide_out_to_right.xml
│   │   ├── drawable/
│   │   │   ├── btn_login_selector.xml
│   │   │   └── hwpush_btn_checkbox_list_star.xml
│   │   ├── layout/
│   │   │   ├── activity_login.xml
│   │   │   ├── hwpush_buttons_layout.xml
│   │   │   ├── hwpush_collect_tip_dialog.xml
│   │   │   ├── hwpush_collection_item.xml
│   │   │   ├── hwpush_collection_listview.xml
│   │   │   ├── hwpush_icons_layout.xml
│   │   │   ├── hwpush_layout2.xml
│   │   │   ├── hwpush_layout4.xml
│   │   │   ├── hwpush_layout7.xml
│   │   │   ├── hwpush_layout8.xml
│   │   │   ├── hwpush_msg_show.xml
│   │   │   └── hwpush_titlebar.xml
│   │   ├── values/
│   │   │   ├── colors.xml
│   │   │   ├── dimen_font.xml
│   │   │   ├── dimens.xml
│   │   │   ├── hwpush_colors.xml
│   │   │   ├── hwpush_strings.xml
│   │   │   ├── hwpush_styles.xml
│   │   │   ├── strings.xml
│   │   │   └── styles.xml
│   │   ├── values-w820dp/
│   │   │   └── dimens.xml
│   │   └── values-zh-rCN/
│   │       └── hwpush_strings.xml
│   └── src/
│       └── io/
│           └── gobelieve/
│               └── im/
│                   └── demo/
│                       ├── BaseActivity.java
│                       ├── HuaweiPushReceiver.java
│                       ├── LoginActivity.java
│                       ├── PushDemoApplication.java
│                       ├── XGMessageReceiver.java
│                       └── XiaomiPushReceiver.java
├── room_demo/
│   ├── .gitignore
│   ├── AndroidManifest.xml
│   ├── build.gradle
│   ├── res/
│   │   ├── anim/
│   │   │   ├── fade_in.xml
│   │   │   ├── fade_out.xml
│   │   │   ├── head_in.xml
│   │   │   ├── head_out.xml
│   │   │   ├── hold.xml
│   │   │   ├── push_bottom_in.xml
│   │   │   ├── push_bottom_out.xml
│   │   │   ├── push_top_in.xml
│   │   │   ├── push_top_in2.xml
│   │   │   ├── push_top_out.xml
│   │   │   ├── push_top_out2.xml
│   │   │   ├── slide_in_from_left.xml
│   │   │   ├── slide_in_from_right.xml
│   │   │   ├── slide_out_to_left.xml
│   │   │   └── slide_out_to_right.xml
│   │   ├── drawable/
│   │   │   └── btn_login_selector.xml
│   │   ├── layout/
│   │   │   ├── activity_login.xml
│   │   │   └── activity_room.xml
│   │   ├── values/
│   │   │   ├── colors.xml
│   │   │   ├── dimen_font.xml
│   │   │   ├── dimens.xml
│   │   │   ├── strings.xml
│   │   │   └── styles.xml
│   │   └── values-w820dp/
│   │       └── dimens.xml
│   └── src/
│       └── io/
│           └── gobelieve/
│               └── im/
│                   └── demo/
│                       ├── IMDemoApplication.java
│                       ├── LoginActivity.java
│                       └── RoomActivity.java
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_Store
.idea



# built application files
*.apk
*.ap_
 
# files for the dex VM
*.dex
 
# Java class files
*.class
 
# generated files
bin/
gen/
out/
build/
 
# Local configuration file (sdk path, etc)
local.properties
 
# Eclipse project files
.classpath
.project
 
# Proguard folder generated by Eclipse
proguard/
 
# Intellij project files
*.iws
.idea/
*.iml
 
# Gradle directory
build/
.gradle/


# Maven directory
target
 
# OS
.DS_Store
*~

proguard-rules.pro

================================================
FILE: README.md
================================================
GoBelieve Android SDK
-------------------

##demo各模块说明
app, group_demo, customer_service_demo是application模块
asynctcp, imsdk, imkit是library模块

1. app模块测试点对点消息
    app模块可以输入自己和对方的uid(整型),就可以直接和对方聊天.
    app模块如果只输入自己的uid,那么会进入会话列表界面
3. group_demo模块测试群组消息
    group_demo模块可以输入自己的uid和群组的id(整型),就可以直接测试群组消息
5. customer_service_demo测试客服消息
    customer_service_demo模块是以客服人员的身份登录,并接受用户发来的客服消息

##应用集成到客户端
1. import asynctcp, imsdk, imkit模块到自己的app工程
2. 在Application的onCreate初始化

        String androidID = Settings.Secure.getString(this.getContentResolver(),
                Settings.Secure.ANDROID_ID);

        //设置设备唯一标识,用于多点登录时设备校验
        IMService.getInstance().setDeviceID(androidID);

        //监听网路状态变更
        IMService.getInstance().registerConnectivityChangeReceiver(getApplicationContext());

        mIMService.setPeerMessageHandler(PeerMessageHandler.getInstance());
        mIMService.setGroupMessageHandler(GroupMessageHandler.getInstance());
        mIMService.setCustomerMessageHandler(CustomerMessageHandler.getInstance());

3. 登录成功后设置uid,token

        IMService.getInstance().setToken(token);
        PeerMessageHandler.getInstance().setUID(uid);
        GroupMessageHandler.getInstance().setUID(uid);

        SyncKeyHandler handler = new SyncKeyHandler(this.getApplicationContext(), String.format("sync_key_%d", uid));
        handler.load();
        IMService.getInstance().setSyncKeyHandler(handler);

4. 打开消息db, 数据库表结构参照demo中的MessageDatabaseHelper源代码

        File p = this.getDir("db", MODE_PRIVATE);
        File f = new File(p, String.format("gobelieve_%d.db", uid));
        String path = f.getPath();
        MessageDatabaseHelper dh = MessageDatabaseHelper.getInstance();
        dh.open(this.getApplicationContext(), path);
        SQLiteDatabase db = dh.getDatabase();
        PeerMessageDB.getInstance().setDb(db);
        EPeerMessageDB.getInstance().setDb(db);
        GroupMessageDB.getInstance().setDb(db);
        CustomerMessageDB.getInstance().setDb(db);

5. 启动IMService接受消息

        IMService.getInstance().start();

6. 添加消息observer,处理相应类型的消息

        //连接状态
        IMService.getInstance().addObserver(ob);

        //点对点消息
        IMService.getInstance().addPeerObserver(ob);
        //群组消息
        IMService.getInstance().addGroupObserver(ob);
        //直播的聊天室消息
        IMService.getInstance().addRoomObserver(ob);
        //实时消息,用于voip的信令
        IMService.getInstance().addRTObserver(ob);
        //系统消息
        IMService.getInstance().addSystemObserver(ob);    

7. 应用进入后台,断开socket链接

        IMService.getInstance().enterBackground();

8. 应用返回前台,重现链接socket
 
        IMService.getInstance().enterForeground();

9.  发送点对点消息

        Intent intent = new Intent(this, PeerMessageActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra("peer_uid", peer_uid);
        intent.putExtra("peer_name", "");
        intent.putExtra("current_uid", uid);
        startActivity(intent);

10. 发送群组消息

        Intent intent = new Intent(this, GroupMessageActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra("group_id", groupId);
        intent.putExtra("group_name", "");
        intent.putExtra("current_uid", uid);
        startActivity(intent);

11. 用户注销

        IMService.getInstance().stop()

================================================
FILE: app/.gitignore
================================================
/build


================================================
FILE: app/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest
    package="io.gobelieve.im.demo"
    xmlns:android="http://schemas.android.com/apk/res/android">


    <uses-permission android:name="android.permission.FLASHLIGHT" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />


    <!--高德地图所需权限-->
    <!--用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
    <!--用于访问GPS定位-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
    <!--获取运营商信息,用于支持提供运营商信息相关的接口-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
    <!--用于访问wifi网络信息,wifi信息会用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
    <!--这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
    <!--用于访问网络,网络定位需要上网-->
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <!--用于读取手机当前的状态-->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
    <!--写入扩展存储,向扩展卡写入数据,用于写入缓存定位数据-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.CAMERA" />




    <application
        android:name=".IMDemoApplication"
        android:usesCleartextTraffic="true"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name">


        <activity
            android:name=".LoginActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/Horizontal_Slide">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            android:name=".MessageListActivity"
            android:exported="true"
            android:windowSoftInputMode="adjustResize"
            android:theme="@style/imkit.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
            </intent-filter>
        </activity>

        <!--高德地图配置-->
        <meta-data
            android:name="com.amap.api.v2.apikey"
            android:value="fe4ad96eb93239914540892d3dfb76f7" />

        <!-- 必需: 应用ID -->
        <meta-data
            android:name="GOBELIEVE_APPID"
            android:value="7" />

        <!-- 必需: 应用KEY -->
        <meta-data
            android:name="GOBELIEVE_APPKEY"
            android:value="sVDIlIiDUm7tWPYWhi6kfNbrqui3ez44" />


        <activity
            android:name="com.beetle.bauhinia.PeerMessageActivity"
            android:exported="true"
            android:windowSoftInputMode="adjustResize|stateHidden"
            android:theme="@style/imkit.ActionBar">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
            </intent-filter>
        </activity>



        <activity
            android:name="com.beetle.bauhinia.GroupMessageActivity"
            android:exported="true"
            android:windowSoftInputMode="adjustResize|stateHidden"
            android:theme="@style/imkit.ActionBar">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
            </intent-filter>
        </activity>

        <activity
            android:name="com.beetle.bauhinia.CustomerMessageActivity"
            android:exported="true"
            android:windowSoftInputMode="adjustResize|stateHidden"
            android:theme="@style/imkit.ActionBar">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
            </intent-filter>
        </activity>

        <activity
            android:name="com.beetle.bauhinia.activity.PhotoActivity"
            android:label="照片"
            android:theme="@style/imkit.ActionBar">
        </activity>

        <activity
            android:name="com.beetle.bauhinia.activity.MapActivity"
            android:label="位置"
            android:theme="@style/imkit.ActionBar">
        </activity>
        <activity
            android:name="com.beetle.bauhinia.activity.LocationPickerActivity"
            android:label="位置"
            android:theme="@style/imkit.ActionBar">
        </activity>

        <activity android:name="com.beetle.bauhinia.activity.CameraActivity"
            android:theme="@style/imkit.NoActionBar"/>

        <activity
            android:name="com.beetle.bauhinia.activity.WebActivity"
            android:label=""
            android:theme="@style/imkit.ActionBar">
        </activity>

        <activity
            android:name="com.beetle.bauhinia.gallery.ui.GalleryGridUI"
            android:label="@string/gallery_chat_files"
            android:launchMode="singleTop"
            android:screenOrientation="portrait"
            android:theme="@style/imkit.ActionBar">
        </activity>

        <activity
            android:name="com.beetle.bauhinia.gallery.ui.GalleryUI"
            android:launchMode="singleTop"
            android:screenOrientation="portrait"
            android:theme="@style/imkit.NoActionBar">
        </activity>


        <activity android:name="com.beetle.bauhinia.activity.OverlayActivity"
            android:theme="@style/imkit.NoActionBar">
        </activity>

        <activity android:name="com.beetle.bauhinia.activity.MessageFileActivity"
            android:label="文件预览"
            android:theme="@style/imkit.ActionBar">
        </activity>
        <activity android:name="com.beetle.bauhinia.activity.PlayerActivity"
            android:theme="@style/imkit.NoActionBar">
        </activity>


        <!-- authorities 当前包名+'.fileprovider' -->
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="io.gobelieve.im.demo.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

    </application>

</manifest>


================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion

    defaultConfig {
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1020
        versionName "1.0.2"
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            res.srcDirs = ['res']
            aidl.srcDirs = ['src']
            jniLibs.srcDirs = ['libs']
            assets.srcDirs = ['src/main/assets', 'assets/']
        }
    }

    buildTypes {
        release {

            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    packagingOptions {
        exclude 'META-INF/DEPENDENCIES.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/dependencies.txt'
        exclude 'META-INF/LGPL2.1'
    }

    lintOptions {
        checkReleaseBuilds false
        abortOnError false
    }
}


dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation project(':imkit')
    implementation project(':imlib')
    implementation project(':imsdk')
    implementation project(':asynctcp')

    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'androidx.appcompat:appcompat:1.0.0'
    implementation 'com.netflix.rxjava:rxjava-core:0.20.7'
    implementation 'com.netflix.rxjava:rxjava-android:0.20.7'
    implementation 'com.squareup.picasso:picasso:2.71828'
}





================================================
FILE: app/res/anim/fade_in.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:fromAlpha="0.0" android:toAlpha="1.0"
    android:duration="300" />

================================================
FILE: app/res/anim/fade_out.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:fromAlpha="1.0" android:toAlpha="0.0"
    android:duration="300" />

================================================
FILE: app/res/anim/head_in.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- 左上角扩大-->
  <scale   xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"  
        android:fromXScale="0.001"   
        android:toXScale="1.0"   
        android:fromYScale="0.001"   
        android:toYScale="1.0"   
        android:pivotX="15%"  
        android:pivotY="25%"  
        android:duration="200" />  
   

================================================
FILE: app/res/anim/head_out.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- 左上角缩小 -->
  <scale   xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"  
        android:fromXScale="1.0"   
        android:toXScale="0.001"   
        android:fromYScale="1.0"   
        android:toYScale="0.001"   
        android:pivotX="15%"  
        android:pivotY="25%"  
        android:duration="200" />  
   

================================================
FILE: app/res/anim/hold.xml
================================================
<?xml version="1.0" encoding="utf-8"?> 
<translate xmlns:android="http://schemas.android.com/apk/res/android"
       android:interpolator="@android:anim/accelerate_interpolator"
       android:fromXDelta="0" android:toXDelta="0"
       android:duration="300" />

================================================
FILE: app/res/anim/push_bottom_in.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- 上下滑入式 -->
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromYDelta="50%p"
        android:toYDelta="0" />

</set>

================================================
FILE: app/res/anim/push_bottom_out.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- 上下滑入式 -->
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    
    <translate
        android:duration="200"
        android:fromYDelta="0"
        android:toYDelta="50%p" />

    

</set>

================================================
FILE: app/res/anim/push_top_in.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- 上下滑入式 -->
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromYDelta="-50%p"
        android:toYDelta="0" />   
</set>

================================================
FILE: app/res/anim/push_top_in2.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- 上下滑入式 -->
<scale   xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"  
        android:fromXScale="1.0"   
        android:toXScale="1.0"   
        android:fromYScale="0"   
        android:toYScale="1.0"   
        android:pivotX="0"  
        android:pivotY="10%"  
        android:duration="200" /> 

================================================
FILE: app/res/anim/push_top_out.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!-- 上下滑入式 -->
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromYDelta="0"
        android:toYDelta="-50%p" />   
</set>

================================================
FILE: app/res/anim/push_top_out2.xml
================================================
<?xml version="1.0" encoding="utf-8"?>

<scale   xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"  
        android:fromXScale="1.0"   
        android:toXScale="1.0"   
        android:fromYScale="1.0"   
        android:toYScale="0"   
        android:pivotX="0"  
        android:pivotY="10%"  
        android:duration="200" /> 

================================================
FILE: app/res/anim/slide_in_from_left.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromXDelta="-100%p"
        android:toXDelta="0" />

</set>

================================================
FILE: app/res/anim/slide_in_from_right.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromXDelta="100%p"
        android:toXDelta="0" />

</set>

================================================
FILE: app/res/anim/slide_out_to_left.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromXDelta="0"
        android:toXDelta="-100%p" />

</set>

================================================
FILE: app/res/anim/slide_out_to_right.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromXDelta="0"
        android:toXDelta="100%p" />

</set>

================================================
FILE: app/res/drawable/btn_login_selector.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/btn_login_pressed" android:state_pressed="true" />
    <item android:drawable="@drawable/btn_login_normal" />


</selector>


================================================
FILE: app/res/layout/activity_conversation.xml
================================================
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/support_toolbar"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:layout_gravity="left"
        android:background="@color/theme_primary"
        />

    <ListView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="0dip"
            android:layout_weight="1" >
    </ListView>
</LinearLayout>

================================================
FILE: app/res/layout/activity_login.xml
================================================
<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg_background">

    <!--发送用户id-->
    <View
        android:id="@+id/line_sender_underline"
        style="@style/login_edittext_underline"
        android:layout_marginTop="248dp" />

    <ImageView
        android:id="@+id/iv_sender"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@id/line_sender_underline"
        android:layout_alignBottom="@id/line_sender_underline"
        android:layout_marginBottom="9dp"
        android:layout_marginLeft="22dp"
        android:src="@drawable/ic_account" />

    <EditText
        android:id="@+id/et_username"
        style="@style/login_edittext"
        android:layout_above="@id/line_sender_underline"
        android:layout_alignBottom="@id/line_sender_underline"
        android:layout_toRightOf="@id/iv_sender"
        android:hint="@string/login_account" />

    <!--接收用户id-->

    <View
        android:id="@+id/line_receiver_underline"
        style="@style/login_edittext_underline"
        android:layout_below="@id/line_sender_underline"
        android:layout_marginTop="44dp" />


    <ImageView
        android:id="@+id/iv_receiver"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@id/line_receiver_underline"
        android:layout_marginBottom="9dp"
        android:layout_marginLeft="22dp"
        android:src="@drawable/ic_account" />

    <EditText
        android:id="@+id/et_target_username"
        style="@style/login_edittext"
        android:layout_alignBottom="@id/line_receiver_underline"
        android:layout_toRightOf="@id/iv_receiver"
        android:hint="@string/login_target_account" />

    <Button
        android:id="@+id/btn_login"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/line_receiver_underline"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginTop="45dp"
        android:background="@drawable/btn_login_selector"
        android:text="@string/login_login"
        android:textColor="@android:color/white"
        android:textSize="@dimen/h2" />


</RelativeLayout>


================================================
FILE: app/res/layout/conversation_message.xml
================================================
<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:paddingLeft="8dp"
    android:paddingRight="8dp">


    <FrameLayout
        android:layout_width="64dp"
        android:layout_height="64dp">

        <ImageView
            android:id="@+id/header"
            android:layout_width="56dp"
            android:layout_height="56dp"
            android:layout_gravity="center"
            android:src="@drawable/avatar_contact" />

        <TextView
            android:id="@+id/unReadCount"
            style="@style/DemoMainNewMassage"
            android:layout_gravity="top|right" />
    </FrameLayout>



    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:orientation="vertical">


        <TextView
            android:id="@+id/name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:textIsSelectable="false"
            android:textSize="16dp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:textIsSelectable="false" />

    </LinearLayout>
</LinearLayout>




================================================
FILE: app/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="common_bg">#fcfcfc</color>
    <color name="common_header_blue">#00abf1</color>
    <color name="view_focused">#11000000</color>
    <color name="view_pressed">@color/view_focused</color>
    <color name="btn_login_normal">#2dafa3</color>
    <color name="btn_login_pressed">@color/common_header_blue</color>
    <color name="btn_gray_normal">#c0c0c0</color>
    <color name="bottom_bar_normal_bg">#2D2F31</color>
    <color name="common_botton_bar_blue">#2ea7e0</color>
    <color name="common_bottom_bar_normal_bg">#2d2f31</color>
    <color name="common_bottom_bar_selected_bg">#161718</color>
    <color name="divider_list">#cccccc</color>
    <color name="blue_337aba">#337aba</color>
    <color name="setting_item_pressed">@color/btn_login_pressed</color>
    <color name="setting_divider">#e6e6e6</color>
    <color name="gray_33">#333333</color>
    <color name="bg_chat">#f2f0eb</color>
    <color name="gray_normal">#666667</color>

    <color name="white_trans_40">#66FFFFFF</color>

    <color name="main_regist">#fffff0</color>

    <color name="theme_primary">#18b000</color>


</resources>


================================================
FILE: app/res/values/dimen_font.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 一般不用h1和h6, header标题h2, catalog标题h3, tab名称h4, 图标文字h5 -->
    <dimen name="large">26sp</dimen>
    <dimen name="h0">24sp</dimen>
    <dimen name="h1">22sp</dimen>
    <dimen name="h2">20sp</dimen>
    <dimen name="h3">18sp</dimen>
    <dimen name="h4">16sp</dimen>
    <dimen name="h5">14sp</dimen>
    <dimen name="h6">12sp</dimen>
    <dimen name="h7">10sp</dimen>
</resources>

================================================
FILE: app/res/values/dimens.xml
================================================
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="header_common_height">46dp</dimen>
    <dimen name="header_button_width">48dp</dimen>

    <!--setting-->
    <dimen name="setting_left_padding">20dp</dimen>
    <dimen name="setting_right_padding">20dp</dimen>
    <dimen name="setting_item_height">47dp</dimen>
    <dimen name="setting_item_left_padding">27dp</dimen>
    <dimen name="setting_item_right_padding">27dp</dimen>
    <dimen name="setting_item_checkbox_right_padding">32dp</dimen>
    <dimen name="setting_checkbox_right_margin">14dp</dimen>


    <dimen name="margin_chat_activity">5dp</dimen>
    <dimen name="size_avatar">50dp</dimen>
</resources>


================================================
FILE: app/res/values/strings.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">IMDemo</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
    <string name="login_account">发送用户id</string>
    <string name="login_target_account">接收用户id</string>
    <string name="login_login">登  录</string>
    <string name="main_settings">设置</string>
    <string name="main_contacts">通讯录</string>
    <string name="setting_notification">接收新消息通知</string>
    <string name="setting_sound">声音</string>
    <string name="setting_vibrate">震动</string>
    <string name="setting_logout">注销</string>
    <string name="chat_send">发 送</string>
    <string name="text_ack_msg">已读</string>
    <string name="text_delivered_msg">送达</string>
    <string name="text_failure">失败</string>
    <string name="text_sended_msg">已发送</string>
    <string name="chat_activity_header">%1$d -> %2$d</string>

</resources>


================================================
FILE: app/res/values/styles.xml
================================================
<resources xmlns:android="http://schemas.android.com/apk/res/android">

    <!--login-->
    <style name="login_edittext_underline">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">1dp</item>
        <item name="android:background">@color/white_trans_40</item>
        <item name="android:layout_marginLeft">15dp</item>
        <item name="android:layout_marginRight">15dp</item>
    </style>

    <style name="login_edittext">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">45dp</item>
        <item name="android:background">@null</item>
        <item name="android:layout_marginLeft">20dp</item>
        <item name="android:layout_marginRight">15dp</item>
        <item name="android:textColorHint">@color/white_trans_40</item>
        <item name="android:textColor">@android:color/white</item>
        <item name="android:textSize">@dimen/h2</item>
        <item name="android:numeric">integer</item>
        <item name="android:singleLine">true</item>

    </style>


    <style name="AnimFade2" parent="@android:style/Animation.Activity">
        <item name="android:activityOpenEnterAnimation">@anim/slide_in_from_right</item>
        <item name="android:activityOpenExitAnimation">@anim/slide_out_to_left</item>
        <item name="android:activityCloseExitAnimation">@anim/slide_out_to_right</item>
        <item name="android:activityCloseEnterAnimation">@anim/slide_in_from_left</item>
    </style>


    <style name="Horizontal_Slide" parent="android:Theme.NoTitleBar">
        <item name="android:windowAnimationStyle">@style/AnimFade2</item>
    </style>

    <style name="DemoMainNewMassage">
        <item name="android:background">@drawable/rc_unread_count_bg</item>
        <item name="android:gravity">center</item>
        <item name="android:textColor">@color/main_regist</item>
        <item name="android:textSize">10sp</item>
        <item name="android:layout_width">18dp</item>
        <item name="android:layout_height">18dp</item>
        <!-- <item name="android:visibility">gone</item>-->
    </style>

</resources>


================================================
FILE: app/src/io/gobelieve/im/demo/BaseActivity.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package io.gobelieve.im.demo;

import android.app.ActivityManager;
import android.content.Context;
import android.os.Bundle;
import androidx.fragment.app.FragmentActivity;

import com.beetle.im.IMService;

import java.util.List;

/**
 * BaseActivity
 * Description: 基础Activity
 */
public abstract class BaseActivity extends FragmentActivity {
    @Override
    protected final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        onBaseCreate(savedInstanceState);
        initView(savedInstanceState);
    }

    /**
     * 必须在此设置一个ContentView,除非它没有界面
     *
     * @param savedInstanceState
     */
    protected abstract void onBaseCreate(Bundle savedInstanceState);

    /**
     * 视图初始化
     * <p/>
     * 处理手势绑定、view和fragment的注入
     *
     * @param savedInstanceState
     */
    protected abstract void initView(Bundle savedInstanceState);



    @Override
    protected void onStop() {
        super.onStop();

        if (!isAppOnForeground()) {
            //app 进入后台,停止IMService,采用push机制接收离线消息
            IMService.getInstance().enterBackground();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        IMService.getInstance().enterForeground();
    }

    /**
     * 程序是否在前台运行
     *
     * @return
     */
    public boolean isAppOnForeground() {
        // Returns a list of application processes that are running on the
        // device

        ActivityManager activityManager =
            (ActivityManager) getApplicationContext().getSystemService(
                Context.ACTIVITY_SERVICE);
        String packageName = getApplicationContext().getPackageName();

        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager
            .getRunningAppProcesses();
        if (appProcesses == null)
            return false;

        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            // The name of the process that this object is associated with.
            if (appProcess.processName.equals(packageName)
                && appProcess.importance
                == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                return true;
            }
        }

        return false;
    }
}


================================================
FILE: app/src/io/gobelieve/im/demo/ConversationView.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package io.gobelieve.im.demo;

import android.content.Context;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import com.squareup.picasso.Picasso;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import io.gobelieve.im.demo.model.Conversation;

public class ConversationView extends FrameLayout implements PropertyChangeListener {
    protected Context context;
    protected LayoutInflater inflater;
    private Conversation conversation = null;

    public ConversationView(Context context) {
        super(context);
        this.context = context;
        this.inflater = LayoutInflater.from(context);
        inflater.inflate(R.layout.conversation_message, this);
    }

    public void setConversation(Conversation c) {
        if (this.conversation != null) {
            this.conversation.removePropertyChangeListener(this);
        }
        this.conversation = c;
        this.conversation.addPropertyChangeListener(this);


        TextView tv = (TextView) this.findViewById(R.id.name);
        tv.setText(c.getName());

        tv = (TextView)this.findViewById(R.id.content);
        tv.setText(c.getDetail());

        int placeholder;
        if (c.type == Conversation.CONVERSATION_PEER) {
            placeholder = R.drawable.avatar_contact;
        } else {
            placeholder = R.drawable.avatar_group;
        }

        String avatar = null;
        if (!TextUtils.isEmpty(c.getAvatar())) {
            avatar = c.getAvatar();
        }

        ImageView imageView = (ImageView) this.findViewById(R.id.header);
        Picasso.get()
                .load(avatar)
                .placeholder(placeholder)
                .into(imageView);

        setUnreadCount();
    }


    private void setUnreadCount() {
        TextView tv = (TextView) this.findViewById(R.id.unReadCount);
        if (conversation.getUnreadCount() > 0) {
            tv.setVisibility(VISIBLE);
            tv.setText(String.valueOf(conversation.getUnreadCount()));
        } else {
            tv.setVisibility(GONE);
        }
    }

    @Override
    public void propertyChange(PropertyChangeEvent event){
        if (event.getPropertyName().equals("detail")) {
            TextView tv = (TextView)this.findViewById(R.id.content);
            tv.setText(this.conversation.getDetail());
        } else if (event.getPropertyName().equals("name")) {
            TextView tv = (TextView) this.findViewById(R.id.name);
            tv.setText(this.conversation.getName());
        } else if (event.getPropertyName().equals("avatar")) {
            int placeholder;
            if (this.conversation.type == Conversation.CONVERSATION_PEER) {
                placeholder = R.drawable.avatar_contact;
            } else {
                placeholder = R.drawable.avatar_group;
            }

            String avatar = null;
            if (!TextUtils.isEmpty(this.conversation.getAvatar())) {
                avatar = this.conversation.getAvatar();
            }

            ImageView imageView = (ImageView) this.findViewById(R.id.header);
            Picasso.get()
                    .load(avatar)
                    .placeholder(placeholder)
                    .into(imageView);
        } else if (event.getPropertyName().equals("unreadCount")) {
            setUnreadCount();
        }
    }
}


================================================
FILE: app/src/io/gobelieve/im/demo/IMDemoApplication.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package io.gobelieve.im.demo;

import android.app.Application;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.HandlerThread;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;

import com.beetle.bauhinia.api.IMHttpAPI;
import com.beetle.bauhinia.handler.CustomerMessageHandler;
import com.beetle.bauhinia.handler.GroupMessageHandler;
import com.beetle.bauhinia.handler.PeerMessageHandler;
import com.beetle.bauhinia.tools.FileCache;
import com.beetle.im.IMService;
import com.beetle.bauhinia.toolbar.emoticon.EmoticonManager;

import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;


/**
 * IMDemoApplication
 * Description:
 */
public class IMDemoApplication extends Application {
    private static final String TAG = "gobelieve";

    private static Application sApplication;

    private HandlerThread imThread;//处理im消息的线程

    private String mDeviceToken;
    public String getDeviceToken() {
        return mDeviceToken;
    }


    @Override
    public void onCreate() {
        super.onCreate();
        sApplication = this;

        imThread = new HandlerThread("im_service");
        imThread.start();

        IMService mIMService = IMService.getInstance();
        //app可以单独部署服务器,给予第三方应用更多的灵活性
        mIMService.setHost("imnode2.gobelieve.io");
        IMHttpAPI.setAPIURL("https://api.gobelieve.io/v2");

        String androidID = Settings.Secure.getString(this.getContentResolver(),
                Settings.Secure.ANDROID_ID);

        //设置设备唯一标识,用于多点登录时设备校验
        mIMService.setDeviceID(androidID);

        mIMService.setLooper(imThread.getLooper());
        //监听网路状态变更
        IMService.getInstance().registerConnectivityChangeReceiver(getApplicationContext());

        //可以在登录成功后,设置每个用户不同的消息存储目录
        FileCache fc = FileCache.getInstance();
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            //can write external storage
            String path = getExternalFilesDir(null).getAbsolutePath();
            File dir1 = new File(path, "download");
            if (!dir1.exists()) {
                dir1.mkdirs();
            }
            fc.setDir(dir1);
            Log.i(TAG, "file cache:" + dir1.getAbsolutePath());
        } else {
            File f = new File(getFilesDir(), "cache");
            if (!f.exists()) {
                f.mkdir();
            }
            fc.setDir(f);
            Log.i(TAG, "file cache:" + this.getDir("cache", MODE_PRIVATE).getAbsolutePath());
        }

        mIMService.setPeerMessageHandler(PeerMessageHandler.getInstance());
        mIMService.setGroupMessageHandler(GroupMessageHandler.getInstance());
        mIMService.setCustomerMessageHandler(CustomerMessageHandler.getInstance());

        //表情资源初始化
        EmoticonManager.getInstance().init(this);
    }

    public static Application getApplication() {
        return sApplication;
    }
}


================================================
FILE: app/src/io/gobelieve/im/demo/LoginActivity.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package io.gobelieve.im.demo;

import android.app.ProgressDialog;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.beetle.bauhinia.CustomerMessageActivity;
import com.beetle.bauhinia.GroupMessageActivity;
import com.beetle.bauhinia.PeerMessageActivity;
import com.beetle.bauhinia.api.IMHttpAPI;
import com.beetle.bauhinia.api.body.PostDeviceToken;
import com.beetle.bauhinia.db.CustomerMessageDB;
import com.beetle.bauhinia.db.GroupMessageDB;
import com.beetle.bauhinia.db.EPeerMessageDB;
import com.beetle.bauhinia.db.PeerMessageDB;
import com.beetle.bauhinia.handler.GroupMessageHandler;
import com.beetle.bauhinia.handler.PeerMessageHandler;
import com.beetle.bauhinia.handler.CustomerMessageHandler;
import com.beetle.bauhinia.handler.SyncKeyHandler;
import com.beetle.im.IMService;

import org.json.JSONObject;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import io.gobelieve.im.demo.model.ConversationDB;
import io.gobelieve.im.demo.model.MessageDatabaseHelper;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;

/**
 * LoginActivity
 * Description: 登录页面,给用户指定消息发送方Id
 */
public class LoginActivity extends BaseActivity implements View.OnClickListener {
    private final String TAG = "demo";

    private static final long APP_ID = 7;

    private static final boolean TEST_PEER = true;
    private static final boolean TEST_GROUP = false;
    private static final boolean TEST_CUSTOMER = false;

    private EditText mEtAccount;
    private EditText mEtTargetAccount;

    AsyncTask mLoginTask;
    @Override
    protected void onBaseCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_login);
    }

    @Override
    protected void initView(Bundle savedInstanceState) {
        Button btnLogin = (Button) findViewById(R.id.btn_login);
        mEtAccount = (EditText) findViewById(R.id.et_username);
        mEtTargetAccount = (EditText) findViewById(R.id.et_target_username);
        if (TEST_PEER) {
            mEtTargetAccount.setHint("接受用户id");
        } else if (TEST_GROUP) {
            mEtTargetAccount.setHint("群组id(15)");
        } else if (TEST_CUSTOMER) {
            mEtTargetAccount.setHint("商店id(7)");
        }
        btnLogin.setOnClickListener(this);
    }

    void openDB(long currentUID) {
        File p = this.getDir("db", MODE_PRIVATE);
        File f = new File(p, String.format("gobelieve_%d.db", currentUID));
        String path = f.getPath();
        MessageDatabaseHelper dh = MessageDatabaseHelper.getInstance();
        dh.open(this.getApplicationContext(), path);
        SQLiteDatabase db = dh.getDatabase();
        Log.i(TAG, "db version:" + db.getVersion());
        PeerMessageDB.getInstance().setDb(db);
        EPeerMessageDB.getInstance().setDb(db);
        GroupMessageDB.getInstance().setDb(db);
        CustomerMessageDB.getInstance().setDb(db);
        ConversationDB.getInstance().setDb(db);
    }

    private void go2Chat(long sender, long receiver, String token) {
        IMService.getInstance().stop();
        PeerMessageDB.getInstance().setDb(null);
        EPeerMessageDB.getInstance().setDb(null);
        GroupMessageDB.getInstance().setDb(null);
        CustomerMessageDB.getInstance().setDb(null);
        ConversationDB.getInstance().setDb(null);


        openDB(sender);

        PeerMessageHandler.getInstance().setUID(sender);
        GroupMessageHandler.getInstance().setUID(sender);
        CustomerMessageHandler.getInstance().setUID(sender);
        CustomerMessageHandler.getInstance().setAppId(APP_ID);
        IMHttpAPI.setToken(token);
        IMService.getInstance().setToken(token);

        SyncKeyHandler handler = new SyncKeyHandler(this.getApplicationContext(), "sync_key");
        handler.load();

        HashMap<Long, Long> groupSyncKeys = handler.getSuperGroupSyncKeys();
        IMService.getInstance().clearSuperGroupSyncKeys();
        for (Map.Entry<Long, Long> e : groupSyncKeys.entrySet()) {
            IMService.getInstance().addSuperGroupSyncKey(e.getKey(), e.getValue());
            Log.i(TAG, "group id:" + e.getKey() + "sync key:" + e.getValue());
        }
        IMService.getInstance().setSyncKey(handler.getSyncKey());
        Log.i(TAG, "sync key:" + handler.getSyncKey());
        IMService.getInstance().setSyncKeyHandler(handler);



        IMService.getInstance().start();

        IMDemoApplication app = (IMDemoApplication)getApplication();
        String deviceToken = app.getDeviceToken();
        if (token != null && deviceToken != null && deviceToken.length() > 0) {
            PostDeviceToken tokenBody = new PostDeviceToken();
            tokenBody.xgDeviceToken = deviceToken;
            IMHttpAPI.Singleton().bindDeviceToken(tokenBody)
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Action1<Object>() {
                        @Override
                        public void call(Object obj) {
                            Log.i("im", "bind success");
                        }
                    }, new Action1<Throwable>() {
                        @Override
                        public void call(Throwable throwable) {
                            Log.i("im", "bind fail");
                        }
                    });
        }

        if (TEST_PEER) {
            Intent intent = new Intent(this, PeerMessageActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra("peer_uid", receiver);
            intent.putExtra("peer_name", "测试");
            intent.putExtra("current_uid", sender);
            startActivity(intent);
        } else if (TEST_GROUP) {
            Intent intent = new Intent(this, GroupMessageActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra("group_id", receiver);
            intent.putExtra("group_name", "测试群");
            intent.putExtra("current_uid", sender);
            startActivity(intent);
        } else if (TEST_CUSTOMER) {
            Intent intent = new Intent(this, CustomerMessageActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra("store_id", receiver);
            intent.putExtra("app_id", APP_ID);
            intent.putExtra("current_uid", sender);
            intent.putExtra("peer_app_id", 0L);
            intent.putExtra("peer_uid", 0L);
            intent.putExtra("peer_app_name", "");
            intent.putExtra("peer_name", "");
            intent.putExtra("store_name", "测试商店");
            intent.putExtra("app_name", "demo");
            intent.putExtra("name", "测试用户");
            startActivity(intent);
        }
        finish();
    }



    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_login) {
            if (mEtAccount.getText().toString().length() <= 0) {
                Toast.makeText(this, "请设置您的用户id", Toast.LENGTH_SHORT).show();
                return;
            }
            final long senderId = Long.parseLong(mEtAccount.getText().toString());
            if (senderId <= 0) {
                Toast.makeText(this, "用户id不能为0或者-1", Toast.LENGTH_SHORT).show();
                return;
            }

            long receiver = 0;
            if (mEtTargetAccount.getText().toString().length() > 0) {
                receiver = Long.parseLong(mEtTargetAccount.getText().toString());
                if (receiver <= 0) {
                    if (TEST_PEER) {
                        Toast.makeText(this, "输入接受者id", Toast.LENGTH_SHORT).show();
                    } else if (TEST_GROUP) {
                        Toast.makeText(this, "输入群组id", Toast.LENGTH_SHORT).show();
                    } else if (TEST_CUSTOMER) {
                        Toast.makeText(this, "输入商店id", Toast.LENGTH_SHORT).show();
                    }
                    return;
                }
            }

            final long receiverId = receiver;

            if (mLoginTask != null) {
                return;
            }

            final ProgressDialog dialog = ProgressDialog.show(this, null, "登录中...");

            mLoginTask = new AsyncTask<Void, Integer, String>() {
                @Override
                protected String doInBackground(Void... urls) {
                    return LoginActivity.this.login(senderId);
                }
                @Override
                protected void onPostExecute(String result) {
                    dialog.dismiss();
                    mLoginTask = null;
                    if (result != null && result.length() > 0) {
                        //设置用户id,进入MainActivity
                        go2Chat(senderId, receiverId, result);
                    } else {
                        Toast.makeText(LoginActivity.this, "登陆失败", Toast.LENGTH_SHORT).show();
                    }
                }
            }.execute();
        }
    }

    private String login(long uid) {
        //调用app自身的登陆接口获取im服务必须的access token,之后可将token保存在本地供下次直接登录IM服务
        String api_url = "http://demo.gobelieve.io";

        String uri = String.format("%s/auth/token", api_url);
        try {
            URL url = new URL(uri);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/json; utf-8");
            connection.setDoOutput(true);
            connection.setUseCaches(false);

            JSONObject json = new JSONObject();
            json.put("uid", uid);
            int PLATFORM_ANDROID = 2;
            String androidID = Settings.Secure.getString(this.getContentResolver(),
                    Settings.Secure.ANDROID_ID);
            json.put("platform_id", PLATFORM_ANDROID);
            json.put("device_id", androidID);
            String data = json.toString();

            try(OutputStream os = connection.getOutputStream()){
                byte[] input = data.getBytes("utf-8");
                os.write(input, 0, input.length);
            }
            int responseCode = connection.getResponseCode();
            if (responseCode != 200){
                System.out.println("login failure code is:" + responseCode);
                return null;
            }
            int len = connection.getHeaderFieldInt("Content-Length", 64*1024);
            byte[] buf = new byte[len];
            InputStream inStream = connection.getInputStream();

            int pos = 0;
            while (pos < len) {
                int n = inStream.read(buf, pos, len - pos);
                if (n == -1) {
                    break;
                }
                pos += n;
            }
            inStream.close();
            if (pos != len) {
                return null;
            }
            String txt = new String(buf, "UTF-8");
            JSONObject jsonObject = new JSONObject(txt);
            String accessToken = jsonObject.getString("token");
            return accessToken;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}


================================================
FILE: app/src/io/gobelieve/im/demo/MessageListActivity.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package io.gobelieve.im.demo;

import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import androidx.appcompat.widget.Toolbar;

import com.beetle.bauhinia.CustomerMessageActivity;
import com.beetle.bauhinia.PeerMessageActivity;
import com.beetle.bauhinia.db.CustomerMessageDB;
import com.beetle.bauhinia.db.EPeerMessageDB;
import com.beetle.bauhinia.db.GroupMessageDB;
import com.beetle.bauhinia.db.ICustomerMessage;
import com.beetle.bauhinia.db.IMessage;
import com.beetle.bauhinia.db.PeerMessageDB;
import com.beetle.bauhinia.db.message.Audio;
import com.beetle.bauhinia.db.message.File;
import com.beetle.bauhinia.db.message.GroupNotification;
import com.beetle.bauhinia.db.message.GroupVOIP;
import com.beetle.bauhinia.db.message.Image;
import com.beetle.bauhinia.db.message.Location;
import com.beetle.bauhinia.db.message.MessageContent;
import com.beetle.bauhinia.db.message.P2PSession;
import com.beetle.bauhinia.db.message.Revoke;
import com.beetle.bauhinia.db.message.Secret;
import com.beetle.bauhinia.db.message.Text;
import com.beetle.bauhinia.db.message.VOIP;
import com.beetle.bauhinia.db.message.Video;
import com.beetle.im.GroupMessageObserver;
import com.beetle.im.IMMessage;
import com.beetle.im.IMService;
import com.beetle.im.IMServiceObserver;
import com.beetle.bauhinia.activity.BaseActivity;

import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.beetle.im.PeerMessageObserver;
import com.beetle.im.SystemMessageObserver;

import io.gobelieve.im.demo.model.Conversation;
import io.gobelieve.im.demo.model.ConversationDB;


public class MessageListActivity extends BaseActivity implements IMServiceObserver,
        PeerMessageObserver,
        GroupMessageObserver,
        SystemMessageObserver,
        AdapterView.OnItemClickListener {
    private static final String TAG = "beetle";

    private List<Conversation> conversations;
    private ListView lv;
    protected long currentUID = 0;


    private static final long APPID = 7;
    private static final long KEFU_ID = 55;


    private BaseAdapter adapter;
    class ConversationAdapter extends BaseAdapter {
        @Override
        public int getCount() {
            return conversations.size();
        }
        @Override
        public Object getItem(int position) {
            return conversations.get(position);
        }
        @Override
        public long getItemId(int position) {
            return position;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ConversationView view = null;
            if (convertView == null) {
                view = new ConversationView(MessageListActivity.this);
            } else {
                view = (ConversationView)convertView;
            }
            Conversation c = conversations.get(position);
            view.setConversation(c);;
            return view;
        }
    }

    // 初始化组件
    private void initWidget() {
        Toolbar toolbar = (Toolbar)findViewById(R.id.support_toolbar);
        setSupportActionBar(toolbar);

        lv = (ListView) findViewById(R.id.list);
        adapter = new ConversationAdapter();
        lv.setAdapter(adapter);
        lv.setOnItemClickListener(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(TAG, "main activity create...");

        setContentView(R.layout.activity_conversation);

        Intent intent = getIntent();

        currentUID = intent.getLongExtra("current_uid", 0);
        if (currentUID == 0) {
            Log.e(TAG, "current uid is 0");
            return;
        }

        IMService im =  IMService.getInstance();
        im.addObserver(this);
        im.addPeerObserver(this);
        im.addGroupObserver(this);
        im.addSystemObserver(this);

        loadConversations();
        initWidget();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        IMService im =  IMService.getInstance();
        im.removeObserver(this);
        im.removePeerObserver(this);
        im.removeGroupObserver(this);
        im.removeSystemObserver(this);
        Log.i(TAG, "message list activity destroyed");
    }


    public  String messageContentToString(MessageContent content) {
        if (content instanceof Text) {
            return ((Text) content).text;
        } else if (content instanceof Image) {
            return "一张图片";
        } else if (content instanceof Audio) {
            return "一段语音";
        } else if (content instanceof File) {
            return "一个文件";
        } else if (content instanceof Video) {
            return "一个视频";
        } else if (content instanceof com.beetle.bauhinia.db.message.Notification) {
            return ((com.beetle.bauhinia.db.message.Notification) content).description;
        } else if (content instanceof Location) {
            return "一个地理位置";
        } else if (content instanceof GroupVOIP) {
            return ((GroupVOIP) content).description;
        } else if (content instanceof VOIP) {
            VOIP voip = (VOIP) content;
            if (voip.videoEnabled) {
                return "视频聊天";
            } else {
                return "语音聊天";
            }
        } else if (content instanceof Secret) {
            return "消息未能解密";
        } else if (content instanceof P2PSession) {
            return "";
        } else {
            return "未知的消息类型";
        }
    }

    void updateConversationDetail(Conversation conv) {
        String detail = messageContentToString(conv.message.content);
        conv.setDetail(detail);
    }

    void updatePeerConversationName(Conversation conv) {
        User u = getUser(conv.cid);
        if (TextUtils.isEmpty(u.name)) {
            conv.setName(u.identifier);
            final Conversation fconv = conv;
            asyncGetUser(conv.cid, new GetUserCallback() {
                @Override
                public void onUser(User u) {
                    fconv.setName(u.name);
                    fconv.setAvatar(u.avatarURL);
                }
            });
        } else {
            conv.setName(u.name);
        }
        conv.setAvatar(u.avatarURL);
    }

    void updateGroupConversationName(Conversation conv) {
        Group g = getGroup(conv.cid);
        if (TextUtils.isEmpty(g.name)) {
            conv.setName(g.identifier);
            final Conversation fconv = conv;
            asyncGetGroup(conv.cid, new GetGroupCallback() {
                @Override
                public void onGroup(Group g) {
                    fconv.setName(g.name);
                    fconv.setAvatar(g.avatarURL);
                }
            });
        } else {
            conv.setName(g.name);
        }
        conv.setAvatar(g.avatarURL);
    }

    void loadConversations() {
        conversations = ConversationDB.getInstance().getConversations();
        boolean customerExists = false;
        for (Conversation conv : conversations) {
            if (conv.type == Conversation.CONVERSATION_PEER) {
                IMessage msg = PeerMessageDB.getInstance().getLastMessage(conv.cid);
                conv.message = msg;

                updatePeerConversationName(conv);
                updateNotificationDesc(conv);
                updateConversationDetail(conv);
            } else if (conv.type == Conversation.CONVERSATION_PEER_SECRET) {
                IMessage msg = EPeerMessageDB.getInstance().getLastMessage(conv.cid);
                conv.message = msg;

                updatePeerConversationName(conv);
                updateNotificationDesc(conv);
                updateConversationDetail(conv);
            } else if (conv.type == Conversation.CONVERSATION_GROUP) {
                IMessage msg = GroupMessageDB.getInstance().getLastMessage(conv.cid);
                conv.message = msg;

                updateGroupConversationName(conv);
                updateNotificationDesc(conv);
                updateConversationDetail(conv);
            }
        }


        Comparator<Conversation> cmp = new Comparator<Conversation>() {
            public int compare(Conversation c1, Conversation c2) {

                int t1 = 0;
                int t2 = 0;
                if (c1.message != null) {
                    t1 = c1.message.timestamp;
                }
                if (c2.message != null) {
                    t2 = c2.message.timestamp;
                }

                if (t1 > t2) {
                    return -1;
                } else if (t1 == t2) {
                    return 0;
                } else {
                    return 1;
                }

            }
        };
        Collections.sort(conversations, cmp);
    }

    public static class User {
        public long uid;
        public String name;
        public String avatarURL;

        //name为nil时,界面显示identifier字段
        public String identifier;
    }

    public static class Group {
        public long gid;
        public String name;
        public String avatarURL;

        //name为nil时,界面显示identifier字段
        public String identifier;
    }



    public interface GetUserCallback {
        void onUser(User u);
    }

    public interface GetGroupCallback {
        void onGroup(Group g);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
                            long id) {
        Conversation conv = conversations.get(position);
        Log.i(TAG, "conv:" + conv.getName());

        if (conv.type == Conversation.CONVERSATION_PEER) {
            onPeerClick(conv.cid);
        } else if (conv.type == Conversation.CONVERSATION_GROUP){
            onGroupClick(conv.cid);
        }
    }

    @Override
    public void onConnectState(IMService.ConnectState state) {

    }



    public Conversation findConversation(long cid, int type) {
        for (int i = 0; i < conversations.size(); i++) {
            Conversation conv = conversations.get(i);
            if (conv.cid == cid && conv.type == type) {
                return conv;
            }
        }
        return null;
    }

    public int findConversationPosition(long cid, int type) {
        for (int i = 0; i < conversations.size(); i++) {
            Conversation conv = conversations.get(i);
            if (conv.cid == cid && conv.type == type) {
                return i;
            }
        }
        return -1;
    }

    public Conversation newPeerConversation(long cid) {
        Conversation conversation = new Conversation();
        conversation.type = Conversation.CONVERSATION_PEER;
        conversation.cid = cid;

        updatePeerConversationName(conversation);
        ConversationDB.getInstance().addConversation(conversation);
        return conversation;
    }

    public Conversation newGroupConversation(long cid) {
        Conversation conversation = new Conversation();
        conversation.type = Conversation.CONVERSATION_GROUP;
        conversation.cid = cid;
        updateGroupConversationName(conversation);
        ConversationDB.getInstance().addConversation(conversation);
        return conversation;
    }

    public static int now() {
        Date date = new Date();
        long t = date.getTime();
        return (int)(t/1000);
    }


    @Override
    public void onPeerSecretMessage(IMMessage msg) {

    }

    @Override
    public void onPeerMessage(IMMessage msg) {
        Log.i(TAG, "on peer message");
        IMessage imsg = new IMessage();
        imsg.timestamp = now();
        imsg.msgLocalID = msg.msgLocalID;
        imsg.sender = msg.sender;
        imsg.receiver = msg.receiver;
        imsg.setContent(msg.content);

        long cid = 0;
        if (msg.sender == this.currentUID) {
            cid = msg.receiver;
        } else {
            cid = msg.sender;
        }

        int pos = findConversationPosition(cid, Conversation.CONVERSATION_PEER);
        Conversation conversation = null;
        if (pos == -1) {
            conversation = newPeerConversation(cid);
        } else {
            conversation = conversations.get(pos);
        }

        conversation.message = imsg;
        updateConversationDetail(conversation);

        if (pos == -1) {
            conversations.add(0, conversation);
            adapter.notifyDataSetChanged();
        } else if (pos > 0) {
            conversations.remove(pos);
            conversations.add(0, conversation);
            adapter.notifyDataSetChanged();
        } else {
            //pos == 0
        }
    }


    @Override
    public void onPeerMessageACK(IMMessage im, int error) {
        Log.i(TAG, "message ack on main");

        long msgLocalID = im.msgLocalID;
        long uid = im.receiver;
        if (msgLocalID == 0) {
            MessageContent c = IMessage.fromRaw(im.plainContent);
            if (c.getType() == MessageContent.MessageType.MESSAGE_REVOKE) {
                Revoke r = (Revoke)c;
                int pos = -1;
                if (!im.secret) {
                    pos = findConversationPosition(uid, Conversation.CONVERSATION_PEER);
                } else {
                    pos = findConversationPosition(uid, Conversation.CONVERSATION_PEER_SECRET);
                }
                Conversation conversation = conversations.get(pos);
                if (r.msgid.equals(conversation.message.getUUID())) {
                    conversation.message.setContent(r);
                    updateNotificationDesc(conversation);
                    updateConversationDetail(conversation);
                }
            }
        }
    }

    @Override
    public void onPeerMessageFailure(IMMessage im) {

    }


    @Override
    public void onGroupMessages(List<IMMessage> msgs) {
        HashMap<Long, Integer> unreadDict = new HashMap<>();
        HashMap<Long, IMMessage> msgDict = new HashMap<>();

        for (IMMessage msg : msgs) {
            int count = 0;
            if (unreadDict.containsKey(msg.receiver)) {
                count = (Integer)unreadDict.get(msg.receiver);
            }
            if (!msg.isGroupNotification && msg.sender != this.currentUID) {
                count += 1;
            }

            unreadDict.put(msg.receiver, count);
            msgDict.put(msg.receiver, msg);
        }

        Iterator iter = msgDict.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<Long, IMMessage> entry = (Map.Entry<Long, IMMessage>)iter.next();

            IMMessage im = entry.getValue();
            Long groupId = entry.getKey();
            int unread = unreadDict.get(groupId);
            onGroupMessage(im, unread);
        }
    }


    public void onGroupMessage(IMMessage msg, int unread) {
        Log.i(TAG, "on group message");
        IMessage imsg = new IMessage();
        imsg.timestamp = msg.timestamp;
        imsg.msgLocalID = msg.msgLocalID;
        imsg.sender = msg.sender;
        imsg.receiver = msg.receiver;
        if (msg.isGroupNotification) {
            GroupNotification groupNotification = GroupNotification.newGroupNotification(msg.content);
            imsg.receiver = groupNotification.groupID;
            imsg.timestamp = groupNotification.timestamp;
            imsg.setContent(groupNotification);
        } else {
            imsg.setContent(msg.content);
        }

        int pos = findConversationPosition(msg.receiver, Conversation.CONVERSATION_GROUP);
        Conversation conversation = null;
        if (pos == -1) {
            conversation = newGroupConversation(msg.receiver);
        } else {
            conversation = conversations.get(pos);
        }

        conversation.message = imsg;
        updateConversationDetail(conversation);

        if (pos == -1) {
            conversations.add(0, conversation);
            adapter.notifyDataSetChanged();
        } else if (pos > 0) {
            conversations.remove(pos);
            conversations.add(0, conversation);
            adapter.notifyDataSetChanged();
        } else {
            //pos == 0
        }
    }

    @Override
    public void onGroupMessageACK(IMMessage im, int error) {
        long msgLocalID = im.msgLocalID;
        long gid = im.receiver;
        if (msgLocalID == 0) {
            MessageContent c = IMessage.fromRaw(im.content);
            if (c.getType() == MessageContent.MessageType.MESSAGE_REVOKE) {
                Revoke r = (Revoke)c;
                int pos = -1;
                pos = findConversationPosition(gid, Conversation.CONVERSATION_GROUP);
                Conversation conversation = conversations.get(pos);
                if (r.msgid.equals(conversation.message.getUUID())) {
                    conversation.message.setContent(r);
                    updateNotificationDesc(conversation);
                    updateConversationDetail(conversation);
                }
            }
        }
    }

    @Override
    public void onGroupMessageFailure(IMMessage im) {

    }


    private void updateNotificationDesc(Conversation conv) {
        final IMessage imsg = conv.message;
        if (imsg == null || imsg.content.getType() != MessageContent.MessageType.MESSAGE_GROUP_NOTIFICATION) {
            return;
        }
        long currentUID = this.currentUID;
        GroupNotification notification = (GroupNotification)imsg.content;
        if (notification.notificationType == GroupNotification.NOTIFICATION_GROUP_CREATED) {
            if (notification.master == currentUID) {
                notification.description = String.format("您创建了\"%s\"群组", notification.groupName);
            } else {
                notification.description = String.format("您加入了\"%s\"群组", notification.groupName);
            }
        } else if (notification.notificationType == GroupNotification.NOTIFICATION_GROUP_DISBAND) {
            notification.description = "群组已解散";
        } else if (notification.notificationType == GroupNotification.NOTIFICATION_GROUP_MEMBER_ADDED) {
            User u = getUser(notification.member);
            if (TextUtils.isEmpty(u.name)) {
                notification.description = String.format("\"%s\"加入群", u.identifier);
                final GroupNotification fnotification = notification;
                final Conversation fconv = conv;
                asyncGetUser(notification.member, new GetUserCallback() {
                    @Override
                    public void onUser(User u) {
                        fnotification.description = String.format("\"%s\"加入群", u.name);
                        if (fconv.message == imsg) {
                            fconv.setDetail(fnotification.description);
                        }
                    }
                });
            } else {
                notification.description = String.format("\"%s\"加入群", u.name);
            }
        } else if (notification.notificationType == GroupNotification.NOTIFICATION_GROUP_MEMBER_LEAVED) {
            User u = getUser(notification.member);
            if (TextUtils.isEmpty(u.name)) {
                notification.description = String.format("\"%s\"离开群", u.identifier);
                final GroupNotification fnotification = notification;
                final Conversation fconv = conv;
                asyncGetUser(notification.member, new GetUserCallback() {
                    @Override
                    public void onUser(User u) {
                        fnotification.description = String.format("\"%s\"离开群", u.name);
                        if (fconv.message == imsg) {
                            fconv.setDetail(fnotification.description);
                        }
                    }
                });
            } else {
                notification.description = String.format("\"%s\"离开群", u.name);
            }
        } else if (notification.notificationType == GroupNotification.NOTIFICATION_GROUP_NAME_UPDATED) {
            notification.description = String.format("群组改名为\"%s\"", notification.groupName);
        }
    }



    @Override
    public void onSystemMessage(String sm) {
        Log.i(TAG, "system message:" + sm);
    }

    public boolean canBack() {
        return false;
    }





    protected User getUser(long uid) {
        User u = new User();
        u.uid = uid;
        u.name = null;
        u.avatarURL = "";
        u.identifier = String.format("%d", uid);
        return u;
    }


    protected void asyncGetUser(long uid, GetUserCallback cb) {
        final long fuid = uid;
        final GetUserCallback fcb = cb;
        new AsyncTask<Void, Integer, User>() {
            @Override
            protected User doInBackground(Void... urls) {
                User u = new User();
                u.uid = fuid;
                u.name = String.format("%d", fuid);
                u.avatarURL = "";
                u.identifier = String.format("%d", fuid);
                return u;
            }
            @Override
            protected void onPostExecute(User result) {
                fcb.onUser(result);
            }
        }.execute();
    }


    protected Group getGroup(long gid) {
        Group g = new Group();
        g.gid = gid;
        g.name = null;
        g.avatarURL = "";
        g.identifier = String.format("%d", gid);
        return g;
    }


    protected void asyncGetGroup(long gid, GetGroupCallback cb) {
        final long fgid = gid;
        final GetGroupCallback fcb = cb;
        new AsyncTask<Void, Integer, Group>() {
            @Override
            protected Group doInBackground(Void... urls) {
                Group g = new Group();
                g.gid = fgid;
                g.name = String.format("%d", fgid);
                g.avatarURL = "";
                g.identifier = String.format("%d", fgid);
                return g;
            }
            @Override
            protected void onPostExecute(Group result) {
                fcb.onGroup(result);
            }
        }.execute();
    }


    protected void onPeerClick(long uid) {
        User u = getUser(uid);

        Intent intent = new Intent(this, PeerMessageActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra("peer_uid", uid);
        if (TextUtils.isEmpty(u.name)) {
            intent.putExtra("peer_name", u.identifier);
        } else {
            intent.putExtra("peer_name", u.name);
        }
        intent.putExtra("current_uid", this.currentUID);
        startActivity(intent);
    }


    protected void onGroupClick(long gid) {
        Log.i(TAG, "group conversation");
    }




}


================================================
FILE: app/src/io/gobelieve/im/demo/model/Conversation.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package io.gobelieve.im.demo.model;

import com.beetle.bauhinia.db.IMessage;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;

/**
 * Created by houxh on 15/3/9.
 */
public class Conversation {
    public static final int CONVERSATION_PEER = 1;
    public static final int CONVERSATION_GROUP = 2;
    public static final int CONVERSATION_CUSTOMER_SERVICE = 3;
    public static final int CONVERSATION_PEER_SECRET = 4;//点对点加密会话

    public static final int STATE_UNINITIALIZE = 0;//未初始化状态
    public static final int STATE_WAIT = 1;//等待对方上线
    public static final int STATE_EXCHANGE = 2;//交换密钥中,暂时未被使用
    public static final int STATE_CONNECTED = 3;//连接成功,可以发送加密消息


    public long rowid;
    public int type;
    public long cid;
    public int state;//p2p加密会话的状态,普通会话此字段无意义
    public IMessage message;

    //search
    public ArrayList<IMessage> messages = new ArrayList<>();

    private String name;
    private String avatar;
    private String detail;
    private int unreadCount;

    private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
            this);

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.removePropertyChangeListener(listener);
    }

    public void addPropertyChangeListener(String propertyName,
                                          PropertyChangeListener listener) {
        changeSupport.addPropertyChangeListener(propertyName, listener);
    }


    public void setName(String name) {
        String old = this.name;
        this.name = name;
        changeSupport.firePropertyChange("name", old, this.name);
    }

    public String getName() {
        return this.name;
    }

    public void setAvatar(String avatar) {
        String old = this.avatar;
        this.avatar = avatar;
        changeSupport.firePropertyChange("avatar", old, this.avatar);
    }

    public String getAvatar() {
        return this.avatar;
    }

    public void setDetail(String detail) {
        String old = this.detail;
        this.detail = detail;
        changeSupport.firePropertyChange("detail", old, this.detail);
    }

    public String getDetail() {
        return this.detail;
    }

    public void setUnreadCount(int unreadCount) {
        int old = this.unreadCount;
        this.unreadCount = unreadCount;
        changeSupport.firePropertyChange("unreadCount", old, this.unreadCount);
    }

    public int getUnreadCount() {
        return this.unreadCount;
    }
}


================================================
FILE: app/src/io/gobelieve/im/demo/model/ConversationDB.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package io.gobelieve.im.demo.model;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;


import java.util.ArrayList;
import java.util.List;

public class ConversationDB {

    private static final String TAG = "goubuli";
    private static final String TABLE_NAME = "conversation";

    public static final String COLUMN_ROWID = "id";
    public static final String COLUMN_STATE = "state";
    public static final String COLUMN_UNREAD = "unread";


    private static ConversationDB instance = new ConversationDB();
    public static ConversationDB getInstance() {
        return instance;
    }

    private SQLiteDatabase mDB;

    public void setDb(SQLiteDatabase db) {
        this.mDB = db;
    }

    public SQLiteDatabase getDb() {
        return this.mDB;
    }

    public List<Conversation> getConversations() {
        ArrayList<Conversation> convs = new ArrayList<>();
        Cursor cursor = null;
        try {
            cursor = mDB.query(TABLE_NAME, new String[]{"id", "cid", "type", "name", "state", "unread"},
                    null, null, null, null, null);
            while (cursor.moveToNext()) {
                long rowid = cursor.getLong(cursor.getColumnIndex("id"));
                long id = cursor.getLong(cursor.getColumnIndex("cid"));
                int type = cursor.getInt(cursor.getColumnIndex("type"));
                String name = cursor.getString(cursor.getColumnIndex("name"));
                int state = cursor.getInt(cursor.getColumnIndex("state"));
                int unread = cursor.getInt(cursor.getColumnIndex("unread"));
                Conversation conv = new Conversation();
                conv.rowid = rowid;
                conv.cid = id;
                conv.type = type;
                conv.state = state;
                conv.setUnreadCount(unread);
                conv.setName(name);
                convs.add(conv);
            }
        } catch (Exception ex) {
            Log.e(TAG, ex.toString());
        } finally {
            if (null != cursor) {
                cursor.close();
            }
        }
        return convs;
    }


    public Conversation getConversation(long cid, int type) {
        Cursor cursor = null;
        try {

            cursor = mDB.query(TABLE_NAME, new String[]{"id", "cid", "type", "name", "unread"},
                    "cid=? AND type=?",
                    new String[]{
                            String.valueOf(cid),
                            String.valueOf(type)
                    },
                    null, null, null);
            if (cursor.moveToNext()) {
                long rowid = cursor.getLong(cursor.getColumnIndex("id"));
                String name = cursor.getString(cursor.getColumnIndex("name"));
                int state = cursor.getInt(cursor.getColumnIndex("state"));
                int unread = cursor.getInt(cursor.getColumnIndex("unread"));
                Conversation conv = new Conversation();
                conv.rowid = rowid;
                conv.cid = cid;
                conv.type = type;
                conv.state = state;
                conv.setUnreadCount(unread);
                conv.setName(name);
                return conv;
            }
        } catch (Exception ex) {
            Log.e(TAG, ex.toString());
        } finally {
            if (null != cursor) {
                cursor.close();
            }
        }
        return null;
    }

    public boolean addConversation(Conversation conv) {
        boolean result = true;

        try {
            mDB.beginTransaction();
            ContentValues values = new ContentValues();
            values.put("cid", conv.cid);
            values.put("type", conv.type);
            values.put("name", conv.getName());
            values.put("state", conv.state);
            values.put("unread", conv.getUnreadCount());
            conv.rowid = mDB.insert(TABLE_NAME, null, values);
            values.clear();
            mDB.setTransactionSuccessful();
        } catch (Exception e) {
            e.printStackTrace();
            result = false;
        } finally {
            mDB.endTransaction();
        }
        return result;
    }

    public boolean setNewCount(long rowid, int count) {
        boolean result;
        try {

            ContentValues values = new ContentValues();
            values.put(COLUMN_UNREAD, count);

            int r = mDB.update(TABLE_NAME,
                    values, "id=?",
                    new String[] {
                        String.valueOf(rowid)
                    });

            result = r > 0;
        } catch (Exception e) {
            Log.e(TAG, e.toString());
            result = false;
        }
        return result;
    }


    public boolean setState(long rowid, int state) {
        boolean result;
        try {

            ContentValues values = new ContentValues();
            values.put(COLUMN_STATE, state);

            int r = mDB.update(TABLE_NAME,
                    values, "id=?",
                    new String[] {
                            String.valueOf(rowid)
                    });

            result = r > 0;
        } catch (Exception e) {
            Log.e(TAG, e.toString());
            result = false;
        }
        return result;
    }

    public boolean resetState(int state) {
        boolean result = true;
        try {

            ContentValues values = new ContentValues();
            values.put(COLUMN_STATE, state);

            mDB.update(TABLE_NAME,
                    values, null,
                    null);

        } catch (Exception e) {
            Log.e(TAG, e.toString());
            result = false;
        }
        return result;
    }


    public boolean removeConversation(Conversation conv) {

        try {
            mDB.beginTransaction();

            mDB.delete(TABLE_NAME, "id=?",
                    new String[] {
                            String.valueOf(conv.rowid)
                    });
            mDB.setTransactionSuccessful();
        } catch (Exception e) {
            e.printStackTrace();
            if (mDB.inTransaction()) {
                mDB.endTransaction();
            }
            return false;
        } finally {
            if (mDB.inTransaction()) {
                mDB.endTransaction();
            }
        }

        return true;
    }
}


================================================
FILE: app/src/io/gobelieve/im/demo/model/MessageDatabaseHelper.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package io.gobelieve.im.demo.model;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class MessageDatabaseHelper {
    private static final String TAG = "goubuli";

    private static final int DATABASE_VERSION  = 3;

    private static final Object lock = new Object();

    private static MessageDatabaseHelper instance;
    private DatabaseHelper databaseHelper;


    private static class DatabaseHelper extends SQLiteOpenHelper {

        DatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.beginTransaction();
            createDatabase(db);
            db.setTransactionSuccessful();
            db.endTransaction();
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            Log.d(TAG, "upgrade database, old version:" + oldVersion + " new version:" + newVersion);
            assert(newVersion == 3);
        }

        private void createDatabase(SQLiteDatabase db) {
            db.execSQL(SQLCreator.PEER_MESSAGE);
            db.execSQL(SQLCreator.GROUP_MESSAGE);
            db.execSQL(SQLCreator.CUSTOMER_MESSAGE);
            db.execSQL(SQLCreator.PEER_MESSAGE_FTS);
            db.execSQL(SQLCreator.GROUP_MESSAGE_FTS);
            db.execSQL(SQLCreator.CUSTOMER_MESSAGE_FTS);
            db.execSQL(SQLCreator.GROUP_MESSAGE_READED);

            db.execSQL(SQLCreator.PEER_MESSAGE_IDX);
            db.execSQL(SQLCreator.PEER_MESSAGE_UUID_IDX);
            db.execSQL(SQLCreator.GROUP_MESSAGE_IDX);
            db.execSQL(SQLCreator.GROUP_MESSAGE_UUID_IDX);

            db.execSQL(SQLCreator.CUSTOMER_MESSAGE_IDX);
            db.execSQL(SQLCreator.CUSTOMER_PEER_MESSAGE_IDX);
            db.execSQL(SQLCreator.CUSTOMER_MESSAGE_UUID_IDX);

            db.execSQL(SQLCreator.CONVERSATION);
            db.execSQL(SQLCreator.CONVERSATION_IDX);
        }
    }

    public static MessageDatabaseHelper getInstance() {
        synchronized (lock) {
            if (instance == null)
                instance = new MessageDatabaseHelper();
            return instance;
        }
    }

    private MessageDatabaseHelper() {

    }

    public void open(Context context, String name) {
        if (this.databaseHelper != null) {
            this.databaseHelper.close();
        }
        this.databaseHelper = new DatabaseHelper(context, name, null, DATABASE_VERSION);
    }

    public SQLiteDatabase getDatabase() {
        return this.databaseHelper.getWritableDatabase();
    }

    public void close() {
        if (this.databaseHelper != null) {
            this.databaseHelper.close();
            this.databaseHelper = null;
        }
    }
}


================================================
FILE: app/src/io/gobelieve/im/demo/model/SQLCreator.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package io.gobelieve.im.demo.model;

public class SQLCreator {
    //cid:peer_uid|group_id|store_id
    public final static String CONVERSATION = "CREATE TABLE IF NOT EXISTS \"conversation\" "
            + "(\"id\" INTEGER PRIMARY KEY NOT NULL , "
            + "\"appid\" INTEGER DEFAULT 0, "
            + "\"target\" INTEGER NOT NULL, "
            + "\"type\" INTEGER NOT NULL, "
            + "\"name\" VARCHAR(255), "
            + "\"attrs\" TEXT, "
            + "\"flags\" INTEGER DEFAULT 0, "
            + "\"detail\" TEXT, "
            + "\"state\" INTEGER DEFAULT 0, "
            + "\"timestamp\" INTEGER DEFAULT 0, "
            + "\"unread\" INTEGER DEFAULT 0) ";


    public final static String CONVERSATION_IDX = "CREATE UNIQUE INDEX [conversation_idx] On [conversation] ( [appid], [target], [type] );";

    public final static String PEER_MESSAGE = "CREATE TABLE \"peer_message\" ( `id` INTEGER PRIMARY KEY AUTOINCREMENT, `peer` INTEGER NOT NULL, `secret` INTEGER DEFAULT 0, `sender` INTEGER NOT NULL, `receiver` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `flags` INTEGER NOT NULL, `content` TEXT, `uuid` TEXT );";

    public final static String GROUP_MESSAGE = "CREATE TABLE \"group_message\" ( `id` INTEGER PRIMARY KEY AUTOINCREMENT, `sender` INTEGER NOT NULL, `group_id` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `flags` INTEGER NOT NULL, `reader_count` INTEGER DEFAULT 0, `content` TEXT, `uuid` TEXT, `reference_count` INTEGER DEFAULT 0, `reference` TEXT,  `tags` TEXT  );";

    public final static String CUSTOMER_MESSAGE = "CREATE TABLE \"customer_message\" ( `id` INTEGER PRIMARY KEY AUTOINCREMENT, `peer_appid` INTEGER NOT NULL, `peer` INTEGER NOT NULL, `store_id` INTEGER NOT NULL, `sender_appid` INTEGER NOT NULL, `sender` INTEGER NOT NULL, `receiver_appid` INTEGER NOT NULL,  `receiver` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `flags` INTEGER NOT NULL, `content` TEXT, `uuid` TEXT );";

    public final static String PEER_MESSAGE_FTS = "CREATE VIRTUAL TABLE peer_message_fts USING fts4(content TEXT);";

    public final static String GROUP_MESSAGE_FTS = "CREATE VIRTUAL TABLE group_message_fts USING fts4(content TEXT);";

    public final static String CUSTOMER_MESSAGE_FTS = "CREATE VIRTUAL TABLE customer_message_fts USING fts4(content TEXT);";

    public final static String PEER_MESSAGE_IDX = "CREATE INDEX `peer_index` ON `peer_message` (`peer`, `secret`, `id`);";
    public final static String GROUP_MESSAGE_IDX = "CREATE INDEX `group_index` ON `group_message` (`group_id`);";
    public final static String CUSTOMER_MESSAGE_IDX = "CREATE INDEX `customer_index` ON `customer_message` (`store_id`);";
    public final static String CUSTOMER_PEER_MESSAGE_IDX = "CREATE INDEX `customer_peer_index` ON `customer_message` (`peer_appid`, `peer`);";

    public final static String PEER_MESSAGE_UUID_IDX = "CREATE UNIQUE INDEX `peer_uuid_index` ON `peer_message` (`uuid`)";
    public final static String GROUP_MESSAGE_UUID_IDX = "CREATE UNIQUE INDEX `group_uuid_index` ON `group_message` (`uuid`)";
    public final static String CUSTOMER_MESSAGE_UUID_IDX = "CREATE UNIQUE INDEX `customer_uuid_index` ON `customer_message` (`uuid`)";


    public final static String GROUP_MESSAGE_READED = "CREATE TABLE \"group_message_readed\" ( `msg_id` INTEGER NOT NULL, `uid` INTEGER NOT NULL, PRIMARY KEY(`msg_id`,`uid`) )";

}


================================================
FILE: asynctcp/.gitignore
================================================
/build


================================================
FILE: asynctcp/build.gradle
================================================
apply plugin: 'com.android.library'


android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion

    defaultConfig {
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_6
        targetCompatibility JavaVersion.VERSION_1_6
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }


    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
}


================================================
FILE: asynctcp/src/androidTest/java/com/beetle/asynctcp/ApplicationTest.java
================================================
package com.beetle.asynctcp;

import android.app.Application;
import android.test.ApplicationTestCase;

/**
 * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
 */
public class ApplicationTest extends ApplicationTestCase<Application> {
    public ApplicationTest() {
        super(Application.class);
    }
}

================================================
FILE: asynctcp/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.beetle.asynctcp">


</manifest>


================================================
FILE: asynctcp/src/main/java/com/beetle/AsyncSSLTCP.java
================================================
package com.beetle;

public class AsyncSSLTCP implements AsyncTCPInterface {
    private int sock;
    private int events;
    private boolean closed;
    private int state;
    private long ssl;
    private long sslCTX;

    private byte[] data;
    
    private TCPConnectCallback connectCallback;
    private TCPReadCallback readCallback;
    private long self;
   

    public void setConnectCallback(TCPConnectCallback cb) {
	connectCallback = cb;
    }
    public void setReadCallback(TCPReadCallback cb) {
	readCallback = cb;
    }
    public native boolean connect(String host, int port);
    public native void close();
    public native void release();

    public native void writeData(byte[] bytes);
    
    public native void startRead();
  

    static {
        System.loadLibrary("async_ssl_tcp");
    }
}


================================================
FILE: asynctcp/src/main/java/com/beetle/AsyncTCP.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package com.beetle;

import java.lang.ref.WeakReference;

public class AsyncTCP implements AsyncTCPInterface {
    private int sock;
    private int events;
    private boolean closed;

    private byte[] data;
    private boolean connecting;
    
    private TCPConnectCallback connectCallback;
    private TCPReadCallback readCallback;
    private long self;
   

    public void setConnectCallback(TCPConnectCallback cb) {
	connectCallback = cb;
    }
    public void setReadCallback(TCPReadCallback cb) {
	readCallback = cb;
    }
    public native boolean connect(String host, int port);
    public native void close();
    public native void release();

    public native void writeData(byte[] bytes);
    
    public native void startRead();
  

    static {
        System.loadLibrary("async_tcp");
    }
}


================================================
FILE: asynctcp/src/main/java/com/beetle/AsyncTCPInterface.java
================================================
package com.beetle;

public interface AsyncTCPInterface {

    public void setConnectCallback(TCPConnectCallback cb);
    public void setReadCallback(TCPReadCallback cb);
    public boolean connect(String host, int port);

    // close async tcp only stop read&write.
    public void close();

    // release the underline resource, like socket fd, java object weak reference.
    public void release();

    public void writeData(byte[] bytes);

    public void startRead();
}


================================================
FILE: asynctcp/src/main/java/com/beetle/AsyncTCPTest.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package com.beetle;

import android.app.Activity;
import android.os.Bundle;
import	android.os.Looper;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;



public class AsyncTCPTest extends Activity  {
	AsyncTCP tcp;
	byte[] recvBuf = new byte[0];
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        Button bt = new Button(this);
        bt.setText( "start" );
        setContentView(bt);
        
                
        bt.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				test();
			}
		});
    }
    
    
    public void test() {
    	if (tcp != null) return;
    	tcp = new AsyncTCP();

    	
    	TCPConnectCallback cb = new TCPConnectCallback() {
    		public void onConnect(Object tcp1, int status) {
    		    if (status != 0) {
    		    	Log.i("Beetle", "connect error");
    		    	tcp.close();
    		    	return;
    		    }
    		    Log.i("Beetle", "connected");
    		    byte[] data = "GET / HTTP/1.1\r\nHost: www.baidu.com\r\nConnection: close\r\n\r\n".getBytes();
    		    tcp.writeData(data);

    		    tcp.startRead();
    		}
    	    };
    	TCPReadCallback read_cb = new TCPReadCallback() {
    		public void onRead(Object tcp1, byte[] data) {
    		    if (data.length == 0) {
    		    	try {
    		    		String result = new String(recvBuf, "UTF-8");
    		    		Log.i("Beetle", result);
    		    	} catch(Exception e) {

    		    	}
    		    	Log.i("Beetle", "tcp closed");
    		    	tcp.close();
    		    	return;
    		    }
    		    
    		    byte[] result = new byte[recvBuf.length + data.length]; 
		        System.arraycopy(recvBuf, 0, result, 0, recvBuf.length); 
		        System.arraycopy(data, 0, result, recvBuf.length, data.length);
		        recvBuf = result;
    		    Log.i("Beetle", "recv data");
    		}	
    		};
    	tcp.setConnectCallback(cb);
    	tcp.setReadCallback(read_cb);
    	tcp.connect("www.baidu.com", 80);
    }
}


================================================
FILE: asynctcp/src/main/java/com/beetle/TCPConnectCallback.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package com.beetle;

public interface TCPConnectCallback {
 
    public void onConnect(Object tcp, int status);
 
}


================================================
FILE: asynctcp/src/main/java/com/beetle/TCPReadCallback.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package com.beetle;

 
public interface TCPReadCallback {
 
    public void onRead(Object tcp, byte[] data);
 
}


================================================
FILE: asynctcp/src/main/res/values/strings.xml
================================================
<resources>
    <string name="app_name">AsyncTCP</string>
</resources>


================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.1.1"
    }
}

ext {
    // Compilation (defined here to ensure consistency between the library and sample app)
    compileSdkVersion = 29
    buildToolsVersion = '29.0.2'

    //android 6.0
    minSdkVersion = 23
    //android 10.0
    targetSdkVersion = 29
    javaVersion = JavaVersion.VERSION_1_8
}


allprojects {
    repositories {
        google()
        jcenter()
    }
}


================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Fri Aug 23 16:50:47 CST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip


================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Settings specified in this file will override any Gradle settings
# configured through the IDE.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.enableJetifier=true
android.useAndroidX=true

================================================
FILE: gradlew
================================================
#!/usr/bin/env bash

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn ( ) {
    echo "$*"
}

die ( ) {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
esac

# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
    JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"


================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windowz variants

if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*
goto execute

:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: imkit/build.gradle
================================================
apply plugin: 'com.android.library'


android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion

    defaultConfig {
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }


    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation project(':imsdk')
    implementation project(':imlib')

    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'androidx.appcompat:appcompat:1.0.0'
    implementation 'androidx.recyclerview:recyclerview:1.0.0';
    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'


    implementation 'com.google.code.gson:gson:2.8.6'
    implementation 'com.squareup.picasso:picasso:2.71828'
    implementation 'com.squareup.retrofit:retrofit:1.9.0'
    implementation 'com.netflix.rxjava:rxjava-core:0.20.7'
    implementation 'com.netflix.rxjava:rxjava-android:0.20.7'
    implementation 'com.squareup.okhttp3:okhttp:4.2.2'
    implementation 'org.apache.commons:commons-io:1.3.2'
    implementation 'joda-time:joda-time:2.10.5'
    implementation 'com.commit451:PhotoView:1.2.5'
    implementation 'cjt.library.wheel:camera:1.1.9'
    implementation 'com.linkedin.android.spyglass:spyglass:2.0.1'
    implementation 'co.lujun:androidtagview:1.1.7'

//    implementation 'com.google.code.gson:gson:2.8.5'
//    implementation 'com.squareup.picasso:picasso:2.71828'
//    implementation 'com.squareup.retrofit:retrofit:1.9.0'
//    implementation 'com.netflix.rxjava:rxjava-core:0.20.7'
//    implementation 'com.netflix.rxjava:rxjava-android:0.20.7'
//    implementation 'com.squareup.okhttp3:okhttp:4.1.0'
//    implementation 'org.apache.commons:commons-io:1.3.2'
//    implementation 'joda-time:joda-time:2.10.3'
//    implementation 'com.commit451:PhotoView:1.2.5'
//    implementation 'com.linkedin.android.spyglass:spyglass:1.4.0'
//    implementation 'cjt.library.wheel:camera:1.1.9'


}


================================================
FILE: imkit/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.beetle.imkit">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                     android:maxSdkVersion="18"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <application>



    </application>



</manifest>

================================================
FILE: imkit/src/main/assets/emoticon
================================================
emoticon_0.png,[微笑]
emoticon_1.png,[撇嘴]
emoticon_2.png,[色]
emoticon_3.png,[发呆]
emoticon_4.png,[得意]
emoticon_5.png,[流泪]
emoticon_6.png,[害羞]
emoticon_7.png,[闭嘴]
emoticon_8.png,[睡]
emoticon_9.png,[大哭]
emoticon_10.png,[尴尬]
emoticon_11.png,[发怒]
emoticon_12.png,[调皮]
emoticon_13.png,[呲牙]
emoticon_14.png,[惊讶]
emoticon_15.png,[难过]
emoticon_16.png,[酷]
emoticon_17.png,[囧]
emoticon_18.png,[抓狂]
emoticon_19.png,[吐]
emoticon_20.png,[偷笑]
emoticon_21.png,[愉快]
emoticon_22.png,[白眼]
emoticon_23.png,[傲慢]
emoticon_24.png,[饥饿]
emoticon_25.png,[困]
emoticon_26.png,[惊恐]
emoticon_27.png,[流汗]
emoticon_28.png,[憨笑]
emoticon_29.png,[悠闲]
emoticon_30.png,[奋斗]
emoticon_31.png,[咒骂]
emoticon_32.png,[疑问]
emoticon_33.png,[嘘]
emoticon_34.png,[晕]
emoticon_35.png,[疯了]
emoticon_36.png,[衰]
emoticon_37.png,[骷髅]
emoticon_38.png,[敲打]
emoticon_39.png,[再见]
emoticon_40.png,[擦汗]
emoticon_41.png,[抠鼻]
emoticon_42.png,[鼓掌]
emoticon_43.png,[糗大了]
emoticon_44.png,[坏笑]
emoticon_45.png,[左哼哼]
emoticon_46.png,[右哼哼]
emoticon_47.png,[哈欠]
emoticon_48.png,[鄙视]
emoticon_49.png,[委屈]
emoticon_50.png,[快哭了]
emoticon_51.png,[阴险]
emoticon_52.png,[亲亲]
emoticon_53.png,[吓]
emoticon_54.png,[可怜]
emoticon_55.png,[菜刀]
emoticon_56.png,[西瓜]
emoticon_57.png,[啤酒]
emoticon_58.png,[篮球]
emoticon_59.png,[乒乓]
emoticon_60.png,[咖啡]
emoticon_61.png,[饭]
emoticon_62.png,[猪头]
emoticon_63.png,[玫瑰]
emoticon_64.png,[凋谢]
emoticon_65.png,[嘴唇]
emoticon_66.png,[爱心]
emoticon_67.png,[心碎]
emoticon_68.png,[蛋糕]
emoticon_69.png,[闪电]
emoticon_70.png,[炸弹]
emoticon_71.png,[刀]
emoticon_72.png,[足球]
emoticon_73.png,[瓢虫]
emoticon_74.png,[便便]
emoticon_75.png,[月亮]
emoticon_76.png,[太阳]
emoticon_77.png,[礼物]
emoticon_78.png,[拥抱]
emoticon_79.png,[强]
emoticon_80.png,[弱]
emoticon_81.png,[握手]
emoticon_82.png,[胜利]
emoticon_83.png,[抱拳]
emoticon_84.png,[勾引]
emoticon_85.png,[拳头]
emoticon_89.png,[OK]
emoticon_92.png,[跳跳]
emoticon_93.png,[发抖]
emoticon_94.png,[怄火]
emoticon_95.png,[转圈]
emoticon_105.png,[嘿哈]
emoticon_106.png,[捂脸]
emoticon_107.png,[奸笑]
emoticon_109.png,[發]
emoticon_110.png,[福]
wx_emoji_11.png,[机智]
wx_emoji_12.png,[皱眉]
wx_emoji_13.png,[耶]
wx_emoji_19.png,[红包]

================================================
FILE: imkit/src/main/java/com/beetle/bauhinia/ChatItemQuickAction.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


/**
 * 私聊长按弹出操作
 */

package com.beetle.bauhinia;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;

import com.beetle.imkit.R;

public class ChatItemQuickAction {
    public enum ChatQuickAction {
        DELETE, FORWARD, RESEND, COPY, REVOKE;

        public String getName(Context context) {
            switch (this) {
                case DELETE:
                    return context.getString(R.string.im_btn_del);
                case FORWARD:
                    return context.getString(R.string.im_btn_forward);
                case RESEND:
                    return context.getString(R.string.im_btn_resend);
                case COPY:
                    return context.getString(R.string.im_btn_copy);
                case REVOKE:
                    return context.getString(R.string.im_btn_revoke);
            }
            return "";
        }
    }

    public interface ChatQuickActionResult {
        void onSelect(ChatQuickAction action);
    }

    public static void showAction(Context context, final ChatQuickAction[] actions,
            final ChatQuickActionResult result) {
        if (actions == null || actions.length < 1)
            return;
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle(context.getString(R.string.im_title_choose));
        CharSequence[] items = new CharSequence[actions.length];
        for (int i = 0; i < actions.length; ++i) {
            items[i] = actions[i].getName(context);
        }
        builder.setItems(items, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int item) {
                if (result != null) {
                    result.onSelect(actions[item]);
                }
            }
        }).show();
    }
}


================================================
FILE: imkit/src/main/java/com/beetle/bauhinia/CustomerMessageActivity.java
================================================
package com.beetle.bauhinia;

import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.beetle.bauhinia.api.IMHttpAPI;
import com.beetle.bauhinia.api.types.Supporter;
import com.beetle.bauhinia.db.CustomerMessageDB;
import com.beetle.bauhinia.db.ICustomerMessage;
import com.beetle.bauhinia.db.MessageFlag;
import com.beetle.bauhinia.db.message.MessageContent;
import com.beetle.bauhinia.db.message.Revoke;
import com.beetle.bauhinia.tools.FileDownloader;
import com.beetle.im.CustomerMessage;
import com.beetle.im.CustomerMessageObserver;
import com.beetle.bauhinia.outbox.CustomerOutbox;
import com.beetle.bauhinia.db.IMessage;
import com.beetle.bauhinia.db.MessageIterator;
import com.beetle.im.IMService;
import com.beetle.im.IMServiceObserver;

import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;

/**
 * Created by houxh on 16/1/18.
 */
public class CustomerMessageActivity extends MessageActivity
        implements CustomerMessageObserver, IMServiceObserver {
    protected String sessionID;
    protected long currentUID;
    protected long appid;//当前appid
    protected long peerAppID;
    protected long peerUID;
    protected long storeID;

    protected String name;//当前用户昵称
    protected String appName;
    protected String peerName;
    protected String peerAppName;
    protected String storeName;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        items[ITEM_VIDEO_CALL_ID] = false;
        super.onCreate(savedInstanceState);
        isShowUserName = true;
        isShowReaded = false;
        isShowReply = false;

        Intent intent = getIntent();
        appid = intent.getLongExtra("app_id", 0);
        currentUID = intent.getLongExtra("current_uid", 0);
        storeID = intent.getLongExtra("store_id", 0);
        peerUID = intent.getLongExtra("peer_uid", 0);
        peerAppID = intent.getLongExtra("peer_app_id", 0);

        peerName = intent.getStringExtra("peer_name");
        if (peerName == null) {
            peerName = "";
        }

        peerAppName = intent.getStringExtra("peer_app_name");
        if (peerAppName == null) {
            peerAppName = "";
        }

        storeName = intent.getStringExtra("store_name");
        if (storeName == null) {
            storeName = "";
        }

        sessionID = intent.getStringExtra("session_id");
        if (sessionID == null) {
            sessionID = "";
        }
        appName = intent.getStringExtra("app_name");
        if (appName == null) {
            appName = "";
        }
        name = intent.getStringExtra("name");
        if (name == null) {
            name = "";
        }

        if (appid == 0 || currentUID == 0) {
            Log.e(TAG, "invalid param");
            finish();
            return;
        }

        Log.i(TAG, "appid:" + appid +" uid:" + currentUID + " peer app id:" + peerAppID + " peer uid:" + peerUID + " store id:" + storeID);

        this.conversationID = "" + peerAppID + "_" + peerUID;
        this.messageDB = CustomerMessageDB.getInstance();
        this.hasLateMore = this.messageID > 0;
        this.hasEarlierMore = true;
        this.loadData();

        if (!TextUtils.isEmpty(storeName)) {
            getSupportActionBar().setTitle(storeName);
        }
        //显示最后一条消息
        if (this.messages.size() > 0) {
            listview.setSelection(this.messages.size() - 1);
        }

        CustomerOutbox.getInstance().addObserver(this);
        IMService.getInstance().addObserver(this);
        IMService.getInstance().addCustomerServiceObserver(this);
        FileDownloader.getInstance().addObserver(this);

        if (peerAppID == 0 || peerUID == 0) {
            this.disableSend();

            IMHttpAPI.Singleton().getSupporter(this.storeID)
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Action1<Supporter>() {
                        @Override
                        public void call(Supporter supporter) {
                            Log.i(TAG, "got supporter:" + supporter.id + " name:" + supporter.name);
                            peerAppID = supporter.appid;
                            peerUID = supporter.id;
                            IMService.ConnectState state = IMService.getInstance().getConnectState();
                            if (state == IMService.ConnectState.STATE_CONNECTED) {
                                enableSend();
                            }
                        }
                    }, new Action1<Throwable>() {
                        @Override
                        public void call(Throwable throwable) {
                            Log.e(TAG, "get supporter err:" + throwable.getMessage());
                        }
                    });
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "peer message activity destory");

        CustomerOutbox.getInstance().removeObserver(this);
        IMService.getInstance().removeObserver(this);
        IMService.getInstance().removeCustomerServiceObserver(this);
        FileDownloader.getInstance().removeObserver(this);
    }



    @Override
    public void onConnectState(IMService.ConnectState state) {
        if (state == IMService.ConnectState.STATE_CONNECTED) {
            if (peerAppID != 0 && peerUID != 0) {
                enableSend();
            }
        } else {
            disableSend();
        }
    }



    @Override
    public void onCustomerMessage(CustomerMessage msg) {
        Log.i(TAG, "recv msg:" + msg.content);
        final ICustomerMessage imsg = new ICustomerMessage();
        imsg.timestamp = msg.timestamp;
        imsg.msgLocalID = msg.msgLocalID;

        imsg.senderAppID = msg.senderAppID;
        imsg.sender = msg.sender;
        imsg.receiverAppID = msg.receiverAppID;
        imsg.receiver = msg.receiver;
        if (msg.senderAppID == appid && msg.sender == this.currentUID) {
            imsg.isOutgoing = true;
            imsg.flags |= MessageFlag.MESSAGE_FLAG_ACK;
        } else {
            imsg.isOutgoing = false;
        }
        imsg.setContent(msg.content);

        long msgPeerAppID;
        long msgPeer;

        if (imsg.isOutgoing) {
            msgPeerAppID = msg.receiverAppID;
            msgPeer = msg.receiver;
        } else {
            msgPeerAppID = msg.senderAppID;
            msgPeer = msg.sender;
        }

        if (peerAppID != 0 && peerUID != 0) {
            if (msgPeerAppID != peerAppID || msgPeer != peerUID) {
                return;
            }
        }

        if (storeID != 0 && imsg.getStoreId() != storeID) {
            return;
        }

        IMessage mm = findMessage(imsg.getUUID());
        if (mm != null) {
            Log.i(TAG, "receive repeat message:" + imsg.getUUID());
            if (imsg.isOutgoing) {
                int flags = imsg.flags;
                flags = flags & ~MessageFlag.MESSAGE_FLAG_FAILURE;
                flags = flags | MessageFlag.MESSAGE_FLAG_ACK;
                mm.setFlags(flags);
            }
            return;
        }
        if (msg.isSelf) {
            return;
        }

        loadUserName(imsg);
        downloadMessageContent(imsg);
        updateNotificationDesc(imsg);
        if (imsg.getType() == MessageContent.MessageType.MESSAGE_REVOKE) {
            Revoke revoke = (Revoke)imsg.content;
            IMessage m = findMessage(revoke.msgid);
            if (m != null) {
                deleteMessage(m);
            }
        }
        insertMessage(imsg);
    }

    @Override
    public void onCustomerMessageACK(CustomerMessage msg) {

        Log.i(TAG, "customer service message ack");

        if (msg.msgLocalID > 0) {
            IMessage imsg = findMessage(msg.msgLocalID);
            if (imsg == null) {
                Log.i(TAG, "can't find msg:" + msg.msgLocalID);
                return;
            }
            imsg.setAck(true);
        } else {
            MessageContent c = IMessage.fromRaw(msg.content);
            if (c.getType() == MessageContent.MessageType.MESSAGE_REVOKE) {
                Revoke r = (Revoke)c;
                IMessage imsg = findMessage(r.msgid);
                if (imsg == null) {
                    Log.i(TAG, "can't find msg:" + r.msgid);
                    return;
                }
                imsg.setContent(r);
                updateNotificationDesc(imsg);
                adapter.notifyDataSetChanged();
            }
        }
    }

    @Override
    public void onCustomerMessageFailure(CustomerMessage msg) {
        Log.i(TAG, "message failure");

        if (msg.msgLocalID > 0) {
            IMessage imsg = findMessage(msg.msgLocalID);
            if (imsg == null) {
                Log.i(TAG, "can't find msg:" + msg.msgLocalID);
                return;
            }
            imsg.setFailure(true);
        } else {
            MessageContent c = IMessage.fromRaw(msg.content);
            if (c.getType() == MessageContent.MessageType.MESSAGE_REVOKE) {
                Toast.makeText(this, "撤回失败", Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    protected MessageIterator createMessageIterator() {
        CustomerMessageDB db = (CustomerMessageDB) messageDB;
        MessageIterator iter = db.newMessageIterator(storeID);
        return iter;
    }

    @Override
    protected MessageIterator createForwardMessageIterator(long messageID) {
        CustomerMessageDB db = (CustomerMessageDB) messageDB;
        MessageIterator iter = db.newForwardMessageIterator(storeID, messageID);
        return iter;
    }

    @Override
    protected MessageIterator createBackwardMessageIterator(long messageID) {
        CustomerMessageDB db = (CustomerMessageDB) messageDB;
        MessageIterator iter = db.newBackwardMessageIterator(storeID, messageID);
        return iter;
    }

    @Override
    protected MessageIterator createMiddleMessageIterator(long messageID) {
        CustomerMessageDB db = (CustomerMessageDB) messageDB;
        MessageIterator iter = db.newMiddleMessageIterator(storeID, messageID);
        return iter;
    }


    @Override
    protected boolean getMessageOutgoing(IMessage msg) {
        ICustomerMessage m = (ICustomerMessage)msg;
        return (msg.sender == currentUID && m.senderAppID == appid);
    }

    @Override
    protected void sendMessage(IMessage imsg) {
        CustomerOutbox.getInstance().sendMessage(imsg);
    }

    @Override
    protected IMessage newOutMessage(MessageContent content) {
        ICustomerMessage msg = new ICustomerMessage();
        msg.senderAppID = appid;
        msg.sender = currentUID;
        msg.receiverAppID = peerAppID;
        msg.receiver = peerUID;

        content.generateRaw(storeID, sessionID, storeName, name, appName);
        msg.content = content;
        return msg;
    }


    @Override
    protected void loadUserName(IMessage msg) {
        if (!(msg instanceof ICustomerMessage)) {
            return;
        }

        User u = new User();
        ICustomerMessage cm = (ICustomerMessage) msg;
        u.name = msg.content.getName();
        u.identifier = String.format("%d", msg.sender);
        u.avatarURL = "";

        msg.setSenderAvatar(u.avatarURL);
        if (TextUtils.isEmpty(u.name)) {
            msg.setSenderName(u.identifier);
        } else {
            msg.setSenderName(u.name);
        }
    }
}


================================================
FILE: imkit/src/main/java/com/beetle/bauhinia/GroupMessageActivity.java
================================================
package com.beetle.bauhinia;

import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.beetle.bauhinia.db.GroupMessageDB;
import com.beetle.bauhinia.db.IMessage;
import com.beetle.bauhinia.db.MessageFlag;
import com.beetle.bauhinia.db.MessageIterator;
import com.beetle.bauhinia.db.message.GroupNotification;
import com.beetle.bauhinia.db.message.MessageContent;
import com.beetle.bauhinia.db.message.Revoke;
import com.beetle.bauhinia.tools.FileDownloader;
import com.beetle.bauhinia.outbox.GroupOutbox;
import com.beetle.im.GroupMessageObserver;
import com.beetle.im.IMMessage;
import com.beetle.im.IMService;
import com.beetle.im.IMServiceObserver;
import com.beetle.im.MessageACK;

import java.util.List;


/**
 * Created by houxh on 15/3/21.
 */
public class GroupMessageActivity extends MessageActivity implements
        IMServiceObserver, GroupMessageObserver {
    protected long currentUID;
    protected long groupID;
    protected String groupName;

    public GroupMessageActivity() {
        super();
        isShowUserName = true;
        isShowReaded = false;
        isShowReply = false;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        items[ITEM_VIDEO_CALL_ID] = false;
        super.onCreate(savedInstanceState);

        Intent intent = getIntent();

        currentUID = intent.getLongExtra("current_uid", 0);
        if (currentUID == 0) {
            Log.e(TAG, "current uid is 0");
            return;
        }
        groupID = intent.getLongExtra("group_id", 0);
        if (groupID == 0) {
            Log.e(TAG, "peer uid is 0");
            return;
        }
        groupName = intent.getStringExtra("group_name");
        if (groupName == null) {
            Log.e(TAG, "peer name is null");
            return;
        }

        messageID = intent.getIntExtra("message_id", 0);

        getSupportActionBar().setTitle(groupName);

        this.messageDB = GroupMessageDB.getInstance();

        this.hasLateMore = this.messageID > 0;
        this.hasEarlierMore = true;
        this.loadData();

        if (this.messages.size() > 0) {
            if (messageID > 0) {
                int index = -1;
                for (int i = 0; i < this.messages.size(); i++) {
                    if (messageID == this.messages.get(i).msgLocalID) {
                        index = i;
                        break;
                    }
                }

                if (index != -1) {
                    listview.setSelection(index);
                }
            } else {
                //显示最后一条消息
                listview.setSelection(this.messages.size() - 1);
            }
        }

        GroupOutbox.getInstance().addObserver(this);
        IMService.getInstance().addObserver(this);
        IMService.getInstance().addGroupObserver(this);
        FileDownloader.getInstance().addObserver(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "peer message activity destory");

        GroupOutbox.getInstance().removeObserver(this);
        IMService.getInstance().removeObserver(this);
        IMService.getInstance().removeGroupObserver(this);
        FileDownloader.getInstance().removeObserver(this);
    }


    @Override
    public void onConnectState(IMService.ConnectState state) {
        if (state == IMService.ConnectState.STATE_CONNECTED) {
            enableSend();
        } else {
            disableSend();
        }
    }

    @Override
    public void onGroupMessages(List<IMMessage> msgs) {
        for (IMMessage msg : msgs) {
            if (msg.isGroupNotification) {
                assert(msg.sender == 0);
                this.onGroupNotification(msg.content);
            } else {
                this.onGroupMessage(msg);
            }
        }

    }

    public void onGroupMessage(IMMessage msg) {
        if (msg.receiver != groupID) {
            return;
        }
        Log.i(TAG, "recv msg:" + msg.content);
        final IMessage imsg = new IMessage();
        imsg.timestamp = msg.timestamp;
        imsg.msgLocalID = msg.msgLocalID;
        imsg.sender = msg.sender;
        imsg.receiver = msg.receiver;
        imsg.setContent(msg.content);
        imsg.isOutgoing = (msg.sender == this.currentUID);
        if (imsg.isOutgoing) {
            imsg.flags |= MessageFlag.MESSAGE_FLAG_ACK;
        }

        IMessage mm = findMessage(imsg.getUUID());
        if (mm != null) {
            Log.i(TAG, "receive repeat message:" + imsg.getUUID());
            if (imsg.isOutgoing) {
                int flags = imsg.flags;
                flags = flags & ~MessageFlag.MESSAGE_FLAG_FAILURE;
                flags = flags | MessageFlag.MESSAGE_FLAG_ACK;
                mm.setFlags(flags);
            }
            return;
        }

        if (msg.isSelf) {
            return;
        }

        loadUserName(imsg);

        downloadMessageContent(imsg);
        updateNotificationDesc(imsg);
        if (imsg.getType() == MessageContent.MessageType.MESSAGE_REVOKE) {
            Revoke revoke = (Revoke)imsg.content;
            IMessage m = findMessage(revoke.msgid);
            if (m != null) {
                replaceMessage(m, imsg);
            }
        } else {
            insertMessage(imsg);
        }
    }

    @Override
    public void onGroupMessageACK(IMMessage im, int error) {
        long msgLocalID = im.msgLocalID;
        long gid = im.receiver;
        if (gid != groupID) {
            return;
        }
        Log.i(TAG, "message ack");

        if (error == MessageACK.MESSAGE_ACK_SUCCESS) {
            if (msgLocalID > 0) {
                IMessage imsg = findMessage(msgLocalID);
                if (imsg == null) {
                    Log.i(TAG, "can't find msg:" + msgLocalID);
                    return;
                }
                imsg.setAck(true);
            } else {
                MessageContent c = IMessage.fromRaw(im.content);
                if (c.getType() == MessageContent.MessageType.MESSAGE_REVOKE) {
                    Revoke r = (Revoke) c;
                    IMessage imsg = findMessage(r.msgid);
                    if (imsg == null) {
                        Log.i(TAG, "can't find msg:" + msgLocalID);
                        return;
                    }
                    imsg.setContent(r);
                    updateNotificationDesc(imsg);
                    adapter.notifyDataSetChanged();
                }
            }
        } else {
            if (msgLocalID > 0) {
                IMessage imsg = findMessage(msgLocalID);
                if (imsg == null) {
                    Log.i(TAG, "can't find msg:" + msgLocalID);
                    return;
                }
                imsg.setFailure(true);
            } else {
                MessageContent c = IMessage.fromRaw(im.content);
                if (c.getType() == MessageContent.MessageType.MESSAGE_REVOKE) {
                    Toast.makeText(this, "撤回失败", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }

    @Override
    public void onGroupMessageFailure(IMMessage im) {
        long msgLocalID = im.msgLocalID;
        long gid = im.receiver;
        if (gid != groupID) {
            return;
        }
        Log.i(TAG, "message failure");

        if (msgLocalID > 0) {
            IMessage imsg = findMessage(msgLocalID);
            if (imsg == null) {
                Log.i(TAG, "can't find msg:" + msgLocalID);
                return;
            }
            imsg.setFailure(true);
        } else {
            MessageContent c = IMessage.fromRaw(im.content);
            if (c.getType() == MessageContent.MessageType.MESSAGE_REVOKE) {
                Toast.makeText(this, "撤回失败", Toast.LENGTH_SHORT).show();
            }
        }
    }

    public void onGroupNotification(String text) {
        GroupNotification notification = GroupNotification.newGroupNotification(text);

        if (notification.groupID != groupID) {
            return;
        }

        IMessage imsg = new IMessage();
        imsg.sender = 0;
        imsg.receiver = groupID;
        imsg.timestamp = notification.timestamp;
        imsg.setContent(notification);

        updateNotificationDesc(imsg);

        if (notification.notificationType == GroupNotification.NOTIFICATION_GROUP_NAME_UPDATED) {
            this.groupName = notification.groupName;
            getSupportActionBar().setTitle(groupName);
        }
        insertMessage(imsg);
    }

    @Override
    protected User getUser(long uid) {
        User u = new User();
        u.uid = uid;
        u.name = null;
        u.avatarURL = "";
        u.identifier = String.format("name:%d", uid);
        return u;
    }

    @Override
    protected void asyncGetUser(long uid, GetUserCallback cb) {
        final long fuid = uid;
        final GetUserCallback fcb = cb;
        new AsyncTask<Void, Integer, User>() {
            @Override
            protected User doInBackground(Void... urls) {
                User u = new User();
                u.uid = fuid;
                u.name = String.format("name:%d", fuid);
                u.avatarURL = "";
                u.identifier = String.format("name:%d", fuid);
                return u;
            }
            @Override
            protected void onPostExecute(User result) {
                fcb.onUser(result);
            }
        }.execute();
    }


    @Override
    protected MessageIterator createMessageIterator() {
        MessageIterator iter = GroupMessageDB.getInstance().newMessageIterator(groupID);
        return iter;
    }

    @Override
    protected MessageIterator createForwardMessageIterator(long messageID) {
        MessageIterator iter = GroupMessageDB.getInstance().newForwardMessageIterator(groupID, messageID);
        return iter;
    }

    @Override
    protected MessageIterator createBackwardMessageIterator(long messageID) {
        MessageIterator iter = GroupMessageDB.getInstance().newBackwardMessageIterator(groupID, messageID);
        return iter;
    }

    @Override
    protected MessageIterator createMiddleMessageIterator(long messageID) {
        MessageIterator iter = GroupMessageDB.getInstance().newMiddleMessageIterator(groupID, messageID);
        return iter;
    }


    @Override
    protected boolean getMessageOutgoing(IMessage msg) {
        return (msg.sender == currentUID);
    }

    @Override
    protected void sendMessage(IMessage imsg) {
        GroupOutbox.getInstance().sendMessage(imsg);
    }


    @Override
    protected void clearConversation() {
        super.clearConversation();
        GroupMessageDB db = GroupMessageDB.getInstance();
        db.clearConversation(this.groupID);
    }

    @Override
    protected IMessage newOutMessage(MessageContent content) {
        IMessage msg = new IMessage();
        msg.sender = currentUID;
        msg.receiver = groupID;
        msg.receiverCount = 0;
        msg.content = content;
        return msg;
    }
}


================================================
FILE: imkit/src/main/java/com/beetle/bauhinia/MessageActivity.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package com.beetle.bauhinia;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.*;

import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.text.ClipboardManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.*;


import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import com.beetle.bauhinia.activity.*;
import com.beetle.bauhinia.db.IMessage;
import com.beetle.bauhinia.db.message.*;
import com.beetle.bauhinia.db.message.Notification;
import com.beetle.bauhinia.gallery.GalleryImage;
import com.beetle.bauhinia.gallery.ui.GalleryUI;
import com.beetle.bauhinia.outbox.OutboxObserver;
import com.beetle.bauhinia.toolbar.EaseChatExtendMenu;
import com.beetle.bauhinia.toolbar.EaseChatInputMenu;
import com.beetle.bauhinia.tools.*;
import com.beetle.bauhinia.view.*;
import com.beetle.im.IMMessage;
import com.beetle.im.IMService;
import com.beetle.imkit.BuildConfig;

import com.beetle.bauhinia.ChatItemQuickAction.ChatQuickAction;
import com.beetle.imkit.R;


abstract public class MessageActivity extends MessageAudioActivity implements
        SwipeRefreshLayout.OnRefreshListener {

    protected static final String TAG = "imservice";


    //permission request code
    private static final int PERMISSIONS_REQUEST = 2;
    private static final int CAMERA_PERMISSIONS_REQUEST = 3;//拍摄
    private static final int LOCATION_PERMISSIONS_REQUEST = 4;//位置
    private static final int PHOTO_PERMISSIONS_REQUEST = 5;//图片
    private static final int VOICE_PERMISSIONS_REQUEST = 6;//语音


    //activity request code
    public static final int SELECT_PICTURE = 101;
    public static final int SELECT_PICTURE_KITKAT = 102;
    public static final int TAKE_PICTURE = 103;
    public static final int PICK_LOCATION = 104;
    public static final int CAPTURE_CAMERA = 105;
    public static final int SELECT_FILE = 106;

    private static final int IN_MSG = 0;
    private static final int OUT_MSG = 1;

    protected boolean isShowUserName = false;
    protected boolean isShowReply = true;//显示回复信息标志
    protected boolean isShowReaded = true;//显示未读/已读

    protected BaseAdapter adapter;
    protected ListView listview;
    protected SwipeRefreshLayout swipeRefresh;
    
    static final int ITEM_TAKE_PICTURE = 1;
    static final int ITEM_PICTURE = 2;
    static final int ITEM_LOCATION = 3;
    static final int ITEM_VIDEO_CALL = 4;
    static final int ITEM_FILE = 5;


    protected static final int ITEM_TAKE_PICTURE_ID = 0;
    protected static final int ITEM_PICTURE_ID = 1;
    protected static final int ITEM_LOCATION_ID = 2;
    protected static final int ITEM_VIDEO_CALL_ID = 3;
    protected static final int ITEM_FILE_ID = 4;

    protected int[] itemStrings = { R.string.attach_take_pic, R.string.attach_picture,
            R.string.attach_location, R.string.attach_video_call, R.string.attach_file };
    protected int[] itemdrawables = { R.drawable.ease_chat_takepic_selector, R.drawable.ease_chat_image_selector,
            R.drawable.ease_chat_location_selector,  R.drawable.ease_chat_video_call_selector, R.drawable.ease_chat_file_selector};
    protected int[] itemIds = { ITEM_TAKE_PICTURE, ITEM_PICTURE, ITEM_LOCATION, ITEM_VIDEO_CALL, ITEM_FILE };

    protected boolean[] items = {true, true, true, true, true};


    protected MenuItemClickListener extendMenuItemClickListener;
    protected EaseChatInputMenu inputMenu;

    /**
     * 扩展菜单栏item点击事件
     *
     */
    class MenuItemClickListener implements EaseChatExtendMenu.EaseChatExtendMenuItemClickListener{
        @Override
        public void onClick(int itemId, View view) {
            switch (itemId) {
                case ITEM_TAKE_PICTURE: // 拍照
                    takePicture();
                    break;
                case ITEM_PICTURE:
                    getPicture(); // 图库选择图片
                    break;
                case ITEM_LOCATION: // 位置
                    if (checkLocationPermission()) {
                        startActivityForResult(new Intent(MessageActivity.this, LocationPickerActivity.class), PICK_LOCATION);
                    } else {
                        requestLocationPermission();
                    }
                    break;
                case ITEM_VIDEO_CALL:
                    call();
                    break;
                case ITEM_FILE:
                    getFile();
                    break;
                default:
                    break;
            }
        }
    }



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chat);

        File f = new File(getCacheDir(), "bh_audio.amr");
        recordFileName = f.getAbsolutePath();
        Log.i(TAG, "record file name:" + recordFileName);

        extendMenuItemClickListener = new MenuItemClickListener();
        inputMenu = (EaseChatInputMenu)findViewById(R.id.input_menu);
        registerExtendMenuItem();
        inputMenu.init();
        inputMenu.setChatInputMenuListener(new EaseChatInputMenu.ChatInputMenuListener() {

            @Override
            public void onSendMessage(String content, List<Long> at, List<String> atNames) {
                // 发送文本消息
                sendTextMessage(content, at, atNames);
            }

            @Override
            public void onFocusChanged(boolean hasFocus) {
                if (hasFocus) {
                    onInputFocusChanged(hasFocus);
                }
            }

            @Override
            public boolean onPressToSpeakBtnTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        try {
                            if (!checkRecordPermission()) {
                                //用户需要再次操作
                                v.setPressed(false);
                                requestRecordPermission();
                            } else {
                                v.setPressed(true);
                                MessageActivity.this.startRecord();
                            }
                        } catch (Exception e) {
                            v.setPressed(false);
                        }
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        if (event.getY() < 0) {
                             MessageActivity.this.showReleaseToCancelHint();
                        } else {
                             MessageActivity.this.showMoveUpToCancelHint();
                        }
                        return true;
                    case MotionEvent.ACTION_UP:
                        v.setPressed(false);
                        if (event.getY() < 0) {
                            // discard the recorded audio.
                            MessageActivity.this.discardRecord();
                        } else {
                            // stop recording and send voice file
                            MessageActivity.this.stopRecord();
                        }
                        return true;
                    default:
                        MessageActivity.this.discardRecord();
                        return false;
                }
            }
            @Override
            public void onAt() {
                MessageActivity.this.onAt();
            }
        });

        SwipeRefreshLayout swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container);
        swipeLayout.setOnRefreshListener(this);
        swipeRefresh = swipeLayout;

        listview = (ListView)findViewById(R.id.list_view);
        adapter = new ChatAdapter();
        listview.setAdapter(adapter);

        listview.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                //hide keyboard
                if (getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
                    InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                    if (getCurrentFocus() != null) {
                        inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
                    }
                }
                inputMenu.hideExtendMenuContainer();
                inputMenu.clearFocus();
                return false;
            }
        });

        listview.setOnScrollListener(new AbsListView.OnScrollListener() {
            private boolean reachBottom = false;

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if (scrollState == SCROLL_STATE_IDLE && reachBottom) {
                    reachBottom = false;
                    int count = loadLaterData();
                    if (count > 0) {
                        adapter.notifyDataSetChanged();
                    }
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                int visibleThreshold = 2;
                if (totalItemCount <= (firstVisibleItem + visibleItemCount + visibleThreshold)) {
                    reachBottom = true;
                }
            }
        });

        audioUtil = new AudioUtil(this);
        audioUtil.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mediaPlayer) {
                if (MessageActivity.this.playingMessage != null) {
                    MessageActivity.this.playingMessage.setPlaying(false);
                    MessageActivity.this.playingMessage = null;
                }
            }
        });
        audioUtil.setOnStopListener(new AudioUtil.OnStopListener() {
            @Override
            public void onStop(int reason) {
                adapter.notifyDataSetChanged();
            }
        });

        audioRecorder = new AudioRecorder(this, this.recordFileName);

        if (IMService.getInstance().getConnectState() != IMService.ConnectState.STATE_CONNECTED) {
            disableSend();
        }

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onBackPressed() {
        Log.i(TAG, "on back pressed");
        //hide keyboard
        if (getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
            InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            if (getCurrentFocus() != null) {
                inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
            }
        }
        inputMenu.hideExtendMenuContainer();
        inputMenu.clearFocus();

        super.onBackPressed();
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "imactivity destory");
        audioUtil.release();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);


        boolean granted = true;
        for (int i = 0; i < grantResults.length; i++) {
            if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                granted = false;
            }
        }

        if (!granted) {
            return;
        }

        if (requestCode == CAMERA_PERMISSIONS_REQUEST) {
            Intent intent = new Intent(this, CameraActivity.class);
            intent.putExtra("dir", getCacheDir().getAbsolutePath());
            startActivityForResult(intent, CAPTURE_CAMERA);
        } else if (requestCode == LOCATION_PERMISSIONS_REQUEST) {
            startActivityForResult(new Intent(MessageActivity.this, LocationPickerActivity.class), PICK_LOCATION);
        } else if (requestCode == PHOTO_PERMISSIONS_REQUEST) {
            getPicture();
        }
    }

    private boolean checkRecordPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            int recordPermission = (checkSelfPermission(Manifest.permission.RECORD_AUDIO));
            return recordPermission == PackageManager.PERMISSION_GRANTED;
        }
        return true;
    }

    private boolean checkPhotoPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            int readExternalPermission = (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE));
            return readExternalPermission == PackageManager.PERMISSION_GRANTED;
        }
        return true;
    }

    private boolean checkLocationPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            int fineLocationPermission = (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION));
            int coarseLocationPermission = (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION));
            return fineLocationPermission == PackageManager.PERMISSION_GRANTED && coarseLocationPermission == PackageManager.PERMISSION_GRANTED;
        }

        return true;
    }

    private boolean checkCameraPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            int recordPermission = (checkSelfPermission(Manifest.permission.RECORD_AUDIO));
            int cameraPermission = (checkSelfPermission(Manifest.permission.CAMERA));
            return recordPermission == PackageManager.PERMISSION_GRANTED && cameraPermission == PackageManager.PERMISSION_GRANTED;
        }
        return true;
    }

    private void requestRecordPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            String[] array = {Manifest.permission.RECORD_AUDIO};
            this.requestPermissions(array, VOICE_PERMISSIONS_REQUEST);
        }
    }


    private void requestPhotoPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            String[] array = {Manifest.permission.READ_EXTERNAL_STORAGE};
            this.requestPermissions(array, PHOTO_PERMISSIONS_REQUEST);
        }
    }

    private void requestLocationPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            String[] array = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
            this.requestPermissions(array, LOCATION_PERMISSIONS_REQUEST);
        }
    }


    private void requestCameraPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            String[] array = {Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA};
            this.requestPermissions(array, CAMERA_PERMISSIONS_REQUEST);
        }
    }

    /**
     * 注册底部菜单扩展栏item; 覆盖此方法时如果不覆盖已有item,item的id需大于3
     */
    protected void registerExtendMenuItem(){
        for(int i = 0; i < itemStrings.length; i++){
            if (items[i]) {
                inputMenu.registerExtendMenuItem(itemStrings[i], itemdrawables[i], itemIds[i], extendMenuItemClickListener);
            }
        }
    }

    static interface ContentTypes {
        public static int UNKNOWN = 0;
        public static int AUDIO = 2;
        public static int IMAGE = 4;
        public static int LOCATION = 6;
        public static int TEXT = 8;
        public static int NOTIFICATION = 10;
        public static int LINK = 12;
        public static int VOIP = 14;
        public static int FILE = 16;
        public static int VIDEO = 18;
        public static int CLASSROOM = 20;
        public static int CONFERENCE = 22;

    }
    private static int VIEW_TYPE_COUNT = 24;

    class ChatAdapter extends BaseAdapter implements ContentTypes {
        @Override
        public int getCount() {
            return messages.size();
        }
        @Override
        public Object getItem(int position) {
            return messages.get(position);
        }
        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public int getItemViewType(int position) {
            final int basic;
            if (messages.get(position).isOutgoing) {
                basic = OUT_MSG;
            } else {
                basic = IN_MSG;
            }
            return getMediaType(position) + basic;
        }

        int getMediaType(int position) {
            IMessage msg = messages.get(position);
            final int media;
            if (msg.content instanceof Text) {
                media = TEXT;
            } else if (msg.content instanceof Image) {
                media = IMAGE;
            } else if (msg.content instanceof Audio) {
                media = AUDIO;
            } else if (msg.content instanceof Location) {
                media = LOCATION;
            } else if (msg.content instanceof Notification) {
                media = NOTIFICATION;
            } else if (msg.content instanceof Link) {
                media = LINK;
            } else if (msg.content instanceof VOIP) {
                media = VOIP;
            } else if (msg.content instanceof com.beetle.bauhinia.db.message.File) {
                media = FILE;
            } else if (msg.content instanceof Video) {
                media = VIDEO;
            } else if (msg.content instanceof Classroom) {
                media = CLASSROOM;
            } else if (msg.content instanceof Conference) {
                media = CONFERENCE;
            } else {
                media = UNKNOWN;
            }

            return media;
        }

        @Override
        public int getViewTypeCount() {
            return VIEW_TYPE_COUNT;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            IMessage msg = messages.get(position);
            MessageRowView rowView = (MessageRowView)convertView;
            if (rowView == null) {
                MessageContent.MessageType msgType = msg.content.getType();
                if (msg.content instanceof Notification) {
                    rowView = new MiddleMessageView(MessageActivity.this, msgType);
                } else  if (msg.isOutgoing) {
                    OutMessageView msgView = new OutMessageView(MessageActivity.this, msgType, isShowReply, isShowReaded);
                    msgView.readedButton.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            IMessage im = (IMessage)v.getTag();
                            Log.i(TAG, "im:" + im.msgLocalID);
                            MessageActivity.this.openUnread(im);
                        }
                    });
                    rowView = msgView;

                } else {
                    InMessageView msgView = new InMessageView(MessageActivity.this, msgType, isShowUserName, isShowReply);
                    rowView = msgView;
                }
                if (rowView != null) {
                    if (rowView.getContentFrame() != null) {
                        final View contentFrame = rowView.getContentFrame();
                        final GestureDetector detector = new GestureDetector(MessageActivity.this, new GestureDetector.SimpleOnGestureListener() {
                            @Override
                            public boolean onDown(MotionEvent e) {
                                //return true for MotionEvent.ACTION_UP
                                return true;
                            }

                            @Override
                            public boolean onDoubleTap(MotionEvent e) {
                                IMessage im = (IMessage)contentFrame.getTag();
                                if (im.getType() == MessageContent.MessageType.MESSAGE_TEXT) {
                                    Text t = (Text) im.content;
                                    Log.i(TAG, "double click:" + t.text);
                                    Intent intent = new Intent();
                                    intent.setClass(MessageActivity.this, OverlayActivity.class);
                                    intent.putExtra("text", t.text);
                                    MessageActivity.this.startActivity(intent);
                                }
                                return true;
                            }

                            @Override
                            public boolean onSingleTapConfirmed(MotionEvent e) {
                                IMessage im = (IMessage)contentFrame.getTag();
                                Log.i(TAG, "im:" + im.msgLocalID);
                                MessageActivity.this.onMessageClicked(im);
                                return true;
                            }

                            @Override
                            public void onLongPress(MotionEvent e) {
                                final IMessage im = (IMessage)contentFrame.getTag();
                                ArrayList<ChatQuickAction> actions = getLongClickActions(im);
                                if (actions.size() == 0) {
                                    return;
                                }

                                ChatItemQuickAction.showAction(MessageActivity.this,
                                        actions.toArray(new ChatQuickAction[actions.size()]),
                                        new ChatItemQuickAction.ChatQuickActionResult() {
                                            @Override
                                            public void onSelect(ChatQuickAction action) {
                                                onActionClickListener(action, im);
                                            }
                                        }
                                );
                            }
                        });

                        contentFrame.setOnTouchListener(new View.OnTouchListener() {
                            @Override
                            public boolean onTouch(View v, MotionEvent event) {
                                return detector.onTouchEvent(event);
                            }
                        });
                    }

                    if (rowView.getReplyButton() != null) {
                        Button replyBtn = rowView.getReplyButton();
                        replyBtn.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                IMessage im = (IMessage)v.getTag();
                                Log.i(TAG, "im:" + im.msgLocalID);
                                MessageActivity.this.openReply(im);
                            }
                        });
                    }
                }
            }
            rowView.setMessage(msg);
            return rowView;
        }
    }

    protected void disableSend() {
        inputMenu.disableSend();
    }

    protected void enableSend() {
        inputMenu.enableSend();
    }

    public void onRefresh() {
        final SwipeRefreshLayout swipeLayout = (SwipeRefreshLayout)findViewById(R.id.swipe_container);
        swipeLayout.setRefreshing(false);

        int count = loadEarlierData();
        if (count > 0) {
            adapter.notifyDataSetChanged();
            listview.setSelection(count);
        }
    }



    protected void clearConversation() {
        Log.i(TAG, "clearConversation");
        messages = new ArrayList<IMessage>();
        adapter.notifyDataSetChanged();
    }


    @Override
    protected void insertMessage(IMessage imsg) {
        super.insertMessage(imsg);
        adapter.notifyDataSetChanged();
        listview.smoothScrollToPosition(messages.size()-1);
    }

    @Override
    protected void replaceMessage(IMessage imsg, IMessage other) {
        super.replaceMessage(imsg, other);
        adapter.notifyDataSetChanged();
    }

    protected void onInputFocusChanged(boolean hasFocus) {
        if (hasFocus) {
            if (hasLateMore) {
                hasLateMore = false;
                this.messageID = 0;
                messages = new ArrayList<IMessage>();
                loadData();
                adapter.notifyDataSetChanged();
                //scroll to bottom
                if (messages.size() > 0) {
                    listview.setSelection(messages.size() - 1);
                }
            } else {
                listview.setSelection(messages.size() - 1);
            }
        }
    }

    void getPicture() {
        if (!this.checkPhotoPermission()) {
            requestPhotoPermission();
            return;
        }

        if (Build.VERSION.SDK_INT <19){
            Intent intent = new Intent();
            intent.setType("image/*");
            intent.setAction(Intent.ACTION_GET_CONTENT);
            startActivityForResult(Intent.createChooser(intent
                    , getString(R.string.product_fotos_get_from))
                    , SELECT_PICTURE);
        } else {
            Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            startActivityForResult(intent, SELECT_PICTURE_KITKAT);
        }
    }

    void takePicture() {
        if (checkCameraPermission()) {
            Intent intent = new Intent(this, CameraActivity.class);
            intent.putExtra("dir", getCacheDir().getAbsolutePath());
            startActivityForResult(intent, CAPTURE_CAMERA);
        } else {
            requestCameraPermission();
        }
    }

    void getFile() {
        Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
        chooseFile.setType("*/*");
        chooseFile.addCategory(Intent.CATEGORY_OPENABLE);
        chooseFile.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
        chooseFile = Intent.createChooser(chooseFile, "选择文件");
        startActivityForResult(chooseFile, SELECT_FILE);
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode != RESULT_OK) {
            Log.i(TAG, "take or select picture fail:" + resultCode);
            return;
        }

        if (requestCode == SELECT_PICTURE || requestCode == SELECT_PICTURE_KITKAT) {
            try {
                Uri selectedImageUri = data.getData();
                Log.i(TAG, "selected image uri:" + selectedImageUri);
                InputStream is = getContentResolver().openInputStream(selectedImageUri);
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inPreferredConfig = Bitmap.Config.ARGB_8888;
                Bitmap bmp = BitmapFactory.decodeStream(is, null, options);
                sendImageMessage(bmp);
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
        } else if (requestCode == PICK_LOCATION) {
            float longitude = data.getFloatExtra("longitude", 0);
            float latitude = data.getFloatExtra("latitude", 0);
            String address = data.getStringExtra("address");

            Log.i(TAG, "address:" + address + " longitude:" + longitude + " latitude:" + latitude);
            sendLocationMessage(longitude, latitude, address);
        } else if (requestCode == CAPTURE_CAMERA) {
            String videoPath = data.getStringExtra("video_path");
            String thumbPath = data.getStringExtra("thumbnail_path");
            String picturePath = data.getStringExtra("picture_path");

            if (!TextUtils.isEmpty(picturePath)) {
                Log.i(TAG, "take picture success:" + picturePath);
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inPreferredConfig = Bitmap.Config.ARGB_8888;
                Bitmap bmp = BitmapFactory.decodeFile(picturePath, options);
                sendImageMessage(bmp);

                //删除临时文件
                new File(picturePath).delete();
            } else if (!TextUtils.isEmpty(videoPath) && !TextUtils.isEmpty(thumbPath)) {
                Log.i(TAG, "take video success:" + videoPath + " thumbnail path:" + thumbPath);
                sendVideoMessage(videoPath, thumbPath);
            }
        } else if (requestCode == SELECT_FILE) {
            Uri fileUri = data.getData();
            sendFileMessage(fileUri);
        } else {
            Log.i(TAG, "invalide request code:" + requestCode);
            return;
        }
    }



    protected void onMessageClicked(IMessage message) {
        if (message.content instanceof Audio) {
            Audio audio = (Audio) message.content;
            if (FileCache.getInstance().isCached(audio.url)) {
                play(message);
            } else {
                FileDownloader.getInstance().download(message);
            }
        } else if (message.content instanceof Image) {
            navigateToViewImage(message);
        } else if (message.content.getType() == MessageContent.MessageType.MESSAGE_LOCATION) {
            Log.i(TAG, "location message clicked");
            Location loc = (Location)message.content;
            startActivity(MapActivity.newIntent(this, loc.longitude, loc.latitude));
        } else if (message.content.getType() == MessageContent.MessageType.MESSAGE_LINK) {
            Link link = (Link)message.content;
            Intent intent = new Intent();
            intent.putExtra("url", link.url);
            intent.setClass(this, WebActivity.class);
            startActivity(intent);
        } else if (message.getType() == MessageContent.MessageType.MESSAGE_FILE) {
            com.beetle.bauhinia.db.message.File f = (com.beetle.bauhinia.db.message.File)message.content;
            Intent intent = new Intent();
            intent.putExtra("url", f.url);
            intent.putExtra("size", f.size);
            intent.putExtra("filename", f.filename);
            intent.setClass(this, MessageFileActivity.class);
            startActivity(intent);
        } else if (message.getType() == MessageContent.MessageType.MESSAGE_VIDEO) {
            Video v = (Video)message.content;
            Intent intent = new Intent();
            intent.putExtra("url", v.url);
            intent.putExtra("sender", message.sender);
            intent.putExtra("secret", message.secret);
            intent.setClass(this, PlayerActivity.class);
            startActivity(intent);
        }
    }

    private void navigateToViewImage(IMessage imageMessage) {
        ArrayList<IMessage> imageMessages = getImageMessages();
        if (imageMessages == null) {
            return;
        }

        int position = 0;
        ArrayList<GalleryImage> galleryImages = new ArrayList<GalleryImage>();
        for (IMessage msg : imageMessages) {
            Image image = (Image) msg.content;
            if (msg.msgLocalID == imageMessage.msgLocalID) {
                position = galleryImages.size();
            }
            galleryImages.add(new GalleryImage(image.url));
        }
        Intent intent = GalleryUI.getCallingIntent(this, galleryImages, position);
        startActivity(intent);
    }

    protected void call() {}

    protected void onAt() {}

    protected void forward(IMessage im) {}

    protected void openUnread(IMessage im) {}

    protected void openReply(IMessage message) {

    }

    protected ArrayList<ChatQuickAction> getLongClickActions(IMessage im) {
        ArrayList<ChatQuickAction> actions = new ArrayList<ChatQuickAction>();

        if (im.content.getType() == MessageContent.MessageType.MESSAGE_TEXT) {
            actions.add(ChatItemQuickAction.ChatQuickAction.COPY);
        }

        if (im.isFailure()) {
            actions.add(ChatQuickAction.RESEND);
        } else {
            if (im.content.getType() == MessageContent.MessageType.MESSAGE_TEXT ||
                    im.content.getType() == MessageContent.
                            MessageType.MESSAGE_IMAGE ||
                    im.content.getType() == MessageContent.
                            MessageType.MESSAGE_AUDIO ||
                    im.content.getType() == MessageContent.
                            MessageType.MESSAGE_VIDEO ||
                    im.content.getType() == MessageContent.
                            MessageType.MESSAGE_LOCATION ||
                    im.content.getType() == MessageContent.MessageType.MESSAGE_FILE) {
                actions.add(ChatQuickAction.FORWARD);
            }
        }
        int now = now();
        if (now >= im.timestamp && (now - im.timestamp) < (REVOKE_EXPIRE-10) && im.isOutgoing) {
            actions.add(ChatQuickAction.REVOKE);
        }
        return actions;
    }

    protected void onActionClickListener(ChatQuickAction action, IMessage im) {
        switch (action) {
            case COPY:
                ClipboardManager clipboard =
                        (ClipboardManager)MessageActivity.this
                                .getSystemService(Context.CLIPBOARD_SERVICE);
                clipboard.setText(((Text) im.content).text);
                break;
            case RESEND:
                MessageActivity.this.resend(im);
                break;
            case REVOKE:
                MessageActivity.this.revoke(im);
                break;
            case FORWARD:
                MessageActivity.this.forward(im);
            default:
                break;
        }

    }

}


================================================
FILE: imkit/src/main/java/com/beetle/bauhinia/MessageAudioActivity.java
================================================
package com.beetle.bauhinia;

import android.app.Activity;
import android.app.AlertDialog;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.beetle.bauhinia.db.IMessage;
import com.beetle.bauhinia.db.message.Audio;
import com.beetle.bauhinia.tools.AudioRecorder;
import com.beetle.bauhinia.tools.AudioUtil;
import com.beetle.bauhinia.tools.DeviceUtil;
import com.beetle.bauhinia.tools.FileCache;
import com.beetle.imkit.R;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.TimerTask;

abstract public class MessageAudioActivity extends MessageBaseActivity {
    IMessage playingMessage;

    //录音相关
    protected Handler mHandler = new Handler();
    protected java.util.Timer sixtySecondsTimer;
    protected java.util.Timer recordingTimer;
    protected AlertDialog alertDialog;

    protected ImageView recordingImageBG;

    protected ImageView recordingImage;

    protected TextView recordingText;

    protected Date mBegin;

    protected String recordFileName;

    protected AudioRecorder audioRecorder;
    protected AudioUtil audioUtil;


    protected class VolumeTimerTask extends TimerTask {
        @Override
        public void run() {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    MessageAudioActivity.this.refreshVolume();
                }
            });
        }
    }


    protected void showReleaseToCancelHint() {
        if (recordingText != null) {
            recordingText.setText(getString(R.string.release_to_cancel));
            recordingText.setBackgroundResource(R.drawable.ease_recording_text_hint_bg);
        }
    }

    protected void showMoveUpToCancelHint() {
        if (recordingText != null) {
            recordingText.setText(getString(R.string.move_up_to_cancel));
            recordingText.setBackgroundColor(Color.TRANSPARENT);
        }
    }

    protected void showRecordDialog() {
        AlertDialog.Builder builder;

        LayoutInflater inflater = (LayoutInflater) this
                .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View layout = inflater.inflate(
                R.layout.conversation_recording_dialog,
                (ViewGroup) findViewById(R.id.conversation_recording));

        recordingImage = (ImageView) layout
                .findViewById(R.id.conversation_recording_range);
        recordingImageBG = (ImageView) layout
                .findViewById(R.id.conversation_recording_white);

        recordingText = (TextView) layout
                .findViewById(R.id.conversation_recording_text);

        showMoveUpToCancelHint();

        builder = new AlertDialog.Builder(this);
        alertDialog = builder.create();
        alertDialog.show();
        alertDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        alertDialog.getWindow().setContentView(layout);
    }

    protected void refreshVolume() {
        if (!this.audioRecorder.isRecording()) {
            return;
        }

        int max = this.audioRecorder.getMaxAmplitude();

        if (max != 0) {
            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) recordingImage
                    .getLayoutParams();
            float scale = max / 7000.0f;
            if (scale < 0.3) {
                recordingImage
                        .setImageResource(R.drawable.record_red);
            } else {
                recordingImage
                        .setImageResource(R.drawable.record_green);
            }
            if (scale > 1) {
                scale = 1;
            }
            int height = recordingImageBG.getHeight()
                    - (int) (scale * recordingImageBG.getHeight());
            params.setMargins(0, 0, 0, -1 * height);
            recordingImage.setLayoutParams(params);

            ((View) recordingImage).scrollTo(0, height);
            // Log.i(TAG, "max amplitude: " + max);
            /**
             * 倒计时提醒
             */
            Date now = new Date();
            long between = (mBegin.getTime() + 60000)
                    - now.getTime();
            if (between < 10000) {
                int second = (int) (Math.floor((between / 1000)));
                if (second == 0) {
                    second = 1;
                }
                recordingText.setText("还剩: " + second + "秒");
            }
        }
    }

    protected void startRecord() {
        if (audioUtil.isPlaying()) {
            audioUtil.stopPlay();
        }

        mBegin = new Date();
        //删除上次录音生成的文件内容
        new File(recordFileName).delete();
        audioRecorder.startRecord();
        sixtySecondsTimer = new java.util.Timer();
        sixtySecondsTimer.schedule(new TimerTask() {

            @Override
            public void run() {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.i(TAG, "recording end by timeout");
                        MessageAudioActivity.this.stopRecord();
                    }
                });
            }
        }, 60000);

        recordingTimer = new java.util.Timer();
        recordingTimer.schedule(new MessageAudioActivity.VolumeTimerTask(), 0, 100);

        showRecordDialog();
    }

    protected void discardRecord() {
        // stop sixty seconds limit
        if (sixtySecondsTimer != null) {
            sixtySecondsTimer.cancel();
            sixtySecondsTimer = null;
        }
        // stop volume task
        if (recordingTimer != null) {
            recordingTimer.cancel();
            recordingTimer = null;
        }
        if (alertDialog != null) {
            alertDialog.dismiss();
        }

        if (MessageAudioActivity.this.audioRecorder.isRecording()) {
            MessageAudioActivity.this.audioRecorder.stopRecord();
        }
    }

    protected void stopRecord() {
        // stop sixty seconds limit
        if (sixtySecondsTimer != null) {
            sixtySecondsTimer.cancel();
            sixtySecondsTimer = null;
        }
        // stop volume task
        if (recordingTimer != null) {
            recordingTimer.cancel();
            recordingTimer = null;
        }
        if (alertDialog != null) {
            alertDialog.dismiss();
        }

        if (MessageAudioActivity.this.audioRecorder.isRecording()) {
            MessageAudioActivity.this.audioRecorder.stopRecord();
            String tfile = audioRecorder.getPathName();
            MessageAudioActivity.this.sendAudioMessage(tfile);
        }
    }



    protected void play(IMessage message) {
        Audio audio = (Audio) message.content;
        Log.i(TAG, "url:" + audio.url);
        if (FileCache.getInstance().isCached(audio.url)) {
            try {
                if (audioRecorder.isRecording()) {
                    audioRecorder.stopRecord();
                }
                if (playingMessage != null && playingMessage == message) {
                    //停止播放
                    audioUtil.stopPlay();
                    playingMessage.setPlaying(false);
                    playingMessage = null;
                } else {
                    if (playingMessage != null) {
                        audioUtil.stopPlay();
                        playingMessage.setPlaying(false);
                    }
                    audioUtil.startPlay(FileCache.getInstance().getCachedFilePath(audio.url));
                    playingMessage = message;
                    message.setPlaying(true);
                    if (!message.isListened() && !message.isOutgoing) {
                        message.setListened(true);
                        markMessageListened(message);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


}

================================================
FILE: imkit/src/main/java/com/beetle/bauhinia/MessageBaseActivity.java
================================================
/*                                                                            
  Copyright (c) 2014-2019, GoBelieve     
    All rights reserved.		    				     			
 
  This source code is licensed under the BSD-style license found in the
  LICENSE file in the root directory of this source tree. An additional grant
  of patent rights can be found in the PATENTS file in the same directory.
*/


package com.beetle.bauhinia;

import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.OpenableColumns;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.widget.Toast;

import com.amap.api.services.core.AMapException;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.geocoder.GeocodeResult;
import com.amap.api.services.geocoder.GeocodeSearch;
import com.amap.api.services.geocoder.RegeocodeQuery;
import com.amap.api.services.geocoder.RegeocodeResult;
import com.beetle.bauhinia.activity.BaseActivity;
import com.beetle.bauhinia.db.IMessage;
import com.beetle.bauhinia.db.IMessageDB;
import com.beetle.bauhinia.db.MessageIterator;
import com.beetle.bauhinia.db.message.ACK;
import com.beetle.bauhinia.db.message.Audio;
import com.beetle.bauhinia.db.message.Image;
import com.beetle.bauhinia.db.message.Location;
import com.beetle.bauhinia.db.message.MessageContent;
import com.beetle.bauhinia.db.message.Revoke;
import com.beetle.bauhinia.db.message.Text;
import com.beetle.bauhinia.db.message.TimeBase;
import com.beetle.bauhinia.db.message.Video;
import com.beetle.bauhinia.outbox.OutboxObserver;
import com.beetle.bauhinia.tools.AudioUtil;
import com.beetle.bauhinia.tools.FileCache;
import com.beetle.bauhinia.tools.FileDownloader;
import com.beetle.bauhinia.tools.TimeUtil;
import com.beetle.bauhinia.tools.VideoUtil;
import com.beetle.im.IMService;
import com.beetle.im.MessageACK;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import com.beetle.imkit.R;

/*
 at对象的用户名问题
 本地显示的优先级 用户备注 > 群内昵称 > 用户名

 派生类实现
 protected void checkAtName(IMessage messages)
 替换掉消息内容中at对象的用户名

 派生类重载
 protected void sendTextMessage(String text, List<Long> at, List<String> atNames)
 将有可能是本地备注的用户名修改为群内昵称或用户名

 */
abstract public class MessageBaseActivity extends BaseActivity implements
        FileDownloader.FileDownloaderObserver,
        OutboxObserver {
    protected static final String TAG = "imservice";

    //消息撤回的时限
    public static final int REVOKE_EXPIRE = 120;

    public static final int PAGE_SIZE = 10;
    public static final int FILE_SIZE_LIMIT = 16*1024*1024;

    //app 启动时间戳,app启动时初始化
    public static int uptime;
    static {
        uptime = now();
        Log.i(TAG, "uptime:" + uptime);
    }

    public static int now() {
        Date date = new Date();
        long t = date.getTime();
        return (int)(t/1000);
    }


    protected int pageSize = PAGE_SIZE;
    protected String conversationID;//uid or groupid or storeid

    protected long messageID;
    protected boolean hasLateMore;
    protected boolean hasEarlierMore;
    protected IMessageDB messageDB;

    protected ArrayList<IMessage> messages = new ArrayList<IMessage>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    protected void loadData() {
        messages = new ArrayList<IMessage>();
        List<IMessage> newMessages;
        if (messageID > 0) {
            newMessages = this.loadConversationData(messageID);
        } else {
            newMessages = this.loadConversationData();
        }

        //删除重复的消息,过滤掉不显示的消息
        HashSet<String> uuidSet = new HashSet<String>();
        for (int i = 0; i < newMessages.size(); i++) {
            IMessage msg = newMessages.get(i);
            if (!TextUtils.isEmpty(msg.getUUID()) && uuidSet.contains(msg.getUUID())) {
                continue;
            }
            if (msg.getType() == MessageContent.MessageType.MESSAGE_P2P_SESSION) {
                continue;
            }
            messages.add(msg);
            if (!TextUtils.isEmpty(msg.getUUID())) {
                uuidSet.add(msg.getUUID());
            }
        }
        int count = messages.size();

        prepareMessage(messages, count);
        resetMessageTimeBase();
    }


    protected int loadEarlierData() {
        int newCount = 0;
        if (!hasEarlierMore) {
            return newCount;
        }
        if (messages.size() == 0) {
            return newCount;
        }

        IMessage firstMsg = null;
        for (int i  = 0; i < messages.size(); i++) {
            IMessage msg = messages.get(i);
            if (msg.msgLocalID > 0) {
                firstMsg = msg;
                break;
            }
        }
        if (firstMsg == null) {
            return newCount;
        }

        HashSet<String> uuidSet = new HashSet<String>();
        for (int i  = 0; i < messages.size(); i++) {
            IMessage msg = messages.get(i);
            if (!TextUtils.isEmpty(msg.getUUID())) {
                uuidSet.add(msg.getUUID());
            }
        }

        List<IMessage> newMessages = this.loadEarlierData(firstMsg.msgLocalID);
        int count = newMessages.size();

        if (count == 0) {
            hasEarlierMore = false;
            return newCount;
        }
        for (int i = count-1; i >= 0; i--) {
            IMessage msg = newMessages.get(i);
            //重复的消息
            if (!TextUtils.isEmpty(msg.getUUID()) && uuidSet.contains(msg.getUUID())) {
                continue;
            }
            //不显示的消息
            if (msg.getType() == MessageContent.MessageType.MESSAGE_P2P_SESSION) {
                continue;
            }

            messages.add(0, msg);
            newCount++;
            if (!TextUtils.isEmpty(msg.getUUID())) {
                uuidSet.add(msg.getUUID());
            }
        }

        prepareMessage(messages, count);
        resetMessageTimeBase();
        return newCount;
    }

    protected int loadLaterData() {
        int newCount = 0;
        if (!this.hasLateMore || messageID == 0) {
            return newCount;
        }

        if (messages.size() == 0) {
            return newCount;
        }

        HashSet<String> uuidSet = new HashSet<String>();
        for (int i  = 0; i < messages.size(); i++) {
            IMessage msg = messages.get(i);
            if (!TextUtils.isEmpty(msg.getUUID())) {
                uuidSet.add(msg.getUUID());
            }
        }

        IMessage msg = messages.get(messages.size() - 1);
        List<IMessage> newMessages = this.loadLaterData(msg.msgLocalID);
        int count = newMessages.size();

        if (count == 0) {
            this.hasLateMore = false;
            return newCount;
        }

        for (int i = 0; i < count; i++) {
            IMessage m = newMessages.get(i);
            //重复消息
            if (!TextUtils.isEmpty(m.getUUID()) && uuidSet.contains(m.getUUID())) {
                continue;
            }
            //不需要显示的消息
            if (msg.getType() == MessageContent.MessageType.MESSAGE_P2P_SESSION) {
                continue;
            }

            prepareMessage(m);
            messages.add(m);
            newCount++;
            if (!TextUtils.isEmpty(msg.getUUID())) {
                uuidSet.add(msg.getUUID());
            }
        }
        resetMessageTimeBase();
        return newCount;
    }


    private List<IMessage> loadConversationData() {
        ArrayList<IMessage> messages = new ArrayList<IMessage>();
        int count = 0;
        MessageIterator iter = createMessageIterator();
        while (iter != null) {
            IMessage msg = iter.next();
            if (msg == null) {
                break;
            }

            messages.add(0, msg);
            if (++count >= pageSize) {
                break;
            }
        }
        return messages;
    }

    private List<IMessage> loadConversationData(long messageID) {
        HashSet<String> uuidSet = new HashSet<String>();
        ArrayList<IMessage> messages = new ArrayList<IMessage>();

        int count = 0;
        MessageIterator iter;

        iter = createMiddleMessageIterator(messageID);

        while (iter != null) {
            IMessage msg = iter.next();
            if (msg == null) {
                break;
            }

            //不加载重复的消息
            if (!TextUtils.isEmpty(msg.getUUID()) && uuidSet.contains(msg.getUUID())) {
                continue;
            }

            if (!TextUtils.isEmpty(msg.getUUID())) {
                uuidSet.add(msg.getUUID());
            }
            messages.add(0, msg);
            if (++count >= pageSize*2) {
                break;
            }
        }

        return messages;
    }

    private List<IMessage> loadEarlierData(long messageID) {
        ArrayList<IMessage> messages = new ArrayList<IMessage>();
        int count = 0;
        MessageIterator iter = createForwardMessageIterator(messageID);
        while (iter != null) {
            IMessage msg = iter.next();
            if (msg == null) {
                break;
            }
            messages.add(0, msg);
            if (++count >= pageSize) {
                break;
            }
        }
        return messages;
    }

    private List<IMessage> loadLaterData(long messageID) {
        ArrayList<IMessage> messages = new ArrayList<IMessage>();
        int count = 0;
        MessageIterator iter = createBackwardMessageIterator(messageID);
        while (true) {
            IMessage msg = iter.next();
            if (msg == null) {
                break;
            }
            messages.add(msg);
            if (++count >= pageSize) {
                break;
            }
        }
        return messages;
    }



    //加载消息发送者的名称和头像信息
    protected void loadUserName(IMessage msg) {
        if (msg.sender == 0) {
            return;
        }

        MessageActivity.User u = getUser(msg.sender);

        msg.setSenderAvatar(u.avatarURL);
        if (TextUtils.isEmpty(u.name)) {
            msg.setSenderName(u.identifier);
            final IMessage fmsg = msg;
            asyncGetUser(msg.sender, new MessageActivity.GetUserCallback() {
                @Override
                public void onUser(MessageActivity.User u) {
                    fmsg.setSenderName(u.name);
                    fmsg.setSenderAvatar(u.avatarURL);
                }
            });
        } else {
            msg.setSenderName(u.name);
        }
    }


    void checkMessageFailureFlag(IMessage msg) {
        if (msg.isOutgoing) {
            if (msg.timestamp < uptime && !msg.isAck()) {
                msg.setFailure(true);
                markMessageFailure(msg);
            }
        }
    }

    protected void updateNotificationDesc(IMessage imsg) {
        if (imsg.getType() == MessageContent.MessageType.MESSAGE_REVOKE) {
            Revoke revoke = (Revoke)imsg.content;
            if (imsg.isOutgoing) {
                revoke.description = getString(R.string.message_revoked, getString(R.string.you));
            } else {
                MessageActivity.User u = this.getUser(imsg.sender);
                String name = !TextUtils.isEmpty(u.name) ? u.name : u.identifier;
                revoke.d
Download .txt
gitextract_tzm_poya/

├── .gitignore
├── README.md
├── app/
│   ├── .gitignore
│   ├── AndroidManifest.xml
│   ├── build.gradle
│   ├── res/
│   │   ├── anim/
│   │   │   ├── fade_in.xml
│   │   │   ├── fade_out.xml
│   │   │   ├── head_in.xml
│   │   │   ├── head_out.xml
│   │   │   ├── hold.xml
│   │   │   ├── push_bottom_in.xml
│   │   │   ├── push_bottom_out.xml
│   │   │   ├── push_top_in.xml
│   │   │   ├── push_top_in2.xml
│   │   │   ├── push_top_out.xml
│   │   │   ├── push_top_out2.xml
│   │   │   ├── slide_in_from_left.xml
│   │   │   ├── slide_in_from_right.xml
│   │   │   ├── slide_out_to_left.xml
│   │   │   └── slide_out_to_right.xml
│   │   ├── drawable/
│   │   │   └── btn_login_selector.xml
│   │   ├── layout/
│   │   │   ├── activity_conversation.xml
│   │   │   ├── activity_login.xml
│   │   │   └── conversation_message.xml
│   │   └── values/
│   │       ├── colors.xml
│   │       ├── dimen_font.xml
│   │       ├── dimens.xml
│   │       ├── strings.xml
│   │       └── styles.xml
│   └── src/
│       └── io/
│           └── gobelieve/
│               └── im/
│                   └── demo/
│                       ├── BaseActivity.java
│                       ├── ConversationView.java
│                       ├── IMDemoApplication.java
│                       ├── LoginActivity.java
│                       ├── MessageListActivity.java
│                       └── model/
│                           ├── Conversation.java
│                           ├── ConversationDB.java
│                           ├── MessageDatabaseHelper.java
│                           └── SQLCreator.java
├── asynctcp/
│   ├── .gitignore
│   ├── build.gradle
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── beetle/
│       │               └── asynctcp/
│       │                   └── ApplicationTest.java
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── beetle/
│           │           ├── AsyncSSLTCP.java
│           │           ├── AsyncTCP.java
│           │           ├── AsyncTCPInterface.java
│           │           ├── AsyncTCPTest.java
│           │           ├── TCPConnectCallback.java
│           │           └── TCPReadCallback.java
│           └── res/
│               └── values/
│                   └── strings.xml
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── imkit/
│   ├── build.gradle
│   ├── libs/
│   │   ├── AMap_Location_V5.1.0_20200708.jar
│   │   ├── AMap_Search_V7.3.0_20200331.jar
│   │   └── Amap_2DMap_V6.0.0_20191106.jar
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── assets/
│           │   └── emoticon
│           ├── java/
│           │   └── com/
│           │       └── beetle/
│           │           └── bauhinia/
│           │               ├── ChatItemQuickAction.java
│           │               ├── CustomerMessageActivity.java
│           │               ├── GroupMessageActivity.java
│           │               ├── MessageActivity.java
│           │               ├── MessageAudioActivity.java
│           │               ├── MessageBaseActivity.java
│           │               ├── PeerMessageActivity.java
│           │               ├── activity/
│           │               │   ├── CameraActivity.java
│           │               │   ├── LocationPickerActivity.java
│           │               │   ├── MapActivity.java
│           │               │   ├── MessageFileActivity.java
│           │               │   ├── OverlayActivity.java
│           │               │   ├── PhotoActivity.java
│           │               │   ├── PlayerActivity.java
│           │               │   └── WebActivity.java
│           │               ├── api/
│           │               │   ├── IMHttpAPI.java
│           │               │   ├── body/
│           │               │   │   └── PostDeviceToken.java
│           │               │   └── types/
│           │               │       ├── Audio.java
│           │               │       ├── File.java
│           │               │       ├── Image.java
│           │               │       ├── Media.java
│           │               │       └── Supporter.java
│           │               ├── handler/
│           │               │   ├── CustomerMessageHandler.java
│           │               │   ├── GroupMessageHandler.java
│           │               │   ├── PeerMessageHandler.java
│           │               │   └── SyncKeyHandler.java
│           │               ├── outbox/
│           │               │   ├── CustomerOutbox.java
│           │               │   ├── GroupOutbox.java
│           │               │   ├── Outbox.java
│           │               │   ├── OutboxObserver.java
│           │               │   └── PeerOutbox.java
│           │               ├── tools/
│           │               │   ├── AudioRecorder.java
│           │               │   ├── AudioUtil.java
│           │               │   ├── BinAscii.java
│           │               │   ├── DeviceUtil.java
│           │               │   ├── FileCache.java
│           │               │   ├── FileDownloader.java
│           │               │   ├── ImageMIME.java
│           │               │   ├── MapUtil.java
│           │               │   ├── TimeUtil.java
│           │               │   └── VideoUtil.java
│           │               └── view/
│           │                   ├── InMessageView.java
│           │                   ├── MessageRowView.java
│           │                   ├── MiddleMessageView.java
│           │                   ├── OutMessageView.java
│           │                   └── TagView.java
│           └── res/
│               ├── anim/
│               │   ├── fade_in.xml
│               │   ├── fade_out.xml
│               │   ├── head_in.xml
│               │   ├── head_out.xml
│               │   ├── hold.xml
│               │   ├── push_bottom_in.xml
│               │   ├── push_bottom_out.xml
│               │   ├── push_top_in.xml
│               │   ├── push_top_in2.xml
│               │   ├── push_top_out.xml
│               │   ├── push_top_out2.xml
│               │   ├── slide_in_from_left.xml
│               │   ├── slide_in_from_right.xml
│               │   ├── slide_out_to_left.xml
│               │   └── slide_out_to_right.xml
│               ├── drawable/
│               │   ├── chat_send_btn.xml
│               │   ├── chatting_setmode_msg_btn.xml
│               │   ├── chatting_setmode_voice_btn.xml
│               │   ├── conversation_recording_round.xml
│               │   ├── ease_chat_file_selector.xml
│               │   ├── ease_chat_image_selector.xml
│               │   ├── ease_chat_location_selector.xml
│               │   ├── ease_chat_press_speak_btn.xml
│               │   ├── ease_chat_send_btn_selector.xml
│               │   ├── ease_chat_takepic_selector.xml
│               │   ├── ease_chat_video_call_selector.xml
│               │   ├── ease_chatting_setmode_keyboard_btn.xml
│               │   ├── ease_chatting_setmode_voice_btn.xml
│               │   ├── ease_edit_text_bg.xml
│               │   ├── ease_recording_text_hint_bg.xml
│               │   ├── ease_type_select_btn.xml
│               │   └── ic_back.xml
│               ├── layout/
│               │   ├── activity_camera.xml
│               │   ├── activity_file.xml
│               │   ├── activity_overlay.xml
│               │   ├── activity_photo.xml
│               │   ├── activity_player.xml
│               │   ├── activity_web.xml
│               │   ├── chat.xml
│               │   ├── chat_container_center.xml
│               │   ├── chat_container_left.xml
│               │   ├── chat_container_right.xml
│               │   ├── chat_location.xml
│               │   ├── conversation_recording_dialog.xml
│               │   └── location_picker.xml
│               ├── menu/
│               │   ├── chat.xml
│               │   ├── location_picker.xml
│               │   └── menu_photo.xml
│               ├── values/
│               │   ├── colors.xml
│               │   ├── dimens.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               ├── values-zh/
│               │   └── strings.xml
│               └── xml/
│                   └── file_paths.xml
├── imlib/
│   ├── build.gradle
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── beetle/
│           │           └── bauhinia/
│           │               ├── activity/
│           │               │   └── BaseActivity.java
│           │               ├── db/
│           │               │   ├── ConversationIterator.java
│           │               │   ├── CustomerMessageDB.java
│           │               │   ├── CustomerPeerMessageDB.java
│           │               │   ├── EPeerMessageDB.java
│           │               │   ├── GroupMessageDB.java
│           │               │   ├── ICustomerMessage.java
│           │               │   ├── IMessage.java
│           │               │   ├── IMessageDB.java
│           │               │   ├── MessageFlag.java
│           │               │   ├── MessageIterator.java
│           │               │   ├── PeerMessageDB.java
│           │               │   ├── SQLCustomerMessageDB.java
│           │               │   ├── SQLGroupMessageDB.java
│           │               │   ├── SQLPeerMessageDB.java
│           │               │   └── message/
│           │               │       ├── ACK.java
│           │               │       ├── Attachment.java
│           │               │       ├── Audio.java
│           │               │       ├── Classroom.java
│           │               │       ├── Conference.java
│           │               │       ├── File.java
│           │               │       ├── GroupNotification.java
│           │               │       ├── GroupVOIP.java
│           │               │       ├── Headline.java
│           │               │       ├── Image.java
│           │               │       ├── Link.java
│           │               │       ├── Location.java
│           │               │       ├── MessageContent.java
│           │               │       ├── Notification.java
│           │               │       ├── P2PSession.java
│           │               │       ├── Readed.java
│           │               │       ├── Revoke.java
│           │               │       ├── Secret.java
│           │               │       ├── Tag.java
│           │               │       ├── Text.java
│           │               │       ├── TimeBase.java
│           │               │       ├── Unknown.java
│           │               │       ├── VOIP.java
│           │               │       └── Video.java
│           │               ├── gallery/
│           │               │   ├── GalleryImage.java
│           │               │   ├── tool/
│           │               │   │   ├── Closeables.java
│           │               │   │   ├── DisplayUtils.java
│           │               │   │   ├── FileUtils.java
│           │               │   │   ├── ImageUtils.java
│           │               │   │   ├── Md5FileNameUtils.java
│           │               │   │   └── StorageUtils.java
│           │               │   ├── ui/
│           │               │   │   ├── GalleryAdapter.java
│           │               │   │   ├── GalleryGridAdapter.java
│           │               │   │   ├── GalleryGridUI.java
│           │               │   │   ├── GalleryUI.java
│           │               │   │   └── PhotoActionPopup.java
│           │               │   └── view/
│           │               │       └── ScrollViewPager.java
│           │               ├── toolbar/
│           │               │   ├── Contact.java
│           │               │   ├── EaseChatExtendMenu.java
│           │               │   ├── EaseChatInputMenu.java
│           │               │   ├── EaseChatPrimaryMenu.java
│           │               │   ├── EaseExpandRecylerView.java
│           │               │   └── emoticon/
│           │               │       ├── Emoticon.java
│           │               │       ├── EmoticonAdapter.java
│           │               │       ├── EmoticonManager.java
│           │               │       ├── EmoticonPanel.java
│           │               │       ├── EmoticonUtils.java
│           │               │       └── ViewPagerAdapter.java
│           │               ├── tools/
│           │               │   └── DisplayUtils.java
│           │               └── view/
│           │                   ├── MessageAudioView.java
│           │                   ├── MessageClassroomView.java
│           │                   ├── MessageContentView.java
│           │                   ├── MessageFileView.java
│           │                   ├── MessageImageView.java
│           │                   ├── MessageLinkView.java
│           │                   ├── MessageLocationView.java
│           │                   ├── MessageNotificationView.java
│           │                   ├── MessageTextView.java
│           │                   ├── MessageUnknownView.java
│           │                   ├── MessageVOIPView.java
│           │                   └── MessageVideoView.java
│           └── res/
│               ├── drawable/
│               │   ├── bg_indicator_dot.xml
│               │   ├── bg_indicator_dot_disable.xml
│               │   ├── bg_indicator_dot_enable.xml
│               │   ├── chatfrom_bg.xml
│               │   ├── chatto_bg.xml
│               │   ├── circle_audio.xml
│               │   ├── gallery_watch_more_picture_background.xml
│               │   └── rounded_corner.xml
│               ├── drawable-mdpi/
│               │   ├── voice_from_icon.xml
│               │   └── voice_to_icon.xml
│               ├── layout/
│               │   ├── chat_content_audio.xml
│               │   ├── chat_content_file.xml
│               │   ├── chat_content_image.xml
│               │   ├── chat_content_link.xml
│               │   ├── chat_content_location.xml
│               │   ├── chat_content_small_text.xml
│               │   ├── chat_content_text.xml
│               │   ├── chat_content_video.xml
│               │   ├── chat_content_voip.xml
│               │   ├── ease_chat_menu_item.xml
│               │   ├── ease_row_expression.xml
│               │   ├── ease_widget_chat_input_menu.xml
│               │   ├── ease_widget_chat_primary_menu.xml
│               │   ├── ease_widget_emojicon.xml
│               │   ├── emoticon_view.xml
│               │   ├── gallery_activity_gallery.xml
│               │   ├── gallery_activity_gallery_grid.xml
│               │   ├── gallery_activity_gallery_grid_item.xml
│               │   ├── gallery_select_dialog_item.xml
│               │   ├── item_emoticon.xml
│               │   └── item_emoticon_page.xml
│               ├── values/
│               │   ├── attrs.xml
│               │   ├── colors.xml
│               │   └── strings.xml
│               └── values-zh/
│                   └── strings.xml
├── imsdk/
│   ├── build.gradle
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── beetle/
│       │               └── im/
│       │                   └── ApplicationTest.java
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── beetle/
│           │           └── im/
│           │               ├── BytePacket.java
│           │               ├── CustomerMessage.java
│           │               ├── CustomerMessageHandler.java
│           │               ├── CustomerMessageObserver.java
│           │               ├── GroupMessageHandler.java
│           │               ├── GroupMessageObserver.java
│           │               ├── IMMessage.java
│           │               ├── IMService.java
│           │               ├── IMServiceObserver.java
│           │               ├── Message.java
│           │               ├── MessageACK.java
│           │               ├── PeerMessageHandler.java
│           │               ├── PeerMessageObserver.java
│           │               ├── RTMessage.java
│           │               ├── RTMessageObserver.java
│           │               ├── RoomMessage.java
│           │               ├── RoomMessageObserver.java
│           │               ├── SyncKeyHandler.java
│           │               ├── SystemMessageObserver.java
│           │               └── Timer.java
│           └── res/
│               └── values/
│                   └── strings.xml
├── push_demo/
│   ├── .gitignore
│   ├── AndroidManifest.xml
│   ├── build.gradle
│   ├── libs/
│   │   ├── HwPush_SDK_V2559.jar
│   │   ├── MiPush_SDK_Client_2_2_16.jar
│   │   ├── Xg_sdk_v2.38_20150405_2046.jar
│   │   ├── jg_filter_sdk_1.1.jar
│   │   ├── mid-sdk-2.10.jar
│   │   └── wup-1.0.0-SNAPSHOT.jar
│   ├── proguard-rules.txt
│   ├── res/
│   │   ├── anim/
│   │   │   ├── fade_in.xml
│   │   │   ├── fade_out.xml
│   │   │   ├── head_in.xml
│   │   │   ├── head_out.xml
│   │   │   ├── hold.xml
│   │   │   ├── push_bottom_in.xml
│   │   │   ├── push_bottom_out.xml
│   │   │   ├── push_top_in.xml
│   │   │   ├── push_top_in2.xml
│   │   │   ├── push_top_out.xml
│   │   │   ├── push_top_out2.xml
│   │   │   ├── slide_in_from_left.xml
│   │   │   ├── slide_in_from_right.xml
│   │   │   ├── slide_out_to_left.xml
│   │   │   └── slide_out_to_right.xml
│   │   ├── drawable/
│   │   │   ├── btn_login_selector.xml
│   │   │   └── hwpush_btn_checkbox_list_star.xml
│   │   ├── layout/
│   │   │   ├── activity_login.xml
│   │   │   ├── hwpush_buttons_layout.xml
│   │   │   ├── hwpush_collect_tip_dialog.xml
│   │   │   ├── hwpush_collection_item.xml
│   │   │   ├── hwpush_collection_listview.xml
│   │   │   ├── hwpush_icons_layout.xml
│   │   │   ├── hwpush_layout2.xml
│   │   │   ├── hwpush_layout4.xml
│   │   │   ├── hwpush_layout7.xml
│   │   │   ├── hwpush_layout8.xml
│   │   │   ├── hwpush_msg_show.xml
│   │   │   └── hwpush_titlebar.xml
│   │   ├── values/
│   │   │   ├── colors.xml
│   │   │   ├── dimen_font.xml
│   │   │   ├── dimens.xml
│   │   │   ├── hwpush_colors.xml
│   │   │   ├── hwpush_strings.xml
│   │   │   ├── hwpush_styles.xml
│   │   │   ├── strings.xml
│   │   │   └── styles.xml
│   │   ├── values-w820dp/
│   │   │   └── dimens.xml
│   │   └── values-zh-rCN/
│   │       └── hwpush_strings.xml
│   └── src/
│       └── io/
│           └── gobelieve/
│               └── im/
│                   └── demo/
│                       ├── BaseActivity.java
│                       ├── HuaweiPushReceiver.java
│                       ├── LoginActivity.java
│                       ├── PushDemoApplication.java
│                       ├── XGMessageReceiver.java
│                       └── XiaomiPushReceiver.java
├── room_demo/
│   ├── .gitignore
│   ├── AndroidManifest.xml
│   ├── build.gradle
│   ├── res/
│   │   ├── anim/
│   │   │   ├── fade_in.xml
│   │   │   ├── fade_out.xml
│   │   │   ├── head_in.xml
│   │   │   ├── head_out.xml
│   │   │   ├── hold.xml
│   │   │   ├── push_bottom_in.xml
│   │   │   ├── push_bottom_out.xml
│   │   │   ├── push_top_in.xml
│   │   │   ├── push_top_in2.xml
│   │   │   ├── push_top_out.xml
│   │   │   ├── push_top_out2.xml
│   │   │   ├── slide_in_from_left.xml
│   │   │   ├── slide_in_from_right.xml
│   │   │   ├── slide_out_to_left.xml
│   │   │   └── slide_out_to_right.xml
│   │   ├── drawable/
│   │   │   └── btn_login_selector.xml
│   │   ├── layout/
│   │   │   ├── activity_login.xml
│   │   │   └── activity_room.xml
│   │   ├── values/
│   │   │   ├── colors.xml
│   │   │   ├── dimen_font.xml
│   │   │   ├── dimens.xml
│   │   │   ├── strings.xml
│   │   │   └── styles.xml
│   │   └── values-w820dp/
│   │       └── dimens.xml
│   └── src/
│       └── io/
│           └── gobelieve/
│               └── im/
│                   └── demo/
│                       ├── IMDemoApplication.java
│                       ├── LoginActivity.java
│                       └── RoomActivity.java
└── settings.gradle
Download .txt
SYMBOL INDEX (1502 symbols across 168 files)

FILE: app/src/io/gobelieve/im/demo/BaseActivity.java
  class BaseActivity (line 26) | public abstract class BaseActivity extends FragmentActivity {
    method onCreate (line 27) | @Override
    method onBaseCreate (line 40) | protected abstract void onBaseCreate(Bundle savedInstanceState);
    method initView (line 49) | protected abstract void initView(Bundle savedInstanceState);
    method onStop (line 53) | @Override
    method onResume (line 63) | @Override
    method isAppOnForeground (line 74) | public boolean isAppOnForeground() {

FILE: app/src/io/gobelieve/im/demo/ConversationView.java
  class ConversationView (line 27) | public class ConversationView extends FrameLayout implements PropertyCha...
    method ConversationView (line 32) | public ConversationView(Context context) {
    method setConversation (line 39) | public void setConversation(Conversation c) {
    method setUnreadCount (line 75) | private void setUnreadCount() {
    method propertyChange (line 85) | @Override

FILE: app/src/io/gobelieve/im/demo/IMDemoApplication.java
  class IMDemoApplication (line 38) | public class IMDemoApplication extends Application {
    method getDeviceToken (line 46) | public String getDeviceToken() {
    method onCreate (line 51) | @Override
    method getApplication (line 102) | public static Application getApplication() {

FILE: app/src/io/gobelieve/im/demo/LoginActivity.java
  class LoginActivity (line 59) | public class LoginActivity extends BaseActivity implements View.OnClickL...
    method onBaseCreate (line 72) | @Override
    method initView (line 77) | @Override
    method openDB (line 92) | void openDB(long currentUID) {
    method go2Chat (line 107) | private void go2Chat(long sender, long receiver, String token) {
    method onClick (line 196) | @Override
    method login (line 252) | private String login(long uid) {

FILE: app/src/io/gobelieve/im/demo/MessageListActivity.java
  class MessageListActivity (line 67) | public class MessageListActivity extends BaseActivity implements IMServi...
    class ConversationAdapter (line 84) | class ConversationAdapter extends BaseAdapter {
      method getCount (line 85) | @Override
      method getItem (line 89) | @Override
      method getItemId (line 93) | @Override
      method getView (line 97) | @Override
    method initWidget (line 112) | private void initWidget() {
    method onCreateOptionsMenu (line 122) | @Override
    method onOptionsItemSelected (line 127) | @Override
    method onCreate (line 132) | @Override
    method onDestroy (line 157) | @Override
    method messageContentToString (line 169) | public  String messageContentToString(MessageContent content) {
    method updateConversationDetail (line 202) | void updateConversationDetail(Conversation conv) {
    method updatePeerConversationName (line 207) | void updatePeerConversationName(Conversation conv) {
    method updateGroupConversationName (line 225) | void updateGroupConversationName(Conversation conv) {
    method loadConversations (line 243) | void loadConversations() {
    class User (line 297) | public static class User {
    class Group (line 306) | public static class Group {
    type GetUserCallback (line 317) | public interface GetUserCallback {
      method onUser (line 318) | void onUser(User u);
    type GetGroupCallback (line 321) | public interface GetGroupCallback {
      method onGroup (line 322) | void onGroup(Group g);
    method onItemClick (line 325) | @Override
    method onConnectState (line 338) | @Override
    method findConversation (line 345) | public Conversation findConversation(long cid, int type) {
    method findConversationPosition (line 355) | public int findConversationPosition(long cid, int type) {
    method newPeerConversation (line 365) | public Conversation newPeerConversation(long cid) {
    method newGroupConversation (line 375) | public Conversation newGroupConversation(long cid) {
    method now (line 384) | public static int now() {
    method onPeerSecretMessage (line 391) | @Override
    method onPeerMessage (line 396) | @Override
    method onPeerMessageACK (line 437) | @Override
    method onPeerMessageFailure (line 463) | @Override
    method onGroupMessages (line 469) | @Override
    method onGroupMessage (line 499) | public void onGroupMessage(IMMessage msg, int unread) {
    method onGroupMessageACK (line 538) | @Override
    method onGroupMessageFailure (line 558) | @Override
    method updateNotificationDesc (line 564) | private void updateNotificationDesc(Conversation conv) {
    method onSystemMessage (line 622) | @Override
    method canBack (line 627) | public boolean canBack() {
    method getUser (line 635) | protected User getUser(long uid) {
    method asyncGetUser (line 645) | protected void asyncGetUser(long uid, GetUserCallback cb) {
    method getGroup (line 666) | protected Group getGroup(long gid) {
    method asyncGetGroup (line 676) | protected void asyncGetGroup(long gid, GetGroupCallback cb) {
    method onPeerClick (line 697) | protected void onPeerClick(long uid) {
    method onGroupClick (line 713) | protected void onGroupClick(long gid) {

FILE: app/src/io/gobelieve/im/demo/model/Conversation.java
  class Conversation (line 22) | public class Conversation {
    method addPropertyChangeListener (line 51) | public void addPropertyChangeListener(PropertyChangeListener listener) {
    method removePropertyChangeListener (line 55) | public void removePropertyChangeListener(PropertyChangeListener listen...
    method addPropertyChangeListener (line 59) | public void addPropertyChangeListener(String propertyName,
    method setName (line 65) | public void setName(String name) {
    method getName (line 71) | public String getName() {
    method setAvatar (line 75) | public void setAvatar(String avatar) {
    method getAvatar (line 81) | public String getAvatar() {
    method setDetail (line 85) | public void setDetail(String detail) {
    method getDetail (line 91) | public String getDetail() {
    method setUnreadCount (line 95) | public void setUnreadCount(int unreadCount) {
    method getUnreadCount (line 101) | public int getUnreadCount() {

FILE: app/src/io/gobelieve/im/demo/model/ConversationDB.java
  class ConversationDB (line 22) | public class ConversationDB {
    method getInstance (line 33) | public static ConversationDB getInstance() {
    method setDb (line 39) | public void setDb(SQLiteDatabase db) {
    method getDb (line 43) | public SQLiteDatabase getDb() {
    method getConversations (line 47) | public List<Conversation> getConversations() {
    method getConversation (line 80) | public Conversation getConversation(long cid, int type) {
    method addConversation (line 115) | public boolean addConversation(Conversation conv) {
    method setNewCount (line 138) | public boolean setNewCount(long rowid, int count) {
    method setState (line 160) | public boolean setState(long rowid, int state) {
    method resetState (line 181) | public boolean resetState(int state) {
    method removeConversation (line 200) | public boolean removeConversation(Conversation conv) {

FILE: app/src/io/gobelieve/im/demo/model/MessageDatabaseHelper.java
  class MessageDatabaseHelper (line 18) | public class MessageDatabaseHelper {
    class DatabaseHelper (line 29) | private static class DatabaseHelper extends SQLiteOpenHelper {
      method DatabaseHelper (line 31) | DatabaseHelper(Context context, String name, SQLiteDatabase.CursorFa...
      method onCreate (line 35) | @Override
      method onUpgrade (line 43) | @Override
      method createDatabase (line 49) | private void createDatabase(SQLiteDatabase db) {
    method getInstance (line 72) | public static MessageDatabaseHelper getInstance() {
    method MessageDatabaseHelper (line 80) | private MessageDatabaseHelper() {
    method open (line 84) | public void open(Context context, String name) {
    method getDatabase (line 91) | public SQLiteDatabase getDatabase() {
    method close (line 95) | public void close() {

FILE: app/src/io/gobelieve/im/demo/model/SQLCreator.java
  class SQLCreator (line 13) | public class SQLCreator {

FILE: asynctcp/src/androidTest/java/com/beetle/asynctcp/ApplicationTest.java
  class ApplicationTest (line 9) | public class ApplicationTest extends ApplicationTestCase<Application> {
    method ApplicationTest (line 10) | public ApplicationTest() {

FILE: asynctcp/src/main/java/com/beetle/AsyncSSLTCP.java
  class AsyncSSLTCP (line 3) | public class AsyncSSLTCP implements AsyncTCPInterface {
    method setConnectCallback (line 18) | public void setConnectCallback(TCPConnectCallback cb) {
    method setReadCallback (line 21) | public void setReadCallback(TCPReadCallback cb) {
    method connect (line 24) | public native boolean connect(String host, int port);
    method close (line 25) | public native void close();
    method release (line 26) | public native void release();
    method writeData (line 28) | public native void writeData(byte[] bytes);
    method startRead (line 30) | public native void startRead();

FILE: asynctcp/src/main/java/com/beetle/AsyncTCP.java
  class AsyncTCP (line 15) | public class AsyncTCP implements AsyncTCPInterface {
    method setConnectCallback (line 28) | public void setConnectCallback(TCPConnectCallback cb) {
    method setReadCallback (line 31) | public void setReadCallback(TCPReadCallback cb) {
    method connect (line 34) | public native boolean connect(String host, int port);
    method close (line 35) | public native void close();
    method release (line 36) | public native void release();
    method writeData (line 38) | public native void writeData(byte[] bytes);
    method startRead (line 40) | public native void startRead();

FILE: asynctcp/src/main/java/com/beetle/AsyncTCPInterface.java
  type AsyncTCPInterface (line 3) | public interface AsyncTCPInterface {
    method setConnectCallback (line 5) | public void setConnectCallback(TCPConnectCallback cb);
    method setReadCallback (line 6) | public void setReadCallback(TCPReadCallback cb);
    method connect (line 7) | public boolean connect(String host, int port);
    method close (line 10) | public void close();
    method release (line 13) | public void release();
    method writeData (line 15) | public void writeData(byte[] bytes);
    method startRead (line 17) | public void startRead();

FILE: asynctcp/src/main/java/com/beetle/AsyncTCPTest.java
  class AsyncTCPTest (line 23) | public class AsyncTCPTest extends Activity  {
    method onCreate (line 26) | @Override
    method test (line 44) | public void test() {

FILE: asynctcp/src/main/java/com/beetle/TCPConnectCallback.java
  type TCPConnectCallback (line 13) | public interface TCPConnectCallback {
    method onConnect (line 15) | public void onConnect(Object tcp, int status);

FILE: asynctcp/src/main/java/com/beetle/TCPReadCallback.java
  type TCPReadCallback (line 14) | public interface TCPReadCallback {
    method onRead (line 16) | public void onRead(Object tcp, byte[] data);

FILE: imkit/src/main/java/com/beetle/bauhinia/ChatItemQuickAction.java
  class ChatItemQuickAction (line 23) | public class ChatItemQuickAction {
    type ChatQuickAction (line 24) | public enum ChatQuickAction {
      method getName (line 27) | public String getName(Context context) {
    type ChatQuickActionResult (line 44) | public interface ChatQuickActionResult {
      method onSelect (line 45) | void onSelect(ChatQuickAction action);
    method showAction (line 48) | public static void showAction(Context context, final ChatQuickAction[]...

FILE: imkit/src/main/java/com/beetle/bauhinia/CustomerMessageActivity.java
  class CustomerMessageActivity (line 31) | public class CustomerMessageActivity extends MessageActivity
    method onCreate (line 46) | @Override
    method onDestroy (line 141) | @Override
    method onConnectState (line 154) | @Override
    method onCustomerMessage (line 167) | @Override
    method onCustomerMessageACK (line 235) | @Override
    method onCustomerMessageFailure (line 263) | @Override
    method createMessageIterator (line 282) | @Override
    method createForwardMessageIterator (line 289) | @Override
    method createBackwardMessageIterator (line 296) | @Override
    method createMiddleMessageIterator (line 303) | @Override
    method getMessageOutgoing (line 311) | @Override
    method sendMessage (line 317) | @Override
    method newOutMessage (line 322) | @Override
    method loadUserName (line 336) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/GroupMessageActivity.java
  class GroupMessageActivity (line 31) | public class GroupMessageActivity extends MessageActivity implements
    method GroupMessageActivity (line 37) | public GroupMessageActivity() {
    method onCreate (line 44) | @Override
    method onDestroy (line 102) | @Override
    method onConnectState (line 114) | @Override
    method onGroupMessages (line 123) | @Override
    method onGroupMessage (line 136) | public void onGroupMessage(IMMessage msg) {
    method onGroupMessageACK (line 183) | @Override
    method onGroupMessageFailure (line 231) | @Override
    method onGroupNotification (line 255) | public void onGroupNotification(String text) {
    method getUser (line 277) | @Override
    method asyncGetUser (line 287) | @Override
    method createMessageIterator (line 309) | @Override
    method createForwardMessageIterator (line 315) | @Override
    method createBackwardMessageIterator (line 321) | @Override
    method createMiddleMessageIterator (line 327) | @Override
    method getMessageOutgoing (line 334) | @Override
    method sendMessage (line 339) | @Override
    method clearConversation (line 345) | @Override
    method newOutMessage (line 352) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/MessageActivity.java
  class MessageActivity (line 62) | abstract public class MessageActivity extends MessageAudioActivity imple...
    class MenuItemClickListener (line 124) | class MenuItemClickListener implements EaseChatExtendMenu.EaseChatExte...
      method onClick (line 125) | @Override
    method onCreate (line 155) | @Override
    method onCreateOptionsMenu (line 300) | @Override
    method onOptionsItemSelected (line 305) | @Override
    method onBackPressed (line 310) | @Override
    method onDestroy (line 327) | @Override
    method onRequestPermissionsResult (line 334) | @Override
    method checkRecordPermission (line 361) | private boolean checkRecordPermission() {
    method checkPhotoPermission (line 369) | private boolean checkPhotoPermission() {
    method checkLocationPermission (line 377) | private boolean checkLocationPermission() {
    method checkCameraPermission (line 387) | private boolean checkCameraPermission() {
    method requestRecordPermission (line 396) | private void requestRecordPermission() {
    method requestPhotoPermission (line 404) | private void requestPhotoPermission() {
    method requestLocationPermission (line 411) | private void requestLocationPermission() {
    method requestCameraPermission (line 419) | private void requestCameraPermission() {
    method registerExtendMenuItem (line 429) | protected void registerExtendMenuItem(){
    type ContentTypes (line 437) | static interface ContentTypes {
    class ChatAdapter (line 454) | class ChatAdapter extends BaseAdapter implements ContentTypes {
      method getCount (line 455) | @Override
      method getItem (line 459) | @Override
      method getItemId (line 463) | @Override
      method getItemViewType (line 468) | @Override
      method getMediaType (line 479) | int getMediaType(int position) {
      method getViewTypeCount (line 511) | @Override
      method getView (line 516) | @Override
    method disableSend (line 618) | protected void disableSend() {
    method enableSend (line 622) | protected void enableSend() {
    method onRefresh (line 626) | public void onRefresh() {
    method clearConversation (line 639) | protected void clearConversation() {
    method insertMessage (line 646) | @Override
    method replaceMessage (line 653) | @Override
    method onInputFocusChanged (line 659) | protected void onInputFocusChanged(boolean hasFocus) {
    method getPicture (line 677) | void getPicture() {
    method takePicture (line 696) | void takePicture() {
    method getFile (line 706) | void getFile() {
    method onActivityResult (line 715) | public void onActivityResult(int requestCode, int resultCode, Intent d...
    method onMessageClicked (line 771) | protected void onMessageClicked(IMessage message) {
    method navigateToViewImage (line 810) | private void navigateToViewImage(IMessage imageMessage) {
    method call (line 829) | protected void call() {}
    method onAt (line 831) | protected void onAt() {}
    method forward (line 833) | protected void forward(IMessage im) {}
    method openUnread (line 835) | protected void openUnread(IMessage im) {}
    method openReply (line 837) | protected void openReply(IMessage message) {
    method getLongClickActions (line 841) | protected ArrayList<ChatQuickAction> getLongClickActions(IMessage im) {
    method onActionClickListener (line 871) | protected void onActionClickListener(ChatQuickAction action, IMessage ...

FILE: imkit/src/main/java/com/beetle/bauhinia/MessageAudioActivity.java
  class MessageAudioActivity (line 30) | abstract public class MessageAudioActivity extends MessageBaseActivity {
    class VolumeTimerTask (line 53) | protected class VolumeTimerTask extends TimerTask {
      method run (line 54) | @Override
    method showReleaseToCancelHint (line 66) | protected void showReleaseToCancelHint() {
    method showMoveUpToCancelHint (line 73) | protected void showMoveUpToCancelHint() {
    method showRecordDialog (line 80) | protected void showRecordDialog() {
    method refreshVolume (line 106) | protected void refreshVolume() {
    method startRecord (line 150) | protected void startRecord() {
    method discardRecord (line 180) | protected void discardRecord() {
    method stopRecord (line 200) | protected void stopRecord() {
    method play (line 224) | protected void play(IMessage message) {

FILE: imkit/src/main/java/com/beetle/bauhinia/MessageBaseActivity.java
  class MessageBaseActivity (line 78) | abstract public class MessageBaseActivity extends BaseActivity implements
    method now (line 96) | public static int now() {
    method onCreate (line 113) | @Override
    method loadData (line 118) | protected void loadData() {
    method loadEarlierData (line 149) | protected int loadEarlierData() {
    method loadLaterData (line 208) | protected int loadLaterData() {
    method loadConversationData (line 258) | private List<IMessage> loadConversationData() {
    method loadConversationData (line 276) | private List<IMessage> loadConversationData(long messageID) {
    method loadEarlierData (line 308) | private List<IMessage> loadEarlierData(long messageID) {
    method loadLaterData (line 325) | private List<IMessage> loadLaterData(long messageID) {
    method loadUserName (line 345) | protected void loadUserName(IMessage msg) {
    method checkMessageFailureFlag (line 369) | void checkMessageFailureFlag(IMessage msg) {
    method updateNotificationDesc (line 378) | protected void updateNotificationDesc(IMessage imsg) {
    method queryLocation (line 401) | protected void queryLocation(final IMessage msg) {
    method downloadMessageContent (line 435) | protected void downloadMessageContent(IMessage msg) {
    method checkAtName (line 471) | protected void checkAtName(IMessage message) {
    method sendReaded (line 475) | protected void sendReaded(IMessage message) {
    method prepareMessage (line 479) | protected void prepareMessage(ArrayList<IMessage> messages, int count) {
    method prepareMessage (line 486) | protected void prepareMessage(IMessage message) {
    method saveMessageAttachment (line 497) | protected void saveMessageAttachment(IMessage msg, String address) {
    method saveMessage (line 501) | protected void saveMessage(IMessage imsg) {
    method removeMessage (line 505) | protected void removeMessage(IMessage imsg) {
    method markMessageListened (line 509) | protected void markMessageListened(IMessage imsg) {
    method markMessageFailure (line 513) | protected void markMessageFailure(IMessage imsg) {
    method eraseMessageFailure (line 518) | protected void eraseMessageFailure(IMessage imsg) {
    method resetMessageTimeBase (line 523) | protected void resetMessageTimeBase() {
    method deleteMessage (line 549) | protected void deleteMessage(IMessage imsg) {
    method replaceMessage (line 563) | protected void replaceMessage(IMessage imsg, IMessage other) {
    method insertMessage (line 577) | protected void insertMessage(IMessage imsg) {
    method sendTextMessage (line 597) | protected void sendTextMessage(String text, List<Long> at, List<String...
    method sendVideoMessage (line 606) | protected void sendVideoMessage(String path, String thumbPath) {
    method sendImageMessage (line 648) | protected void sendImageMessage(Bitmap bmp) {
    method sendAudioMessage (line 740) | protected void sendAudioMessage(String tfile) {
    method sendLocationMessage (line 767) | protected void sendLocationMessage(float longitude, float latitude, St...
    method sendFileMessage (line 773) | protected void sendFileMessage(Uri uri) {
    method getFileInfo (line 811) | private Pair<String, Long> getFileInfo(Uri uri) {
    method sendMessageContent (line 832) | protected void sendMessageContent(MessageContent content) {
    method onAudioUploadSuccess (line 854) | @Override
    method onAudioUploadFail (line 867) | @Override
    method onImageUploadSuccess (line 877) | @Override
    method onImageUploadFail (line 890) | @Override
    method onVideoUploadSuccess (line 900) | @Override
    method onVideoUploadFail (line 913) | @Override
    method onFileUploadSuccess (line 923) | @Override
    method onFileUploadFail (line 936) | @Override
    method onFileDownloadSuccess (line 946) | @Override
    method onFileDownloadFail (line 955) | @Override
    method revoke (line 964) | protected void revoke(IMessage msg) {
    method resend (line 988) | protected void resend(IMessage msg) {
    method getMessageOutgoing (line 994) | abstract protected boolean getMessageOutgoing(IMessage msg);
    method newOutMessage (line 995) | abstract protected IMessage newOutMessage(MessageContent content);
    method sendMessage (line 996) | abstract protected void sendMessage(IMessage imsg);
    method createMessageIterator (line 997) | abstract protected MessageIterator createMessageIterator();
    method createForwardMessageIterator (line 998) | abstract protected MessageIterator createForwardMessageIterator(long m...
    method createBackwardMessageIterator (line 999) | abstract protected MessageIterator createBackwardMessageIterator(long ...
    method createMiddleMessageIterator (line 1000) | abstract protected MessageIterator createMiddleMessageIterator(long me...
    method findMessage (line 1003) | protected IMessage findMessage(long msgLocalID) {
    method findMessage (line 1012) | protected IMessage findMessage(String uuid) {
    method getImageMessages (line 1026) | protected ArrayList<IMessage> getImageMessages() {
    method localFileURL (line 1059) | protected String localFileURL(String ext) {
    method localVideoURL (line 1064) | protected String localVideoURL() {
    method localImageURL (line 1069) | protected String localImageURL() {
    method localAudioURL (line 1074) | protected String localAudioURL() {
    class User (line 1080) | public static class User {
    method getUser (line 1089) | protected User getUser(long uid) {
    type GetUserCallback (line 1098) | public interface GetUserCallback {
      method onUser (line 1099) | void onUser(User u);
    method asyncGetUser (line 1102) | protected void asyncGetUser(long uid, GetUserCallback cb) {

FILE: imkit/src/main/java/com/beetle/bauhinia/PeerMessageActivity.java
  class PeerMessageActivity (line 22) | public class PeerMessageActivity extends MessageActivity implements
    method onCreate (line 30) | @Override
    method onDestroy (line 105) | @Override
    method onConnectState (line 117) | @Override
    method onPeerMessage (line 127) | @Override
    method onPeerSecretMessage (line 180) | @Override
    method onPeerMessageACK (line 237) | @Override
    method onPeerMessageFailure (line 293) | @Override
    method handleP2PSession (line 316) | protected void handleP2PSession(IMessage imsg) {
    method createMessageIterator (line 321) | @Override
    method createForwardMessageIterator (line 328) | @Override
    method createBackwardMessageIterator (line 335) | @Override
    method createMiddleMessageIterator (line 342) | @Override
    method getMessageOutgoing (line 350) | @Override
    method sendMessage (line 356) | @Override
    method newOutMessage (line 362) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/activity/CameraActivity.java
  class CameraActivity (line 28) | public class CameraActivity extends BaseActivity {
    method onCreate (line 35) | @Override
    method storeByteArray (line 127) | public void storeByteArray(String fileName, ByteArrayOutputStream byte...
    method saveBitmap (line 135) | boolean saveBitmap(Bitmap bitmap, String fileName) {
    method onStart (line 147) | @Override
    method onResume (line 167) | @Override
    method onPause (line 173) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/activity/LocationPickerActivity.java
  class LocationPickerActivity (line 46) | public class LocationPickerActivity extends BaseActivity implements Geoc...
    method newIntent (line 65) | public static Intent newIntent(Context context) {
    method onCreate (line 71) | @Override
    method onCreateOptionsMenu (line 107) | @Override
    method onOptionsItemSelected (line 113) | @Override
    method onResume (line 136) | @Override
    method onPause (line 145) | @Override
    method onSaveInstanceState (line 154) | @Override
    method onDestroy (line 163) | @Override
    method setLocation (line 169) | private void setLocation(double latitude, double longitude, String add...
    method onRegeocodeSearched (line 187) | @Override
    method onGeocodeSearched (line 202) | @Override
    method setUpMap (line 209) | private void setUpMap() {
    method setupLocationStyle (line 216) | private void setupLocationStyle(){
    method activate (line 223) | @Override
    method deactivate (line 246) | @Override
    method onLocationChanged (line 258) | @Override
    method stopLocation (line 274) | private void stopLocation() {
    method queryLocation (line 284) | private void queryLocation() {
    method pinUp (line 290) | private void pinUp() {
    method pinDown (line 297) | private void pinDown() {
    method getPinY (line 304) | private int getPinY() {
    method setLabel (line 308) | private void setLabel(String address) {

FILE: imkit/src/main/java/com/beetle/bauhinia/activity/MapActivity.java
  class MapActivity (line 31) | public class MapActivity extends BaseActivity implements GeocodeSearch.O...
    method newIntent (line 44) | public static Intent newIntent(Context context, float longitude, float...
    method onCreate (line 52) | @Override
    method onNavigation (line 80) | public void onNavigation(View sender) {
    method onResume (line 88) | @Override
    method onPause (line 97) | @Override
    method onSaveInstanceState (line 106) | @Override
    method onDestroy (line 115) | @Override
    method queryLocation (line 121) | private void queryLocation() {
    method setLocation (line 127) | private void setLocation(double latitude, double longitude, String add...
    method onRegeocodeSearched (line 139) | @Override
    method onGeocodeSearched (line 154) | @Override
    method onLocationChanged (line 161) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/activity/MessageFileActivity.java
  class MessageFileActivity (line 44) | public class MessageFileActivity extends BaseActivity {
    method onCreate (line 52) | @Override
    method onOpen (line 81) | public void onOpen(View v) {
    method download (line 93) | private void download(final String url) {
    method openFile (line 129) | public static void openFile(Context context, String filename, File url...

FILE: imkit/src/main/java/com/beetle/bauhinia/activity/OverlayActivity.java
  class OverlayActivity (line 23) | public class OverlayActivity extends BaseActivity {
    method onCreate (line 25) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/activity/PhotoActivity.java
  class PhotoActivity (line 25) | public class PhotoActivity extends BaseActivity {
    method newIntent (line 30) | public static Intent newIntent(Context context, String url) {
    method onCreate (line 37) | @Override
    method onCreateOptionsMenu (line 54) | @Override
    method onOptionsItemSelected (line 61) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/activity/PlayerActivity.java
  class PlayerActivity (line 32) | public class PlayerActivity extends BaseActivity {
    method onCreate (line 40) | @Override
    method showControl (line 90) | private void showControl() {
    method download (line 101) | private void download(final String url) {

FILE: imkit/src/main/java/com/beetle/bauhinia/activity/WebActivity.java
  class WebActivity (line 23) | public class WebActivity extends BaseActivity {
    method onCreate (line 25) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/api/IMHttpAPI.java
  class IMHttpAPI (line 38) | public class IMHttpAPI {
    method newIMHttp (line 41) | private static IMHttp newIMHttp() {
    method Singleton (line 61) | public static IMHttp Singleton() {
    method setAPIURL (line 76) | public static void setAPIURL(String url) {
    method setToken (line 80) | public static void setToken(String token) {
    type IMHttp (line 85) | public interface IMHttp {
      method bindDeviceToken (line 86) | @POST("/device/bind")
      method unBindDeviceToken (line 89) | @POST("/device/unbind")
      method postImages (line 92) | @POST("/images")
      method postAudios (line 95) | @POST("/audios")
      method postFile (line 98) | @Multipart
      method getSupporter (line 102) | @GET("/supporters")

FILE: imkit/src/main/java/com/beetle/bauhinia/api/body/PostDeviceToken.java
  class PostDeviceToken (line 18) | public class PostDeviceToken {

FILE: imkit/src/main/java/com/beetle/bauhinia/api/types/Audio.java
  class Audio (line 16) | public class Audio extends Media{

FILE: imkit/src/main/java/com/beetle/bauhinia/api/types/File.java
  class File (line 13) | public class File extends Media{

FILE: imkit/src/main/java/com/beetle/bauhinia/api/types/Image.java
  class Image (line 16) | public class Image extends Media{

FILE: imkit/src/main/java/com/beetle/bauhinia/api/types/Media.java
  class Media (line 18) | public class Media {

FILE: imkit/src/main/java/com/beetle/bauhinia/api/types/Supporter.java
  class Supporter (line 3) | public class Supporter {

FILE: imkit/src/main/java/com/beetle/bauhinia/handler/CustomerMessageHandler.java
  class CustomerMessageHandler (line 15) | public class CustomerMessageHandler implements com.beetle.im.CustomerMes...
    method getInstance (line 19) | public static CustomerMessageHandler getInstance() {
    method setUID (line 26) | public void setUID(long uid) {
    method setAppId (line 29) | public void setAppId(long appid) {
    method repairFailureMessage (line 33) | private void repairFailureMessage(String uuid) {
    method handleMessage (line 52) | @Override
    method handleMessageACK (line 93) | @Override
    method handleMessageFailure (line 113) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/handler/GroupMessageHandler.java
  class GroupMessageHandler (line 23) | public class GroupMessageHandler implements com.beetle.im.GroupMessageHa...
    method getInstance (line 27) | public static GroupMessageHandler getInstance() {
    method now (line 32) | public static int now() {
    method setUID (line 41) | public void setUID(long uid) {
    method repairFailureMessage (line 45) | private void repairFailureMessage(String uuid) {
    method handleMessages (line 61) | @Override
    method handleMessageACK (line 159) | public boolean handleMessageACK(IMMessage im, int error) {
    method handleMessageFailure (line 195) | public boolean handleMessageFailure(IMMessage im) {

FILE: imkit/src/main/java/com/beetle/bauhinia/handler/PeerMessageHandler.java
  class PeerMessageHandler (line 25) | public class PeerMessageHandler implements com.beetle.im.PeerMessageHand...
    method getInstance (line 27) | public static PeerMessageHandler getInstance() {
    method setUID (line 34) | public void setUID(long uid) {
    method repaireFailureMessage (line 38) | private void repaireFailureMessage(String uuid) {
    method handleMessage (line 54) | public boolean handleMessage(IMMessage msg) {
    method handleMessageACK (line 106) | public boolean handleMessageACK(IMMessage im, int error) {
    method now (line 152) | public static int now() {
    method handleMessageFailure (line 159) | public boolean handleMessageFailure(IMMessage im) {

FILE: imkit/src/main/java/com/beetle/bauhinia/handler/SyncKeyHandler.java
  class SyncKeyHandler (line 17) | public class SyncKeyHandler implements com.beetle.im.SyncKeyHandler {
    method SyncKeyHandler (line 26) | public SyncKeyHandler(Context context, String name) {
    method getSyncKey (line 31) | public long getSyncKey() {
    method getSuperGroupSyncKeys (line 35) | public HashMap<Long, Long> getSuperGroupSyncKeys() {
    method saveSyncKey (line 39) | public boolean saveSyncKey(long syncKey) {
    method saveGroupSyncKey (line 44) | public boolean saveGroupSyncKey(long groupID, long syncKey) {
    method load (line 49) | public void load() {
    method save (line 71) | private boolean save() {

FILE: imkit/src/main/java/com/beetle/bauhinia/outbox/CustomerOutbox.java
  class CustomerOutbox (line 23) | public class CustomerOutbox extends Outbox {
    method getInstance (line 25) | public static CustomerOutbox getInstance() {
    method updateMessageContent (line 29) | @Override
    method markMessageFailure (line 34) | @Override
    method sendRawMessage (line 39) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/outbox/GroupOutbox.java
  class GroupOutbox (line 23) | public class GroupOutbox extends Outbox{
    method getInstance (line 25) | public static GroupOutbox getInstance() {
    method sendRawMessage (line 29) | @Override
    method updateMessageContent (line 40) | @Override
    method markMessageFailure (line 45) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/outbox/Outbox.java
  class Outbox (line 35) | public abstract class Outbox {
    method addObserver (line 40) | public void addObserver(OutboxObserver ob) {
    method removeObserver (line 47) | public void removeObserver(OutboxObserver ob) {
    method sendMessage (line 52) | public void sendMessage(IMessage imsg) {
    method uploadFile (line 94) | public boolean uploadFile(final IMessage msg, final String path) {
    method uploadVideo (line 139) | public boolean uploadVideo(final IMessage msg, final String path, Stri...
    method uploadSecretVideo (line 198) | public boolean uploadSecretVideo(final IMessage msg, final String path...
    method uploadImage (line 252) | public boolean uploadImage(final IMessage msg, String filePath) {
    method uploadAudio (line 286) | public boolean uploadAudio(final IMessage msg, final String filePath) {
    method uploadSecretImage (line 316) | public boolean uploadSecretImage(final IMessage msg, String filePath) {
    method uploadSecretAudio (line 348) | public boolean uploadSecretAudio(final IMessage msg, String file) {
    method onUploadAudioSuccess (line 375) | private void onUploadAudioSuccess(IMessage msg, String url) {
    method onUploadAudioFail (line 381) | private void onUploadAudioFail(IMessage msg) {
    method onUploadImageSuccess (line 387) | private void onUploadImageSuccess(IMessage msg, String url) {
    method onUploadImageFail (line 393) | private void onUploadImageFail(IMessage msg) {
    method onUploadVideoSuccess (line 399) | private void onUploadVideoSuccess(IMessage msg, String url, String thu...
    method onUploadVideoFail (line 405) | private void onUploadVideoFail(IMessage msg) {
    method onUploadFileSuccess (line 412) | private void onUploadFileSuccess(IMessage msg, String url) {
    method onUploadFileFail (line 418) | private void onUploadFileFail(IMessage msg) {
    method sendImageMessage (line 424) | protected void sendImageMessage(IMessage imsg, String url) {
    method sendAudioMessage (line 431) | protected void sendAudioMessage(IMessage imsg, String url) {
    method sendVideoMessage (line 438) | protected void sendVideoMessage(IMessage imsg, String url, String thum...
    method sendFileMessage (line 445) | protected void sendFileMessage(IMessage imsg, String url) {
    method saveImageURL (line 452) | protected void saveImageURL(IMessage msg, String url) {
    method saveAudioURL (line 465) | protected void saveAudioURL(IMessage msg, String url) {
    method saveVideoURL (line 478) | protected void saveVideoURL(IMessage msg, String url, String thumbURL) {
    method saveFileURL (line 492) | protected void saveFileURL(IMessage msg, String url) {
    method encrypt (line 506) | protected boolean encrypt(IMMessage msg, String uuid) {
    method encryptFile (line 511) | protected String encryptFile(String path, long peerUID) {
    method markMessageFailure (line 516) | abstract protected void markMessageFailure(IMessage msg);
    method updateMessageContent (line 518) | abstract protected void updateMessageContent(long id, String content);
    method sendRawMessage (line 520) | abstract protected void sendRawMessage(IMessage imsg, String raw);

FILE: imkit/src/main/java/com/beetle/bauhinia/outbox/OutboxObserver.java
  type OutboxObserver (line 5) | public interface OutboxObserver {
    method onAudioUploadSuccess (line 6) | public void onAudioUploadSuccess(IMessage msg, String url);
    method onAudioUploadFail (line 7) | public void onAudioUploadFail(IMessage msg);
    method onImageUploadSuccess (line 8) | public void onImageUploadSuccess(IMessage msg, String url);
    method onImageUploadFail (line 9) | public void onImageUploadFail(IMessage msg);
    method onVideoUploadSuccess (line 11) | public void onVideoUploadSuccess(IMessage msg, String url, String thum...
    method onVideoUploadFail (line 12) | public void onVideoUploadFail(IMessage msg);
    method onFileUploadSuccess (line 14) | public void onFileUploadSuccess(IMessage msg, String url);
    method onFileUploadFail (line 15) | public void onFileUploadFail(IMessage msg);

FILE: imkit/src/main/java/com/beetle/bauhinia/outbox/PeerOutbox.java
  class PeerOutbox (line 23) | public class PeerOutbox extends Outbox {
    method getInstance (line 27) | public static PeerOutbox getInstance() {
    method markMessageFailure (line 33) | @Override
    method updateMessageContent (line 38) | @Override
    method sendRawMessage (line 43) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/tools/AudioRecorder.java
  class AudioRecorder (line 22) | public class AudioRecorder {
    method AudioRecorder (line 30) | public AudioRecorder(Context context, String path) {
    method isRecording (line 42) | public boolean isRecording() {
    method getPathName (line 46) | public String getPathName() {
    method getMaxAmplitude (line 49) | public int getMaxAmplitude() {
    method startRecord (line 53) | public void startRecord() {
    method stopRecord (line 95) | public void stopRecord() {

FILE: imkit/src/main/java/com/beetle/bauhinia/tools/AudioUtil.java
  class AudioUtil (line 29) | public class AudioUtil{
    method AudioUtil (line 51) | public AudioUtil(Context context) {
    method setOnCompletionListener (line 62) | public void setOnCompletionListener(OnCompletionListener l) {
    method setOnStopListener (line 66) | public void setOnStopListener(OnStopListener l) {
    method getAudioDuration (line 70) | public static long getAudioDuration(String fileName) throws IOException {
    method startPlay (line 99) | public void startPlay(final String fileName) throws IllegalStateExcept...
    method stopPlay (line 119) | public void stopPlay() throws IllegalStateException {
    method isPlaying (line 130) | public synchronized boolean isPlaying() {
    method release (line 137) | public void release() {
    method startPlaying (line 145) | private void startPlaying(final String fileName)
    method stopPlaying (line 192) | private void stopPlaying() throws IllegalStateException {
    method stopPlaying (line 196) | private void stopPlaying(int reason) throws IllegalStateException {
    type OnStopListener (line 214) | public interface OnStopListener {
      method onStop (line 215) | void onStop(int reason);

FILE: imkit/src/main/java/com/beetle/bauhinia/tools/BinAscii.java
  class BinAscii (line 16) | public class BinAscii {
    method bin2Hex (line 36) | public final static String bin2Hex(byte[] b) {

FILE: imkit/src/main/java/com/beetle/bauhinia/tools/DeviceUtil.java
  class DeviceUtil (line 18) | public class DeviceUtil {
    method isFullStorage (line 19) | public static boolean isFullStorage() {
    method isMediaMounted (line 33) | public static boolean isMediaMounted() {

FILE: imkit/src/main/java/com/beetle/bauhinia/tools/FileCache.java
  class FileCache (line 30) | public class FileCache {
    method getInstance (line 32) | public static FileCache getInstance() {
    method setDir (line 37) | public void setDir(File dir) {
    method moveFile (line 42) | public void moveFile(String key, String src) throws IOException {
    method storeFile (line 55) | public void storeFile(String key, InputStream inputStream) throws IOEx...
    method storeByteArray (line 63) | public void storeByteArray(String key, ByteArrayOutputStream byteStrea...
    method storeFile (line 71) | public void storeFile(String key, byte[] data) throws IOException {
    method removeFile (line 80) | public void removeFile(String key) {
    method getCachedFilePath (line 85) | public String getCachedFilePath(String key) {
    method isCached (line 90) | public boolean isCached(String key) {
    method getFileName (line 95) | private String getFileName(String key) {
    method copy (line 124) | public void copy(File src, File dst) throws IOException {

FILE: imkit/src/main/java/com/beetle/bauhinia/tools/FileDownloader.java
  class FileDownloader (line 30) | public class FileDownloader {
    type FileDownloaderObserver (line 31) | public interface FileDownloaderObserver {
      method onFileDownloadSuccess (line 32) | public void onFileDownloadSuccess(IMessage msg);
      method onFileDownloadFail (line 33) | public void onFileDownloadFail(IMessage msg);
    method getInstance (line 37) | public static FileDownloader getInstance() {
    method addObserver (line 49) | public void addObserver(FileDownloaderObserver ob) {
    method removeObserver (line 56) | public void removeObserver(FileDownloaderObserver ob) {
    method isDownloading (line 60) | public boolean isDownloading(IMessage msg) {
    method download (line 72) | public void download(final IMessage imsg) {
    method onDownloadSuccess (line 126) | private void onDownloadSuccess(IMessage msg) {
    method onDownloadFail (line 132) | private void onDownloadFail(IMessage msg) {

FILE: imkit/src/main/java/com/beetle/bauhinia/tools/ImageMIME.java
  class ImageMIME (line 23) | public class ImageMIME {
    method getMimeType (line 24) | public static String getMimeType(File file) {
    method isValidPNG (line 44) | public static boolean isValidPNG(InputStream is) {
    method isValidJPEG (line 62) | public static boolean isValidJPEG(InputStream is, long size) {

FILE: imkit/src/main/java/com/beetle/bauhinia/tools/MapUtil.java
  class MapUtil (line 28) | public class MapUtil {
    method isAvailable (line 29) | public static boolean isAvailable(Context context, String packageName){
    method openBaidu (line 44) | public static void openBaidu(Context context, String poiname, double l...
    method isBaiduAvailable (line 56) | public static boolean isBaiduAvailable(Context context) {
    method openAMap (line 60) | public static void openAMap(Context context, String poiname, double lo...
    method isAMapAvailable (line 75) | public static boolean isAMapAvailable(Context context) {
    method openMap (line 79) | public static void openMap(Context context, String poiname, double lon...

FILE: imkit/src/main/java/com/beetle/bauhinia/tools/TimeUtil.java
  class TimeUtil (line 20) | public class TimeUtil {
    method now (line 23) | public static int now() {
    method formatTimeBase (line 29) | public static String formatTimeBase(long ts) {
    method isToday (line 54) | static private boolean isToday(long ts) {
    method isYesterday (line 59) | static private boolean isYesterday(long ts) {
    method isInWeek (line 65) | static private boolean isInWeek(long ts) {
    method isInYear (line 77) | static private boolean isInYear(long ts) {
    method isSameDay (line 88) | static private boolean isSameDay(long ts1, long ts2) {

FILE: imkit/src/main/java/com/beetle/bauhinia/tools/VideoUtil.java
  class VideoUtil (line 22) | public class VideoUtil {
    class Metadata (line 27) | public static class Metadata {
    method createVideoThumbnail (line 36) | public static Bitmap createVideoThumbnail(String filePath) {
    method getVideoMetadata (line 61) | public static Metadata getVideoMetadata(String filePath) {
    method getTrackInfo (line 87) | private static boolean getTrackInfo(String filePath, Metadata meta) {
    method isAcc (line 115) | public static boolean isAcc(String mime) {
    method isH264 (line 118) | public static boolean isH264(String mime) {

FILE: imkit/src/main/java/com/beetle/bauhinia/view/InMessageView.java
  class InMessageView (line 31) | public class InMessageView extends MessageRowView {
    method InMessageView (line 37) | public InMessageView(Context context, MessageContent.MessageType type,...
    method InMessageView (line 41) | public InMessageView(Context context, MessageContent.MessageType type,...
    method setMessage (line 64) | public void setMessage(IMessage msg) {
    method propertyChange (line 83) | @Override
    method updateReplyButton (line 114) | void updateReplyButton() {

FILE: imkit/src/main/java/com/beetle/bauhinia/view/MessageRowView.java
  class MessageRowView (line 19) | public class MessageRowView extends FrameLayout implements PropertyChang...
    method MessageRowView (line 26) | public MessageRowView(Context context) {
    method addContent (line 30) | protected void addContent(MessageContent.MessageType type, ViewGroup v...
    method setMessage (line 83) | public void setMessage(IMessage msg) {
    method getMessage (line 109) | public IMessage getMessage() {
    method getContentView (line 113) | public View getContentView() {
    method getContentFrame (line 117) | public View getContentFrame() {
    method getReplyButton (line 121) | public Button getReplyButton() {
    method propertyChange (line 125) | @Override

FILE: imkit/src/main/java/com/beetle/bauhinia/view/MiddleMessageView.java
  class MiddleMessageView (line 20) | public class MiddleMessageView extends MessageRowView {
    method MiddleMessageView (line 22) | public MiddleMessageView(Context context, MessageContent.MessageType t...
    method setMessage (line 31) | public void setMessage(IMessage msg) {

FILE: imkit/src/main/java/com/beetle/bauhinia/view/OutMessageView.java
  class OutMessageView (line 33) | public class OutMessageView extends MessageRowView {
    method OutMessageView (line 39) | public OutMessageView(Context context, MessageContent.MessageType type...
    method setMessage (line 62) | public void setMessage(IMessage msg) {
    method propertyChange (line 116) | @Override
    method updateReadedButton (line 179) | void updateReadedButton() {
    method updateReplyButton (line 200) | void updateReplyButton() {

FILE: imkit/src/main/java/com/beetle/bauhinia/view/TagView.java
  class TagView (line 11) | public class TagView extends TagContainerLayout {
    method TagView (line 12) | public TagView(Context context) {
    method TagView (line 16) | public TagView(Context context, AttributeSet attrs) {
    method TagView (line 20) | public TagView(Context context, AttributeSet attrs, int defStyleAttr) {
    method onMeasure (line 26) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/activity/BaseActivity.java
  class BaseActivity (line 27) | public class BaseActivity extends AppCompatActivity {
    method onCreate (line 30) | @Override
    method onResume (line 35) | @Override
    method onStop (line 51) | @Override
    method canBack (line 62) | public boolean canBack() {
    method onOptionsItemSelected (line 66) | public boolean onOptionsItemSelected(MenuItem item) {
    method isAppOnForeground (line 83) | public boolean isAppOnForeground() {
    method showBack (line 109) | protected void showBack(boolean show) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/ConversationIterator.java
  type ConversationIterator (line 11) | public interface ConversationIterator {
    method next (line 12) | public IMessage next();

FILE: imlib/src/main/java/com/beetle/bauhinia/db/CustomerMessageDB.java
  class CustomerMessageDB (line 8) | public class CustomerMessageDB extends SQLCustomerMessageDB implements I...
    method getInstance (line 11) | public static CustomerMessageDB getInstance() {
    method clearConversation (line 17) | public boolean clearConversation(String conversationID) {
    method saveMessageAttachment (line 22) | public void saveMessageAttachment(IMessage msg, String address) {
    method saveMessage (line 28) | public void saveMessage(IMessage imsg) {
    method removeMessage (line 34) | public void removeMessage(IMessage imsg) {
    method markMessageListened (line 39) | public void markMessageListened(IMessage imsg) {
    method markMessageFailure (line 44) | public void markMessageFailure(IMessage imsg) {
    method eraseMessageFailure (line 49) | public void eraseMessageFailure(IMessage imsg) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/CustomerPeerMessageDB.java
  class CustomerPeerMessageDB (line 8) | public class CustomerPeerMessageDB extends SQLCustomerMessageDB implemen...
    method getInstance (line 11) | public static CustomerPeerMessageDB getInstance() {
    class PeerId (line 16) | private static class PeerId {
    method parsePeerId (line 21) | PeerId parsePeerId(String conversationID) {
    method newMessageIterator (line 34) | public MessageIterator newMessageIterator(String conversationID) {
    method newForwardMessageIterator (line 39) | public MessageIterator newForwardMessageIterator(String conversationID...
    method newBackwardMessageIterator (line 44) | public MessageIterator newBackwardMessageIterator(String conversationI...
    method newMiddleMessageIterator (line 49) | public MessageIterator newMiddleMessageIterator(String conversationID,...
    method clearConversation (line 54) | public boolean clearConversation(String conversationID) {
    method saveMessageAttachment (line 59) | public void saveMessageAttachment(IMessage msg, String address) {
    method saveMessage (line 65) | public void saveMessage(IMessage imsg) {
    method removeMessage (line 71) | public void removeMessage(IMessage imsg) {
    method markMessageListened (line 76) | public void markMessageListened(IMessage imsg) {
    method markMessageFailure (line 81) | public void markMessageFailure(IMessage imsg) {
    method eraseMessageFailure (line 86) | public void eraseMessageFailure(IMessage imsg) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/EPeerMessageDB.java
  class EPeerMessageDB (line 3) | public class EPeerMessageDB extends BasePeerMessageDB {
    method getInstance (line 6) | public static EPeerMessageDB getInstance() {
    method EPeerMessageDB (line 10) | EPeerMessageDB() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/GroupMessageDB.java
  class GroupMessageDB (line 9) | public class GroupMessageDB extends SQLGroupMessageDB implements IMessag...
    method getInstance (line 14) | public static GroupMessageDB getInstance() {
    method clearConversation (line 19) | public boolean clearConversation(String conversationID) {
    method saveMessageAttachment (line 24) | public void saveMessageAttachment(IMessage msg, String address) {
    method saveMessage (line 30) | public void saveMessage(IMessage imsg) {
    method removeMessage (line 35) | public void removeMessage(IMessage imsg) {
    method markMessageListened (line 40) | public void markMessageListened(IMessage imsg) {
    method markMessageFailure (line 45) | public void markMessageFailure(IMessage imsg) {
    method eraseMessageFailure (line 50) | public void eraseMessageFailure(IMessage imsg) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/ICustomerMessage.java
  class ICustomerMessage (line 9) | public class ICustomerMessage  extends IMessage {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/IMessage.java
  class IMessage (line 66) | public class IMessage implements Cloneable {
    method IMessage (line 91) | public IMessage() {
    method clone (line 95) | @Override
    method fromRaw (line 107) | public static MessageContent fromRaw(String raw) {
    method setContent (line 187) | public void setContent(String raw) {
    method setContent (line 191) | public void setContent(MessageContent content) {
    method getStoreId (line 195) | public long getStoreId() {
    method getUUID (line 203) | public String getUUID() {
    method getReference (line 211) | public String getReference() {
    method getType (line 219) | public MessageContent.MessageType getType() {
    method addPropertyChangeListener (line 230) | public void addPropertyChangeListener(PropertyChangeListener listener) {
    method removePropertyChangeListener (line 234) | public void removePropertyChangeListener(PropertyChangeListener listen...
    method addPropertyChangeListener (line 238) | public void addPropertyChangeListener(String propertyName,
    method setUploading (line 243) | public void setUploading(boolean uploading) {
    method getUploading (line 249) | public boolean getUploading() {
    method setPlaying (line 253) | public void setPlaying(boolean playing) {
    method getPlaying (line 259) | public boolean getPlaying() {
    method setDownloading (line 263) | public void setDownloading(boolean downloading) {
    method getDownloading (line 269) | public boolean getDownloading() {
    method setFlags (line 273) | public void setFlags(int f) {
    method isFailure (line 279) | public boolean isFailure() {
    method setFailure (line 283) | public void setFailure(boolean f) {
    method isAck (line 293) | public boolean isAck() {
    method setAck (line 297) | public void setAck(boolean ack) {
    method isListened (line 307) | public boolean isListened() {
    method setListened (line 312) | public void setListened(boolean listened) {
    method setReaded (line 323) | public void setReaded(boolean readed) {
    method isReaded (line 333) | public boolean isReaded() {
    method getGeocoding (line 338) | public boolean getGeocoding() {
    method setGeocoding (line 342) | public void setGeocoding(boolean geocoding) {
    method setSenderName (line 348) | public void setSenderName(String senderName) {
    method getSenderName (line 354) | public String getSenderName() {
    method setSenderAvatar (line 358) | public void setSenderAvatar(String senderAvatar) {
    method getSenderAvatar (line 364) | public String getSenderAvatar() {
    method getReaderCount (line 368) | public int getReaderCount() {
    method setReaderCount (line 372) | public void setReaderCount(int count) {
    method getReferenceCount (line 378) | public int getReferenceCount() {
    method setReferenceCount (line 382) | public void setReferenceCount(int count) {
    method addTag (line 388) | public void addTag(String tag) {
    method deleteTag (line 395) | public void deleteTag(String tag) {
    method getTags (line 403) | public List<String> getTags() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/IMessageDB.java
  type IMessageDB (line 7) | public interface IMessageDB {
    method newMessageIterator (line 10) | MessageIterator newMessageIterator(long conversationID);
    method newForwardMessageIterator (line 12) | MessageIterator newForwardMessageIterator(long conversationID, long fi...
    method newBackwardMessageIterator (line 14) | MessageIterator newBackwardMessageIterator(long conversationID, long m...
    method newMiddleMessageIterator (line 16) | MessageIterator newMiddleMessageIterator(long conversationID, long msg...
    method clearConversation (line 18) | boolean clearConversation(String conversationID);
    method saveMessageAttachment (line 19) | void saveMessageAttachment(IMessage msg, String address);
    method saveMessage (line 20) | void saveMessage(IMessage imsg);
    method removeMessage (line 21) | void removeMessage(IMessage imsg);
    method markMessageListened (line 22) | void markMessageListened(IMessage imsg);
    method markMessageFailure (line 23) | void markMessageFailure(IMessage imsg);
    method eraseMessageFailure (line 24) | void eraseMessageFailure(IMessage imsg);

FILE: imlib/src/main/java/com/beetle/bauhinia/db/MessageFlag.java
  class MessageFlag (line 5) | public class MessageFlag {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/MessageIterator.java
  type MessageIterator (line 11) | public interface MessageIterator {
    method next (line 12) | public IMessage next();

FILE: imlib/src/main/java/com/beetle/bauhinia/db/PeerMessageDB.java
  class BasePeerMessageDB (line 4) | class BasePeerMessageDB extends SQLPeerMessageDB implements IMessageDB {
    method clearConversation (line 6) | public boolean clearConversation(String conversationID) {
    method saveMessageAttachment (line 11) | public void saveMessageAttachment(IMessage msg, String address) {
    method saveMessage (line 17) | public void saveMessage(IMessage imsg) {
    method removeMessage (line 22) | public void removeMessage(IMessage imsg) {
    method markMessageListened (line 26) | public void markMessageListened(IMessage imsg) {
    method markMessageFailure (line 30) | public void markMessageFailure(IMessage imsg) {
    method eraseMessageFailure (line 34) | public void eraseMessageFailure(IMessage imsg) {
  class PeerMessageDB (line 40) | public class PeerMessageDB extends BasePeerMessageDB {
    method getInstance (line 43) | public static PeerMessageDB getInstance() {
    method PeerMessageDB (line 48) | PeerMessageDB() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/SQLCustomerMessageDB.java
  class SQLCustomerMessageDB (line 16) | public class SQLCustomerMessageDB {
    class CustomerMessageIterator (line 18) | private class CustomerMessageIterator implements MessageIterator{
      method CustomerMessageIterator (line 21) | public CustomerMessageIterator() {}
      method CustomerMessageIterator (line 23) | public CustomerMessageIterator(SQLiteDatabase db, long storeID) {
      method CustomerMessageIterator (line 28) | public CustomerMessageIterator(SQLiteDatabase db, long storeID, long...
      method next (line 34) | public IMessage next() {
    class CustomerPeerMessageIterator (line 49) | private class CustomerPeerMessageIterator extends CustomerMessageItera...
      method CustomerPeerMessageIterator (line 50) | public CustomerPeerMessageIterator(SQLiteDatabase db, long peerAppID...
      method CustomerPeerMessageIterator (line 55) | public CustomerPeerMessageIterator(SQLiteDatabase db, long peerAppID...
    method setDb (line 70) | public void setDb(SQLiteDatabase db) {
    method getDb (line 74) | public SQLiteDatabase getDb() {
    method insertFTS (line 78) | private boolean insertFTS(long msgLocalID, String text) {
    method insertMessage (line 88) | public boolean insertMessage(IMessage m, long peerAppID, long peer) {
    method updateContent (line 118) | public boolean updateContent(long msgLocalID, String content) {
    method acknowledgeMessage (line 126) | public boolean acknowledgeMessage(long msgLocalID) {
    method markMessageFailure (line 130) | public boolean markMessageFailure(long msgLocalID) {
    method markMessageListened (line 134) | public boolean markMessageListened(long msgLocalID) {
    method eraseMessageFailure (line 138) | public boolean eraseMessageFailure(long msgLocalID) {
    method addFlag (line 143) | public boolean addFlag(long msgLocalID, int f) {
    method removeFlag (line 158) | public boolean removeFlag(long msgLocalID, int f) {
    method updateFlag (line 172) | public boolean updateFlag(long msgLocalID, int flags) {
    method removeMessage (line 179) | public boolean removeMessage(long msgLocalID) {
    method removeMessageIndex (line 185) | public boolean removeMessageIndex(long msgLocalID) {
    method clearConversation (line 191) | public boolean clearConversation(long storeID) {
    method clearConversation (line 196) | public boolean clearConversation(long appid, long uid) {
    method newMessageIterator (line 201) | public MessageIterator newMessageIterator(long storeID) {
    method newForwardMessageIterator (line 205) | public MessageIterator newForwardMessageIterator(long storeID, long fi...
    method newBackwardMessageIterator (line 209) | public MessageIterator newBackwardMessageIterator(long storeID, long m...
    method newMiddleMessageIterator (line 213) | public MessageIterator newMiddleMessageIterator(long storeID, long msg...
    method newCustomerPeerMessageIterator (line 218) | public MessageIterator newCustomerPeerMessageIterator(long appid, long...
    method newCustomerPeerForwardMessageIterator (line 222) | public MessageIterator newCustomerPeerForwardMessageIterator(long appi...
    method newCustomerPeerBackwardMessageIterator (line 226) | public MessageIterator newCustomerPeerBackwardMessageIterator(long app...
    method newCustomerPeerMiddleMessageIterator (line 230) | public MessageIterator newCustomerPeerMiddleMessageIterator(long appid...
    method tokenizer (line 235) | private String tokenizer(String key) {
    method search (line 248) | public ArrayList<IMessage> search(String key) {
    method getMessage (line 271) | private ICustomerMessage getMessage(Cursor cursor) {
    method getMessage (line 285) | public ICustomerMessage getMessage(long id) {
    method getMessageId (line 296) | public long getMessageId(String uuid) {
    method getMessage (line 310) | public ICustomerMessage getMessage(String uuid) {
    method getLastMessage (line 321) | public ICustomerMessage getLastMessage(long storeID) {
    method getLastMessage (line 333) | public ICustomerMessage getLastMessage(long appid, long uid) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/SQLGroupMessageDB.java
  class SQLGroupMessageDB (line 22) | public class SQLGroupMessageDB  {
    class GroupMessageIterator (line 23) | private class GroupMessageIterator implements MessageIterator{
      method next (line 25) | public IMessage next() {
    class ForwardGroupMessageIterator (line 41) | private class ForwardGroupMessageIterator extends GroupMessageIterator {
      method ForwardGroupMessageIterator (line 42) | public ForwardGroupMessageIterator(SQLiteDatabase db, long group_id)  {
      method ForwardGroupMessageIterator (line 48) | public ForwardGroupMessageIterator(SQLiteDatabase db, long group_id,...
    class BackwarkGroupMessageIterator (line 55) | private class BackwarkGroupMessageIterator extends GroupMessageIterator {
      method BackwarkGroupMessageIterator (line 56) | public BackwarkGroupMessageIterator(SQLiteDatabase db, long group_id...
    class MiddleGroupMessageIterator (line 65) | private class MiddleGroupMessageIterator extends GroupMessageIterator {
      method MiddleGroupMessageIterator (line 66) | public MiddleGroupMessageIterator(SQLiteDatabase db, long group_id, ...
    class TopicGroupMessageIterator (line 73) | private class TopicGroupMessageIterator extends GroupMessageIterator {
      method TopicGroupMessageIterator (line 74) | public TopicGroupMessageIterator(SQLiteDatabase db, long group_id, S...
    class GroupConversationIterator (line 82) | public class GroupConversationIterator implements ConversationIterator {
      method GroupConversationIterator (line 85) | public GroupConversationIterator(SQLiteDatabase db) {
      method next (line 89) | public IMessage next() {
    method setDb (line 116) | public void setDb(SQLiteDatabase db) {
    method getDb (line 120) | public SQLiteDatabase getDb() {
    method insertFTS (line 124) | private boolean insertFTS(int msgLocalID, String text) {
    method incrementReferenceCount (line 133) | boolean incrementReferenceCount(String uuid) {
    method insertMessage (line 143) | public boolean insertMessage(IMessage msg, long gid) {
    method insertMessages (line 171) | public boolean insertMessages(List<IMessage> msgs) {
    method updateContent (line 208) | public boolean updateContent(long msgLocalID, String content) {
    method acknowledgeMessage (line 216) | public int acknowledgeMessage(long msgLocalID) {
    method markMessageFailure (line 220) | public int markMessageFailure(long msgLocalID) {
    method markMessageListened (line 224) | public int markMessageListened(long msgLocalID) {
    method markMessageReaded (line 228) | public int markMessageReaded(long msgLocalID) {
    method eraseMessageFailure (line 232) | public boolean eraseMessageFailure(long msgLocalID) {
    method addFlag (line 237) | public int addFlag(long msgLocalID, int f) {
    method removeFlag (line 255) | private boolean removeFlag(long msgLocalID, int f) {
    method updateFlag (line 269) | public boolean updateFlag(long msgLocalID, int flags) {
    method removeMessage (line 276) | public boolean removeMessage(long msgLocalID) {
    method removeMessageIndex (line 282) | public boolean removeMessageIndex(long msgLocalID, long gid) {
    method clearConversation (line 288) | public boolean clearConversation(long gid) {
    method newMessageIterator (line 293) | public MessageIterator newMessageIterator(long gid) {
    method newForwardMessageIterator (line 297) | public MessageIterator newForwardMessageIterator(long gid, long firstM...
    method newBackwardMessageIterator (line 301) | public MessageIterator newBackwardMessageIterator(long gid, long msgID) {
    method newMiddleMessageIterator (line 305) | public MessageIterator newMiddleMessageIterator(long gid, long msgID) {
    method newTopicMessageIterator (line 309) | public MessageIterator newTopicMessageIterator(long gid, String uuid) {
    method newConversationIterator (line 313) | public ConversationIterator newConversationIterator() {
    method tokenizer (line 319) | private String tokenizer(String key) {
    method search (line 332) | public ArrayList<IMessage> search(String key) {
    method getMessage (line 356) | private IMessage getMessage(Cursor cursor) {
    method getMessage (line 378) | public IMessage getMessage(long id) {
    method getMessage (line 390) | public IMessage getMessage(String uuid) {
    method getLastMessage (line 401) | public IMessage getLastMessage(long gid) {
    method getMessageId (line 415) | public long getMessageId(String uuid) {
    method addMessageTag (line 429) | public boolean addMessageTag(long msgId, String tag) {
    method removeMessageTag (line 450) | public boolean removeMessageTag(long msgId, String tag) {
    method addMessageReader (line 479) | public boolean addMessageReader(long msgId, long uid) {
    method getMessageReaders (line 512) | public List<Long> getMessageReaders(long msgId) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/SQLPeerMessageDB.java
  class SQLPeerMessageDB (line 17) | public class SQLPeerMessageDB {
    class PeerMessageIterator (line 19) | private class PeerMessageIterator implements MessageIterator{
      method next (line 22) | public IMessage next() {
    class ForwardPeerMessageInterator (line 37) | private class ForwardPeerMessageInterator extends PeerMessageIterator {
      method ForwardPeerMessageInterator (line 38) | public ForwardPeerMessageInterator(SQLiteDatabase db, long peer)  {
      method ForwardPeerMessageInterator (line 44) | public ForwardPeerMessageInterator(SQLiteDatabase db, long peer, lon...
    class BackwardPeerMessageInterator (line 51) | private class BackwardPeerMessageInterator extends PeerMessageIterator {
      method BackwardPeerMessageInterator (line 52) | public BackwardPeerMessageInterator(SQLiteDatabase db, long peer, lo...
    class MiddlePeerMessageInterator (line 59) | private class MiddlePeerMessageInterator extends PeerMessageIterator {
      method MiddlePeerMessageInterator (line 60) | public MiddlePeerMessageInterator(SQLiteDatabase db, long peer, long...
    class PeerConversationIterator (line 68) | public class PeerConversationIterator implements ConversationIterator {
      method PeerConversationIterator (line 70) | public PeerConversationIterator(SQLiteDatabase db) {
      method next (line 75) | public IMessage next() {
    method setDb (line 98) | public void setDb(SQLiteDatabase db) {
    method getDb (line 102) | public SQLiteDatabase getDb() {
    method insertMessage (line 107) | public boolean insertMessage(IMessage msg, long uid) {
    method updateContent (line 134) | public boolean updateContent(long msgLocalID, String content) {
    method acknowledgeMessage (line 141) | public int acknowledgeMessage(long msgLocalID) {
    method markMessageFailure (line 145) | public int markMessageFailure(long msgLocalID) {
    method markMessageListened (line 149) | public int markMessageListened(long msgLocalID) {
    method markMessageReaded (line 153) | public int markMessageReaded(long msgLocalID) {
    method eraseMessageFailure (line 157) | public boolean eraseMessageFailure(long msgLocalID) {
    method addFlag (line 162) | public int addFlag(long msgLocalID, int f) {
    method removeFlag (line 181) | public boolean removeFlag(long msgLocalID, int f) {
    method updateFlag (line 197) | public boolean updateFlag(long msgLocalID, int flags) {
    method removeMessage (line 205) | public boolean removeMessage(long msgLocalID) {
    method removeMessageIndex (line 211) | public boolean removeMessageIndex(long msgLocalID) {
    method clearConversation (line 216) | public boolean clearConversation(long uid) {
    method newMessageIterator (line 222) | public MessageIterator newMessageIterator(long uid) {
    method newForwardMessageIterator (line 227) | public MessageIterator newForwardMessageIterator(long uid, long firstM...
    method newBackwardMessageIterator (line 232) | public MessageIterator newBackwardMessageIterator(long uid, long msgID) {
    method newMiddleMessageIterator (line 237) | public MessageIterator newMiddleMessageIterator(long uid, long msgID) {
    method newConversationIterator (line 241) | public ConversationIterator newConversationIterator() {
    method tokenizer (line 245) | private String tokenizer(String key) {
    method search (line 258) | public ArrayList<IMessage> search(String key) {
    method insertFTS (line 282) | private boolean insertFTS(int msgLocalID, String text) {
    method getMessage (line 291) | private IMessage getMessage(Cursor cursor) {
    method getMessage (line 304) | public IMessage getMessage(long id) {
    method getMessage (line 316) | public IMessage getMessage(String uuid) {
    method getLastMessage (line 329) | public IMessage getLastMessage(long peer) {
    method getMessageId (line 343) | public long getMessageId(String uuid) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/ACK.java
  class ACK (line 5) | public class ACK extends Notification {
    method getType (line 7) | public MessageType getType() {
    method newACK (line 12) | public static ACK newACK(int error) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Attachment.java
  class Attachment (line 7) | public  class Attachment extends MessageContent {
    method getType (line 12) | public MessageType getType() {
    method newAttachment (line 18) | public static Attachment newAttachment(int msgLocalID, String address) {
    method newURLAttachment (line 31) | public static Attachment newURLAttachment(int msgLocalID, String url) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Audio.java
  class Audio (line 10) | public  class Audio extends MessageContent {
    method Audio (line 14) | Audio(String url, long duration, String uuid) {
    method Audio (line 28) | public Audio(Audio other, String url) {
    method newAudio (line 41) | private static Audio newAudio(String url, long duration, String uuid) {
    method newAudio (line 46) | public static Audio newAudio(String url, long duration) {
    method getType (line 51) | public MessageType getType() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Classroom.java
  class Classroom (line 5) | public class Classroom extends MessageContent {
    method getType (line 18) | public MessageType getType() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Conference.java
  class Conference (line 5) | public class Conference extends MessageContent {
    method getType (line 18) | public MessageContent.MessageType getType() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/File.java
  class File (line 10) | public class File extends MessageContent {
    method File (line 15) | public File(String url, String filename, int size) {
    method File (line 32) | public File(File other, String url) {
    method getType (line 46) | public MessageType getType() {
    method newFile (line 50) | public static File newFile(String url, String filename, int size) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/GroupNotification.java
  class GroupNotification (line 10) | public  class GroupNotification extends Notification {
    method getType (line 19) | public MessageType getType() {
    method newGroupNotification (line 44) | public static GroupNotification newGroupNotification(String text) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/GroupVOIP.java
  class GroupVOIP (line 6) | public  class GroupVOIP extends Notification {
    method getType (line 10) | public MessageType getType() {
    method newGroupVOIP (line 15) | public static GroupVOIP newGroupVOIP(long initiator, boolean finished) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Headline.java
  class Headline (line 7) | public  class Headline extends Notification {
    method getDescription (line 10) | public String getDescription() {
    method getType (line 13) | public MessageType getType() {
    method newHeadline (line 19) | public static Headline newHeadline(String headline) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Image.java
  class Image (line 10) | public class Image extends MessageContent {
    method Image (line 15) | public Image(String url, int width, int height, String uuid) {
    method Image (line 30) | public Image(Image other, String url) {
    method getType (line 45) | public MessageType getType() {
    method newImage (line 49) | private static Image newImage(String url, int width, int height, Strin...
    method newImage (line 53) | public static Image newImage(String url, int width, int height) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Link.java
  class Link (line 5) | public  class Link extends MessageContent {
    method getType (line 10) | public MessageType getType() { return MessageType.MESSAGE_LINK; }

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Location.java
  class Location (line 9) | public  class Location extends MessageContent {
    method getType (line 13) | public MessageType getType() { return MessageType.MESSAGE_LOCATION; }
    method newLocation (line 16) | public static Location newLocation(float latitude, float longitude) {
    method newLocation (line 20) | public static Location newLocation(float latitude, float longitude, St...

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/MessageContent.java
  class MessageContent (line 10) | public abstract class MessageContent implements Cloneable {
    type MessageType (line 34) | public enum MessageType {
    method clone (line 60) | @Override
    method MessageContent (line 85) | public MessageContent() {
    method MessageContent (line 89) | public MessageContent(String uuid) {
    method MessageContent (line 93) | public MessageContent(MessageContent other) {
    method getType (line 104) | public MessageType getType() {
    method getRaw (line 108) | public String getRaw() {
    method setRaw (line 111) | public void setRaw(String raw) {
    method getUUID (line 115) | public String getUUID() {
    method setUUID (line 119) | public void setUUID(String uuid) {
    method getGroupId (line 123) | public long getGroupId() {
    method setGroupId (line 127) | public void setGroupId(long groupId) {
    method getStoreId (line 133) | public long getStoreId() {
    method setStoreId (line 137) | public void setStoreId(long storeId) {
    method getSessionId (line 141) | public String getSessionId() {
    method setSessionId (line 145) | public void setSessionId(String sessionId) {
    method setName (line 150) | public void setName(String name) {
    method getName (line 154) | public String getName() {
    method setAppName (line 158) | public void setAppName(String appName) {
    method getAppName (line 162) | public String getAppName() {
    method setStoreName (line 166) | public void setStoreName(String storeName) {
    method getStoreName (line 170) | public String getStoreName() {
    method getReference (line 174) | public String getReference() {
    method setReference (line 178) | public void setReference(String ref) {
    method generateRaw (line 182) | public void generateRaw(String uuid) {
    method generateRaw (line 196) | public void generateRaw(long groupId) {
    method generateRaw (line 210) | public void generateRaw(String uuid, String reference, long groupId) {
    method generateRaw (line 234) | public void generateRaw(long storeId, String sessionId, String storeNa...

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Notification.java
  class Notification (line 5) | public  abstract class Notification extends MessageContent {
    method getDescription (line 8) | public String getDescription() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/P2PSession.java
  class P2PSession (line 8) | public class P2PSession extends MessageContent {
    method newP2PSession (line 16) | public static P2PSession newP2PSession(String channelID, String devicd...
    method getType (line 34) | public MessageType getType() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Readed.java
  class Readed (line 5) | public class Readed extends MessageContent {
    method newReaded (line 8) | public static Readed newReaded(String msgid) {
    method getType (line 19) | public MessageContent.MessageType getType() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Revoke.java
  class Revoke (line 5) | public class Revoke extends Notification {
    method newRevoke (line 8) | public static Revoke newRevoke(String msgid) {
    method getType (line 20) | public MessageType getType() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Secret.java
  class Secret (line 5) | public class Secret extends MessageContent {
    method newSecret (line 10) | public static Secret newSecret(String ciphertext, int type, String uui...
    method getType (line 28) | public MessageType getType() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Tag.java
  class Tag (line 8) | public class Tag extends MessageContent {
    method newAddTag (line 16) | public static Tag newAddTag(String msgid, String t) {
    method newDeleteTag (line 30) | public static Tag newDeleteTag(String msgid, String t) {
    method getType (line 44) | public MessageType getType() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Text.java
  class Text (line 13) | public class Text extends MessageContent {
    method newText (line 21) | public static Text newText(String text) {
    method newText (line 34) | public static Text newText(String text, List<Long> at, List<String> at...
    method Text (line 61) | public Text(String text) {
    method Text (line 71) | public Text() {
    method getType (line 76) | public MessageType getType() {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/TimeBase.java
  class TimeBase (line 7) | public  class TimeBase extends Notification {
    method getType (line 9) | public MessageType getType() {
    method newTimeBase (line 14) | public static TimeBase newTimeBase(int timestamp) {

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Unknown.java
  class Unknown (line 3) | public  class Unknown extends MessageContent {}

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/VOIP.java
  class VOIP (line 5) | public  class VOIP extends MessageContent {
    method getType (line 18) | public MessageType getType() {
    method newVOIP (line 24) | public static VOIP newVOIP(int flag, int duration, boolean videoEnable...

FILE: imlib/src/main/java/com/beetle/bauhinia/db/message/Video.java
  class Video (line 10) | public class Video  extends MessageContent{
    method Video (line 17) | public Video(String url, String thumbnail, int width, int height, int ...
    method Video (line 37) | public Video(Video other, String url, String thumbnail) {
    method getType (line 55) | public MessageType getType() { return MessageType.MESSAGE_VIDEO; }
    method newVideo (line 57) | private static Video newVideo(String url, String thumbnail, int width,...
    method newVideo (line 61) | public static Video newVideo(String url, String thumbnail, int width, ...

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/GalleryImage.java
  class GalleryImage (line 19) | public class GalleryImage implements Parcelable {
    method GalleryImage (line 23) | public GalleryImage(String path) {
    method describeContents (line 27) | @Override
    method writeToParcel (line 32) | @Override
    method GalleryImage (line 37) | protected GalleryImage(Parcel in) {
    method createFromParcel (line 42) | @Override
    method newArray (line 47) | @Override
    method toString (line 53) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/tool/Closeables.java
  class Closeables (line 36) | public final class Closeables {
    method Closeables (line 39) | private Closeables() {}
    method close (line 70) | public static void close(@Nullable Closeable closeable,
    method closeQuietly (line 101) | public static void closeQuietly(@Nullable InputStream inputStream) {
    method closeQuietly (line 122) | public static void closeQuietly(@Nullable Reader reader) {
    method closeQuietly (line 130) | public static void closeQuietly(@Nullable OutputStream outputStream) {

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/tool/DisplayUtils.java
  class DisplayUtils (line 19) | public class DisplayUtils {
    method getSizeByGivenAbsSize (line 21) | public static int getSizeByGivenAbsSize(Context context, int givenAbsS...
    method getScreenWidth (line 25) | public static int getScreenWidth(Context context) {
    method getScreenHeight (line 29) | public static int getScreenHeight(Context context) {
    method getScreenDensity (line 33) | public static float getScreenDensity(Context context) {
    method getScreenDensityDpi (line 37) | public static int getScreenDensityDpi(Context context) {
    method dp2px (line 41) | public static int dp2px(Context context, float dp) {
    method px2dp (line 46) | public static int px2dp(Context context, float px) {
    method px2sp (line 51) | public static int px2sp(Context context, float pxValue) {
    method sp2px (line 55) | public static int sp2px(Context context, float spValue) {

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/tool/FileUtils.java
  class FileUtils (line 18) | public class FileUtils {
    method mkdirIfNeed (line 20) | public static void mkdirIfNeed(File file) {

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/tool/ImageUtils.java
  class ImageUtils (line 26) | public class ImageUtils {
    method savePNGImage (line 28) | public static String savePNGImage(Context context, String srcPath, Bit...
    method savePNGImageWithFileName (line 36) | public static String savePNGImageWithFileName(Context context, String ...
    method updateMediaStore (line 57) | public static void updateMediaStore(Context context, File savedFile) {

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/tool/Md5FileNameUtils.java
  class Md5FileNameUtils (line 21) | public class Md5FileNameUtils {
    method getMd5FileName (line 26) | public static String getMd5FileName(String url) {
    method getMD5 (line 32) | private static byte[] getMD5(byte[] data) {

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/tool/StorageUtils.java
  class StorageUtils (line 21) | public class StorageUtils {
    method getAlbumDir (line 25) | public static String getAlbumDir(Context context) {
    method getAppDir (line 34) | public static String getAppDir(Context context) {
    method getCacheDir (line 43) | public static String getCacheDir(Context context) {
    method isSDCardAvailable (line 54) | public static boolean isSDCardAvailable() {

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/ui/GalleryAdapter.java
  class GalleryAdapter (line 43) | public class GalleryAdapter extends PagerAdapter {
    method GalleryAdapter (line 50) | public GalleryAdapter(Context context, List<GalleryImage> photos) {
    method getCount (line 57) | @Override
    method isViewFromObject (line 62) | @Override
    method instantiateItem (line 67) | @Override
    method saveImageToPhone (line 110) | private void saveImageToPhone(final PhotoView photoView, final String ...
    method destroyItem (line 145) | @Override
    method setOnItemClickListener (line 150) | public void setOnItemClickListener(OnItemClickListener listener) {
    type OnItemClickListener (line 154) | public interface OnItemClickListener {
      method onItemClick (line 155) | void onItemClick(ViewGroup container, View view, int position);

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/ui/GalleryGridAdapter.java
  class GalleryGridAdapter (line 30) | public class GalleryGridAdapter extends BaseAdapter {
    method GalleryGridAdapter (line 37) | public GalleryGridAdapter(Context context, List<GalleryImage> imagesLi...
    method getCount (line 43) | @Override
    method getItem (line 48) | @Override
    method getItemId (line 53) | @Override
    method getView (line 58) | @Override
    method setConvertViewSize (line 83) | private void setConvertViewSize(final View convertView) {
    class ViewHolder (line 88) | public static class ViewHolder {

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/ui/GalleryGridUI.java
  class GalleryGridUI (line 31) | public class GalleryGridUI extends BaseActivity {
    method getCallingIntent (line 43) | public static Intent getCallingIntent(Context context, ArrayList<Galle...
    method onCreate (line 50) | @Override
    method handleIntent (line 58) | private void handleIntent(Intent intent) {
    method initView (line 63) | private void initView() {
    method navigateToViewImageDetail (line 76) | private void navigateToViewImageDetail(int position) {

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/ui/GalleryUI.java
  class GalleryUI (line 30) | public class GalleryUI extends BaseActivity {
    method getCallingIntent (line 45) | public static Intent getCallingIntent(Context context, ArrayList<Galle...
    method getCallingIntent (line 51) | public static Intent getCallingIntent(Context context, ArrayList<Galle...
    method onCreate (line 58) | @Override
    method initViews (line 66) | private void initViews() {
    method navigateToViewMorePicture (line 71) | private void navigateToViewMorePicture() {
    method init (line 76) | private void init() {
    method hideViewMorePictureButton (line 102) | private void hideViewMorePictureButton() {
    method showViewMorePictureButton (line 106) | private void showViewMorePictureButton() {

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/ui/PhotoActionPopup.java
  class PhotoActionPopup (line 34) | public class PhotoActionPopup {
    method createDialog (line 37) | public static Dialog createDialog(Context context, final Listener list...
    method pickItem (line 57) | private static void pickItem(ListAdapter adapter, int position) {
    method getListAdapter (line 62) | private static ListAdapter getListAdapter(final Context context, final...
    class ChoiceListItem (line 78) | private static final class ChoiceListItem {
      method ChoiceListItem (line 85) | public ChoiceListItem(int id, String caption, Runnable action) {
      method onPick (line 91) | public void onPick() {
      method toString (line 97) | @Override
      method getId (line 102) | public int getId() {
    type Listener (line 107) | public interface Listener {
      method onSaveToPhone (line 108) | void onSaveToPhone();

FILE: imlib/src/main/java/com/beetle/bauhinia/gallery/view/ScrollViewPager.java
  class ScrollViewPager (line 19) | public class ScrollViewPager extends ViewPager {
    method ScrollViewPager (line 23) | public ScrollViewPager(Context context) {
    method ScrollViewPager (line 27) | public ScrollViewPager(Context context, AttributeSet attrs) {
    method onInterceptTouchEvent (line 31) | @Override
    method onTouchEvent (line 43) | @Override
    method setAdapter (line 51) | @Override
    method setAdapter (line 56) | public void setAdapter(PagerAdapter arg0, int index) {
    method setEnableTouchScroll (line 61) | public void setEnableTouchScroll(boolean isEnable) {

FILE: imlib/src/main/java/com/beetle/bauhinia/toolbar/Contact.java
  class Contact (line 17) | public class Contact implements Mentionable {
    method Contact (line 22) | public Contact(long uid, String name) {
    method getUid (line 27) | public long getUid() {
    method getName (line 30) | public String getName() {
    method getTextForDisplayMode (line 38) | @NonNull
    method getDeleteStyle (line 51) | @Override
    method getSuggestibleId (line 58) | @Override
    method getSuggestiblePrimaryText (line 63) | @Override
    method describeContents (line 68) | @Override
    method writeToParcel (line 73) | @Override
    method Contact (line 79) | public Contact(Parcel in) {
    method createFromParcel (line 86) | public Contact createFromParcel(Parcel in) {
    method newArray (line 90) | public Contact[] newArray(int size) {

FILE: imlib/src/main/java/com/beetle/bauhinia/toolbar/EaseChatExtendMenu.java
  class EaseChatExtendMenu (line 35) | public class EaseChatExtendMenu extends GridView {
    method EaseChatExtendMenu (line 40) | public EaseChatExtendMenu(Context context, AttributeSet attrs, int def...
    method EaseChatExtendMenu (line 44) | public EaseChatExtendMenu(Context context, AttributeSet attrs) {
    method EaseChatExtendMenu (line 49) | public EaseChatExtendMenu(Context context) {
    method dip2px (line 54) | public static int dip2px(Context context, float dipValue){
    method init (line 58) | private void init(Context context, AttributeSet attrs){
    method init (line 73) | public void init(){
    method registerMenuItem (line 89) | public void registerMenuItem(String name, int drawableRes, int itemId,...
    method registerMenuItem (line 110) | public void registerMenuItem(int nameRes, int drawableRes, int itemId,...
    class ItemAdapter (line 115) | private class ItemAdapter extends ArrayAdapter<ChatMenuItemModel>{
      method ItemAdapter (line 119) | public ItemAdapter(Context context, List<ChatMenuItemModel> objects) {
      method getView (line 124) | @Override
    type EaseChatExtendMenuItemClickListener (line 149) | public interface EaseChatExtendMenuItemClickListener{
      method onClick (line 150) | void onClick(int itemId, View view);
    class ChatMenuItemModel (line 154) | class ChatMenuItemModel{
    class ChatMenuItem (line 161) | class ChatMenuItem extends LinearLayout {
      method ChatMenuItem (line 165) | public ChatMenuItem(Context context, AttributeSet attrs, int defStyl...
      method ChatMenuItem (line 169) | public ChatMenuItem(Context context, AttributeSet attrs) {
      method ChatMenuItem (line 174) | public ChatMenuItem(Context context) {
      method init (line 179) | private void init(Context context, AttributeSet attrs) {
      method setImage (line 185) | public void setImage(int resid) {
      method setText (line 189) | public void setText(int resid) {
      method setText (line 193) | public void setText(String text) {

FILE: imlib/src/main/java/com/beetle/bauhinia/toolbar/EaseChatInputMenu.java
  class EaseChatInputMenu (line 49) | public class
    method EaseChatInputMenu (line 64) | public EaseChatInputMenu(Context context, AttributeSet attrs, int defS...
    method EaseChatInputMenu (line 68) | public EaseChatInputMenu(Context context, AttributeSet attrs) {
    method EaseChatInputMenu (line 73) | public EaseChatInputMenu(Context context) {
    method init (line 78) | private void init(Context context, AttributeSet attrs) {
    method init (line 169) | public void init() {
    method disableSend (line 174) | public void disableSend() {
    method enableSend (line 185) | public void enableSend() {
    method clearFocus (line 195) | public void clearFocus() {
    method atUser (line 199) | public void atUser(long uid, String name) {
    method onClick (line 208) | @Override
    method registerExtendMenuItem (line 268) | public void registerExtendMenuItem(String name, int drawableRes, int i...
    method registerExtendMenuItem (line 285) | public void registerExtendMenuItem(int nameRes, int drawableRes, int i...
    method processEmoticon (line 293) | protected void processEmoticon() {
    method onQueryReceived (line 314) | @Override
    method toggleMore (line 326) | protected void toggleMore() {
    method toggleEmojicon (line 350) | protected void toggleEmojicon() {
    method hideKeyboard (line 376) | public void hideKeyboard() {
    method hideExtendMenuContainer (line 385) | public void hideExtendMenuContainer() {
    method onBackPressed (line 398) | public boolean onBackPressed() {
    method setChatInputMenuListener (line 407) | public void setChatInputMenuListener(ChatInputMenuListener listener) {
    type ChatInputMenuListener (line 411) | public interface ChatInputMenuListener {
      method onSendMessage (line 418) | void onSendMessage(String content, List<Long> at, List<String> atNam...
      method onPressToSpeakBtnTouch (line 426) | boolean onPressToSpeakBtnTouch(View v, MotionEvent event);
      method onFocusChanged (line 432) | void onFocusChanged(boolean hasFocus);
      method onAt (line 437) | void onAt();

FILE: imlib/src/main/java/com/beetle/bauhinia/toolbar/EaseChatPrimaryMenu.java
  class EaseChatPrimaryMenu (line 31) | public class EaseChatPrimaryMenu extends RelativeLayout  {
    method EaseChatPrimaryMenu (line 46) | public EaseChatPrimaryMenu(Context context, AttributeSet attrs, int de...
    method EaseChatPrimaryMenu (line 51) | public EaseChatPrimaryMenu(Context context, AttributeSet attrs) {
    method EaseChatPrimaryMenu (line 55) | public EaseChatPrimaryMenu(Context context) {
    method init (line 60) | private void init(final Context context, AttributeSet attrs) {
    method setModeVoice (line 82) | public void setModeVoice() {
    method setModeKeyboard (line 97) | public void setModeKeyboard() {
    method toggleFaceImage (line 114) | public void toggleFaceImage(){
    method showNormalFaceImage (line 122) | public void showNormalFaceImage(){
    method showSelectedFaceImage (line 127) | public void showSelectedFaceImage(){
    method hideKeyboard (line 135) | public void hideKeyboard() {
    method showKeyboard (line 142) | public void showKeyboard() {

FILE: imlib/src/main/java/com/beetle/bauhinia/toolbar/EaseExpandRecylerView.java
  class EaseExpandRecylerView (line 21) | public class EaseExpandRecylerView extends RecyclerView {
    method EaseExpandRecylerView (line 23) | public EaseExpandRecylerView(Context context) {
    method EaseExpandRecylerView (line 27) | public EaseExpandRecylerView(Context context, AttributeSet attrs) {
    method onMeasure (line 31) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/toolbar/emoticon/Emoticon.java
  class Emoticon (line 11) | public class Emoticon {
    method getId (line 21) | public int getId() {
    method setId (line 25) | public void setId(int id) {
    method getDesc (line 29) | public String getDesc() {
    method setDesc (line 33) | public void setDesc(String desc) {
    method getName (line 37) | public String getName() {
    method setName (line 41) | public void setName(String name) {
    method setBitmap (line 44) | public void setBitmap(Bitmap bitmap) {
    method getBitmap (line 47) | public Bitmap getBitmap() {

FILE: imlib/src/main/java/com/beetle/bauhinia/toolbar/emoticon/EmoticonAdapter.java
  class EmoticonAdapter (line 22) | public class EmoticonAdapter extends RecyclerView.Adapter<EmoticonAdapte...
    method EmoticonAdapter (line 29) | public EmoticonAdapter(Context context, @Nullable List<Emoticon> data) {
    method onCreateViewHolder (line 37) | @Override
    method onBindViewHolder (line 43) | @Override
    method getItemCount (line 61) | @Override
    method getItem (line 66) | public Emoticon getItem(int position) {
    method setOnClickListener (line 70) | public void setOnClickListener(OnItemClickListener listener) {
    type OnItemClickListener (line 76) | public interface OnItemClickListener {
      method onClick (line 78) | void onClick(int position);
    class BaseViewHolder (line 81) | class BaseViewHolder extends RecyclerView.ViewHolder {
      method BaseViewHolder (line 85) | public BaseViewHolder(View itemView) {

FILE: imlib/src/main/java/com/beetle/bauhinia/toolbar/emoticon/EmoticonManager.java
  class EmoticonManager (line 30) | public class EmoticonManager {
    method getInstance (line 69) | public static EmoticonManager getInstance() {
    method init (line 79) | public void init(Context context) {
    method loadUnicodeEmoji (line 96) | private void loadUnicodeEmoji(Context context) {
    method loadImageEmoji (line 117) | private void loadImageEmoji(Context context) {
    method getPageData (line 142) | private List<Emoticon> getPageData(int page) {
    method getEmoticonPageList (line 159) | public List<List<Emoticon>> getEmoticonPageList() {
    method addEmoticon (line 174) | public SpannableString addEmoticon(Context context, int imgId, String ...
    method getEmoticonStr (line 195) | public SpannableString getEmoticonStr(CharSequence text) {
    method dealEmoticon (line 208) | private void dealEmoticon(SpannableString spannableString,  String reg...
    class InstanceContainer (line 226) | private static class InstanceContainer {

FILE: imlib/src/main/java/com/beetle/bauhinia/toolbar/emoticon/EmoticonPanel.java
  class EmoticonPanel (line 30) | public class EmoticonPanel extends FrameLayout {
    method EmoticonPanel (line 57) | public EmoticonPanel(@NonNull Context context) {
    method EmoticonPanel (line 61) | public EmoticonPanel(@NonNull Context context, @Nullable AttributeSet ...
    method init (line 66) | public void init(Context context, @Nullable AttributeSet attrs) {
    method initData (line 74) | private void initData(Context context, @Nullable AttributeSet attrs) {
    method initView (line 90) | private void initView(Context context) {
    method initViewPager (line 96) | private void initViewPager() {
    method initIndicator (line 147) | private void initIndicator() {
    method drawIndicatorViews (line 164) | private void drawIndicatorViews(int index) {
    method setOnItemEmoticonClickListener (line 184) | public void setOnItemEmoticonClickListener(OnItemEmoticonClickListener...
    type OnItemEmoticonClickListener (line 188) | public interface OnItemEmoticonClickListener {
      method onEmoticonClick (line 190) | void onEmoticonClick(SpannableString spannableString);
      method onEmoticonDeleted (line 192) | void onEmoticonDeleted();

FILE: imlib/src/main/java/com/beetle/bauhinia/toolbar/emoticon/EmoticonUtils.java
  class EmoticonUtils (line 23) | public class EmoticonUtils {
    method EMOJI_CODE_TO_SYMBOL (line 82) | private static int EMOJI_CODE_TO_SYMBOL(int x) {
    method EmojiCodeToString (line 86) | public static String EmojiCodeToString(int x) {
    method readFile (line 98) | public static List<String> readFile(Context context, String fileName) {
    method getEmojiMap (line 117) | public static Map<String, String> getEmojiMap() {
    method getEmojiEncodeSet (line 121) | public static Set<String> getEmojiEncodeSet() {
    method getEmoticonSize (line 125) | private static int getEmoticonSize(Context context) {
    method getNormalSize (line 136) | public static int getNormalSize(Context context) {
    method getSmallSize (line 140) | public static int getSmallSize(Context context) {

FILE: imlib/src/main/java/com/beetle/bauhinia/toolbar/emoticon/ViewPagerAdapter.java
  class ViewPagerAdapter (line 16) | public class ViewPagerAdapter extends PagerAdapter {
    method ViewPagerAdapter (line 20) | public ViewPagerAdapter(List<View> pageViewList) {
    method getItemPosition (line 24) | @Override
    method getCount (line 29) | @Override
    method isViewFromObject (line 34) | @Override
    method destroyItem (line 39) | @Override
    method instantiateItem (line 44) | @NonNull

FILE: imlib/src/main/java/com/beetle/bauhinia/tools/DisplayUtils.java
  class DisplayUtils (line 9) | public class DisplayUtils {
    method getSizeByGivenAbsSize (line 11) | public static int getSizeByGivenAbsSize(Context context, int givenAbsS...
    method getScreenWidth (line 15) | public static int getScreenWidth(Context context) {
    method getScreenHeight (line 19) | public static int getScreenHeight(Context context) {
    method getScreenDensity (line 23) | public static float getScreenDensity(Context context) {
    method getScreenDensityDpi (line 27) | public static int getScreenDensityDpi(Context context) {
    method dp2px (line 31) | public static int dp2px(Context context, float dp) {
    method px2dp (line 36) | public static int px2dp(Context context, float px) {
    method px2sp (line 41) | public static int px2sp(Context context, float pxValue) {
    method sp2px (line 45) | public static int sp2px(Context context, float spValue) {

FILE: imlib/src/main/java/com/beetle/bauhinia/view/MessageAudioView.java
  class MessageAudioView (line 29) | public class MessageAudioView extends MessageContentView {
    method MessageAudioView (line 30) | public MessageAudioView(Context context) {
    class AudioHolder (line 35) | class AudioHolder  {
      method AudioHolder (line 40) | AudioHolder(View view) {
    method setMessage (line 47) | @Override
    method propertyChange (line 92) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/view/MessageClassroomView.java
  class MessageClassroomView (line 11) | public class MessageClassroomView extends MessageContentView {
    method MessageClassroomView (line 12) | public MessageClassroomView(Context context) {
    method setMessage (line 17) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/view/MessageContentView.java
  class MessageContentView (line 21) | public class MessageContentView extends FrameLayout implements PropertyC...
    method MessageContentView (line 26) | public MessageContentView(Context context) {
    method setMessage (line 32) | public void setMessage(IMessage msg) {
    method getMessage (line 40) | public IMessage getMessage() {
    method propertyChange (line 44) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/view/MessageFileView.java
  class MessageFileView (line 24) | public class MessageFileView extends MessageContentView {
    method MessageFileView (line 28) | public MessageFileView(Context context) {
    method setMessage (line 38) | public void setMessage(IMessage msg) {
    method formatSize (line 73) | private String formatSize(int size) {
    method propertyChange (line 84) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/view/MessageImageView.java
  class MessageImageView (line 25) | public class MessageImageView extends MessageContentView {
    method MessageImageView (line 30) | public MessageImageView(Context context) {
    method setMessage (line 38) | public void setMessage(IMessage msg) {
    method propertyChange (line 76) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/view/MessageLinkView.java
  class MessageLinkView (line 22) | public class MessageLinkView extends MessageContentView {
    method MessageLinkView (line 24) | public MessageLinkView(Context context) {
    method setMessage (line 30) | public void setMessage(IMessage msg) {
    method propertyChange (line 49) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/view/MessageLocationView.java
  class MessageLocationView (line 24) | public class MessageLocationView extends MessageContentView {
    method MessageLocationView (line 28) | public MessageLocationView(Context context) {
    method setMessage (line 36) | public void setMessage(IMessage msg) {
    method propertyChange (line 52) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/view/MessageNotificationView.java
  class MessageNotificationView (line 22) | public class MessageNotificationView extends MessageContentView {
    method MessageNotificationView (line 23) | public MessageNotificationView(Context context) {
    method setMessage (line 30) | @Override
    method propertyChange (line 41) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/view/MessageTextView.java
  class MessageTextView (line 20) | public class MessageTextView extends MessageContentView {
    method MessageTextView (line 23) | public MessageTextView(Context context) {
    method setMessage (line 29) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/view/MessageUnknownView.java
  class MessageUnknownView (line 19) | public class MessageUnknownView extends MessageContentView {
    method MessageUnknownView (line 20) | public MessageUnknownView(Context context) {
    method setMessage (line 24) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/view/MessageVOIPView.java
  class MessageVOIPView (line 27) | public class MessageVOIPView extends MessageContentView {
    method MessageVOIPView (line 29) | public MessageVOIPView(Context context) {
    method setMessage (line 34) | @Override

FILE: imlib/src/main/java/com/beetle/bauhinia/view/MessageVideoView.java
  class MessageVideoView (line 29) | public class MessageVideoView extends MessageContentView {
    method MessageVideoView (line 36) | public MessageVideoView(Context context) {
    method setMessage (line 47) | public void setMessage(IMessage msg) {
    method propertyChange (line 98) | @Override

FILE: imsdk/src/androidTest/java/com/beetle/im/ApplicationTest.java
  class ApplicationTest (line 19) | public class ApplicationTest extends ApplicationTestCase<Application> {
    method ApplicationTest (line 20) | public ApplicationTest() {

FILE: imsdk/src/main/java/com/beetle/im/BytePacket.java
  class BytePacket (line 19) | public class BytePacket {
    method writeInt64 (line 20) | static public void writeInt64(long v, byte[] dst, int pos) {
    method writeInt32 (line 28) | static public void writeInt32(int v, byte[] dst, int pos) {
    method writeInt16 (line 36) | static public void writeInt16(short v, byte[] dst, int pos) {
    method readInt64 (line 44) | static public long readInt64(byte[] bytes, int pos) {
    method readInt32 (line 50) | static public int readInt32(byte[] bytes, int pos) {
    method readInt16 (line 56) | static public short readInt16(byte[] bytes, int pos) {
    method packInetAddress (line 62) | static public int packInetAddress(byte[] bytes) {
    method unpackInetAddress (line 68) | static public byte[] unpackInetAddress(int iaddr) {
    method ltonl (line 77) | static public int ltonl(int v) {
    method ntoll (line 87) | static public int ntoll(int v) {
    method ltohl (line 98) | static public int ltohl(int v) {
    method htoll (line 109) | static public int htoll(int v) {
    method ntohl (line 119) | static public int ntohl(int v) {
    method htonl (line 129) | static public int htonl(int v) {

FILE: imsdk/src/main/java/com/beetle/im/CustomerMessage.java
  class CustomerMessage (line 16) | public class CustomerMessage extends IMMessage {

FILE: imsdk/src/main/java/com/beetle/im/CustomerMessageHandler.java
  type CustomerMessageHandler (line 16) | public interface CustomerMessageHandler {
    method handleMessage (line 17) | public boolean handleMessage(CustomerMessage msg);
    method handleMessageACK (line 18) | public boolean handleMessageACK(CustomerMessage msg);
    method handleMessageFailure (line 19) | public boolean handleMessageFailure(CustomerMessage msg);

FILE: imsdk/src/main/java/com/beetle/im/CustomerMessageObserver.java
  type CustomerMessageObserver (line 16) | public interface CustomerMessageObserver {
    method onCustomerMessage (line 17) | public void onCustomerMessage(CustomerMessage msg);
    method onCustomerMessageACK (line 18) | public void onCustomerMessageACK(CustomerMessage msg);
    method onCustomerMessageFailure (line 19) | public void onCustomerMessageFailure(CustomerMessage msg);

FILE: imsdk/src/main/java/com/beetle/im/GroupMessageHandler.java
  type GroupMessageHandler (line 18) | public interface GroupMessageHandler {
    method handleMessages (line 19) | public boolean handleMessages(List<IMMessage> msgs);
    method handleMessageACK (line 20) | public boolean handleMessageACK(IMMessage msg, int error);
    method handleMessageFailure (line 21) | public boolean handleMessageFailure(IMMessage msg);

FILE: imsdk/src/main/java/com/beetle/im/GroupMessageObserver.java
  type GroupMessageObserver (line 19) | public interface GroupMessageObserver {
    method onGroupMessages (line 20) | public void onGroupMessages(List<IMMessage> msg);
    method onGroupMessageACK (line 21) | public void onGroupMessageACK(IMMessage msg, int error);
    method onGroupMessageFailure (line 22) | public void onGroupMessageFailure(IMMessage msg);

FILE: imsdk/src/main/java/com/beetle/im/IMMessage.java
  class IMMessage (line 17) | public class IMMessage {

FILE: imsdk/src/main/java/com/beetle/im/IMService.java
  class IMService (line 52) | public class IMService {
    type ConnectState (line 71) | public enum ConnectState {
    class GroupSync (line 119) | private static class GroupSync {
    method getInstance (line 152) | public static IMService getInstance() {
    method IMService (line 156) | public IMService() {
    method getConnectState (line 164) | public ConnectState getConnectState() {
    method setLooper (line 168) | public void setLooper(Looper looper) {
    method getLooper (line 173) | public Looper getLooper() {
    method createTimer (line 177) | private void createTimer() {
    method setConnectTimeout (line 204) | public void setConnectTimeout(int connectTimeout) {
    method setHost (line 207) | public void setHost(String host) {
    method setToken (line 211) | public void setToken(String token) {
    method setDeviceID (line 215) | public void setDeviceID(String deviceID) {
    method setKeepAlive (line 219) | public void setKeepAlive(boolean keepAlive) {
    method setWakeLock (line 223) | public void setWakeLock(PowerManager.WakeLock wl) {
    method setSyncKey (line 227) | public void setSyncKey(long syncKey) {
    method addSuperGroupSyncKey (line 231) | public void addSuperGroupSyncKey(long groupID, long syncKey) {
    method removeSuperGroupSyncKey (line 239) | public void removeSuperGroupSyncKey(long groupID) {
    method clearSuperGroupSyncKeys (line 243) | public void clearSuperGroupSyncKeys() {
    method setSyncKeyHandler (line 247) | public void setSyncKeyHandler(SyncKeyHandler handler) {
    method setPeerMessageHandler (line 251) | public void setPeerMessageHandler(PeerMessageHandler handler) {
    method setGroupMessageHandler (line 254) | public void setGroupMessageHandler(GroupMessageHandler handler) {
    method setCustomerMessageHandler (line 257) | public void setCustomerMessageHandler(CustomerMessageHandler handler) {
    method addObserver (line 262) | public void addObserver(IMServiceObserver ob) {
    method removeObserver (line 269) | public void removeObserver(IMServiceObserver ob) {
    method addPeerObserver (line 274) | public void addPeerObserver(PeerMessageObserver ob) {
    method removePeerObserver (line 281) | public void removePeerObserver(PeerMessageObserver ob) {
    method addGroupObserver (line 285) | public void addGroupObserver(GroupMessageObserver ob) {
    method removeGroupObserver (line 292) | public void removeGroupObserver(GroupMessageObserver ob) {
    method addSystemObserver (line 296) | public void addSystemObserver(SystemMessageObserver ob) {
    method removeSystemObserver (line 303) | public void removeSystemObserver(SystemMessageObserver ob) {
    method addCustomerServiceObserver (line 307) | public void addCustomerServiceObserver(CustomerMessageObserver ob) {
    method removeCustomerServiceObserver (line 314) | public void removeCustomerServiceObserver(CustomerMessageObserver ob) {
    method addRTObserver (line 318) | public void addRTObserver(RTMessageObserver ob) {
    method removeRTObserver (line 325) | public void removeRTObserver(RTMessageObserver ob){
    method addRoomObserver (line 329) | public void addRoomObserver(RoomMessageObserver ob) {
    method removeRoomObserver (line 336) | public void removeRoomObserver(RoomMessageObserver ob) {
    method enterBackground (line 340) | public void enterBackground() {
    method _enterBackground (line 349) | public void _enterBackground() {
    method enterForeground (line 362) | public void enterForeground() {
    method _enterForeground (line 371) | public void _enterForeground() {
    method isNetworkConnected (line 379) | static boolean isNetworkConnected(NetworkCapabilities cap) {
    method isOnNet (line 383) | private static boolean isOnNet(Context context) {
    class NetworkCallback (line 405) | static class NetworkCallback extends ConnectivityManager.NetworkCallba...
      method NetworkCallback (line 407) | public NetworkCallback(Context context) {
      method onAvailable (line 411) | @Override
      method onLost (line 432) | @Override
    class HeartbeatReceiver (line 472) | static class HeartbeatReceiver extends BroadcastReceiver {
      method onReceive (line 475) | @Override
    method registerConnectivityChangeReceiver (line 498) | public void registerConnectivityChangeReceiver(Context context) {
    method startAlarm (line 515) | public void startAlarm(Context context) {
    method stopAlarm (line 540) | public void stopAlarm(Context context) {
    method start (line 549) | public void start() {
    method _start (line 558) | private void _start() {
    method stop (line 581) | public void stop() {
    method _stop (line 590) | private void _stop() {
    method suspend (line 609) | private void suspend() {
    method resume (line 622) | private void resume() {
    method sendPeerMessageAsync (line 638) | public void sendPeerMessageAsync(final IMMessage im) {
    method sendPeerMessage (line 653) | public boolean sendPeerMessage(IMMessage im) {
    method sendGroupMessageAsync (line 673) | public void sendGroupMessageAsync(final IMMessage im) {
    method sendGroupMessage (line 688) | public boolean sendGroupMessage(IMMessage im) {
    method sendCustomerMessageAsync (line 708) | public void sendCustomerMessageAsync(final CustomerMessage im) {
    method sendCustomerMessage (line 724) | public boolean sendCustomerMessage(CustomerMessage im) {
    method sendRTMessageAsync (line 744) | public void sendRTMessageAsync(final RTMessage rt) {
    method sendRTMessage (line 754) | public boolean sendRTMessage(RTMessage rt) {
    method sendRoomMessageAsync (line 765) | public void sendRoomMessageAsync(final RoomMessage rm) {
    method sendRoomMessage (line 774) | public boolean sendRoomMessage(RoomMessage rm) {
    method sendEnterRoom (line 782) | private void sendEnterRoom(long roomID) {
    method sendLeaveRoom (line 789) | private void sendLeaveRoom(long roomID) {
    method enterRoom (line 797) | public void enterRoom(final long roomID) {
    method leaveRoom (line 811) | public void leaveRoom(final long roomID) {
    method close (line 827) | private void close() {
    method now (line 898) | private static int now() {
    method refreshHost (line 904) | private void refreshHost() {
    method startConnectTimer (line 938) | private void startConnectTimer() {
    method onConnected (line 952) | private void onConnected() {
    method connect (line 983) | private void connect() {
    method heartbeat (line 1089) | private void heartbeat() {
    method handleAuthStatus (line 1110) | private void handleAuthStatus(Message msg) {
    method handleIMMessage (line 1123) | private void handleIMMessage(Message msg) {
    method handleGroupIMMessage (line 1153) | private void handleGroupIMMessage(Message msg) {
    method handleGroupNotification (line 1173) | private void handleGroupNotification(Message msg) {
    method handleClose (line 1198) | private void handleClose() {
    method handleACK (line 1203) | private void handleACK(Message msg) {
    method handleSystemMessage (line 1299) | private void handleSystemMessage(Message msg) {
    method handleCustomerMessage (line 1309) | private void handleCustomerMessage(Message msg) {
    method handleRTMessage (line 1323) | private void handleRTMessage(Message msg) {
    method handleRoomMessage (line 1336) | private void handleRoomMessage(Message msg) {
    method handleSyncNotify (line 1349) | private void handleSyncNotify(Message msg) {
    method handleSyncBegin (line 1369) | private void handleSyncBegin(Message msg) {
    method handleSyncEnd (line 1373) | private void handleSyncEnd(Message msg) {
    method handleSyncGroupNotify (line 1404) | private void handleSyncGroupNotify(Message msg) {
    method handleSyncGroupBegin (line 1431) | private void handleSyncGroupBegin(Message msg) {
    method handleSyncGroupEnd (line 1436) | private void handleSyncGroupEnd(Message msg) {
    method handleMetadata (line 1477) | private void handleMetadata(Message msg) {
    method handlePong (line 1481) | private void handlePong(Message msg) {
    method handleMessage (line 1485) | private void handleMessage(Message msg) {
    method appendData (line 1604) | private void appendData(byte[] data) {
    method handleData (line 1616) | private boolean handleData(byte[] data) {
    method sendAuth (line 1645) | private void sendAuth() {
    method sendSync (line 1659) | private void sendSync(long syncKey) {
    method sendSyncKey (line 1666) | private void sendSyncKey(long syncKey) {
    method sendGroupSync (line 1673) | private void sendGroupSync(long groupID, long syncKey) {
    method sendGroupSyncKey (line 1683) | private void sendGroupSyncKey(long groupID, long syncKey) {
    method sendACK (line 1693) | private void sendACK(int seq) {
    method sendHeartbeat (line 1702) | private void sendHeartbeat() {
    method sendMessage (line 1729) | private boolean sendMessage(Message msg) {
    method publishGroupMessages (line 1746) | private void publishGroupMessages(final List<IMMessage> msgs) {
    method publishGroupMessageACK (line 1758) | private void publishGroupMessageACK(final IMMessage im, final int erro...
    method publishGroupMessageFailure (line 1770) | private void publishGroupMessageFailure(final IMMessage im) {
    method publishPeerMessage (line 1782) | private void publishPeerMessage(final IMMessage msg) {
    method publishPeerSecretMessage (line 1794) | private void publishPeerSecretMessage(final IMMessage msg) {
    method publishPeerMessageACK (line 1808) | private void publishPeerMessageACK(final IMMessage msg, final int erro...
    method publishPeerMessageFailure (line 1821) | private void publishPeerMessageFailure(final IMMessage msg) {
    method publishConnectState (line 1835) | private void publishConnectState() {
    method publishCustomerMessage (line 1848) | private void publishCustomerMessage(final CustomerMessage cs) {
    method publishCustomerServiceMessageACK (line 1861) | private void publishCustomerServiceMessageACK(final CustomerMessage ms...
    method publishCustomerServiceMessageFailure (line 1875) | private void publishCustomerServiceMessageFailure(final CustomerMessag...
    method runOnMainThread (line 1887) | private void runOnMainThread(Runnable r) {
    method runOnWorkerThread (line 1891) | private void runOnWorkerThread(Runnable r) {
    method runOnThread (line 1895) | private void runOnThread(Looper looper, Handler handler, Runnable r) {
    method assertLooper (line 1903) | private void assertLooper() {

FILE: imsdk/src/main/java/com/beetle/im/IMServiceObserver.java
  type IMServiceObserver (line 16) | public interface IMServiceObserver {
    method onConnectState (line 17) | public void onConnectState(IMService.ConnectState state);

FILE: imsdk/src/main/java/com/beetle/im/Message.java
  class Command (line 20) | class Command{
  class Flag (line 62) | class Flag {
  class AuthenticationToken (line 75) | class AuthenticationToken {
  class GroupSyncKey (line 85) | class GroupSyncKey {
  class SyncNotify (line 90) | class SyncNotify {
  class GroupSyncNotify (line 94) | class GroupSyncNotify {
  class Metadata (line 99) | class Metadata {
  class Message (line 104) | public class Message {
    method pack (line 116) | public byte[] pack() {
    method unpack (line 259) | public boolean unpack(byte[] data) {

FILE: imsdk/src/main/java/com/beetle/im/MessageACK.java
  class MessageACK (line 4) | public class MessageACK {

FILE: imsdk/src/main/java/com/beetle/im/PeerMessageHandler.java
  type PeerMessageHandler (line 16) | public interface PeerMessageHandler {
    method handleMessage (line 17) | public boolean handleMessage(IMMessage msg);
    method handleMessageACK (line 18) | public boolean handleMessageACK(IMMessage msg, int error);
    method handleMessageFailure (line 19) | public boolean handleMessageFailure(IMMessage msg);

FILE: imsdk/src/main/java/com/beetle/im/PeerMessageObserver.java
  type PeerMessageObserver (line 16) | public interface PeerMessageObserver {
    method onPeerMessage (line 17) | public void onPeerMessage(IMMessage msg);
    method onPeerSecretMessage (line 18) | public void onPeerSecretMessage(IMMessage msg);
    method onPeerMessageACK (line 19) | public void onPeerMessageACK(IMMessage msg, int error);
    method onPeerMessageFailure (line 20) | public void onPeerMessageFailure(IMMessage msg);

FILE: imsdk/src/main/java/com/beetle/im/RTMessage.java
  class RTMessage (line 16) | public class RTMessage {

FILE: imsdk/src/main/java/com/beetle/im/RTMessageObserver.java
  type RTMessageObserver (line 16) | public interface RTMessageObserver {
    method onRTMessage (line 17) | void onRTMessage(RTMessage rt);

FILE: imsdk/src/main/java/com/beetle/im/RoomMessage.java
  class RoomMessage (line 16) | public class RoomMessage {

FILE: imsdk/src/main/java/com/beetle/im/RoomMessageObserver.java
  type RoomMessageObserver (line 16) | public interface RoomMessageObserver {
    method onRoomMessage (line 17) | public void onRoomMessage(RoomMessage msg);

FILE: imsdk/src/main/java/com/beetle/im/SyncKeyHandler.java
  type SyncKeyHandler (line 17) | public interface SyncKeyHandler {
    method saveSyncKey (line 18) | boolean saveSyncKey(long syncKey);
    method saveGroupSyncKey (line 19) | boolean saveGroupSyncKey(long groupID, long syncKey);

FILE: imsdk/src/main/java/com/beetle/im/SystemMessageObserver.java
  type SystemMessageObserver (line 16) | public interface SystemMessageObserver {
    method onSystemMessage (line 17) | public void onSystemMessage(String sm);

FILE: imsdk/src/main/java/com/beetle/im/Timer.java
  class Timer (line 22) | public abstract class Timer {
    class TimerHandler (line 29) | class TimerHandler extends Handler {
      method handleMessage (line 30) | @Override
      method TimerHandler (line 43) | public TimerHandler(Looper loop) {
    method Timer (line 49) | public Timer(Looper looper) {
    method Timer (line 53) | public Timer() {
    method setTimer (line 57) | public void setTimer(long start, long interval) {
    method setTimer (line 66) | public void setTimer(long start) {
    method resume (line 75) | public void resume() {
    method suspend (line 80) | public void suspend() {
    method fire (line 85) | protected abstract void fire();

FILE: push_demo/src/io/gobelieve/im/demo/BaseActivity.java
  class BaseActivity (line 26) | public abstract class BaseActivity extends FragmentActivity {
    method onCreate (line 27) | @Override
    method onBaseCreate (line 40) | protected abstract void onBaseCreate(Bundle savedInstanceState);
    method initView (line 49) | protected abstract void initView(Bundle savedInstanceState);
    method onStop (line 53) | @Override
    method onResume (line 63) | @Override
    method isAppOnForeground (line 74) | public boolean isAppOnForeground() {

FILE: push_demo/src/io/gobelieve/im/demo/HuaweiPushReceiver.java
  class HuaweiPushReceiver (line 23) | public class HuaweiPushReceiver extends PushEventReceiver {
    method showPushMessage (line 29) | public void showPushMessage(int type, String msg) {
    method onToken (line 42) | @Override
    method onPushMsg (line 54) | @Override
    method onEvent (line 66) | public void onEvent(Context context, Event event, Bundle extras) {

FILE: push_demo/src/io/gobelieve/im/demo/LoginActivity.java
  class LoginActivity (line 43) | public class LoginActivity extends BaseActivity implements View.OnClickL...
    method onBaseCreate (line 48) | @Override
    method initView (line 53) | @Override
    method go2Chat (line 62) | private void go2Chat(long sender, long receiver, String token) {
    method onClick (line 66) | @Override
    method login (line 117) | private String login(long uid) {
    method bin2Hex (line 182) | public final static String bin2Hex(byte[] b) {

FILE: push_demo/src/io/gobelieve/im/demo/PushDemoApplication.java
  class PushDemoApplication (line 40) | public class PushDemoApplication extends Application {
    method onCreate (line 53) | @Override
    method initPush (line 67) | private void initPush() {
    method getApplication (line 77) | public static PushDemoApplication getApplication() {
    method isXiaomiDevice (line 81) | private boolean isXiaomiDevice() {
    method initXGPush (line 86) | private void initXGPush() {
    method initXiaomiPush (line 103) | private void initXiaomiPush() {
    method setXiaomiPushToken (line 111) | public void setXiaomiPushToken(String token) {
    method isHuaweiDevice (line 119) | private boolean isHuaweiDevice() {
    method initHuaweiPush (line 124) | private void initHuaweiPush() {
    method setHuaweiPushToken (line 128) | public void setHuaweiPushToken(String token) {
    method setXGPushToken (line 136) | public void setXGPushToken(String token) {
    method bindDeviceTokenToIM (line 144) | public void bindDeviceTokenToIM() {
    method bindWithHuawei (line 159) | private void bindWithHuawei() {
    method bindWithXiaomi (line 165) | private void bindWithXiaomi() {
    method bindWithXG (line 171) | private void bindWithXG() {
    method bindDeviceTokenToIM (line 177) | private void bindDeviceTokenToIM(PostDeviceToken postDeviceToken) {

FILE: push_demo/src/io/gobelieve/im/demo/XGMessageReceiver.java
  class XGMessageReceiver (line 27) | public class XGMessageReceiver extends XGPushBaseReceiver {
    method show (line 31) | private void show(Context context, String text) {
    method onNotifactionShowedResult (line 37) | @Override
    method onUnregisterResult (line 46) | @Override
    method onSetTagResult (line 62) | @Override
    method onDeleteTagResult (line 78) | @Override
    method onNotifactionClickedResult (line 95) | @Override
    method onRegisterResult (line 134) | @Override
    method onTextMessage (line 154) | @Override

FILE: push_demo/src/io/gobelieve/im/demo/XiaomiPushReceiver.java
  class XiaomiPushReceiver (line 48) | public class XiaomiPushReceiver extends PushMessageReceiver  {
    method onReceivePassThroughMessage (line 58) | @Override
    method onNotificationMessageClicked (line 72) | @Override
    method onNotificationMessageArrived (line 85) | @Override
    method onCommandResult (line 96) | @Override
    method onReceiveRegisterResult (line 144) | @Override

FILE: room_demo/src/io/gobelieve/im/demo/IMDemoApplication.java
  class IMDemoApplication (line 31) | public class IMDemoApplication extends Application {
    method onCreate (line 34) | @Override

FILE: room_demo/src/io/gobelieve/im/demo/LoginActivity.java
  class LoginActivity (line 49) | public class LoginActivity extends FragmentActivity implements View.OnCl...
    method onCreate (line 55) | @Override
    method go2Chat (line 68) | private void go2Chat(long sender, long receiver, String token) {
    method onClick (line 90) | @Override
    method login (line 138) | private String login(long uid) {
    method bin2Hex (line 202) | public final static String bin2Hex(byte[] b) {

FILE: room_demo/src/io/gobelieve/im/demo/RoomActivity.java
  class RoomActivity (line 27) | public class RoomActivity extends MessageActivity implements RoomMessage...
    method onCreate (line 33) | @Override
    method onDestroy (line 63) | @Override
    method onRoomMessage (line 72) | @Override
    method onConnectState (line 87) | @Override
    method saveMessage (line 98) | protected void saveMessage(IMessage imsg) {
    method sendMessage (line 104) | @Override
    method sendTextMessage (line 114) | protected void sendTextMessage(String text, List<Long> at, List<String...
Condensed preview — 384 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (980K chars).
[
  {
    "path": ".gitignore",
    "chars": 467,
    "preview": ".DS_Store\n.idea\n\n\n\n# built application files\n*.apk\n*.ap_\n \n# files for the dex VM\n*.dex\n \n# Java class files\n*.class\n \n#"
  },
  {
    "path": "README.md",
    "chars": 3309,
    "preview": "GoBelieve Android SDK\n-------------------\n\n##demo各模块说明\napp, group_demo, customer_service_demo是application模块\nasynctcp, im"
  },
  {
    "path": "app/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "app/AndroidManifest.xml",
    "chars": 6629,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest\n    package=\"io.gobelieve.im.demo\"\n    xmlns:android=\"http://schemas.an"
  },
  {
    "path": "app/build.gradle",
    "chars": 2003,
    "preview": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildTool"
  },
  {
    "path": "app/res/anim/fade_in.xml",
    "chars": 249,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<alpha xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:int"
  },
  {
    "path": "app/res/anim/fade_out.xml",
    "chars": 249,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<alpha xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:int"
  },
  {
    "path": "app/res/anim/head_in.xml",
    "chars": 450,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 左上角扩大-->\n  <scale   xmlns:android=\"http://schemas.android.com/apk/res/androi"
  },
  {
    "path": "app/res/anim/head_out.xml",
    "chars": 451,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 左上角缩小 -->\n  <scale   xmlns:android=\"http://schemas.android.com/apk/res/andro"
  },
  {
    "path": "app/res/anim/hold.xml",
    "chars": 261,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?> \n<translate xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       and"
  },
  {
    "path": "app/res/anim/push_bottom_in.xml",
    "chars": 240,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 上下滑入式 -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n"
  },
  {
    "path": "app/res/anim/push_bottom_out.xml",
    "chars": 251,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 上下滑入式 -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n"
  },
  {
    "path": "app/res/anim/push_top_in.xml",
    "chars": 243,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 上下滑入式 -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n"
  },
  {
    "path": "app/res/anim/push_top_in2.xml",
    "chars": 436,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 上下滑入式 -->\n<scale   xmlns:android=\"http://schemas.android.com/apk/res/android"
  },
  {
    "path": "app/res/anim/push_top_out.xml",
    "chars": 243,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 上下滑入式 -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n"
  },
  {
    "path": "app/res/anim/push_top_out2.xml",
    "chars": 422,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<scale   xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        andr"
  },
  {
    "path": "app/res/anim/slide_in_from_left.xml",
    "chars": 227,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <translate"
  },
  {
    "path": "app/res/anim/slide_in_from_right.xml",
    "chars": 226,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <translate"
  },
  {
    "path": "app/res/anim/slide_out_to_left.xml",
    "chars": 227,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <translate"
  },
  {
    "path": "app/res/anim/slide_out_to_right.xml",
    "chars": 226,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <translate"
  },
  {
    "path": "app/res/drawable/btn_login_selector.xml",
    "chars": 272,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item "
  },
  {
    "path": "app/res/layout/activity_conversation.xml",
    "chars": 806,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       "
  },
  {
    "path": "app/res/layout/activity_login.xml",
    "chars": 2478,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    a"
  },
  {
    "path": "app/res/layout/conversation_message.xml",
    "chars": 1610,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    an"
  },
  {
    "path": "app/res/values/colors.xml",
    "chars": 1173,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"common_bg\">#fcfcfc</color>\n    <color name=\"common_h"
  },
  {
    "path": "app/res/values/dimen_font.xml",
    "chars": 437,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- 一般不用h1和h6, header标题h2, catalog标题h3, tab名称h4, 图标文字h5 -->\n    "
  },
  {
    "path": "app/res/values/dimens.xml",
    "chars": 829,
    "preview": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal"
  },
  {
    "path": "app/res/values/strings.xml",
    "chars": 942,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">IMDemo</string>\n    <string name=\"hello_"
  },
  {
    "path": "app/res/values/styles.xml",
    "chars": 2161,
    "preview": "<resources xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <!--login-->\n    <style name=\"login_edittext"
  },
  {
    "path": "app/src/io/gobelieve/im/demo/BaseActivity.java",
    "chars": 2670,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "app/src/io/gobelieve/im/demo/ConversationView.java",
    "chars": 3847,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "app/src/io/gobelieve/im/demo/IMDemoApplication.java",
    "chars": 3365,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "app/src/io/gobelieve/im/demo/LoginActivity.java",
    "chars": 11904,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "app/src/io/gobelieve/im/demo/MessageListActivity.java",
    "chars": 23500,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "app/src/io/gobelieve/im/demo/model/Conversation.java",
    "chars": 3084,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "app/src/io/gobelieve/im/demo/model/ConversationDB.java",
    "chars": 6824,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "app/src/io/gobelieve/im/demo/model/MessageDatabaseHelper.java",
    "chars": 3330,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "app/src/io/gobelieve/im/demo/model/SQLCreator.java",
    "chars": 3828,
    "preview": "/*                                                                            \r\n  Copyright (c) 2014-2019, GoBelieve    "
  },
  {
    "path": "asynctcp/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "asynctcp/build.gradle",
    "chars": 777,
    "preview": "apply plugin: 'com.android.library'\n\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVe"
  },
  {
    "path": "asynctcp/src/androidTest/java/com/beetle/asynctcp/ApplicationTest.java",
    "chars": 350,
    "preview": "package com.beetle.asynctcp;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\""
  },
  {
    "path": "asynctcp/src/main/AndroidManifest.xml",
    "chars": 153,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" package=\"com"
  },
  {
    "path": "asynctcp/src/main/java/com/beetle/AsyncSSLTCP.java",
    "chars": 823,
    "preview": "package com.beetle;\n\npublic class AsyncSSLTCP implements AsyncTCPInterface {\n    private int sock;\n    private int event"
  },
  {
    "path": "asynctcp/src/main/java/com/beetle/AsyncTCP.java",
    "chars": 1211,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "asynctcp/src/main/java/com/beetle/AsyncTCPInterface.java",
    "chars": 478,
    "preview": "package com.beetle;\n\npublic interface AsyncTCPInterface {\n\n    public void setConnectCallback(TCPConnectCallback cb);\n  "
  },
  {
    "path": "asynctcp/src/main/java/com/beetle/AsyncTCPTest.java",
    "chars": 2470,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "asynctcp/src/main/java/com/beetle/TCPConnectCallback.java",
    "chars": 512,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "asynctcp/src/main/java/com/beetle/TCPReadCallback.java",
    "chars": 509,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "asynctcp/src/main/res/values/strings.xml",
    "chars": 71,
    "preview": "<resources>\n    <string name=\"app_name\">AsyncTCP</string>\n</resources>\n"
  },
  {
    "path": "build.gradle",
    "chars": 626,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    r"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 230,
    "preview": "#Fri Aug 23 16:50:47 CST 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "gradle.properties",
    "chars": 906,
    "preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Settings specified in this file will override any "
  },
  {
    "path": "gradlew",
    "chars": 5080,
    "preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start "
  },
  {
    "path": "gradlew.bat",
    "chars": 2314,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
  },
  {
    "path": "imkit/build.gradle",
    "chars": 2492,
    "preview": "apply plugin: 'com.android.library'\n\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVe"
  },
  {
    "path": "imkit/src/main/AndroidManifest.xml",
    "chars": 483,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          pa"
  },
  {
    "path": "imkit/src/main/assets/emoticon",
    "chars": 2081,
    "preview": "emoticon_0.png,[微笑]\nemoticon_1.png,[撇嘴]\nemoticon_2.png,[色]\nemoticon_3.png,[发呆]\nemoticon_4.png,[得意]\nemoticon_5.png,[流泪]\ne"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/ChatItemQuickAction.java",
    "chars": 2232,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/CustomerMessageActivity.java",
    "chars": 11530,
    "preview": "package com.beetle.bauhinia;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nim"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/GroupMessageActivity.java",
    "chars": 11124,
    "preview": "package com.beetle.bauhinia;\n\nimport android.content.Intent;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimpo"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/MessageActivity.java",
    "chars": 34824,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/MessageAudioActivity.java",
    "chars": 8199,
    "preview": "package com.beetle.bauhinia;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.graphics.Color"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/MessageBaseActivity.java",
    "chars": 36249,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/PeerMessageActivity.java",
    "chars": 11549,
    "preview": "package com.beetle.bauhinia;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.util.Log;\nimport a"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/activity/CameraActivity.java",
    "chars": 6235,
    "preview": "package com.beetle.bauhinia.activity;\n\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport and"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/activity/LocationPickerActivity.java",
    "chars": 10302,
    "preview": "package com.beetle.bauhinia.activity;\r\n\r\nimport android.animation.ObjectAnimator;\r\nimport android.content.Context;\r\nimpo"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/activity/MapActivity.java",
    "chars": 5052,
    "preview": "package com.beetle.bauhinia.activity;\r\n\r\nimport android.content.Context;\r\nimport android.content.Intent;\r\nimport android"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/activity/MessageFileActivity.java",
    "chars": 7308,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/activity/OverlayActivity.java",
    "chars": 1886,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/activity/PhotoActivity.java",
    "chars": 2166,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/activity/PlayerActivity.java",
    "chars": 4589,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/activity/WebActivity.java",
    "chars": 1984,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/api/IMHttpAPI.java",
    "chars": 3209,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/api/body/PostDeviceToken.java",
    "chars": 924,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/api/types/Audio.java",
    "chars": 513,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/api/types/File.java",
    "chars": 471,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/api/types/Image.java",
    "chars": 513,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/api/types/Media.java",
    "chars": 632,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/api/types/Supporter.java",
    "chars": 161,
    "preview": "package com.beetle.bauhinia.api.types;\n\npublic class Supporter {\n    public long id;\n    public long appid;\n    public S"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/handler/CustomerMessageHandler.java",
    "chars": 3842,
    "preview": "package com.beetle.bauhinia.handler;\nimport android.text.TextUtils;\n\nimport com.beetle.bauhinia.db.CustomerMessageDB;\nim"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/handler/GroupMessageHandler.java",
    "chars": 7555,
    "preview": "package com.beetle.bauhinia.handler;\n\nimport android.text.TextUtils;\n\nimport com.beetle.bauhinia.db.GroupMessageDB;\nimpo"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/handler/PeerMessageHandler.java",
    "chars": 5850,
    "preview": "package com.beetle.bauhinia.handler;\n\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport com.beetle.bauhini"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/handler/SyncKeyHandler.java",
    "chars": 2730,
    "preview": "package com.beetle.bauhinia.handler;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport a"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/outbox/CustomerOutbox.java",
    "chars": 1633,
    "preview": "/*\n  Copyright (c) 2014-2019, GoBelieve\n    All rights reserved.\n\n  This source code is licensed under the BSD-style lic"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/outbox/GroupOutbox.java",
    "chars": 1401,
    "preview": "/*\n  Copyright (c) 2014-2019, GoBelieve\n    All rights reserved.\n\n  This source code is licensed under the BSD-style lic"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/outbox/Outbox.java",
    "chars": 21160,
    "preview": "/*\n  Copyright (c) 2014-2019, GoBelieve\n    All rights reserved.\n\n  This source code is licensed under the BSD-style lic"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/outbox/OutboxObserver.java",
    "chars": 583,
    "preview": "package com.beetle.bauhinia.outbox;\n\nimport com.beetle.bauhinia.db.IMessage;\n\npublic interface OutboxObserver {\n    publ"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/outbox/PeerOutbox.java",
    "chars": 1734,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/tools/AudioRecorder.java",
    "chars": 3330,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/tools/AudioUtil.java",
    "chars": 6182,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/tools/BinAscii.java",
    "chars": 1130,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/tools/DeviceUtil.java",
    "chars": 1050,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/tools/FileCache.java",
    "chars": 4394,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/tools/FileDownloader.java",
    "chars": 4268,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/tools/ImageMIME.java",
    "chars": 2423,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/tools/MapUtil.java",
    "chars": 3211,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/tools/TimeUtil.java",
    "chars": 3290,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/tools/VideoUtil.java",
    "chars": 4318,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/view/InMessageView.java",
    "chars": 4537,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/view/MessageRowView.java",
    "chars": 3961,
    "preview": "package com.beetle.bauhinia.view;\n\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.view.Gr"
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/view/MiddleMessageView.java",
    "chars": 1159,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/view/OutMessageView.java",
    "chars": 8989,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imkit/src/main/java/com/beetle/bauhinia/view/TagView.java",
    "chars": 2076,
    "preview": "package com.beetle.bauhinia.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view"
  },
  {
    "path": "imkit/src/main/res/anim/fade_in.xml",
    "chars": 249,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<alpha xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:int"
  },
  {
    "path": "imkit/src/main/res/anim/fade_out.xml",
    "chars": 249,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<alpha xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:int"
  },
  {
    "path": "imkit/src/main/res/anim/head_in.xml",
    "chars": 450,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 左上角扩大-->\n  <scale   xmlns:android=\"http://schemas.android.com/apk/res/androi"
  },
  {
    "path": "imkit/src/main/res/anim/head_out.xml",
    "chars": 451,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 左上角缩小 -->\n  <scale   xmlns:android=\"http://schemas.android.com/apk/res/andro"
  },
  {
    "path": "imkit/src/main/res/anim/hold.xml",
    "chars": 261,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?> \n<translate xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       and"
  },
  {
    "path": "imkit/src/main/res/anim/push_bottom_in.xml",
    "chars": 240,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 上下滑入式 -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n"
  },
  {
    "path": "imkit/src/main/res/anim/push_bottom_out.xml",
    "chars": 251,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 上下滑入式 -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n"
  },
  {
    "path": "imkit/src/main/res/anim/push_top_in.xml",
    "chars": 243,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 上下滑入式 -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n"
  },
  {
    "path": "imkit/src/main/res/anim/push_top_in2.xml",
    "chars": 436,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 上下滑入式 -->\n<scale   xmlns:android=\"http://schemas.android.com/apk/res/android"
  },
  {
    "path": "imkit/src/main/res/anim/push_top_out.xml",
    "chars": 243,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- 上下滑入式 -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n"
  },
  {
    "path": "imkit/src/main/res/anim/push_top_out2.xml",
    "chars": 422,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<scale   xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        andr"
  },
  {
    "path": "imkit/src/main/res/anim/slide_in_from_left.xml",
    "chars": 227,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <translate"
  },
  {
    "path": "imkit/src/main/res/anim/slide_in_from_right.xml",
    "chars": 226,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <translate"
  },
  {
    "path": "imkit/src/main/res/anim/slide_out_to_left.xml",
    "chars": 227,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <translate"
  },
  {
    "path": "imkit/src/main/res/anim/slide_out_to_right.xml",
    "chars": 226,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <translate"
  },
  {
    "path": "imkit/src/main/res/drawable/chat_send_btn.xml",
    "chars": 457,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector\n  xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item"
  },
  {
    "path": "imkit/src/main/res/drawable/chatting_setmode_msg_btn.xml",
    "chars": 735,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item "
  },
  {
    "path": "imkit/src/main/res/drawable/chatting_setmode_voice_btn.xml",
    "chars": 725,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item "
  },
  {
    "path": "imkit/src/main/res/drawable/conversation_recording_round.xml",
    "chars": 332,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" \n     android:"
  },
  {
    "path": "imkit/src/main/res/drawable/ease_chat_file_selector.xml",
    "chars": 372,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n    <item "
  },
  {
    "path": "imkit/src/main/res/drawable/ease_chat_image_selector.xml",
    "chars": 375,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n    <item "
  },
  {
    "path": "imkit/src/main/res/drawable/ease_chat_location_selector.xml",
    "chars": 286,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n    <item "
  },
  {
    "path": "imkit/src/main/res/drawable/ease_chat_press_speak_btn.xml",
    "chars": 767,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item "
  },
  {
    "path": "imkit/src/main/res/drawable/ease_chat_send_btn_selector.xml",
    "chars": 842,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item "
  },
  {
    "path": "imkit/src/main/res/drawable/ease_chat_takepic_selector.xml",
    "chars": 284,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n    <item "
  },
  {
    "path": "imkit/src/main/res/drawable/ease_chat_video_call_selector.xml",
    "chars": 390,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item "
  },
  {
    "path": "imkit/src/main/res/drawable/ease_chatting_setmode_keyboard_btn.xml",
    "chars": 435,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector\n  xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item"
  },
  {
    "path": "imkit/src/main/res/drawable/ease_chatting_setmode_voice_btn.xml",
    "chars": 537,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector\n  xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item"
  },
  {
    "path": "imkit/src/main/res/drawable/ease_edit_text_bg.xml",
    "chars": 520,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n    <ite"
  },
  {
    "path": "imkit/src/main/res/drawable/ease_recording_text_hint_bg.xml",
    "chars": 195,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <corners"
  },
  {
    "path": "imkit/src/main/res/drawable/ease_type_select_btn.xml",
    "chars": 490,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector\n  xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item"
  },
  {
    "path": "imkit/src/main/res/drawable/ic_back.xml",
    "chars": 352,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\""
  },
  {
    "path": "imkit/src/main/res/layout/activity_camera.xml",
    "chars": 736,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "imkit/src/main/res/layout/activity_file.xml",
    "chars": 2264,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n        xmlns:android=\"http://"
  },
  {
    "path": "imkit/src/main/res/layout/activity_overlay.xml",
    "chars": 1017,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n "
  },
  {
    "path": "imkit/src/main/res/layout/activity_photo.xml",
    "chars": 743,
    "preview": "<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tool"
  },
  {
    "path": "imkit/src/main/res/layout/activity_player.xml",
    "chars": 722,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n        xmlns:android=\"http://"
  },
  {
    "path": "imkit/src/main/res/layout/activity_web.xml",
    "chars": 582,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\" andro"
  },
  {
    "path": "imkit/src/main/res/layout/chat.xml",
    "chars": 2209,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "imkit/src/main/res/layout/chat_container_center.xml",
    "chars": 623,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  "
  },
  {
    "path": "imkit/src/main/res/layout/chat_container_left.xml",
    "chars": 3216,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns"
  },
  {
    "path": "imkit/src/main/res/layout/chat_container_right.xml",
    "chars": 4158,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns"
  },
  {
    "path": "imkit/src/main/res/layout/chat_location.xml",
    "chars": 1620,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns"
  },
  {
    "path": "imkit/src/main/res/layout/conversation_recording_dialog.xml",
    "chars": 1472,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\tandroid"
  },
  {
    "path": "imkit/src/main/res/layout/location_picker.xml",
    "chars": 1176,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andro"
  },
  {
    "path": "imkit/src/main/res/menu/chat.xml",
    "chars": 290,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\""
  },
  {
    "path": "imkit/src/main/res/menu/location_picker.xml",
    "chars": 286,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\""
  },
  {
    "path": "imkit/src/main/res/menu/menu_photo.xml",
    "chars": 244,
    "preview": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\""
  },
  {
    "path": "imkit/src/main/res/values/colors.xml",
    "chars": 487,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"map_address\">#fafafa</color>\n    <color name=\"gray_n"
  },
  {
    "path": "imkit/src/main/res/values/dimens.xml",
    "chars": 105,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <dimen name=\"pin_margin\">19dp</dimen>\n</resources>"
  },
  {
    "path": "imkit/src/main/res/values/strings.xml",
    "chars": 3301,
    "preview": "<resources>\n\n    <string name=\"product_fotos_get_from\">Get photo from:</string>\n\n    <string name=\"im_title_choose\">Choo"
  },
  {
    "path": "imkit/src/main/res/values/styles.xml",
    "chars": 1327,
    "preview": "<resources>\n    <style name=\"imkit.ActionBar\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <item name=\"android:"
  },
  {
    "path": "imkit/src/main/res/values-zh/strings.xml",
    "chars": 2794,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"product_fotos_get_from\">Get photo from:</string>\n\n "
  },
  {
    "path": "imkit/src/main/res/xml/file_paths.xml",
    "chars": 272,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<paths xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <external-"
  },
  {
    "path": "imlib/build.gradle",
    "chars": 1424,
    "preview": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVer"
  },
  {
    "path": "imlib/src/main/AndroidManifest.xml",
    "chars": 103,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.beetle.imlib\" />\n"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/activity/BaseActivity.java",
    "chars": 3311,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/ConversationIterator.java",
    "chars": 264,
    "preview": "package com.beetle.bauhinia.db;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\n"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/CustomerMessageDB.java",
    "chars": 1425,
    "preview": "package com.beetle.bauhinia.db;\n\nimport com.beetle.bauhinia.db.message.Location;\n\n/**\n * Created by houxh on 16/1/18.\n *"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/CustomerPeerMessageDB.java",
    "chars": 2848,
    "preview": "package com.beetle.bauhinia.db;\n\nimport com.beetle.bauhinia.db.message.Location;\n\n/**\n * Created by houxh on 16/1/18.\n *"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/EPeerMessageDB.java",
    "chars": 289,
    "preview": "package com.beetle.bauhinia.db;\n\npublic class EPeerMessageDB extends BasePeerMessageDB {\n    private static EPeerMessage"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/GroupMessageDB.java",
    "chars": 1409,
    "preview": "package com.beetle.bauhinia.db;\n\nimport com.beetle.bauhinia.db.message.Location;\n\n/**\n * Created by houxh on 15/3/21.\n *"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/ICustomerMessage.java",
    "chars": 188,
    "preview": "package com.beetle.bauhinia.db;\n\n\n/**\n * Created by houxh on 14-7-22.\n */\n\n\npublic class ICustomerMessage  extends IMess"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/IMessage.java",
    "chars": 13012,
    "preview": "package com.beetle.bauhinia.db;\n\nimport com.beetle.bauhinia.db.message.*;\nimport com.google.gson.Gson;\nimport com.google"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/IMessageDB.java",
    "chars": 799,
    "preview": "package com.beetle.bauhinia.db;\n\n/**\n * Created by houxh on 2017/11/13.\n */\n\npublic interface IMessageDB {\n\n    //获取最近的消"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/MessageFlag.java",
    "chars": 387,
    "preview": "package com.beetle.bauhinia.db;\n\n\n\npublic class MessageFlag {\n    public static final int MESSAGE_FLAG_DELETE = 1;\n    p"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/MessageIterator.java",
    "chars": 227,
    "preview": "package com.beetle.bauhinia.db;\n\nimport android.util.Log;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\n"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/PeerMessageDB.java",
    "chars": 1389,
    "preview": "package com.beetle.bauhinia.db;\nimport com.beetle.bauhinia.db.message.Location;\n\nclass BasePeerMessageDB extends SQLPeer"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/SQLCustomerMessageDB.java",
    "chars": 12595,
    "preview": "package com.beetle.bauhinia.db;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.da"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/SQLGroupMessageDB.java",
    "chars": 18909,
    "preview": "package com.beetle.bauhinia.db;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.da"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/SQLPeerMessageDB.java",
    "chars": 12295,
    "preview": "package com.beetle.bauhinia.db;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.da"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/ACK.java",
    "chars": 551,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.JsonObject;\n\npublic class ACK extends Notification {\n   "
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Attachment.java",
    "chars": 1412,
    "preview": "package com.beetle.bauhinia.db.message;\n\n\nimport com.beetle.bauhinia.db.IMessage;\nimport com.google.gson.JsonObject;\n\npu"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Audio.java",
    "chars": 1492,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.JsonObject;\n\nimport org.json.JSONException;\nimport org.j"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Classroom.java",
    "chars": 474,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.annotations.SerializedName;\n\npublic class Classroom exte"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Conference.java",
    "chars": 506,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.annotations.SerializedName;\n\npublic class Conference ext"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/File.java",
    "chars": 1437,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.JsonObject;\n\nimport org.json.JSONException;\nimport org.j"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/GroupNotification.java",
    "chars": 5113,
    "preview": "package com.beetle.bauhinia.db.message;\n\n\nimport com.beetle.bauhinia.db.IMessage;\nimport com.google.gson.*;\n\nimport java"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/GroupVOIP.java",
    "chars": 790,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.beetle.bauhinia.db.IMessage;\nimport com.google.gson.JsonObject;\n\npub"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Headline.java",
    "chars": 793,
    "preview": "package com.beetle.bauhinia.db.message;\n\n\nimport com.beetle.bauhinia.db.IMessage;\nimport com.google.gson.JsonObject;\n\npu"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Image.java",
    "chars": 1595,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.JsonObject;\n\nimport org.json.JSONException;\nimport org.j"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Link.java",
    "chars": 297,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.beetle.bauhinia.db.IMessage;\n\npublic  class Link extends MessageCont"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Location.java",
    "chars": 1331,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport android.text.TextUtils;\nimport com.beetle.bauhinia.db.IMessage;\nimport c"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/MessageContent.java",
    "chars": 7004,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport android.text.TextUtils;\n\nimport com.google.gson.annotations.SerializedNa"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Notification.java",
    "chars": 214,
    "preview": "package com.beetle.bauhinia.db.message;\n\n\n\npublic  abstract class Notification extends MessageContent {\n    public Strin"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/P2PSession.java",
    "chars": 1026,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.JsonObject;\nimport com.google.gson.annotations.Serialize"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Readed.java",
    "chars": 609,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.JsonObject;\n\npublic class Readed extends MessageContent "
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Revoke.java",
    "chars": 593,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.JsonObject;\n\npublic class Revoke extends Notification {\n"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Secret.java",
    "chars": 800,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.JsonObject;\n\npublic class Secret extends MessageContent "
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Tag.java",
    "chars": 1233,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.JsonObject;\nimport com.google.gson.annotations.Serialize"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Text.java",
    "chars": 2220,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport android.text.SpannableString;\nimport android.text.TextUtils;\n\nimport com"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/TimeBase.java",
    "chars": 650,
    "preview": "package com.beetle.bauhinia.db.message;\n\n\nimport com.beetle.bauhinia.db.IMessage;\nimport com.google.gson.JsonObject;\n\npu"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Unknown.java",
    "chars": 89,
    "preview": "package com.beetle.bauhinia.db.message;\n\npublic  class Unknown extends MessageContent {}\n"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/VOIP.java",
    "chars": 1038,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.JsonObject;\n\npublic  class VOIP extends MessageContent {"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/db/message/Video.java",
    "chars": 2090,
    "preview": "package com.beetle.bauhinia.db.message;\n\nimport com.google.gson.JsonObject;\n\nimport org.json.JSONException;\nimport org.j"
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/gallery/GalleryImage.java",
    "chars": 1436,
    "preview": "/*                                                                            \n  Copyright (c) 2014-2019, GoBelieve     "
  },
  {
    "path": "imlib/src/main/java/com/beetle/bauhinia/gallery/tool/Closeables.java",
    "chars": 4806,
    "preview": "/*\n * Copyright (C) 2007 The Guava Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you "
  }
]

// ... and 184 more files (download for full content)

About this extraction

This page contains the full source code of the GoBelieveIO/im_android GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 384 files (876.1 KB), approximately 212.7k tokens, and a symbol index with 1502 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!