Commit b979c75194cd950ba968a5eedea12f21c5f7f61e

Authored by 谷俊
1 parent 0c0bc784

demo修改为支持3.0版本功能

Showing 62 changed files with 1820 additions and 411 deletions
.idea/misc.xml
1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2 <project version="4">
3   - <component name="EntryPointsManager">
4   - <entry_points version="2.0" />
5   - </component>
6 3 <component name="NullableNotNullManager">
7 4 <option name="myDefaultNullable" value="android.support.annotation.Nullable" />
8 5 <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
... ... @@ -27,17 +24,7 @@
27 24 </value>
28 25 </option>
29 26 </component>
30   - <component name="ProjectLevelVcsManager" settingsEditedManually="false">
31   - <OptionsSetting value="true" id="Add" />
32   - <OptionsSetting value="true" id="Remove" />
33   - <OptionsSetting value="true" id="Checkout" />
34   - <OptionsSetting value="true" id="Update" />
35   - <OptionsSetting value="true" id="Status" />
36   - <OptionsSetting value="true" id="Edit" />
37   - <ConfirmationsSetting value="0" id="Add" />
38   - <ConfirmationsSetting value="0" id="Remove" />
39   - </component>
40   - <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
  27 + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
41 28 <output url="file://$PROJECT_DIR$/build/classes" />
42 29 </component>
43 30 <component name="ProjectType">
... ...
.idea/modules.xml
... ... @@ -2,12 +2,10 @@
2 2 <project version="4">
3 3 <component name="ProjectModuleManager">
4 4 <modules>
5   - <module fileurl="file://$PROJECT_DIR$/CNChatNDemo.iml" filepath="$PROJECT_DIR$/CNChatNDemo.iml" />
  5 + <module fileurl="file://D:\gitlab\CNIMDemo\CNChatNDemo.iml" filepath="D:\gitlab\CNIMDemo\CNChatNDemo.iml" />
6 6 <module fileurl="file://$PROJECT_DIR$/CNIMDemo.iml" filepath="$PROJECT_DIR$/CNIMDemo.iml" />
7   - <module fileurl="file://$PROJECT_DIR$/CNIMDemo.iml" filepath="$PROJECT_DIR$/CNIMDemo.iml" />
8   - <module fileurl="file://$PROJECT_DIR$/CNIMDemo23.iml" filepath="$PROJECT_DIR$/CNIMDemo23.iml" />
9   - <module fileurl="file://$PROJECT_DIR$/CNIMDemo5.iml" filepath="$PROJECT_DIR$/CNIMDemo5.iml" />
10   - <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
  7 + <module fileurl="file://D:\gitlab\CNIMDemo\CNIMDemo23.iml" filepath="D:\gitlab\CNIMDemo\CNIMDemo23.iml" />
  8 + <module fileurl="file://D:\gitlab\CNIMDemo\CNIMDemo5.iml" filepath="D:\gitlab\CNIMDemo\CNIMDemo5.iml" />
11 9 <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
12 10 </modules>
13 11 </component>
... ...
app/build.gradle
... ... @@ -27,11 +27,17 @@ android {
27 27 minifyEnabled true
28 28 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
29 29 signingConfig signingConfigs.myConfig
  30 + ndk {
  31 + abiFilters "armeabi-v7a", "arm64-v8a"
  32 + }
30 33 }
31 34 debug {
32 35 minifyEnabled false
33 36 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
34 37 debuggable true
  38 + ndk {
  39 + abiFilters "armeabi-v7a", "arm64-v8a"
  40 + }
35 41 }
36 42 }
37 43 }
... ... @@ -46,5 +52,5 @@ dependencies {
46 52 compile 'com.android.support:recyclerview-v7:23.4.0'
47 53 compile 'com.github.bumptech.glide:glide:3.7.0'
48 54  
49   - compile 'com.cnlive:lib_cnutil:2.0.1'
  55 +// compile 'com.cnlive:lib_cnutil:2.0.1'
50 56 }
... ...
app/src/main/AndroidManifest.xml
... ... @@ -2,18 +2,20 @@
2 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 3 package="com.cnlive.im">
4 4  
5   - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
6   - <uses-permission android:name="android.permission.INTERNET" />
7 5 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
8 6 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
9   - <uses-permission android:name="android.permission.READ_PHONE_STATE" />
10   - <uses-permission android:name="android.permission.RECORD_AUDIO" />
  7 + <uses-permission android:name="android.permission.CAMERA" />
  8 + <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
11 9 <uses-permission android:name="android.permission.GET_TASKS" />
12   - <uses-permission android:name="android.permission.WAKE_LOCK" />
  10 + <uses-permission android:name="android.permission.INTERNET" />
13 11 <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
14   - <uses-permission android:name="android.permission.VIBRATE" />
15   - <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  12 + <uses-permission android:name="android.permission.READ_LOGS" />
  13 + <uses-permission android:name="android.permission.READ_PHONE_STATE" />
16 14 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  15 + <uses-permission android:name="android.permission.RECORD_AUDIO" />
  16 + <uses-permission android:name="android.permission.VIBRATE" />
  17 + <uses-permission android:name="android.permission.WAKE_LOCK" />
  18 + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
17 19  
18 20 <application
19 21 android:name=".CNLiveApplication"
... ... @@ -21,7 +23,7 @@
21 23 android:icon="@mipmap/ic_launcher"
22 24 android:label="@string/app_name"
23 25 android:supportsRtl="true"
24   - android:theme="@style/AppTheme">
  26 + android:theme="@style/AppTheme.NoActionBar">
25 27 <activity android:name=".ui.MainActivity">
26 28 <intent-filter>
27 29 <action android:name="android.intent.action.MAIN" />
... ... @@ -46,20 +48,54 @@
46 48 <activity android:name=".ui.PrivateActivity"
47 49 android:screenOrientation="portrait"/>
48 50  
  51 + <activity android:name=".ui.VideoActivity"
  52 + android:screenOrientation="portrait"
  53 + android:launchMode="singleTop"/>
  54 +
  55 + <activity android:name=".ui.ImageViewActivity"
  56 + android:screenOrientation="portrait"
  57 + android:launchMode="singleTop"/>
  58 +
  59 + <!-- 【必须】消息收发service -->
49 60 <service
50   - android:name="io.rong.imlib.ipc.RongService"
  61 + android:name="com.tencent.qalsdk.service.QalService"
51 62 android:exported="true"
52   - android:process=":ipc" />
  63 + android:process=":QALSERVICE" >
  64 + </service>
53 65 <service
54   - android:name="io.rong.imlib.ReConnectService"
55   - android:exported="true" />
  66 + android:name="com.tencent.qalsdk.service.QalAssistService"
  67 + android:exported="false"
  68 + android:process=":QALSERVICE" >
  69 + </service>
56 70  
  71 + <!-- 【必须】 离线消息广播接收器 -->
57 72 <receiver
58   - android:name="io.rong.imlib.ConnectChangeReceiver"
59   - android:exported="true" />
  73 + android:name="com.tencent.qalsdk.QALBroadcastReceiver"
  74 + android:exported="false">
  75 + <intent-filter>
  76 + <action android:name="com.tencent.qalsdk.broadcast.qal" />
  77 + </intent-filter>
  78 + </receiver>
60 79 <receiver
61   - android:name="io.rong.imlib.HeartbeatReceiver"
62   - android:process=":ipc" />
  80 + android:name="com.tencent.qalsdk.core.NetConnInfoCenter" android:process=":QALSERVICE">
  81 + <intent-filter>
  82 + <action android:name="android.intent.action.BOOT_COMPLETED" />
  83 + </intent-filter>
  84 + <intent-filter>
  85 + <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
  86 + </intent-filter>
  87 + <intent-filter>
  88 + <action android:name="android.intent.action.TIME_SET" />
  89 + </intent-filter>
  90 + <intent-filter>
  91 + <action android:name="android.intent.action.TIMEZONE_CHANGED" />
  92 + </intent-filter>
  93 +
  94 + <!-- ImSDK 3.0.2 后添加 -->
  95 + <intent-filter>
  96 + <action android:name="com.tencent.qalsdk.service.TASK_REMOVED" />
  97 + </intent-filter>
  98 + </receiver>
63 99  
64 100 </application>
65 101  
... ...
app/src/main/java/com/cnlive/im/CNLiveApplication.java
1 1 package com.cnlive.im;
2 2  
3 3 import android.app.Application;
  4 +import android.content.Context;
4 5  
5 6 import com.cnlive.libs.util.Config;
6 7  
... ... @@ -11,10 +12,17 @@ import com.cnlive.libs.util.Config;
11 12 * @desc ${TODD}
12 13 */
13 14 public class CNLiveApplication extends Application {
  15 + private static Context context;
  16 +
14 17 @Override
15 18 public void onCreate() {
16 19 super.onCreate();
17   - Config.init(this, "60_j07o9s9b65", "dc1e76f87c7c2d83dcedb8a1204ec22fca3e156b21eb0d",true);
  20 + context = getApplicationContext();
  21 + Config.init(this, "60_j07o9s9b65", "dc1e76f87c7c2d83dcedb8a1204ec22fca3e156b21eb0d");
  22 + }
  23 +
  24 + public static Context getContext(){
  25 + return context;
18 26 }
19 27 }
20 28  
... ...
app/src/main/java/com/cnlive/im/adapter/ChatRoomAdpter.java
1 1 package com.cnlive.im.adapter;
2 2  
3 3 import android.content.Context;
4   -import android.database.Cursor;
5 4 import android.graphics.Color;
6   -import android.net.Uri;
7   -import android.provider.ContactsContract;
8   -import android.provider.MediaStore;
  5 +import android.graphics.drawable.AnimationDrawable;
9 6 import android.support.v7.widget.RecyclerView;
10   -import android.util.Log;
11 7 import android.view.LayoutInflater;
12 8 import android.view.View;
13 9 import android.view.ViewGroup;
14   -import android.view.WindowManager;
15 10 import android.widget.ImageView;
16   -import android.widget.LinearLayout;
17 11 import android.widget.TextView;
18 12  
19 13 import com.bumptech.glide.Glide;
20 14 import com.cnlive.im.R;
21 15 import com.cnlive.im.adapter.base.BaseRecyclerAdapter;
22   -import com.cnlive.im.adapter.base.VoiceItemClickListener;
  16 +import com.cnlive.im.adapter.base.ItemClickListener;
23 17 import com.cnlive.im.mode.ImagMessage;
24 18 import com.cnlive.im.mode.StringMessage;
  19 +import com.cnlive.im.mode.VideoMessage;
25 20 import com.cnlive.im.mode.VoiceMessage;
  21 +import com.cnlive.im.util.FileUtil;
  22 +import com.cnlive.libs.util.chat.base.IChat;
26 23  
27 24 import org.json.JSONException;
28 25 import org.json.JSONObject;
29 26  
30   -import java.text.SimpleDateFormat;
31   -import java.util.Calendar;
32   -import java.util.Date;
33   -import java.util.HashMap;
34   -import java.util.Locale;
35   -
36 27 /**
37 28 * @author 陈硕
38 29 * @time 2017/7/14 14:35
... ... @@ -46,8 +37,10 @@ public class ChatRoomAdpter extends BaseRecyclerAdapter {
46 37 private int imaOppsite = 4;
47 38 private int voiceUser = 5;
48 39 private int voiceOppsite = 6;
  40 + private int videoUser = 7;
  41 + private int videoOppsite = 8;
49 42 private Context mContext;
50   - private VoiceItemClickListener mVoiceItemClickListener;
  43 + private ItemClickListener mItemClickListener;
51 44  
52 45 private boolean isPrivate;
53 46  
... ... @@ -58,8 +51,8 @@ public class ChatRoomAdpter extends BaseRecyclerAdapter {
58 51 }
59 52  
60 53  
61   - public void setonVoiceItemClickListener(VoiceItemClickListener voiveItemClickListener) {
62   - this.mVoiceItemClickListener = voiveItemClickListener;
  54 + public void setonVoiceItemClickListener(ItemClickListener itemClickListener) {
  55 + this.mItemClickListener = itemClickListener;
63 56 }
64 57  
65 58 @Override
... ... @@ -80,6 +73,12 @@ public class ChatRoomAdpter extends BaseRecyclerAdapter {
80 73 return voiceUser;
81 74 else return voiceOppsite;
82 75  
  76 + } else if (o instanceof VideoMessage) {
  77 + VideoMessage o1 = (VideoMessage) o;
  78 + if (o1.isUserSend())
  79 + return videoUser;
  80 + else return videoOppsite;
  81 +
83 82 }
84 83 return 0;
85 84 }
... ... @@ -98,6 +97,10 @@ public class ChatRoomAdpter extends BaseRecyclerAdapter {
98 97 return new VoiceMessageHolder(LayoutInflater.from(mContext).inflate(R.layout.voice_layout_item_user, null));
99 98 } else if (viewType == voiceOppsite) {
100 99 return new VoiceMessageHolder(LayoutInflater.from(mContext).inflate(R.layout.voice_layout_item_oppsite, null));
  100 + } else if (viewType == videoUser) {
  101 + return new VideoMessageHolder(LayoutInflater.from(mContext).inflate(R.layout.video_layout_item_user, null));
  102 + } else if (viewType == videoOppsite) {
  103 + return new VideoMessageHolder(LayoutInflater.from(mContext).inflate(R.layout.video_layout_item_oppsite, null));
101 104 }
102 105 return null;
103 106 }
... ... @@ -108,42 +111,22 @@ public class ChatRoomAdpter extends BaseRecyclerAdapter {
108 111 StringMessageHolder holder1 = (StringMessageHolder) holder;
109 112 Object o = mItems.get(position);
110 113 StringMessage o1 = (StringMessage) o;
111   - if (isPrivate) {
112   - try {
113   - holder1.msg_text.setText((String) (new JSONObject(o1.getCnMessage().getContent()).get("message")));
114   - } catch (JSONException e) {
115   - e.printStackTrace();
116   - }
117   - } else {
118   - holder1.msg_text.setText(o1.getCnMessage().getContent());
119   - }
120   - holder1.user_name.setText(o1.getCnMessage().getUserInfo().getUserName());
121   - holder1.user_name.setTextColor(Color.parseColor("#d61d0c"));
122   - holder1.msg_text.setTextColor(Color.BLACK);
  114 + holder1.showMessage(o1);
123 115 } else if (holder instanceof ImaMessageHolder) {
124 116 ImaMessageHolder holder1 = (ImaMessageHolder) holder;
125 117 Object o = mItems.get(position);
126 118 ImagMessage o1 = (ImagMessage) o;
127   - holder1.ima_user_name.setTextColor(Color.parseColor("#d61d0c"));
128   - holder1.img_content.getLayoutParams().height = 200;
129   - holder1.img_content.getLayoutParams().width = 200;
130   - holder1.img_content.setLayoutParams(holder1.img_content.getLayoutParams());
131   - Glide.with(mContext).load(o1.getCnImgMessage().getRemoteUri()).into(holder1.img_content);
132   - holder1.ima_user_name.setText(o1.getCnImgMessage().getUserInfo().getUserName());
  119 + holder1.showMessage(o1);
133 120 } else if (holder instanceof VoiceMessageHolder) {
134   - VoiceMessageHolder holder1 = (VoiceMessageHolder) holder;
135   - Object o = mItems.get(position);
136   - VoiceMessage o1 = (VoiceMessage) o;
137   - holder1.voice_user_name.setText(o1.getCnVoiceMessage().getUserInfo().getUserName());
138   - final Uri voiceUri = o1.getCnVoiceMessage().getVoiceUri();
139   - int duration = o1.getCnVoiceMessage().getVoiceTime();
140   - holder1.voice_duration.setText(String.valueOf(duration).concat("\""));
141   - holder1.itemView.setOnClickListener(new View.OnClickListener() {
142   - @Override
143   - public void onClick(View v) {
144   - mVoiceItemClickListener.onItemClick(voiceUri);
145   - }
146   - });
  121 + final VoiceMessageHolder holder1 = (VoiceMessageHolder) holder;
  122 + final Object o = mItems.get(position);
  123 + final VoiceMessage o1 = (VoiceMessage) o;
  124 + holder1.showMessage(o1);
  125 + } else if (holder instanceof VideoMessageHolder) {
  126 + final VideoMessageHolder holder1 = (VideoMessageHolder) holder;
  127 + final Object o = mItems.get(position);
  128 + final VideoMessage o1 = (VideoMessage) o;
  129 + holder1.showMessage(o1);
147 130 }
148 131  
149 132 }
... ... @@ -151,12 +134,48 @@ public class ChatRoomAdpter extends BaseRecyclerAdapter {
151 134 public class StringMessageHolder extends RecyclerView.ViewHolder {
152 135 private TextView user_name;
153 136 private TextView msg_text;
  137 + private TextView status;
154 138  
155 139 public StringMessageHolder(View itemView) {
156 140 super(itemView);
157 141 user_name = (TextView) itemView.findViewById(R.id.user_name);
158 142 msg_text = (TextView) itemView.findViewById(R.id.msg_text);
  143 + status = (TextView) itemView.findViewById(R.id.status);
  144 + }
  145 +
  146 + public void showMessage(StringMessage item) {
  147 + user_name.setText(item.getCnMessage().getUserInfo().getUserName());
159 148  
  149 + switch (item.getCnMessage().getStatus()) {
  150 + case IChat.CN_MSG_STATUS_SENDING:
  151 + if (status != null)
  152 + status.setText("发送中");
  153 + sendMsg(item);
  154 + break;
  155 + case IChat.CN_MSG_STATUS_SEND_FAIL:
  156 + if (status != null)
  157 + status.setText("发送失败");
  158 + sendMsg(item);
  159 + break;
  160 + case IChat.CN_MSG_STATUS_SEND_SUCCESS:
  161 + if (status != null)
  162 + status.setText("发送成功");
  163 + sendMsg(item);
  164 + break;
  165 + }
  166 + }
  167 +
  168 + private void sendMsg(StringMessage item) {
  169 + if (isPrivate) {
  170 + try {
  171 + msg_text.setText((String) (new JSONObject(item.getCnMessage().getContent()).get("message")));
  172 + } catch (JSONException e) {
  173 + e.printStackTrace();
  174 + }
  175 + } else {
  176 + msg_text.setText(item.getCnMessage().getContent());
  177 + }
  178 + msg_text.setTextColor(Color.BLACK);
160 179 }
161 180 }
162 181  
... ... @@ -164,11 +183,74 @@ public class ChatRoomAdpter extends BaseRecyclerAdapter {
164 183  
165 184 private TextView ima_user_name;
166 185 private ImageView img_content;
  186 + private TextView status;
167 187  
168 188 public ImaMessageHolder(View itemView) {
169 189 super(itemView);
170 190 ima_user_name = (TextView) itemView.findViewById(R.id.img_user_name);
171 191 img_content = (ImageView) itemView.findViewById(R.id.img_content);
  192 + status = (TextView) itemView.findViewById(R.id.status);
  193 + }
  194 +
  195 + public void showMessage(final ImagMessage imagMessage) {
  196 + ima_user_name.setText(imagMessage.getCnImgMessage().getUserInfo().getUserName());
  197 + img_content.getLayoutParams().height = 200;
  198 + img_content.getLayoutParams().width = 200;
  199 + img_content.setLayoutParams(img_content.getLayoutParams());
  200 + switch (imagMessage.getCnImgMessage().getStatus()) {
  201 + case IChat.CN_MSG_STATUS_SENDING:
  202 + if (status != null)
  203 + status.setText("发送中");
  204 + Glide.with(mContext).load(imagMessage.getCnImgMessage().getImagePath()).into(img_content);
  205 + break;
  206 + case IChat.CN_MSG_STATUS_SEND_FAIL:
  207 + if (status != null)
  208 + status.setText("发送失败");
  209 + Glide.with(mContext).load(imagMessage.getCnImgMessage().getImagePath()).into(img_content);
  210 + break;
  211 + case IChat.CN_MSG_STATUS_SEND_SUCCESS:
  212 + if (status != null)
  213 + status.setText("发送成功");
  214 + sendSuccess(imagMessage);
  215 + break;
  216 + }
  217 + }
  218 +
  219 + private void sendSuccess(final ImagMessage imagMessage) {
  220 + if (imagMessage.getCnImgMessage().isSelf()) {
  221 + Glide.with(mContext).load(imagMessage.getCnImgMessage().getImagePath()).into(img_content);
  222 + } else {
  223 + String thumbUuid = imagMessage.getCnImgMessage().getThumbUuid();
  224 + final String imagePath = FileUtil.getCacheFilePath(thumbUuid);
  225 + if (FileUtil.isCacheFileExist(thumbUuid)) {
  226 + if (img_content != null && mContext != null)
  227 + Glide.with(mContext).load(imagePath).into(img_content);
  228 + } else {
  229 + if (!imagMessage.isDownloading()) {
  230 + imagMessage.setDownloading(true);
  231 + imagMessage.getCnImgMessage().getThumbImage(imagePath, new IChat.OnDownloadListener() {
  232 + @Override
  233 + public void onSuccess() {
  234 + imagMessage.setDownloading(false);
  235 + if (img_content != null && mContext != null)
  236 + Glide.with(mContext).load(imagePath).into(img_content);
  237 + }
  238 +
  239 + @Override
  240 + public void onError(int i, String s) {
  241 + imagMessage.setDownloading(false);
  242 + }
  243 + });
  244 + }
  245 + }
  246 + }
  247 + img_content.setOnClickListener(new View.OnClickListener() {
  248 + @Override
  249 + public void onClick(View v) {
  250 + if (mItemClickListener != null)
  251 + mItemClickListener.onImageClick(imagMessage);
  252 + }
  253 + });
172 254 }
173 255 }
174 256  
... ... @@ -176,14 +258,127 @@ public class ChatRoomAdpter extends BaseRecyclerAdapter {
176 258  
177 259  
178 260 private TextView voice_user_name;
179   - private TextView voice_content;
  261 + private ImageView voiceAnim;
180 262 private TextView voice_duration;
  263 + private View voice_none_read;
  264 + private TextView status;
181 265  
182 266 public VoiceMessageHolder(View itemView) {
183 267 super(itemView);
184 268 voice_user_name = (TextView) itemView.findViewById(R.id.voice_user_name);
185   - voice_content = (TextView) itemView.findViewById(R.id.voice_content);
  269 + voiceAnim = (ImageView) itemView.findViewById(R.id.voiceAnim);
186 270 voice_duration = (TextView) itemView.findViewById(R.id.voice_duration);
  271 + voice_none_read = itemView.findViewById(R.id.noneRead);
  272 + status = (TextView) itemView.findViewById(R.id.status);
  273 + }
  274 +
  275 + public void showMessage(final VoiceMessage voiceMessage) {
  276 + voice_user_name.setText(voiceMessage.getCnVoiceMessage().getUserInfo().getUserName());
  277 + int duration = voiceMessage.getCnVoiceMessage().getVoiceTime();
  278 + voice_duration.setText(String.valueOf(duration).concat("\""));
  279 + switch (voiceMessage.getCnVoiceMessage().getStatus()) {
  280 + case IChat.CN_MSG_STATUS_SENDING:
  281 + if (status != null)
  282 + status.setText("发送中");
  283 + break;
  284 + case IChat.CN_MSG_STATUS_SEND_FAIL:
  285 + if (status != null)
  286 + status.setText("发送失败");
  287 + break;
  288 + case IChat.CN_MSG_STATUS_SEND_SUCCESS:
  289 + if (status != null)
  290 + status.setText("发送成功");
  291 + sendSuccess(voiceMessage);
  292 + break;
  293 + }
  294 + }
  295 +
  296 + private void sendSuccess(final VoiceMessage voiceMessage) {
  297 + if (voice_none_read != null)
  298 + voice_none_read.setVisibility(voiceMessage.getCnVoiceMessage().isRead() ? View.GONE : View.VISIBLE);
  299 + itemView.setOnClickListener(new View.OnClickListener() {
  300 + @Override
  301 + public void onClick(View v) {
  302 + if (mItemClickListener != null)
  303 + mItemClickListener.onItemClick(voiceMessage, (AnimationDrawable) voiceAnim.getBackground());
  304 + if (voice_none_read != null)
  305 + voice_none_read.setVisibility(View.GONE);
  306 + }
  307 + });
  308 + }
  309 + }
  310 +
  311 + public class VideoMessageHolder extends RecyclerView.ViewHolder {
  312 +
  313 + private TextView video_user_name;
  314 + private ImageView video_snapshot;
  315 + private View videoLayout;
  316 + private TextView status;
  317 +
  318 + public VideoMessageHolder(View itemView) {
  319 + super(itemView);
  320 + video_user_name = (TextView) itemView.findViewById(R.id.user_name);
  321 + video_snapshot = (ImageView) itemView.findViewById(R.id.img_content);
  322 + videoLayout = itemView.findViewById(R.id.videoLayout);
  323 + status = (TextView) itemView.findViewById(R.id.status);
  324 + }
  325 +
  326 + public void showMessage(final VideoMessage videoMessage) {
  327 + video_user_name.setText(videoMessage.getCnVideoMessage().getUserInfo().getUserName());
  328 + switch (videoMessage.getCnVideoMessage().getStatus()) {
  329 + case IChat.CN_MSG_STATUS_SENDING:
  330 + if (status != null)
  331 + status.setText("发送中");
  332 + Glide.with(mContext).load(videoMessage.getCnVideoMessage().getSnapshotPath()).into(video_snapshot);
  333 + break;
  334 + case IChat.CN_MSG_STATUS_SEND_FAIL:
  335 + if (status != null)
  336 + status.setText("发送失败");
  337 + Glide.with(mContext).load(videoMessage.getCnVideoMessage().getSnapshotPath()).into(video_snapshot);
  338 + break;
  339 + case IChat.CN_MSG_STATUS_SEND_SUCCESS:
  340 + if (status != null)
  341 + status.setText("发送成功");
  342 + sendSuccess(videoMessage);
  343 + break;
  344 + }
  345 + }
  346 +
  347 + private void sendSuccess(final VideoMessage videoMessage) {
  348 + videoLayout.setOnClickListener(new View.OnClickListener() {
  349 + @Override
  350 + public void onClick(View v) {
  351 + if (mItemClickListener != null)
  352 + mItemClickListener.onVideoClick(videoMessage);
  353 + }
  354 + });
  355 + if (videoMessage.getCnVideoMessage().isSelf()) {
  356 + Glide.with(mContext).load(videoMessage.getCnVideoMessage().getSnapshotPath()).into(video_snapshot);
  357 + } else {
  358 + String snapshotUuid = videoMessage.getCnVideoMessage().getSnapshot().getUuid();
  359 + final String imagePath = FileUtil.getCacheFilePath(snapshotUuid);
  360 + if (FileUtil.isCacheFileExist(snapshotUuid)) {
  361 + if (video_snapshot != null && mContext != null)
  362 + Glide.with(mContext).load(imagePath).into(video_snapshot);
  363 + } else {
  364 + if (!videoMessage.isDownloading()) {
  365 + videoMessage.setDownloading(true);
  366 + videoMessage.getCnVideoMessage().getSnapshot().getImage(imagePath, new IChat.OnDownloadListener() {
  367 + @Override
  368 + public void onSuccess() {
  369 + videoMessage.setDownloading(false);
  370 + if (video_snapshot != null && mContext != null)
  371 + Glide.with(mContext).load(imagePath).into(video_snapshot);
  372 + }
  373 +
  374 + @Override
  375 + public void onError(int i, String s) {
  376 + videoMessage.setDownloading(false);
  377 + }
  378 + });
  379 + }
  380 + }
  381 + }
187 382 }
188 383 }
189 384  
... ...
app/src/main/java/com/cnlive/im/adapter/CommentAdapter.java
... ... @@ -10,7 +10,7 @@ import android.widget.TextView;
10 10  
11 11 import com.bumptech.glide.Glide;
12 12 import com.cnlive.im.R;
13   -import com.cnlive.libs.util.model.CommentItem;
  13 +import com.cnlive.libs.util.comment.model.CommentItem;
14 14  
15 15 import java.util.ArrayList;
16 16 import java.util.List;
... ...
app/src/main/java/com/cnlive/im/adapter/base/VoiceItemClickListener.java renamed to app/src/main/java/com/cnlive/im/adapter/base/ItemClickListener.java
1 1 package com.cnlive.im.adapter.base;
2 2  
3   -import android.net.Uri;
  3 +import android.graphics.drawable.AnimationDrawable;
  4 +
  5 +import com.cnlive.im.mode.ImagMessage;
  6 +import com.cnlive.im.mode.VideoMessage;
  7 +import com.cnlive.im.mode.VoiceMessage;
4 8  
5 9 /**
6 10 * @author 陈硕
7 11 * @time 2017/7/14 17:50
8 12 * @desc ${TODD}
9 13 */
10   -public interface VoiceItemClickListener {
11   - void onItemClick(Uri uri);
  14 +public interface ItemClickListener {
  15 + void onItemClick(VoiceMessage voiceMessage, AnimationDrawable animationDrawable);
  16 +
  17 + void onVideoClick(VideoMessage videoMessage);
  18 +
  19 + void onImageClick(ImagMessage imagMessage);
12 20 }
... ...
app/src/main/java/com/cnlive/im/mode/ImagMessage.java
... ... @@ -12,6 +12,8 @@ public class ImagMessage {
12 12 private CNImgMessage cnImgMessage;
13 13 boolean isUserSend;
14 14  
  15 + private boolean isDownloading = false;
  16 +
15 17  
16 18 public String getType() {
17 19 return type;
... ... @@ -37,7 +39,15 @@ public class ImagMessage {
37 39 isUserSend = userSend;
38 40 }
39 41  
40   - public ImagMessage( String type,CNImgMessage cnImgMessage, boolean isUserSend) {
  42 + public boolean isDownloading() {
  43 + return isDownloading;
  44 + }
  45 +
  46 + public void setDownloading(boolean downloading) {
  47 + isDownloading = downloading;
  48 + }
  49 +
  50 + public ImagMessage(String type, CNImgMessage cnImgMessage, boolean isUserSend) {
41 51 this.type = type;
42 52 this.cnImgMessage = cnImgMessage;
43 53 this.isUserSend = isUserSend;
... ...
app/src/main/java/com/cnlive/im/mode/UgcVideoMessage.java 0 → 100644
  1 +package com.cnlive.im.mode;
  2 +
  3 +import com.cnlive.libs.util.chat.model.CNUgcMessage;
  4 +
  5 +/**
  6 + * Created by gujun on 2017/12/19.
  7 + */
  8 +
  9 +public class UgcVideoMessage {
  10 + private String type;
  11 + private CNUgcMessage cnUgcMessage;
  12 + boolean isUserSend;
  13 +
  14 + private boolean isDownloading = false;
  15 +
  16 + public UgcVideoMessage(String type, CNUgcMessage cnUgcMessage, boolean isUserSend) {
  17 + this.type = type;
  18 + this.cnUgcMessage = cnUgcMessage;
  19 + this.isUserSend = isUserSend;
  20 + }
  21 +
  22 + public String getType() {
  23 + return type;
  24 + }
  25 +
  26 + public void setType(String type) {
  27 + this.type = type;
  28 + }
  29 +
  30 + public CNUgcMessage getCnUgcMessage() {
  31 + return cnUgcMessage;
  32 + }
  33 +
  34 + public void setCnUgcMessage(CNUgcMessage cnUgcMessage) {
  35 + this.cnUgcMessage = cnUgcMessage;
  36 + }
  37 +
  38 + public boolean isUserSend() {
  39 + return isUserSend;
  40 + }
  41 +
  42 + public void setUserSend(boolean userSend) {
  43 + isUserSend = userSend;
  44 + }
  45 +
  46 + public boolean isDownloading() {
  47 + return isDownloading;
  48 + }
  49 +
  50 + public void setDownloading(boolean downloading) {
  51 + isDownloading = downloading;
  52 + }
  53 +}
  54 +
... ...
app/src/main/java/com/cnlive/im/mode/VideoMessage.java 0 → 100644
  1 +package com.cnlive.im.mode;
  2 +
  3 +import com.cnlive.libs.util.chat.model.CNVideoMessage;
  4 +
  5 +/**
  6 + * @author 陈硕
  7 + * @time 2017/7/14 16:51
  8 + * @desc ${TODD}
  9 + */
  10 +public class VideoMessage {
  11 + private String type;
  12 + private CNVideoMessage cnVideoMessage;
  13 + boolean isUserSend;
  14 +
  15 + private boolean isDownloading = false;
  16 +
  17 + public VideoMessage(String type, CNVideoMessage cnVideoMessage, boolean isUserSend) {
  18 + this.type = type;
  19 + this.cnVideoMessage = cnVideoMessage;
  20 + this.isUserSend = isUserSend;
  21 + }
  22 +
  23 + public String getType() {
  24 + return type;
  25 + }
  26 +
  27 + public void setType(String type) {
  28 + this.type = type;
  29 + }
  30 +
  31 + public CNVideoMessage getCnVideoMessage() {
  32 + return cnVideoMessage;
  33 + }
  34 +
  35 + public void setCnVideoMessage(CNVideoMessage cnVideoMessage) {
  36 + this.cnVideoMessage = cnVideoMessage;
  37 + }
  38 +
  39 + public boolean isUserSend() {
  40 + return isUserSend;
  41 + }
  42 +
  43 + public void setUserSend(boolean userSend) {
  44 + isUserSend = userSend;
  45 + }
  46 +
  47 + public boolean isDownloading() {
  48 + return isDownloading;
  49 + }
  50 +
  51 + public void setDownloading(boolean downloading) {
  52 + isDownloading = downloading;
  53 + }
  54 +}
... ...
app/src/main/java/com/cnlive/im/receiver/CNPushMessageReceiver.java
1   -package com.cnlive.im.receiver;
2   -
3   -import android.content.Context;
4   -
5   -import com.cnlive.libs.util.chat.model.CNNotificationMessage;
6   -import com.cnlive.libs.util.chat.receiver.SealNotificationReceiver;
7   -
8   -
9   -/**
10   - * Created by Lynn on 2/17/2017.
11   - */
12   -
13   -public class CNPushMessageReceiver extends SealNotificationReceiver {
14   -
15   - @Override
16   - public boolean onNotificationMessageArrived(Context var1, CNNotificationMessage var2) {
17   - //返回false,会弹出SDK默认的通知;返回true,SDK不会弹出通知,通知需要您自定义
18   - return false;
19   - }
20   -
21   - @Override
22   - public boolean onNotificationMessageClicked(Context var1, CNNotificationMessage var2) {
23   - //返回false,会走SDK默认的处理逻辑,即点击该通知则会打开会话列表或会话界面;返回true,则由您自定义处理逻辑
24   - return false;
25   - }
26   -}
  1 +//package com.cnlive.im.receiver;
  2 +//
  3 +//import android.content.Context;
  4 +//
  5 +//import com.cnlive.libs.util.chat.model.CNNotificationMessage;
  6 +//import com.cnlive.libs.util.chat.receiver.SealNotificationReceiver;
  7 +//
  8 +//
  9 +///**
  10 +// * Created by Lynn on 2/17/2017.
  11 +// */
  12 +//
  13 +//public class CNPushMessageReceiver extends SealNotificationReceiver {
  14 +//
  15 +// @Override
  16 +// public boolean onNotificationMessageArrived(Context var1, CNNotificationMessage var2) {
  17 +// //返回false,会弹出SDK默认的通知;返回true,SDK不会弹出通知,通知需要您自定义
  18 +// return false;
  19 +// }
  20 +//
  21 +// @Override
  22 +// public boolean onNotificationMessageClicked(Context var1, CNNotificationMessage var2) {
  23 +// //返回false,会走SDK默认的处理逻辑,即点击该通知则会打开会话列表或会话界面;返回true,则由您自定义处理逻辑
  24 +// return false;
  25 +// }
  26 +//}
... ...
app/src/main/java/com/cnlive/im/ui/ChatRoomActivity.java
... ... @@ -5,10 +5,14 @@ import android.app.Activity;
5 5 import android.content.Context;
6 6 import android.content.Intent;
7 7 import android.content.pm.PackageManager;
  8 +import android.graphics.Bitmap;
  9 +import android.graphics.drawable.AnimationDrawable;
  10 +import android.media.ThumbnailUtils;
8 11 import android.net.Uri;
9 12 import android.os.Build;
10 13 import android.os.Bundle;
11 14 import android.os.Handler;
  15 +import android.provider.MediaStore;
12 16 import android.support.annotation.NonNull;
13 17 import android.support.v4.app.ActivityCompat;
14 18 import android.support.v4.content.ContextCompat;
... ... @@ -33,24 +37,28 @@ import android.widget.Toast;
33 37  
34 38 import com.cnlive.im.R;
35 39 import com.cnlive.im.adapter.ChatRoomAdpter;
36   -import com.cnlive.im.adapter.base.VoiceItemClickListener;
  40 +import com.cnlive.im.adapter.base.ItemClickListener;
37 41 import com.cnlive.im.mode.ImagMessage;
38 42 import com.cnlive.im.mode.StringMessage;
  43 +import com.cnlive.im.mode.VideoMessage;
39 44 import com.cnlive.im.mode.VoiceMessage;
40 45 import com.cnlive.im.util.AudioRecordUtil;
  46 +import com.cnlive.im.util.FileUtil;
  47 +import com.cnlive.im.util.MediaUtil;
41 48 import com.cnlive.im.util.MessageType;
42   -import com.cnlive.im.util.PlayerUtil;
43 49 import com.cnlive.im.util.TimeUtils;
44 50 import com.cnlive.im.util.UploadImageUtils;
45 51 import com.cnlive.libs.util.chat.ChatUtil;
46 52 import com.cnlive.libs.util.chat.base.IChat;
  53 +import com.cnlive.libs.util.chat.model.CNBaseMessage;
47 54 import com.cnlive.libs.util.chat.model.CNImgMessage;
48 55 import com.cnlive.libs.util.chat.model.CNMessage;
49 56 import com.cnlive.libs.util.chat.model.CNUserInfo;
  57 +import com.cnlive.libs.util.chat.model.CNVideoMessage;
50 58 import com.cnlive.libs.util.chat.model.CNVoiceMessage;
51 59  
52   -import org.json.JSONException;
53   -
  60 +import java.io.File;
  61 +import java.io.FileInputStream;
54 62 import java.util.ArrayList;
55 63  
56 64  
... ... @@ -59,10 +67,13 @@ import java.util.ArrayList;
59 67 * @time 2017/3/7 14:36
60 68 * @desc ${TODD}
61 69 */
62   -public class ChatRoomActivity extends AppCompatActivity implements View.OnClickListener, VoiceItemClickListener {
  70 +public class ChatRoomActivity extends AppCompatActivity implements View.OnClickListener, ItemClickListener {
63 71 private static final String TAG = "ChatRoomActivity";
64   - private ArrayList<Object> groupChatOneListMy;
65   - private String roomIdOne = "ChatRoom05";
  72 +
  73 + private final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 0x2001;
  74 +
  75 + private ArrayList<String> groupChatOneListMy;
  76 + private String roomIdOne = "ChatRoom10";
66 77 private EditText editText;
67 78 private Button send_messageOneBtn;
68 79 private RecyclerView listViewOne;
... ... @@ -70,7 +81,7 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL
70 81 private Button foundChatBtn;
71 82 private Handler mHandler;
72 83 private RelativeLayout re_chat;
73   -// private LinearLayout lin_user;
  84 + // private LinearLayout lin_user;
74 85 // private EditText user_id, user_name;
75 86 private Button exit_chat1;
76 87 public static String user_name_string;
... ... @@ -100,8 +111,6 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL
100 111  
101 112 private String mFilePath;
102 113  
103   - private PlayerUtil playerUtil;
104   -
105 114 // 所需的全部权限
106 115 static final String[] PERMISSIONS = new String[]{
107 116 Manifest.permission.RECORD_AUDIO,
... ... @@ -130,7 +139,6 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL
130 139 ChatUtil.login(new CNUserInfo(user_id_string, user_name_string, ""), connectListener);
131 140 else ChatUtil.logOut(connectListener);
132 141 requestPermission();
133   - playerUtil = new PlayerUtil(this);
134 142  
135 143 }
136 144  
... ... @@ -169,6 +177,9 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL
169 177 keybordBtn = (ImageView) findViewById(R.id.keybord);
170 178 keybordBtn.setOnClickListener(this);
171 179  
  180 + findViewById(R.id.videoBtn).setOnClickListener(this);
  181 + findViewById(R.id.ugcVideoBtn).setOnClickListener(this);
  182 +
172 183  
173 184 StartListener();
174 185  
... ... @@ -181,43 +192,21 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL
181 192 */
182 193 private IChat.OnSendMessageListener sendMessageListener = new IChat.OnSendMessageListener() {
183 194 @Override
184   - public void onAttached(Object o) {
185   -
  195 + public void onAttached(CNBaseMessage o) {
  196 + showMessage(o);
186 197 }
187 198  
188 199 @Override
189   - public void onSuccess(final Object o) throws JSONException {
190   - mHandler.post(new Runnable() {
191   - @Override
192   - public void run() {
193   - if (o instanceof CNMessage) {
194   - CNMessage o1 = (CNMessage) o;
195   - chatListAdapterOne.addItem(new StringMessage(MessageType.stringMessage, o1, true));
196   - } else if (o instanceof CNImgMessage) {
197   - CNImgMessage o1 = (CNImgMessage) o;
198   - chatListAdapterOne.addItem(new ImagMessage(MessageType.imaMessage, o1, true));
199   - } else if (o instanceof CNVoiceMessage) {
200   - CNVoiceMessage o1 = (CNVoiceMessage) o;
201   - VoiceMessage voiceMessage = new VoiceMessage(MessageType.voiceMessage, o1, true);
202   - chatListAdapterOne.addItem(voiceMessage);
203   - //发送成功后删除保存在本地的录制文件
204   - mAudioRecordUtil.deleteRecordFile(mFilePath);
205   -
206   - }
207   - listViewOne.smoothScrollToPosition(chatListAdapterOne.getItemCount() - 1);
208   - }
209   - });
  200 + public void onSuccess(final CNBaseMessage o) {
  201 + updateItem(o);
210 202 }
211 203  
212 204 @Override
213   - public void onError(Object o, int i, String s) {
214   - if (o instanceof CNImgMessage) {
215   -
216   - }
  205 + public void onError(CNBaseMessage o, int i, String s) {
  206 + updateItem(o);
217 207 }
218 208 };
219 209  
220   -
221 210 //连接状态监听
222 211 private IChat.OnConnectStatusListener connectStatusListener = new IChat.OnConnectStatusListener() {
223 212 @Override
... ... @@ -229,28 +218,59 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL
229 218  
230 219 private IChat.OnReceiveMessageListener receiveMessageListener = new IChat.OnReceiveMessageListener() {
231 220 @Override
232   - public void processMessage(final Object o) {
233   - mHandler.post(new Runnable() {
234   - @Override
235   - public void run() {
236   - if (o instanceof CNMessage) {
237   - CNMessage o1 = (CNMessage) o;
238   - chatListAdapterOne.addItem(new StringMessage(MessageType.stringMessage, o1, false));
239   - } else if (o instanceof CNImgMessage) {
240   - CNImgMessage o1 = (CNImgMessage) o;
241   - chatListAdapterOne.addItem(new ImagMessage(MessageType.imaMessage, o1, false));
242   - } else if (o instanceof CNVoiceMessage) {
243   - CNVoiceMessage o1 = (CNVoiceMessage) o;
244   - VoiceMessage voiceMessage = new VoiceMessage(MessageType.voiceMessage, o1, false);
245   - chatListAdapterOne.addItem(voiceMessage);
246   - }
247   - listViewOne.smoothScrollToPosition(chatListAdapterOne.getItemCount() - 1);
248   - }
249   - });
250   -
  221 + public void processMessage(final CNBaseMessage o) {
  222 + showMessage(o);
251 223 }
252 224 };
253 225  
  226 + /**
  227 + * 更新消息
  228 + */
  229 + public void updateItem(CNBaseMessage o) {
  230 + int updateIndex = groupChatOneListMy.indexOf(o.getMessageId());
  231 + if (updateIndex < 0 || chatListAdapterOne.getItemCount() <= 0) return;
  232 + if (o.getMsgType() == IChat.CN_MSG_TYPE_TEXT) {
  233 + CNMessage o1 = (CNMessage) o;
  234 + chatListAdapterOne.updateItem(new StringMessage(MessageType.stringMessage, o1, o1.isSelf()), updateIndex);
  235 + } else if (o.getMsgType() == IChat.CN_MSG_TYPE_IMAGE) {
  236 + CNImgMessage o1 = (CNImgMessage) o;
  237 + chatListAdapterOne.updateItem(new ImagMessage(MessageType.imaMessage, o1, o1.isSelf()), updateIndex);
  238 + } else if (o.getMsgType() == IChat.CN_MSG_TYPE_VOICE) {
  239 + CNVoiceMessage o1 = (CNVoiceMessage) o;
  240 + VoiceMessage voiceMessage = new VoiceMessage(MessageType.voiceMessage, o1, o1.isSelf());
  241 + chatListAdapterOne.updateItem(voiceMessage, updateIndex);
  242 + } else if (o.getMsgType() == IChat.CN_MSG_TYPE_VIDEO) {
  243 + CNVideoMessage ol = (CNVideoMessage) o;
  244 + VideoMessage videoMessage = new VideoMessage(MessageType.videoMessage, ol, ol.isSelf());
  245 + chatListAdapterOne.updateItem(videoMessage, updateIndex);
  246 + }
  247 + }
  248 +
  249 + /**
  250 + * 展示消息
  251 + *
  252 + * @param o
  253 + */
  254 + private void showMessage(CNBaseMessage o) {
  255 + groupChatOneListMy.add(o.getMessageId());
  256 + if (o.getMsgType() == IChat.CN_MSG_TYPE_TEXT) {
  257 + CNMessage o1 = (CNMessage) o;
  258 + chatListAdapterOne.addItem(new StringMessage(MessageType.stringMessage, o1, o1.isSelf()));
  259 + } else if (o.getMsgType() == IChat.CN_MSG_TYPE_IMAGE) {
  260 + CNImgMessage o1 = (CNImgMessage) o;
  261 + chatListAdapterOne.addItem(new ImagMessage(MessageType.imaMessage, o1, o1.isSelf()));
  262 + } else if (o.getMsgType() == IChat.CN_MSG_TYPE_VOICE) {
  263 + CNVoiceMessage o1 = (CNVoiceMessage) o;
  264 + VoiceMessage voiceMessage = new VoiceMessage(MessageType.voiceMessage, o1, o1.isSelf());
  265 + chatListAdapterOne.addItem(voiceMessage);
  266 + } else if (o.getMsgType() == IChat.CN_MSG_TYPE_VIDEO) {
  267 + CNVideoMessage ol = (CNVideoMessage) o;
  268 + VideoMessage videoMessage = new VideoMessage(MessageType.videoMessage, ol, ol.isSelf());
  269 + chatListAdapterOne.addItem(videoMessage);
  270 + }
  271 + listViewOne.smoothScrollToPosition(chatListAdapterOne.getItemCount() - 1);
  272 + }
  273 +
254 274  
255 275 //聊天室操作
256 276 private IChat.OnChatRoomActionListener chatRoomActionListener = new IChat.OnChatRoomActionListener() {
... ... @@ -333,7 +353,7 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL
333 353 }
334 354 break;
335 355 case R.id.creatChat:
336   - ChatUtil.joinChatRoom(roomIdOne, 20, onOperationListener);
  356 + ChatUtil.joinChatRoom(roomIdOne, -1, onOperationListener);
337 357 break;
338 358 case R.id.exit_chat1:
339 359 ChatUtil.quitChatRoom(roomIdOne, onOperationListener);
... ... @@ -356,9 +376,30 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL
356 376 isVoiceBtnVisible = false;
357 377 }
358 378 break;
  379 + case R.id.videoBtn:
  380 + openSystemRecorder();
  381 + break;
  382 + case R.id.ugcVideoBtn:
  383 +
  384 + break;
359 385 }
360 386 }
361 387  
  388 + private void openSystemRecorder() {
  389 + // 创建拍照Intent并将控制权返回给调用的程序
  390 + Intent intent = new Intent();
  391 + intent.setAction(MediaStore.ACTION_VIDEO_CAPTURE);
  392 + intent.addCategory(Intent.CATEGORY_DEFAULT);
  393 +
  394 + // 保存录像到指定的路径
  395 + File file = new File("/sdcard/video.mp4");
  396 + Uri uri = Uri.fromFile(file);
  397 + intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
  398 +
  399 + // 启动图像捕获Intent
  400 + startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
  401 + }
  402 +
362 403  
363 404 public void fromPicture() {
364 405 if (Build.VERSION.SDK_INT >= 23) {
... ... @@ -394,7 +435,12 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL
394 435 Uri uri = Uri.parse("file://" + picturePath);
395 436 ChatUtil.sendImaMessage(IChat.CHATROOM, roomIdOne, uri, uri, sendMessageListener);
396 437 break;
397   -
  438 + case CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE:
  439 + String videoPath = data.getData().getPath();
  440 + Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Images.Thumbnails.FULL_SCREEN_KIND);
  441 + String imgPath = FileUtil.createFile(bitmap, System.currentTimeMillis() + "");
  442 + ChatUtil.sendVideoMessage(IChat.CHATROOM, roomIdOne, videoPath, imgPath, MediaUtil.getInstance().getDuration(videoPath), sendMessageListener);
  443 + break;
398 444 default:
399 445 break;
400 446 }
... ... @@ -425,11 +471,137 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL
425 471 }
426 472 };
427 473  
  474 + /**
  475 + * 播放语音文件
  476 + *
  477 + * @param voicePath
  478 + * @param animationDrawable
  479 + */
  480 + private void startVoice(String voicePath, final AnimationDrawable animationDrawable) {
  481 + try {
  482 + FileInputStream fis = new FileInputStream(voicePath);
  483 + MediaUtil.getInstance().play(fis);
  484 + animationDrawable.start();
  485 + MediaUtil.getInstance().setEventListener(new MediaUtil.EventListener() {
  486 + @Override
  487 + public void onStop() {
  488 + animationDrawable.stop();
  489 + animationDrawable.selectDrawable(0);
  490 + }
  491 + });
  492 + } catch (Exception e) {
  493 + }
  494 + }
428 495  
429 496 @Override
430   - public void onItemClick(Uri uri) {
431   - playerUtil.start(uri);
  497 + public void onItemClick(VoiceMessage voiceMessage, final AnimationDrawable animationDrawable) {
  498 + if (voiceMessage == null) {
  499 + Toast.makeText(this, "数据异常", Toast.LENGTH_LONG).show();
  500 + return;
  501 + }
  502 + if (voiceMessage.getCnVoiceMessage().isSelf()) {
  503 + startVoice(voiceMessage.getCnVoiceMessage().getVoiceUri().getPath(), animationDrawable);
  504 + } else {
  505 + //设置本地已读
  506 + voiceMessage.getCnVoiceMessage().setRead(true);
  507 + String voiceUuid = voiceMessage.getCnVoiceMessage().getUuid();
  508 + final String voicePath = FileUtil.getCacheFilePath(voiceUuid);
  509 + if (FileUtil.isCacheFileExist(voiceUuid)) {
  510 + File file = new File(voicePath);
  511 + if (file.length() < voiceMessage.getCnVoiceMessage().getDataSize()) {
  512 + Toast.makeText(context, "请稍等,正在下载...", Toast.LENGTH_SHORT).show();
  513 + return;
  514 + }
  515 + startVoice(voicePath, animationDrawable);
  516 + } else {
  517 + voiceMessage.getCnVoiceMessage().getVoice(voicePath, new IChat.OnDownloadListener() {
  518 + @Override
  519 + public void onSuccess() {
  520 + startVoice(voicePath, animationDrawable);
  521 + }
  522 +
  523 + @Override
  524 + public void onError(int i, String s) {
432 525  
  526 + }
  527 + });
  528 + }
  529 + }
  530 + }
  531 +
  532 + @Override
  533 + public void onVideoClick(VideoMessage videoMessage) {
  534 + if (videoMessage.getCnVideoMessage().isSelf()) {
  535 + Intent intent = new Intent(ChatRoomActivity.this, VideoActivity.class);
  536 + intent.putExtra("videoPath", videoMessage.getCnVideoMessage().getVideoPath());
  537 + startActivity(intent);
  538 + } else {
  539 + String videoUuid = videoMessage.getCnVideoMessage().getVideo().getUuid();
  540 + final String videoPath = FileUtil.getCacheFilePath(videoUuid);
  541 + if (FileUtil.isCacheFileExist(videoUuid)) {
  542 + Intent intent = new Intent(ChatRoomActivity.this, VideoActivity.class);
  543 + intent.putExtra("videoPath", videoPath);
  544 + startActivity(intent);
  545 + } else {
  546 + videoMessage.getCnVideoMessage().getVideo().getVideo(videoPath, new IChat.OnDownloadListener() {
  547 + @Override
  548 + public void onSuccess() {
  549 + Intent intent = new Intent(ChatRoomActivity.this, VideoActivity.class);
  550 + intent.putExtra("videoPath", videoPath);
  551 + startActivity(intent);
  552 + }
  553 +
  554 + @Override
  555 + public void onError(int i, String s) {
  556 +
  557 + }
  558 + });
  559 + }
  560 + }
  561 +
  562 + }
  563 +
  564 + @Override
  565 + public void onImageClick(final ImagMessage imagMessage) {
  566 + if (imagMessage.getCnImgMessage().isSelf()) {
  567 + Intent intent = new Intent(ChatRoomActivity.this, ImageViewActivity.class);
  568 + intent.putExtra("path", imagMessage.getCnImgMessage().getImagePath());
  569 + startActivity(intent);
  570 + } else {
  571 + String remoteUuid = imagMessage.getCnImgMessage().getRemoteUuid();
  572 + final String imagePath = FileUtil.getCacheFilePath(remoteUuid);
  573 + if (FileUtil.isCacheFileExist(remoteUuid)) {
  574 + File file = new File(imagePath);
  575 + if (file.length() < imagMessage.getCnImgMessage().getRemoteSize()) {
  576 + Toast.makeText(context, "请稍等,正在下载...", Toast.LENGTH_SHORT).show();
  577 + return;
  578 + }
  579 + Intent intent = new Intent(ChatRoomActivity.this, ImageViewActivity.class);
  580 + intent.putExtra("path", imagePath);
  581 + startActivity(intent);
  582 + } else {
  583 + if (imagMessage.isDownloading()) {
  584 + Toast.makeText(context, "请稍等,正在下载...", Toast.LENGTH_SHORT).show();
  585 + } else {
  586 + imagMessage.setDownloading(true);
  587 + imagMessage.getCnImgMessage().getRemoteImage(imagePath, new IChat.OnDownloadListener() {
  588 + @Override
  589 + public void onSuccess() {
  590 + imagMessage.setDownloading(false);
  591 + Intent intent = new Intent(ChatRoomActivity.this, ImageViewActivity.class);
  592 + intent.putExtra("path", imagePath);
  593 + startActivity(intent);
  594 + }
  595 +
  596 + @Override
  597 + public void onError(int i, String s) {
  598 + imagMessage.setDownloading(false);
  599 + Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();
  600 + }
  601 + });
  602 + }
  603 + }
  604 + }
433 605 }
434 606  
435 607  
... ... @@ -444,14 +616,15 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL
444 616 Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) &&
445 617 (ContextCompat.checkSelfPermission(context,
446 618 Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED)
447   - ) {
  619 + && (ContextCompat.checkSelfPermission(context,
  620 + Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED)) {
448 621 StartListener();
449 622  
450 623 //判断是否开启语音权限
451 624 } else {
452 625 //请求获取摄像头权限
453 626 ActivityCompat.requestPermissions((Activity) context,
454   - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO}, VOICE_REQUEST_CODE);
  627 + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA}, VOICE_REQUEST_CODE);
455 628 }
456 629 }
457 630  
... ... @@ -592,4 +765,16 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL
592 765 }
593 766 };
594 767  
  768 + @Override
  769 + protected void onPause() {
  770 + super.onPause();
  771 + MediaUtil.getInstance().stop();
  772 + }
  773 +
  774 + @Override
  775 + protected void onDestroy() {
  776 + super.onDestroy();
  777 + ChatUtil.removeReceiveMessageListener(receiveMessageListener);
  778 + ChatUtil.removeConnectListener(connectListener);
  779 + }
595 780 }
... ...
app/src/main/java/com/cnlive/im/ui/CommentActivity.java
... ... @@ -13,14 +13,14 @@ import android.widget.Toast;
13 13  
14 14 import com.cnlive.im.R;
15 15 import com.cnlive.im.adapter.CommentAdapter;
16   -import com.cnlive.libs.util.chat.model.ErrorMessage;
17 16 import com.cnlive.libs.util.comment.CommentUtil;
18 17 import com.cnlive.libs.util.comment.base.CommentCallback;
19 18 import com.cnlive.libs.util.comment.base.CommentListCallback;
20 19 import com.cnlive.libs.util.comment.base.CommentProgramCallback;
21   -import com.cnlive.libs.util.model.CommentItem;
22   -import com.cnlive.libs.util.model.CommentPage;
23   -import com.cnlive.libs.util.model.CommentProgram;
  20 +import com.cnlive.libs.util.comment.model.CommentItem;
  21 +import com.cnlive.libs.util.comment.model.CommentPage;
  22 +import com.cnlive.libs.util.comment.model.CommentProgram;
  23 +import com.cnlive.libs.util.comment.model.ErrorMessage;
24 24  
25 25 import java.util.List;
26 26  
... ...
app/src/main/java/com/cnlive/im/ui/ImageViewActivity.java 0 → 100644
  1 +package com.cnlive.im.ui;
  2 +
  3 +import android.app.Activity;
  4 +import android.os.Bundle;
  5 +import android.support.annotation.Nullable;
  6 +import android.widget.ImageView;
  7 +
  8 +import com.bumptech.glide.Glide;
  9 +import com.cnlive.im.R;
  10 +
  11 +/**
  12 + * Created by gujun on 2017/12/18.
  13 + */
  14 +
  15 +public class ImageViewActivity extends Activity {
  16 +
  17 + private ImageView imageView;
  18 +
  19 + private String imagePath;
  20 +
  21 + @Override
  22 + protected void onCreate(@Nullable Bundle savedInstanceState) {
  23 + super.onCreate(savedInstanceState);
  24 + setContentView(R.layout.activity_image_view);
  25 + imageView = (ImageView) findViewById(R.id.image);
  26 + imagePath = getIntent().getStringExtra("path");
  27 + Glide.with(this).load(imagePath).into(imageView);
  28 + }
  29 +}
... ...
app/src/main/java/com/cnlive/im/ui/PrivateActivity.java
... ... @@ -6,6 +6,9 @@ import android.content.Context;
6 6 import android.content.Intent;
7 7 import android.content.pm.PackageManager;
8 8 import android.database.Cursor;
  9 +import android.graphics.Bitmap;
  10 +import android.graphics.drawable.AnimationDrawable;
  11 +import android.media.ThumbnailUtils;
9 12 import android.net.Uri;
10 13 import android.os.Build;
11 14 import android.os.Bundle;
... ... @@ -29,33 +32,38 @@ import android.widget.Button;
29 32 import android.widget.EditText;
30 33 import android.widget.ImageView;
31 34 import android.widget.LinearLayout;
32   -import android.widget.ListView;
33 35 import android.widget.RelativeLayout;
34 36 import android.widget.TextView;
35 37 import android.widget.Toast;
36 38  
37 39 import com.cnlive.im.R;
38 40 import com.cnlive.im.adapter.ChatRoomAdpter;
39   -import com.cnlive.im.adapter.base.VoiceItemClickListener;
  41 +import com.cnlive.im.adapter.base.ItemClickListener;
40 42 import com.cnlive.im.mode.CNMessageModole;
41 43 import com.cnlive.im.mode.ImagMessage;
42 44 import com.cnlive.im.mode.StringMessage;
  45 +import com.cnlive.im.mode.VideoMessage;
43 46 import com.cnlive.im.mode.VoiceMessage;
44 47 import com.cnlive.im.util.AudioRecordUtil;
  48 +import com.cnlive.im.util.FileUtil;
  49 +import com.cnlive.im.util.MediaUtil;
45 50 import com.cnlive.im.util.MessageType;
46   -import com.cnlive.im.util.PlayerUtil;
47 51 import com.cnlive.im.util.TimeUtils;
48 52 import com.cnlive.im.util.ToStringUtils;
49 53 import com.cnlive.libs.util.chat.ChatUtil;
50 54 import com.cnlive.libs.util.chat.base.IChat;
  55 +import com.cnlive.libs.util.chat.model.CNBaseMessage;
51 56 import com.cnlive.libs.util.chat.model.CNImgMessage;
52 57 import com.cnlive.libs.util.chat.model.CNMessage;
53 58 import com.cnlive.libs.util.chat.model.CNUserInfo;
  59 +import com.cnlive.libs.util.chat.model.CNVideoMessage;
54 60 import com.cnlive.libs.util.chat.model.CNVoiceMessage;
55 61  
56 62 import org.json.JSONException;
57 63 import org.json.JSONObject;
58 64  
  65 +import java.io.File;
  66 +import java.io.FileInputStream;
59 67 import java.util.ArrayList;
60 68  
61 69 import static com.cnlive.im.R.id.opposite_id_edit;
... ... @@ -64,10 +72,12 @@ import static com.cnlive.im.R.id.opposite_id_edit;
64 72 * Created by Lynn on 2017/7/24.
65 73 */
66 74  
67   -public class PrivateActivity extends AppCompatActivity implements View.OnClickListener, VoiceItemClickListener {
  75 +public class PrivateActivity extends AppCompatActivity implements View.OnClickListener, ItemClickListener {
68 76  
69 77 private static final String TAG = "PrivateChatActivity";
70 78  
  79 + private final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 0x2001;
  80 +
71 81 // 所需的全部权限
72 82 static final String[] PERMISSIONS = new String[]{
73 83 Manifest.permission.RECORD_AUDIO,
... ... @@ -87,7 +97,7 @@ public class PrivateActivity extends AppCompatActivity implements View.OnClickLi
87 97 private EditText messageContent;
88 98 private Button sendMessageBtn;
89 99 private ChatRoomAdpter chatListAdapter;
90   - private ArrayList<Object> messageList = new ArrayList<>();
  100 + private ArrayList<String> messageList = new ArrayList<>();
91 101 // private CNMessage cnMessage;
92 102 private LinearLayout linearLayoutUseID;
93 103 private EditText user_id_edit;
... ... @@ -108,7 +118,6 @@ public class PrivateActivity extends AppCompatActivity implements View.OnClickLi
108 118 private ImageView keybordBtn;
109 119 private Button sendVoice;
110 120 private AudioRecordUtil mAudioRecordUtil;
111   - private PlayerUtil playerUtil;
112 121 private String mFilePath;
113 122 private PopupWindowFactory mPop;
114 123 private RelativeLayout privateLayout;
... ... @@ -132,9 +141,8 @@ public class PrivateActivity extends AppCompatActivity implements View.OnClickLi
132 141 mAudioRecordUtil.setOnAudioStatusUpdateListener(onAudioStatusUpdateListener);
133 142 mHandler = new Handler();
134 143 ChatUtil.setOnConnectStatusListener(connectStatusListener);
135   - ChatUtil.setOnReceiveMessageListener(receiveMessageListener);
  144 + ChatUtil.setOnReceivePrivateMessageListener(receiveMessageListener);
136 145 requestPermission();
137   - playerUtil = new PlayerUtil(this);
138 146 }
139 147  
140 148 private void initView() {
... ... @@ -184,6 +192,9 @@ public class PrivateActivity extends AppCompatActivity implements View.OnClickLi
184 192 chatListView.setLayoutManager(new LinearLayoutManager(PrivateActivity.this));
185 193 chatListView.setAdapter(chatListAdapter);
186 194  
  195 + findViewById(R.id.videoBtn).setOnClickListener(this);
  196 + findViewById(R.id.ugcVideoBtn).setOnClickListener(this);
  197 +
187 198 StartListener();
188 199 }
189 200  
... ... @@ -251,9 +262,31 @@ public class PrivateActivity extends AppCompatActivity implements View.OnClickLi
251 262 case R.id.ima_send:
252 263 sendMessage(IMAGE_MESSAGE);
253 264 break;
  265 + case R.id.videoBtn:
  266 + openSystemRecorder();
  267 + break;
  268 + case R.id.ugcVideoBtn:
  269 +
  270 + break;
254 271 }
255 272 }
256 273  
  274 + private void openSystemRecorder() {
  275 + // 创建拍照Intent并将控制权返回给调用的程序
  276 + Intent intent = new Intent();
  277 + intent.setAction(MediaStore.ACTION_VIDEO_CAPTURE);
  278 + intent.addCategory(Intent.CATEGORY_DEFAULT);
  279 +
  280 + // 保存录像到指定的路径
  281 + File file = new File("/sdcard/video.mp4");
  282 + Uri uri = Uri.fromFile(file);
  283 + intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
  284 +
  285 + // 启动图像捕获Intent
  286 + startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
  287 + }
  288 +
  289 +
257 290 private void sendMessage(String type) {
258 291 if (sendInfo == 2) {
259 292 Toast.makeText(this, "等待对方接受邀请", Toast.LENGTH_SHORT).show();
... ... @@ -329,6 +362,12 @@ public class PrivateActivity extends AppCompatActivity implements View.OnClickLi
329 362 Uri uri = Uri.parse("file://" + picturePath);
330 363 ChatUtil.sendImaMessage(IChat.PRIVATE, oppositeID, uri, uri, sendMessageListener);
331 364 break;
  365 + case CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE:
  366 + String videoPath = data.getData().getPath();
  367 + Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Images.Thumbnails.FULL_SCREEN_KIND);
  368 + String imgPath = FileUtil.createFile(bitmap, System.currentTimeMillis() + "");
  369 + ChatUtil.sendVideoMessage(IChat.PRIVATE, oppositeID, videoPath, imgPath, MediaUtil.getInstance().getDuration(videoPath), sendMessageListener);
  370 + break;
332 371  
333 372 default:
334 373 break;
... ... @@ -365,120 +404,110 @@ public class PrivateActivity extends AppCompatActivity implements View.OnClickLi
365 404 /**
366 405 * 发送消息监听
367 406 */
368   -
369 407 private IChat.OnSendMessageListener sendMessageListener = new IChat.OnSendMessageListener() {
370 408 @Override
371   - public void onAttached(Object o) {
  409 + public void onAttached(CNBaseMessage o) {
  410 + showMessage(o, false);
372 411 }
373 412  
374 413 @Override
375   - public void onSuccess(final Object o) throws JSONException {
376   - if (View.VISIBLE == vistor_btn.getVisibility()) {
377   - vistor_btn.setVisibility(View.GONE);
378   - }
379   -
380   - mHandler.post(new Runnable() {
381   - @Override
382   - public void run() {
383   - if (o instanceof CNMessage) {
384   - CNMessage o1 = (CNMessage) o;
385   - JSONObject jsonObject = null;
386   - try {
387   - jsonObject = new JSONObject(o1.getContent().toString());
388   - String type = (String) jsonObject.get("type");
389   - String message = (String) jsonObject.get("message");
390   - Toast.makeText(PrivateActivity.this, "发送消息成功", Toast.LENGTH_SHORT).show();
391   - if ("3".equals(type) && message.equals("你好我们可以进行私聊吗")) {
392   - sendInfo = 2;
393   - Toast.makeText(PrivateActivity.this, "申请已发送等待对方验证", Toast.LENGTH_SHORT).show();
394   - } else if ("3".equals(type) && message.equals("拒绝")) {
395   - sendInfo = 5;
396   - } else if ("3".equals(type) && message.equals("同意")) {
397   - sendInfo = 1;
398   - } else if ("4".equals(type)) {
399   - chatListAdapter.addItem(new StringMessage(MessageType.stringMessage, o1, true));
400   - chatListView.smoothScrollToPosition(chatListAdapter.getItemCount() - 1);
401   -
402   - }
403   - } catch (JSONException e) {
404   -
405   -
406   - }
407   - } else if (o instanceof CNImgMessage) {
408   - CNImgMessage o1 = (CNImgMessage) o;
409   - chatListAdapter.addItem(new ImagMessage(MessageType.imaMessage, o1, true));
410   - chatListView.smoothScrollToPosition(chatListAdapter.getItemCount() - 1);
411   - } else if (o instanceof CNVoiceMessage) {
412   - CNVoiceMessage o1 = (CNVoiceMessage) o;
413   - VoiceMessage voiceMessage = new VoiceMessage(MessageType.voiceMessage, o1, true);
414   - chatListAdapter.addItem(voiceMessage);
415   - //发送成功后删除保存在本地的录制文件
416   - mAudioRecordUtil.deleteRecordFile(mFilePath);
417   - chatListView.smoothScrollToPosition(chatListAdapter.getItemCount() - 1);
418   - }
419   - }
420   - });
  414 + public void onSuccess(final CNBaseMessage o) {
  415 + updateItem(o);
421 416 }
422 417  
423 418 @Override
424   - public void onError(Object o, int i, String s) {
  419 + public void onError(CNBaseMessage o, int i, String s) {
  420 + updateItem(o);
425 421 }
426 422 };
427 423  
428   -
429 424 //连接状态监听
430 425 private IChat.OnConnectStatusListener connectStatusListener = new IChat.OnConnectStatusListener() {
431 426 @Override
432 427 public void onConnectStatus(int i, String s) {
433   - Log.i(TAG, "私聊连接状态监听私聊" + i + " " + s);
434   -
435   -
  428 + Log.i(TAG, "连接状态监听" + i + " " + s);
436 429 }
437 430 };
  431 +
  432 +
438 433 //接收消息监听
439 434 private IChat.OnReceiveMessageListener receiveMessageListener = new IChat.OnReceiveMessageListener() {
440 435 @Override
441   - public void processMessage(final Object o) {
442   - mHandler.post(new Runnable() {
443   - @Override
444   - public void run() {
445   - if (o instanceof CNMessage) {
446   - CNMessage o1 = (CNMessage) o;
447   - JSONObject jsonObject = null;
448   - try {
449   - jsonObject = new JSONObject(o1.getContent().toString());
450   - String type = (String) jsonObject.get("type");
451   - if ("3".equals(type) && "你好我们可以进行私聊吗".equals(jsonObject.get("message"))) {
452   - vistor_btn.setVisibility(View.GONE);
453   - agree_reject_lin.setVisibility(View.VISIBLE);
454   - } else if ("3".equals(type) && "同意".equals(jsonObject.get("message"))) {
455   - sendInfo = 1;
456   - } else if ("3".equals(type) && "拒绝".equals(jsonObject.get("message"))) {
457   - sendInfo = 4;
458   - } else if ("4".equals(type)) {
459   - Log.v(TAG, o1.getContent().toString());
460   - chatListAdapter.addItem(new StringMessage(MessageType.stringMessage, o1, false));
461   - chatListView.smoothScrollToPosition(chatListAdapter.getItemCount() - 1);
462   - }
  436 + public void processMessage(final CNBaseMessage o) {
  437 + showMessage(o, true);
  438 + }
  439 + };
463 440  
464   - } catch (JSONException e) {
465   - e.printStackTrace();
466   - }
467   - } else if (o instanceof CNImgMessage) {
468   - CNImgMessage o1 = (CNImgMessage) o;
469   - chatListAdapter.addItem(new ImagMessage(MessageType.imaMessage, o1, false));
470   - chatListView.smoothScrollToPosition(chatListAdapter.getItemCount() - 1);
471   - } else if (o instanceof CNVoiceMessage) {
472   - CNVoiceMessage o1 = (CNVoiceMessage) o;
473   - VoiceMessage voiceMessage = new VoiceMessage(MessageType.voiceMessage, o1, false);
474   - chatListAdapter.addItem(voiceMessage);
  441 + /**
  442 + * 更新消息
  443 + */
  444 + public void updateItem(CNBaseMessage o) {
  445 + int updateIndex = messageList.indexOf(o.getMessageId());
  446 + if (updateIndex < 0 || chatListAdapter.getItemCount() <= 0) return;
  447 + if (o.getMsgType() == IChat.CN_MSG_TYPE_TEXT) {
  448 + CNMessage o1 = (CNMessage) o;
  449 + chatListAdapter.updateItem(new StringMessage(MessageType.stringMessage, o1, o1.isSelf()), updateIndex);
  450 + } else if (o.getMsgType() == IChat.CN_MSG_TYPE_IMAGE) {
  451 + CNImgMessage o1 = (CNImgMessage) o;
  452 + chatListAdapter.updateItem(new ImagMessage(MessageType.imaMessage, o1, o1.isSelf()), updateIndex);
  453 + } else if (o.getMsgType() == IChat.CN_MSG_TYPE_VOICE) {
  454 + CNVoiceMessage o1 = (CNVoiceMessage) o;
  455 + VoiceMessage voiceMessage = new VoiceMessage(MessageType.voiceMessage, o1, o1.isSelf());
  456 + chatListAdapter.updateItem(voiceMessage, updateIndex);
  457 + } else if (o.getMsgType() == IChat.CN_MSG_TYPE_VIDEO) {
  458 + CNVideoMessage ol = (CNVideoMessage) o;
  459 + VideoMessage videoMessage = new VideoMessage(MessageType.videoMessage, ol, ol.isSelf());
  460 + chatListAdapter.updateItem(videoMessage, updateIndex);
  461 + }
  462 + }
  463 +
  464 + /**
  465 + * 展示消息
  466 + *
  467 + * @param o
  468 + */
  469 + private void showMessage(CNBaseMessage o, boolean isReceivedMsg) {
  470 + messageList.add(o.getMessageId());
  471 + if (o.getMsgType() == IChat.CN_MSG_TYPE_TEXT) {
  472 + if (isReceivedMsg) {
  473 + CNMessage o1 = (CNMessage) o;
  474 + JSONObject jsonObject = null;
  475 + try {
  476 + jsonObject = new JSONObject(o1.getContent().toString());
  477 + String type = (String) jsonObject.get("type");
  478 + if ("3".equals(type) && "你好我们可以进行私聊吗".equals(jsonObject.get("message"))) {
  479 + vistor_btn.setVisibility(View.GONE);
  480 + agree_reject_lin.setVisibility(View.VISIBLE);
  481 + } else if ("3".equals(type) && "同意".equals(jsonObject.get("message"))) {
  482 + sendInfo = 1;
  483 + } else if ("3".equals(type) && "拒绝".equals(jsonObject.get("message"))) {
  484 + sendInfo = 4;
  485 + } else if ("4".equals(type)) {
  486 + Log.v(TAG, o1.getContent().toString());
  487 + chatListAdapter.addItem(new StringMessage(MessageType.stringMessage, o1, false));
475 488 chatListView.smoothScrollToPosition(chatListAdapter.getItemCount() - 1);
476 489 }
  490 + } catch (JSONException e) {
  491 + e.printStackTrace();
477 492 }
478   - });
479   -
  493 + } else {
  494 + CNMessage o1 = (CNMessage) o;
  495 + chatListAdapter.addItem(new StringMessage(MessageType.stringMessage, o1, o1.isSelf()));
  496 + }
  497 + } else if (o.getMsgType() == IChat.CN_MSG_TYPE_IMAGE) {
  498 + CNImgMessage o1 = (CNImgMessage) o;
  499 + chatListAdapter.addItem(new ImagMessage(MessageType.imaMessage, o1, o1.isSelf()));
  500 + } else if (o.getMsgType() == IChat.CN_MSG_TYPE_VOICE) {
  501 + CNVoiceMessage o1 = (CNVoiceMessage) o;
  502 + VoiceMessage voiceMessage = new VoiceMessage(MessageType.voiceMessage, o1, o1.isSelf());
  503 + chatListAdapter.addItem(voiceMessage);
  504 + } else if (o.getMsgType() == IChat.CN_MSG_TYPE_VIDEO) {
  505 + CNVideoMessage ol = (CNVideoMessage) o;
  506 + VideoMessage videoMessage = new VideoMessage(MessageType.videoMessage, ol, ol.isSelf());
  507 + chatListAdapter.addItem(videoMessage);
480 508 }
481   - };
  509 + chatListView.smoothScrollToPosition(chatListAdapter.getItemCount() - 1);
  510 + }
482 511  
483 512 /**
484 513 * 开启扫描之前判断权限是否打开
... ... @@ -489,14 +518,15 @@ public class PrivateActivity extends AppCompatActivity implements View.OnClickLi
489 518 Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) &&
490 519 (ContextCompat.checkSelfPermission(context,
491 520 Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED)
492   - ) {
  521 + && (ContextCompat.checkSelfPermission(context,
  522 + Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED)) {
493 523 StartListener();
494 524  
495 525 //判断是否开启语音权限
496 526 } else {
497 527 //请求获取摄像头权限
498 528 ActivityCompat.requestPermissions((Activity) context,
499   - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO}, VOICE_REQUEST_CODE);
  529 + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA}, VOICE_REQUEST_CODE);
500 530 }
501 531 }
502 532  
... ... @@ -638,8 +668,149 @@ public class PrivateActivity extends AppCompatActivity implements View.OnClickLi
638 668 }
639 669 };
640 670  
  671 + /**
  672 + * 播放语音文件
  673 + *
  674 + * @param voicePath
  675 + * @param animationDrawable
  676 + */
  677 + private void startVoice(String voicePath, final AnimationDrawable animationDrawable) {
  678 + try {
  679 + FileInputStream fis = new FileInputStream(voicePath);
  680 + MediaUtil.getInstance().play(fis);
  681 + animationDrawable.start();
  682 + MediaUtil.getInstance().setEventListener(new MediaUtil.EventListener() {
  683 + @Override
  684 + public void onStop() {
  685 + animationDrawable.stop();
  686 + animationDrawable.selectDrawable(0);
  687 + }
  688 + });
  689 + } catch (Exception e) {
  690 + }
  691 + }
  692 +
  693 + @Override
  694 + public void onItemClick(VoiceMessage voiceMessage, final AnimationDrawable animationDrawable) {
  695 + if (voiceMessage == null) {
  696 + Toast.makeText(this, "数据异常", Toast.LENGTH_LONG).show();
  697 + return;
  698 + }
  699 + if (voiceMessage.getCnVoiceMessage().isSelf()) {
  700 + startVoice(voiceMessage.getCnVoiceMessage().getVoiceUri().getPath(), animationDrawable);
  701 + } else {
  702 + //设置本地已读
  703 + voiceMessage.getCnVoiceMessage().setRead(true);
  704 + String voiceUuid = voiceMessage.getCnVoiceMessage().getUuid();
  705 + final String voicePath = FileUtil.getCacheFilePath(voiceUuid);
  706 + if (FileUtil.isCacheFileExist(voiceUuid)) {
  707 + File file = new File(voicePath);
  708 + if (file.length() < voiceMessage.getCnVoiceMessage().getDataSize()) {
  709 + Toast.makeText(context, "请稍等,正在下载...", Toast.LENGTH_SHORT).show();
  710 + return;
  711 + }
  712 + startVoice(voicePath, animationDrawable);
  713 + } else {
  714 + voiceMessage.getCnVoiceMessage().getVoice(voicePath, new IChat.OnDownloadListener() {
  715 + @Override
  716 + public void onSuccess() {
  717 + startVoice(voicePath, animationDrawable);
  718 + }
  719 +
  720 + @Override
  721 + public void onError(int i, String s) {
  722 +
  723 + }
  724 + });
  725 + }
  726 + }
  727 + }
  728 +
  729 + @Override
  730 + public void onVideoClick(VideoMessage videoMessage) {
  731 + if (videoMessage.getCnVideoMessage().isSelf()) {
  732 + Intent intent = new Intent(PrivateActivity.this, VideoActivity.class);
  733 + intent.putExtra("videoPath", videoMessage.getCnVideoMessage().getVideoPath());
  734 + startActivity(intent);
  735 + } else {
  736 + String videoUuid = videoMessage.getCnVideoMessage().getVideo().getUuid();
  737 + final String videoPath = FileUtil.getCacheFilePath(videoUuid);
  738 + if (FileUtil.isCacheFileExist(videoUuid)) {
  739 + Intent intent = new Intent(PrivateActivity.this, VideoActivity.class);
  740 + intent.putExtra("videoPath", videoPath);
  741 + startActivity(intent);
  742 + } else {
  743 + videoMessage.getCnVideoMessage().getVideo().getVideo(videoPath, new IChat.OnDownloadListener() {
  744 + @Override
  745 + public void onSuccess() {
  746 + Intent intent = new Intent(PrivateActivity.this, VideoActivity.class);
  747 + intent.putExtra("videoPath", videoPath);
  748 + startActivity(intent);
  749 + }
  750 +
  751 + @Override
  752 + public void onError(int i, String s) {
  753 +
  754 + }
  755 + });
  756 + }
  757 + }
  758 +
  759 + }
  760 +
  761 + @Override
  762 + public void onImageClick(final ImagMessage imagMessage) {
  763 + if (imagMessage.getCnImgMessage().isSelf()) {
  764 + Intent intent = new Intent(PrivateActivity.this, ImageViewActivity.class);
  765 + intent.putExtra("path", imagMessage.getCnImgMessage().getImagePath());
  766 + startActivity(intent);
  767 + } else {
  768 + String remoteUuid = imagMessage.getCnImgMessage().getRemoteUuid();
  769 + final String imagePath = FileUtil.getCacheFilePath(remoteUuid);
  770 + if (FileUtil.isCacheFileExist(remoteUuid)) {
  771 + File file = new File(imagePath);
  772 + if (file.length() < imagMessage.getCnImgMessage().getRemoteSize()) {
  773 + Toast.makeText(context, "请稍等,正在下载...", Toast.LENGTH_SHORT).show();
  774 + return;
  775 + }
  776 + Intent intent = new Intent(PrivateActivity.this, ImageViewActivity.class);
  777 + intent.putExtra("path", imagePath);
  778 + startActivity(intent);
  779 + } else {
  780 + if (imagMessage.isDownloading()) {
  781 + Toast.makeText(context, "请稍等,正在下载...", Toast.LENGTH_SHORT).show();
  782 + } else {
  783 + imagMessage.setDownloading(true);
  784 + imagMessage.getCnImgMessage().getRemoteImage(imagePath, new IChat.OnDownloadListener() {
  785 + @Override
  786 + public void onSuccess() {
  787 + imagMessage.setDownloading(false);
  788 + Intent intent = new Intent(PrivateActivity.this, ImageViewActivity.class);
  789 + intent.putExtra("path", imagePath);
  790 + startActivity(intent);
  791 + }
  792 +
  793 + @Override
  794 + public void onError(int i, String s) {
  795 + imagMessage.setDownloading(false);
  796 + Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();
  797 + }
  798 + });
  799 + }
  800 + }
  801 + }
  802 + }
  803 +
  804 + @Override
  805 + protected void onPause() {
  806 + super.onPause();
  807 + MediaUtil.getInstance().stop();
  808 + }
  809 +
641 810 @Override
642   - public void onItemClick(Uri uri) {
643   - playerUtil.start(uri);
  811 + protected void onDestroy() {
  812 + super.onDestroy();
  813 + ChatUtil.removeReceiveMessageListener(receiveMessageListener);
  814 + ChatUtil.removeConnectListener(connectListener);
644 815 }
645 816 }
... ...
app/src/main/java/com/cnlive/im/ui/VideoActivity.java 0 → 100644
  1 +package com.cnlive.im.ui;
  2 +
  3 +import android.app.Activity;
  4 +import android.content.Intent;
  5 +import android.media.MediaPlayer;
  6 +import android.os.Bundle;
  7 +import android.support.annotation.Nullable;
  8 +import android.widget.VideoView;
  9 +
  10 +import com.cnlive.im.R;
  11 +
  12 +/**
  13 + * Created by gujun on 2017/12/12.
  14 + */
  15 +
  16 +public class VideoActivity extends Activity {
  17 + private String videoPath;
  18 + private VideoView videoView;
  19 + private boolean isStart = false;
  20 +
  21 + @Override
  22 + protected void onCreate(@Nullable Bundle savedInstanceState) {
  23 + super.onCreate(savedInstanceState);
  24 + setContentView(R.layout.activity_play);
  25 + init(getIntent());
  26 + }
  27 +
  28 + @Override
  29 + protected void onNewIntent(Intent intent) {
  30 + super.onNewIntent(intent);
  31 + init(intent);
  32 + }
  33 +
  34 + private void init(Intent intent) {
  35 + videoPath = intent.getStringExtra("videoPath");
  36 +
  37 + videoView = (VideoView) findViewById(R.id.video);
  38 + videoView.setVideoPath(videoPath);
  39 + videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  40 + @Override
  41 + public void onPrepared(MediaPlayer mp) {
  42 + isStart = true;
  43 + videoView.start();
  44 + }
  45 + });
  46 + }
  47 +
  48 + @Override
  49 + protected void onResume() {
  50 + super.onResume();
  51 + if (videoView != null && isStart) {
  52 + videoView.start();
  53 + }
  54 + }
  55 +
  56 + @Override
  57 + protected void onPause() {
  58 + super.onPause();
  59 + if (videoView != null && isStart) {
  60 + videoView.pause();
  61 + }
  62 + }
  63 +
  64 + @Override
  65 + protected void onDestroy() {
  66 + super.onDestroy();
  67 + if (videoView != null) {
  68 + videoView.stopPlayback();
  69 + videoView = null;
  70 + }
  71 + }
  72 +}
... ...
app/src/main/java/com/cnlive/im/util/FileUtil.java 0 → 100644
  1 +package com.cnlive.im.util;
  2 +
  3 +import android.app.Activity;
  4 +import android.content.ContentUris;
  5 +import android.content.Context;
  6 +import android.database.Cursor;
  7 +import android.graphics.Bitmap;
  8 +import android.net.Uri;
  9 +import android.os.Build;
  10 +import android.os.Environment;
  11 +import android.provider.DocumentsContract;
  12 +import android.provider.MediaStore;
  13 +import android.util.Log;
  14 +
  15 +import com.cnlive.im.CNLiveApplication;
  16 +
  17 +import java.io.ByteArrayOutputStream;
  18 +import java.io.File;
  19 +import java.io.FileOutputStream;
  20 +import java.io.IOException;
  21 +
  22 +/**
  23 + * 文件工具类
  24 + */
  25 +public class FileUtil {
  26 +
  27 + private static final String TAG = "FileUtil";
  28 + private static String pathDiv = "/";
  29 + private static File cacheDir = !isExternalStorageWritable() ? CNLiveApplication.getContext().getFilesDir() : CNLiveApplication.getContext().getExternalCacheDir();
  30 +
  31 + private FileUtil() {
  32 + /* cannot be instantiated */
  33 + throw new UnsupportedOperationException("cannot be instantiated");
  34 + }
  35 +
  36 +
  37 + /**
  38 + * 创建临时文件
  39 + *
  40 + * @param type 文件类型
  41 + */
  42 + public static File getTempFile(FileType type) {
  43 + try {
  44 + File file = File.createTempFile(type.toString(), null, cacheDir);
  45 + file.deleteOnExit();
  46 + return file;
  47 + } catch (IOException e) {
  48 + return null;
  49 + }
  50 + }
  51 +
  52 +
  53 + /**
  54 + * 获取缓存文件地址
  55 + */
  56 + public static String getCacheFilePath(String fileName) {
  57 + return cacheDir.getAbsolutePath() + pathDiv + fileName;
  58 + }
  59 +
  60 +
  61 + /**
  62 + * 判断缓存文件是否存在
  63 + */
  64 + public static boolean isCacheFileExist(String fileName) {
  65 + File file = new File(getCacheFilePath(fileName));
  66 + return file.exists();
  67 + }
  68 +
  69 +
  70 + /**
  71 + * 将图片存储为文件
  72 + *
  73 + * @param bitmap 图片
  74 + */
  75 + public static String createFile(Bitmap bitmap, String filename) {
  76 + File f = new File(cacheDir, filename);
  77 + try {
  78 + if (f.createNewFile()) {
  79 + ByteArrayOutputStream bos = new ByteArrayOutputStream();
  80 + bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
  81 + byte[] bitmapdata = bos.toByteArray();
  82 + FileOutputStream fos = new FileOutputStream(f);
  83 + fos.write(bitmapdata);
  84 + fos.flush();
  85 + fos.close();
  86 + }
  87 + } catch (IOException e) {
  88 + Log.e(TAG, "create bitmap file error" + e);
  89 + }
  90 + if (f.exists()) {
  91 + return f.getAbsolutePath();
  92 + }
  93 + return null;
  94 + }
  95 +
  96 + /**
  97 + * 将数据存储为文件
  98 + *
  99 + * @param data 数据
  100 + */
  101 + public static void createFile(byte[] data, String filename) {
  102 + File f = new File(cacheDir, filename);
  103 + try {
  104 + if (f.createNewFile()) {
  105 + FileOutputStream fos = new FileOutputStream(f);
  106 + fos.write(data);
  107 + fos.flush();
  108 + fos.close();
  109 + }
  110 + } catch (IOException e) {
  111 + Log.e(TAG, "create file error" + e);
  112 + }
  113 + }
  114 +
  115 +
  116 + /**
  117 + * 判断缓存文件是否存在
  118 + */
  119 + public static boolean isFileExist(String fileName, String type) {
  120 + if (isExternalStorageWritable()) {
  121 + File dir = CNLiveApplication.getContext().getExternalFilesDir(type);
  122 + if (dir != null) {
  123 + File f = new File(dir, fileName);
  124 + return f.exists();
  125 + }
  126 + }
  127 + return false;
  128 + }
  129 +
  130 +
  131 + /**
  132 + * 将数据存储为文件
  133 + *
  134 + * @param data 数据
  135 + * @param fileName 文件名
  136 + * @param type 文件类型
  137 + */
  138 + public static File createFile(byte[] data, String fileName, String type) {
  139 + if (isExternalStorageWritable()) {
  140 + File dir = CNLiveApplication.getContext().getExternalFilesDir(type);
  141 + if (dir != null) {
  142 + File f = new File(dir, fileName);
  143 + try {
  144 + if (f.createNewFile()) {
  145 + FileOutputStream fos = new FileOutputStream(f);
  146 + fos.write(data);
  147 + fos.flush();
  148 + fos.close();
  149 + return f;
  150 + }
  151 + } catch (IOException e) {
  152 + Log.e(TAG, "create file error" + e);
  153 + return null;
  154 + }
  155 + }
  156 + }
  157 + return null;
  158 + }
  159 +
  160 +
  161 + /**
  162 + * 从URI获取图片文件地址
  163 + *
  164 + * @param context 上下文
  165 + * @param uri 文件uri
  166 + */
  167 + public static String getImageFilePath(Context context, Uri uri) {
  168 + if (uri == null) {
  169 + return null;
  170 + }
  171 + String path = null;
  172 + final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
  173 + if (isKitKat) {
  174 + if (!isMediaDocument(uri)) {
  175 + try {
  176 + final String docId = DocumentsContract.getDocumentId(uri);
  177 + final String[] split = docId.split(":");
  178 + Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
  179 + final String selection = "_id=?";
  180 + final String[] selectionArgs = new String[]{
  181 + split[1]
  182 + };
  183 + path = getDataColumn(context, contentUri, selection, selectionArgs);
  184 + } catch (IllegalArgumentException e) {
  185 + path = null;
  186 + }
  187 + }
  188 + }
  189 + if (path == null) {
  190 + String[] projection = {MediaStore.Images.Media.DATA};
  191 + Cursor cursor = ((Activity) context).managedQuery(uri, projection, null, null, null);
  192 + if (cursor != null) {
  193 + int column_index = cursor
  194 + .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
  195 + cursor.moveToFirst();
  196 + return cursor.getString(column_index);
  197 + }
  198 +
  199 + path = null;
  200 + }
  201 + return path;
  202 + }
  203 +
  204 +
  205 + /**
  206 + * 从URI获取文件地址
  207 + *
  208 + * @param context 上下文
  209 + * @param uri 文件uri
  210 + */
  211 + public static String getFilePath(Context context, Uri uri) {
  212 + final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
  213 + // DocumentProvider
  214 + if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
  215 + // ExternalStorageProvider
  216 + if (isExternalStorageDocument(uri)) {
  217 + final String docId = DocumentsContract.getDocumentId(uri);
  218 + final String[] split = docId.split(":");
  219 + final String type = split[0];
  220 +
  221 + if ("primary".equalsIgnoreCase(type)) {
  222 + return Environment.getExternalStorageDirectory() + "/" + split[1];
  223 + }
  224 +
  225 + // TODO handle non-primary volumes
  226 + }
  227 + // DownloadsProvider
  228 + else if (isDownloadsDocument(uri)) {
  229 +
  230 + final String id = DocumentsContract.getDocumentId(uri);
  231 + final Uri contentUri = ContentUris.withAppendedId(
  232 + Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
  233 +
  234 + return getDataColumn(context, contentUri, null, null);
  235 + }
  236 + // MediaProvider
  237 + else if (isMediaDocument(uri)) {
  238 + final String docId = DocumentsContract.getDocumentId(uri);
  239 + final String[] split = docId.split(":");
  240 + final String type = split[0];
  241 +
  242 + Uri contentUri = null;
  243 + if ("image".equals(type)) {
  244 + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
  245 + } else if ("video".equals(type)) {
  246 + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
  247 + } else if ("audio".equals(type)) {
  248 + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  249 + }
  250 +
  251 + final String selection = "_id=?";
  252 + final String[] selectionArgs = new String[]{
  253 + split[1]
  254 + };
  255 +
  256 + return getDataColumn(context, contentUri, selection, selectionArgs);
  257 + }
  258 + }
  259 + // MediaStore (and general)
  260 + else if ("content".equalsIgnoreCase(uri.getScheme())) {
  261 + return getDataColumn(context, uri, null, null);
  262 + }
  263 + // File
  264 + else if ("file".equalsIgnoreCase(uri.getScheme())) {
  265 + return uri.getPath();
  266 + }
  267 +
  268 + return null;
  269 + }
  270 +
  271 +
  272 + /**
  273 + * Get the value of the data column for this Uri. This is useful for
  274 + * MediaStore Uris, and other file-based ContentProviders.
  275 + *
  276 + * @param context The context.
  277 + * @param uri The Uri to query.
  278 + * @param selection (Optional) Filter used in the query.
  279 + * @param selectionArgs (Optional) Selection arguments used in the query.
  280 + * @return The value of the _data column, which is typically a file path.
  281 + */
  282 + private static String getDataColumn(Context context, Uri uri, String selection,
  283 + String[] selectionArgs) {
  284 + Cursor cursor = null;
  285 + final String column = "_data";
  286 + final String[] projection = {column};
  287 + try {
  288 + cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
  289 + if (cursor != null && cursor.moveToFirst()) {
  290 + final int index = cursor.getColumnIndexOrThrow(column);
  291 + return cursor.getString(index);
  292 + }
  293 + } finally {
  294 + if (cursor != null)
  295 + cursor.close();
  296 + }
  297 + return null;
  298 + }
  299 +
  300 +
  301 + /**
  302 + * 判断外部存储是否可用
  303 + */
  304 + public static boolean isExternalStorageWritable() {
  305 + String state = Environment.getExternalStorageState();
  306 + if (Environment.MEDIA_MOUNTED.equals(state)) {
  307 + return true;
  308 + }
  309 + Log.e(TAG, "ExternalStorage not mounted");
  310 + return false;
  311 + }
  312 +
  313 + public static boolean isMediaDocument(Uri uri) {
  314 + return "com.android.providers.media.documents".equals(uri.getAuthority());
  315 + }
  316 +
  317 + public static boolean isExternalStorageDocument(Uri uri) {
  318 + return "com.android.externalstorage.documents".equals(uri.getAuthority());
  319 + }
  320 +
  321 + /**
  322 + * @param uri The Uri to check.
  323 + * @return Whether the Uri authority is DownloadsProvider.
  324 + */
  325 + public static boolean isDownloadsDocument(Uri uri) {
  326 + return "com.android.providers.downloads.documents".equals(uri.getAuthority());
  327 + }
  328 +
  329 +
  330 + public enum FileType {
  331 + IMG,
  332 + AUDIO,
  333 + VIDEO,
  334 + FILE,
  335 + }
  336 +
  337 +
  338 +}
... ...
app/src/main/java/com/cnlive/im/util/MediaUtil.java 0 → 100644
  1 +package com.cnlive.im.util;
  2 +
  3 +import android.media.MediaPlayer;
  4 +import android.net.Uri;
  5 +import android.util.Log;
  6 +
  7 +import com.cnlive.im.CNLiveApplication;
  8 +
  9 +import java.io.FileInputStream;
  10 +import java.io.IOException;
  11 +
  12 +/**
  13 + * 媒体播放工具
  14 + */
  15 +public class MediaUtil {
  16 +
  17 + private static final String TAG = "MediaUtil";
  18 +
  19 + private MediaPlayer player;
  20 + private EventListener eventListener;
  21 +
  22 + private MediaUtil() {
  23 + player = new MediaPlayer();
  24 + }
  25 +
  26 + private static MediaUtil instance = new MediaUtil();
  27 +
  28 + public static MediaUtil getInstance() {
  29 + return instance;
  30 + }
  31 +
  32 + public MediaPlayer getPlayer() {
  33 + return player;
  34 + }
  35 +
  36 +
  37 + public void setEventListener(final EventListener eventListener) {
  38 + if (player != null) {
  39 + player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
  40 + @Override
  41 + public void onCompletion(MediaPlayer mp) {
  42 + eventListener.onStop();
  43 + }
  44 + });
  45 + }
  46 + this.eventListener = eventListener;
  47 + }
  48 +
  49 + public void play(FileInputStream inputStream) {
  50 + try {
  51 + if (eventListener != null) {
  52 + eventListener.onStop();
  53 + }
  54 + player.reset();
  55 + player.setDataSource(inputStream.getFD());
  56 + player.prepare();
  57 + player.start();
  58 + } catch (IOException e) {
  59 + Log.e(TAG, "play error:" + e);
  60 + }
  61 +
  62 +
  63 + }
  64 +
  65 +
  66 + public void stop() {
  67 + if (player != null && player.isPlaying()) {
  68 + player.stop();
  69 + }
  70 + }
  71 +
  72 + public long getDuration(String path) {
  73 + player = MediaPlayer.create(CNLiveApplication.getContext(), Uri.parse(path));
  74 + return player.getDuration();
  75 + }
  76 +
  77 +
  78 + /**
  79 + * 播放器事件监听
  80 + */
  81 + public interface EventListener {
  82 + void onStop();
  83 + }
  84 +}
... ...
app/src/main/java/com/cnlive/im/util/MessageType.java
... ... @@ -9,4 +9,5 @@ public class MessageType {
9 9 public static final String stringMessage = "1";
10 10 public static final String imaMessage = "2";
11 11 public static final String voiceMessage = "3";
  12 + public static final String videoMessage = "4";
12 13 }
... ...
app/src/main/java/com/cnlive/im/util/PlayerUtil.java deleted 100644 → 0
1   -package com.cnlive.im.util;
2   -
3   -import android.content.Context;
4   -import android.media.MediaPlayer;
5   -import android.net.Uri;
6   -
7   -/**
8   - * Created by Lynn on 2017/7/21.
9   - */
10   -
11   -public class PlayerUtil implements IVoiceManager{
12   - private final String TAG = "PlayerUtil";
13   - private String path;
14   - private Context mContext;
15   -
16   - private MediaPlayer mediaPlayer;
17   -
18   - public PlayerUtil(Context context){
19   - this.mContext = context;
20   -// mediaPlayer = new MediaPlayer();
21   -// mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
22   -// @Override
23   -// public void onCompletion(MediaPlayer mediaPlayer) {
24   -//// mediaPlayer.stop();
25   -// stop();
26   -// }
27   -// });
28   - }
29   -
30   - @Override
31   - public boolean start(Uri uri) {
32   - try {
33   - mediaPlayer = new MediaPlayer();
34   - mediaPlayer.setOnCompletionListener(onCompletionListener);
35   - mediaPlayer.setOnPreparedListener(onPreparedListener);
36   - mediaPlayer.setDataSource(mContext, uri);
37   - mediaPlayer.prepare();
38   -// mediaPlayer.start();
39   - }catch (Exception e){
40   - e.printStackTrace();
41   - }
42   - return false;
43   - }
44   -
45   - @Override
46   - public boolean stop() {
47   - mediaPlayer.stop();
48   - mediaPlayer.release();
49   - mediaPlayer = null;
50   - return false;
51   - }
52   -
53   - @Override
54   - public void onDestory() {
55   - mediaPlayer.release();
56   - mediaPlayer = null;
57   - }
58   -
59   - private MediaPlayer.OnCompletionListener onCompletionListener = new MediaPlayer.OnCompletionListener() {
60   - @Override
61   - public void onCompletion(MediaPlayer mediaPlayer) {
62   - stop();
63   - }
64   - };
65   -
66   - private MediaPlayer.OnPreparedListener onPreparedListener = new MediaPlayer.OnPreparedListener() {
67   - @Override
68   - public void onPrepared(MediaPlayer mediaPlayer) {
69   - mediaPlayer.start();
70   - }
71   - };
72   -}
app/src/main/jniLibs/arm64-v8a/libBugly.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/arm64-v8a/lib_imcore_group_ext_gyp.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/arm64-v8a/lib_imcore_jni_gyp.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/arm64-v8a/lib_imcore_msg_ext_gyp.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/arm64-v8a/lib_imcore_sns_ext_gyp.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/arm64-v8a/lib_imcore_ugc_ext_gyp.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/arm64-v8a/libgnustl_shared.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/arm64-v8a/libqalcodecwrapper.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/arm64-v8a/libqalmsfboot.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/arm64-v8a/libwtcrypto.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/libBugly.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/lib_imcore_group_ext_gyp.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/lib_imcore_jni_gyp.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/lib_imcore_msg_ext_gyp.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/lib_imcore_sns_ext_gyp.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/lib_imcore_ugc_ext_gyp.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/libgnustl_shared.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/libqalcodecwrapper.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/libqalmsfboot.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/libwtcrypto.so 0 → 100644
No preview for this file type
app/src/main/res/drawable/left_voice.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<animation-list
  3 + android:oneshot="false"
  4 + xmlns:android="http://schemas.android.com/apk/res/android">
  5 + <item android:drawable="@drawable/left_voice3" android:duration="200" />
  6 + <item android:drawable="@drawable/left_voice1" android:duration="200" />
  7 + <item android:drawable="@drawable/left_voice2" android:duration="200" />
  8 + <item android:drawable="@drawable/left_voice3" android:duration="200" />
  9 +</animation-list>
0 10 \ No newline at end of file
... ...
app/src/main/res/drawable/left_voice1.png 0 → 100644

1.05 KB

app/src/main/res/drawable/left_voice2.png 0 → 100644

1.31 KB

app/src/main/res/drawable/left_voice3.png 0 → 100644

1.58 KB

app/src/main/res/drawable/right_voice.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<animation-list
  3 + android:oneshot="false"
  4 + xmlns:android="http://schemas.android.com/apk/res/android">
  5 + <item android:drawable="@drawable/right_voice3" android:duration="200" />
  6 + <item android:drawable="@drawable/right_voice1" android:duration="200" />
  7 + <item android:drawable="@drawable/right_voice2" android:duration="200" />
  8 + <item android:drawable="@drawable/right_voice3" android:duration="200" />
  9 +</animation-list>
0 10 \ No newline at end of file
... ...
app/src/main/res/drawable/right_voice1.png 0 → 100644

1.05 KB

app/src/main/res/drawable/right_voice2.png 0 → 100644

1.28 KB

app/src/main/res/drawable/right_voice3.png 0 → 100644

1.42 KB

app/src/main/res/drawable/voice_none_read.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +
  3 +<shape xmlns:android="http://schemas.android.com/apk/res/android"
  4 + android:shape="oval">
  5 + <solid android:color="#ff0000" />
  6 + <corners android:radius="10dp"/>
  7 + <stroke
  8 + android:width="1dp"
  9 + android:color="#8a8a8a" />
  10 +</shape>
0 11 \ No newline at end of file
... ...
app/src/main/res/layout/activity_groupchat.xml
... ... @@ -117,6 +117,18 @@
117 117 android:layout_height="wrap_content"
118 118 android:text="退出" />
119 119  
  120 + <Button
  121 + android:id="@+id/videoBtn"
  122 + android:layout_width="wrap_content"
  123 + android:layout_height="wrap_content"
  124 + android:text="视频文件"/>
  125 +
  126 + <Button
  127 + android:id="@+id/ugcVideoBtn"
  128 + android:layout_width="wrap_content"
  129 + android:layout_height="wrap_content"
  130 + android:text="短视频"/>
  131 +
120 132 </LinearLayout>
121 133  
122 134 </LinearLayout>
... ...
app/src/main/res/layout/activity_image_view.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:background="@android:color/black"
  6 + android:orientation="vertical">
  7 +
  8 + <ImageView
  9 + android:id="@+id/image"
  10 + android:layout_width="match_parent"
  11 + android:layout_height="match_parent"
  12 + android:scaleType="centerInside" />
  13 +
  14 +</LinearLayout>
0 15 \ No newline at end of file
... ...
app/src/main/res/layout/activity_play.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:orientation="vertical"
  6 + android:gravity="center">
  7 +
  8 + <VideoView
  9 + android:id="@+id/video"
  10 + android:layout_width="match_parent"
  11 + android:layout_height="match_parent" />
  12 +
  13 +</LinearLayout>
0 14 \ No newline at end of file
... ...
app/src/main/res/layout/activity_private_chat.xml
... ... @@ -36,6 +36,18 @@
36 36 android:layout_height="wrap_content"
37 37 android:text="邀请对方聊天" />
38 38  
  39 + <Button
  40 + android:id="@+id/videoBtn"
  41 + android:layout_width="wrap_content"
  42 + android:layout_height="wrap_content"
  43 + android:text="视频文件"/>
  44 +
  45 + <Button
  46 + android:id="@+id/ugcVideoBtn"
  47 + android:layout_width="wrap_content"
  48 + android:layout_height="wrap_content"
  49 + android:text="短视频"/>
  50 +
39 51  
40 52 <LinearLayout
41 53 android:id="@+id/edit_layout_se"
... ...
app/src/main/res/layout/imag_layout_item_oppsite.xml
... ... @@ -17,15 +17,15 @@
17 17 android:layout_height="wrap_content"
18 18 android:layout_alignParentLeft="true"
19 19 android:layout_centerVertical="true"
20   - android:text="游客" />
  20 + android:text="游客"
  21 + android:textColor="#d61d0c" />
21 22  
22 23 <ImageView
23 24 android:id="@+id/img_content"
24 25 android:layout_width="40dp"
25 26 android:layout_height="40dp"
26 27 android:layout_marginLeft="5dp"
27   - android:layout_toRightOf="@+id/img_user_name"
28   - android:src="@drawable/vod_detail_good_on" />
  28 + android:layout_toRightOf="@+id/img_user_name"/>
29 29  
30 30 </RelativeLayout>
31 31  
... ...
app/src/main/res/layout/imag_layout_item_user.xml
1 1 <?xml version="1.0" encoding="utf-8"?>
2   -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2 +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 3 android:layout_width="match_parent"
4 4 android:layout_height="match_parent"
5 5 android:orientation="vertical"
6 6 android:paddingBottom="10dp"
7 7 android:paddingTop="10dp">
8 8  
9   - <RelativeLayout
  9 + <LinearLayout
10 10 android:layout_width="wrap_content"
11   - android:layout_height="wrap_content">
  11 + android:layout_height="wrap_content"
  12 + android:layout_alignParentRight="true"
  13 + android:orientation="horizontal">
12 14  
13 15 <TextView
14   - android:layout_centerVertical="true"
15   - android:id="@+id/img_user_name"
  16 + android:id="@+id/status"
16 17 android:layout_width="wrap_content"
17 18 android:layout_height="wrap_content"
18   - android:layout_alignParentRight="true"
19   - android:text="游客" />
  19 + android:layout_gravity="center_vertical"
  20 + android:layout_marginRight="5dp"
  21 + android:gravity="right"
  22 + android:textColor="@android:color/holo_blue_light" />
20 23  
21 24 <ImageView
22   - android:layout_toLeftOf="@+id/img_user_name"
23   - android:layout_marginRight="5dp"
24 25 android:id="@+id/img_content"
25 26 android:layout_width="40dp"
26 27 android:layout_height="40dp"
27   - android:src="@drawable/vod_detail_good_on"/>
  28 + android:layout_marginRight="5dp" />
  29 +
  30 + <TextView
  31 + android:id="@+id/img_user_name"
  32 + android:layout_width="wrap_content"
  33 + android:layout_height="wrap_content"
  34 + android:layout_gravity="center_vertical"
  35 + android:text="游客"
  36 + android:textColor="#d61d0c"/>
28 37  
29   - </RelativeLayout>
  38 + </LinearLayout>
30 39  
31   -</LinearLayout>
32 40 \ No newline at end of file
  41 +</RelativeLayout>
33 42 \ No newline at end of file
... ...
app/src/main/res/layout/string_layout_item_oppsite.xml
... ... @@ -3,8 +3,8 @@
3 3 android:layout_width="wrap_content"
4 4 android:layout_height="wrap_content"
5 5 android:orientation="vertical"
6   - android:paddingTop="10dp"
7   - android:paddingBottom="10dp">
  6 + android:paddingBottom="10dp"
  7 + android:paddingTop="10dp">
8 8  
9 9 <RelativeLayout
10 10 android:id="@+id/re_chat_room"
... ... @@ -24,11 +24,12 @@
24 24 android:id="@+id/msg_text"
25 25 android:layout_width="wrap_content"
26 26 android:layout_height="wrap_content"
  27 + android:layout_marginLeft="5dp"
27 28 android:layout_toRightOf="@id/user_name"
28 29 android:text="vfgfgf"
29 30 android:textColor="@android:color/black"
30   - android:textSize="15sp"
31   - android:layout_marginLeft="5dp"/>
  31 + android:textSize="15sp" />
  32 +
32 33 </RelativeLayout>
33 34  
34 35 </RelativeLayout>
35 36 \ No newline at end of file
... ...
app/src/main/res/layout/string_layout_item_user.xml
... ... @@ -5,31 +5,43 @@
5 5 android:paddingBottom="10dp"
6 6 android:paddingTop="10dp">
7 7  
8   - <RelativeLayout
  8 + <LinearLayout
9 9 android:id="@+id/re_chat_room"
10 10 android:layout_width="wrap_content"
11   - android:layout_height="wrap_content">
  11 + android:layout_height="wrap_content"
  12 + android:layout_alignParentRight="true"
  13 + android:orientation="horizontal">
12 14  
13 15 <TextView
14   - android:id="@+id/user_name"
  16 + android:id="@+id/status"
15 17 android:layout_width="wrap_content"
16 18 android:layout_height="wrap_content"
17   - android:layout_alignParentRight="true"
18   - android:gravity="center_vertical"
19   - android:text="ddd"
20   - android:textColor="#d61d0c"
21   - android:textSize="14sp" />
  19 + android:layout_gravity="center_vertical"
  20 + android:layout_marginRight="5dp"
  21 + android:gravity="right"
  22 + android:textColor="@android:color/holo_blue_light" />
22 23  
23 24 <TextView
24 25 android:id="@+id/msg_text"
25 26 android:layout_width="wrap_content"
26 27 android:layout_height="wrap_content"
27   - android:layout_toLeftOf="@id/user_name"
  28 +
  29 + android:layout_marginRight="5dp"
28 30 android:text="vfgfgf"
29 31 android:textColor="@android:color/black"
30   - android:textSize="15sp"
31   - android:layout_marginRight="5dp"/>
32   - </RelativeLayout>
  32 + android:textSize="15sp" />
  33 +
  34 + <TextView
  35 + android:id="@+id/user_name"
  36 + android:layout_width="wrap_content"
  37 + android:layout_height="wrap_content"
  38 + android:layout_gravity="right"
  39 + android:gravity="center_vertical"
  40 + android:text="ddd"
  41 + android:textColor="#d61d0c"
  42 + android:textSize="14sp" />
  43 +
  44 + </LinearLayout>
33 45  
34 46  
35 47 </RelativeLayout>
36 48 \ No newline at end of file
... ...
app/src/main/res/layout/video_layout_item_oppsite.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:orientation="vertical"
  6 + android:paddingBottom="10dp"
  7 + android:paddingTop="10dp">
  8 +
  9 +
  10 + <RelativeLayout
  11 + android:layout_width="wrap_content"
  12 + android:layout_height="wrap_content">
  13 +
  14 + <TextView
  15 + android:id="@+id/user_name"
  16 + android:layout_width="wrap_content"
  17 + android:layout_height="wrap_content"
  18 + android:layout_alignParentLeft="true"
  19 + android:layout_centerVertical="true"
  20 + android:layout_margin="5dp"
  21 + android:text="游客"
  22 + android:textColor="#d61d0c" />
  23 +
  24 + <RelativeLayout
  25 + android:id="@+id/videoLayout"
  26 + android:layout_width="100dp"
  27 + android:layout_height="150dp"
  28 + android:layout_toRightOf="@+id/user_name">
  29 +
  30 + <ImageView
  31 + android:id="@+id/img_content"
  32 + android:layout_width="100dp"
  33 + android:layout_height="150dp"
  34 + android:layout_marginLeft="5dp"
  35 + android:scaleType="centerInside"
  36 + android:src="@drawable/vod_detail_good_on" />
  37 +
  38 + <ImageView
  39 + android:layout_width="30dp"
  40 + android:layout_height="30dp"
  41 + android:layout_centerInParent="true"
  42 + android:src="@android:drawable/ic_media_play" />
  43 +
  44 + </RelativeLayout>
  45 +
  46 + </RelativeLayout>
  47 +
  48 +</LinearLayout>
0 49 \ No newline at end of file
... ...
app/src/main/res/layout/video_layout_item_user.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:orientation="vertical"
  6 + android:paddingBottom="10dp"
  7 + android:paddingTop="10dp">
  8 +
  9 + <LinearLayout
  10 + android:layout_width="wrap_content"
  11 + android:layout_height="wrap_content"
  12 + android:orientation="horizontal"
  13 + android:layout_alignParentRight="true">
  14 +
  15 + <TextView
  16 + android:id="@+id/status"
  17 + android:layout_width="wrap_content"
  18 + android:layout_height="wrap_content"
  19 + android:layout_gravity="center_vertical"
  20 + android:layout_marginRight="5dp"
  21 + android:gravity="right"
  22 + android:textColor="@android:color/holo_blue_light" />
  23 +
  24 + <RelativeLayout
  25 + android:id="@+id/videoLayout"
  26 + android:layout_width="100dp"
  27 + android:layout_height="150dp"
  28 + android:layout_toLeftOf="@+id/user_name">
  29 +
  30 + <ImageView
  31 + android:id="@+id/img_content"
  32 + android:layout_width="100dp"
  33 + android:layout_height="150dp"
  34 + android:layout_marginRight="5dp"
  35 + android:scaleType="centerInside"
  36 + android:src="@drawable/vod_detail_good_on" />
  37 +
  38 + <ImageView
  39 + android:layout_width="30dp"
  40 + android:layout_height="30dp"
  41 + android:layout_centerInParent="true"
  42 + android:src="@android:drawable/ic_media_play" />
  43 +
  44 + </RelativeLayout>
  45 +
  46 + <TextView
  47 + android:id="@+id/user_name"
  48 + android:layout_width="wrap_content"
  49 + android:layout_height="wrap_content"
  50 + android:layout_gravity="center_vertical"
  51 + android:layout_margin="5dp"
  52 + android:text="游客"
  53 + android:textColor="#d61d0c" />
  54 +
  55 + </LinearLayout>
  56 +
  57 +</RelativeLayout>
0 58 \ No newline at end of file
... ...
app/src/main/res/layout/voice_layout_item_oppsite.xml
... ... @@ -16,15 +16,26 @@
16 16 android:layout_height="wrap_content"
17 17 android:layout_alignParentLeft="true"
18 18 android:layout_centerVertical="true"
19   - android:text="游客" />
  19 + android:text="游客"
  20 + android:textColor="#d61d0c" />
20 21  
21   - <TextView
  22 + <RelativeLayout
22 23 android:id="@+id/voice_content"
23   - android:layout_width="wrap_content"
24   - android:layout_height="50dp"
  24 + android:layout_width="71dp"
  25 + android:layout_height="48dp"
  26 + android:layout_marginLeft="5dp"
25 27 android:layout_toRightOf="@+id/voice_user_name"
26   - android:background="@drawable/voice_bg_left"
27   - android:layout_marginLeft="5dp"/>
  28 + android:background="@drawable/voice_bg_left">
  29 +
  30 + <ImageView
  31 + android:id="@+id/voiceAnim"
  32 + android:layout_width="11dp"
  33 + android:layout_height="17dp"
  34 + android:layout_centerVertical="true"
  35 + android:layout_marginLeft="10dp"
  36 + android:background="@drawable/left_voice" />
  37 +
  38 + </RelativeLayout>
28 39  
29 40 <TextView
30 41 android:id="@+id/voice_duration"
... ... @@ -33,6 +44,15 @@
33 44 android:layout_centerVertical="true"
34 45 android:layout_toRightOf="@id/voice_content" />
35 46  
  47 + <View
  48 + android:id="@+id/noneRead"
  49 + android:layout_width="10dp"
  50 + android:layout_height="10dp"
  51 + android:layout_centerVertical="true"
  52 + android:layout_marginLeft="2dp"
  53 + android:layout_toRightOf="@+id/voice_duration"
  54 + android:background="@drawable/voice_none_read" />
  55 +
36 56  
37 57 </RelativeLayout>
38 58  
... ...
app/src/main/res/layout/voice_layout_item_user.xml
... ... @@ -5,33 +5,52 @@
5 5 android:paddingBottom="10dp"
6 6 android:paddingTop="10dp">
7 7  
8   - <RelativeLayout
  8 + <LinearLayout
9 9 android:layout_width="wrap_content"
10   - android:layout_height="wrap_content">
  10 + android:layout_height="wrap_content"
  11 + android:layout_alignParentRight="true">
11 12  
12 13 <TextView
13   - android:id="@+id/voice_user_name"
  14 + android:id="@+id/status"
14 15 android:layout_width="wrap_content"
15 16 android:layout_height="wrap_content"
16   - android:layout_alignParentRight="true"
17   - android:layout_centerVertical="true"
18   - android:text="游客" />
  17 + android:layout_gravity="center_vertical"
  18 + android:layout_marginRight="5dp"
  19 + android:gravity="right"
  20 + android:textColor="@android:color/holo_blue_light" />
19 21  
20 22 <TextView
21   - android:id="@+id/voice_content"
  23 + android:id="@+id/voice_duration"
22 24 android:layout_width="wrap_content"
23   - android:layout_height="50dp"
24   - android:layout_toLeftOf="@+id/voice_user_name"
25   - android:background="@drawable/voice_bg_right"
26   - android:layout_marginRight="5dp"/>
  25 + android:layout_height="wrap_content"
  26 + android:layout_gravity="center_vertical" />
  27 +
  28 + <RelativeLayout
  29 + android:id="@+id/voice_content"
  30 + android:layout_width="71dp"
  31 + android:layout_height="48dp"
  32 + android:layout_marginRight="5dp"
  33 + android:background="@drawable/voice_bg_right">
  34 +
  35 + <ImageView
  36 + android:id="@+id/voiceAnim"
  37 + android:layout_width="11dp"
  38 + android:layout_height="17dp"
  39 + android:layout_alignParentRight="true"
  40 + android:layout_centerVertical="true"
  41 + android:layout_marginRight="10dp"
  42 + android:background="@drawable/right_voice" />
  43 +
  44 + </RelativeLayout>
27 45  
28 46 <TextView
29   - android:id="@+id/voice_duration"
  47 + android:id="@+id/voice_user_name"
30 48 android:layout_width="wrap_content"
31 49 android:layout_height="wrap_content"
32   - android:layout_centerVertical="true"
33   - android:layout_toLeftOf="@id/voice_content" />
  50 + android:layout_gravity="center_vertical"
  51 + android:text="游客"
  52 + android:textColor="#d61d0c" />
34 53  
35   - </RelativeLayout>
  54 + </LinearLayout>
36 55  
37 56 </RelativeLayout>
38 57 \ No newline at end of file
... ...