Commit dd175e595daff5b537a20766b78627f028edffc5
1 parent
7aca54d0
聊天室添加发送图片以及语音消息
Showing
32 changed files
with
940 additions
and
155 deletions
app/libs/libcnliveutil.jar
No preview for this file type
app/src/main/AndroidManifest.xml
| ... | ... | @@ -2,7 +2,6 @@ |
| 2 | 2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
| 3 | 3 | package="com.cnlive.im"> |
| 4 | 4 | |
| 5 | - | |
| 6 | 5 | <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |
| 7 | 6 | <uses-permission android:name="android.permission.INTERNET" /> |
| 8 | 7 | <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> |
| ... | ... | @@ -17,44 +16,37 @@ |
| 17 | 16 | <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> |
| 18 | 17 | |
| 19 | 18 | <application |
| 20 | - android:name="com.cnlive.im.CNLiveApplication" | |
| 19 | + android:name=".CNLiveApplication" | |
| 21 | 20 | android:allowBackup="true" |
| 22 | 21 | android:icon="@mipmap/ic_launcher" |
| 23 | 22 | android:label="@string/app_name" |
| 24 | 23 | android:supportsRtl="true" |
| 25 | 24 | android:theme="@style/AppTheme"> |
| 26 | - <activity android:name="com.cnlive.im.ui.MainActivity"> | |
| 25 | + <activity android:name=".ui.MainActivity"> | |
| 27 | 26 | <intent-filter> |
| 28 | 27 | <action android:name="android.intent.action.MAIN" /> |
| 29 | 28 | |
| 30 | 29 | <category android:name="android.intent.category.LAUNCHER" /> |
| 31 | 30 | </intent-filter> |
| 32 | 31 | </activity> |
| 33 | - | |
| 34 | - | |
| 35 | 32 | <activity |
| 36 | - android:name="com.cnlive.im.ui.ChatRoomActivity" | |
| 33 | + android:name=".ui.ChatRoomActivity" | |
| 37 | 34 | android:theme="@style/Theme.AppCompat.Light.NoActionBar" |
| 38 | - android:windowSoftInputMode="adjustResize"></activity> | |
| 39 | - | |
| 35 | + android:windowSoftInputMode="adjustResize" /> | |
| 40 | 36 | <activity |
| 41 | - android:name="com.cnlive.im.ui.LoGinActivity" | |
| 37 | + android:name=".ui.LoGinActivity" | |
| 42 | 38 | android:screenOrientation="portrait" /> |
| 43 | - | |
| 44 | 39 | <activity |
| 45 | 40 | android:name=".ui.UserLoginActivity" |
| 46 | 41 | android:screenOrientation="portrait" /> |
| 47 | - | |
| 48 | 42 | <activity |
| 49 | - android:name="com.cnlive.im.ui.CommentActivity" | |
| 43 | + android:name=".ui.CommentActivity" | |
| 50 | 44 | android:screenOrientation="portrait" /> |
| 51 | 45 | |
| 52 | - | |
| 53 | 46 | <service |
| 54 | 47 | android:name="io.rong.imlib.ipc.RongService" |
| 55 | 48 | android:exported="true" |
| 56 | 49 | android:process=":ipc" /> |
| 57 | - | |
| 58 | 50 | <service |
| 59 | 51 | android:name="io.rong.imlib.ReConnectService" |
| 60 | 52 | android:exported="true" /> |
| ... | ... | @@ -62,10 +54,10 @@ |
| 62 | 54 | <receiver |
| 63 | 55 | android:name="io.rong.imlib.ConnectChangeReceiver" |
| 64 | 56 | android:exported="true" /> |
| 65 | - | |
| 66 | 57 | <receiver |
| 67 | 58 | android:name="io.rong.imlib.HeartbeatReceiver" |
| 68 | 59 | android:process=":ipc" /> |
| 60 | + | |
| 69 | 61 | </application> |
| 70 | 62 | |
| 71 | 63 | </manifest> |
| 72 | 64 | \ No newline at end of file | ... | ... |
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; | |
| 4 | 5 | import android.graphics.Color; |
| 5 | 6 | import android.net.Uri; |
| 7 | +import android.provider.ContactsContract; | |
| 8 | +import android.provider.MediaStore; | |
| 6 | 9 | import android.support.v7.widget.RecyclerView; |
| 10 | +import android.util.Log; | |
| 7 | 11 | import android.view.LayoutInflater; |
| 8 | 12 | import android.view.View; |
| 9 | 13 | import android.view.ViewGroup; |
| 14 | +import android.view.WindowManager; | |
| 10 | 15 | import android.widget.ImageView; |
| 16 | +import android.widget.LinearLayout; | |
| 11 | 17 | import android.widget.TextView; |
| 12 | 18 | |
| 13 | 19 | import com.bumptech.glide.Glide; |
| ... | ... | @@ -18,6 +24,12 @@ import com.cnlive.im.mode.ImagMessage; |
| 18 | 24 | import com.cnlive.im.mode.StringMessage; |
| 19 | 25 | import com.cnlive.im.mode.VoiceMessage; |
| 20 | 26 | |
| 27 | +import java.text.SimpleDateFormat; | |
| 28 | +import java.util.Calendar; | |
| 29 | +import java.util.Date; | |
| 30 | +import java.util.HashMap; | |
| 31 | +import java.util.Locale; | |
| 32 | + | |
| 21 | 33 | /** |
| 22 | 34 | * @author 陈硕 |
| 23 | 35 | * @time 2017/7/14 14:35 |
| ... | ... | @@ -100,6 +112,9 @@ public class ChatRoomAdpter extends BaseRecyclerAdapter { |
| 100 | 112 | Object o = mItems.get(position); |
| 101 | 113 | ImagMessage o1 = (ImagMessage) o; |
| 102 | 114 | holder1.ima_user_name.setTextColor(Color.parseColor("#d61d0c")); |
| 115 | + holder1.img_content.getLayoutParams().height = 200; | |
| 116 | + holder1.img_content.getLayoutParams().width = 200; | |
| 117 | + holder1.img_content.setLayoutParams(holder1.img_content.getLayoutParams()); | |
| 103 | 118 | Glide.with(mContext).load(o1.getCnImgMessage().getRemoteUri()).into(holder1.img_content); |
| 104 | 119 | holder1.ima_user_name.setText(o1.getCnImgMessage().getUserInfo().getUserName()); |
| 105 | 120 | } else if (holder instanceof VoiceMessageHolder) { |
| ... | ... | @@ -108,6 +123,8 @@ public class ChatRoomAdpter extends BaseRecyclerAdapter { |
| 108 | 123 | VoiceMessage o1 = (VoiceMessage) o; |
| 109 | 124 | holder1.voice_user_name.setText(o1.getCnVoiceMessage().getUserInfo().getUserName()); |
| 110 | 125 | final Uri voiceUri = o1.getCnVoiceMessage().getVoiceUri(); |
| 126 | + int duration = o1.getCnVoiceMessage().getVoiceTime(); | |
| 127 | + holder1.voice_duration.setText(String.valueOf(duration).concat("\"")); | |
| 111 | 128 | holder1.itemView.setOnClickListener(new View.OnClickListener() { |
| 112 | 129 | @Override |
| 113 | 130 | public void onClick(View v) { |
| ... | ... | @@ -146,15 +163,15 @@ public class ChatRoomAdpter extends BaseRecyclerAdapter { |
| 146 | 163 | |
| 147 | 164 | |
| 148 | 165 | private TextView voice_user_name; |
| 149 | - private ImageView voice_content; | |
| 166 | + private TextView voice_content; | |
| 167 | + private TextView voice_duration; | |
| 150 | 168 | |
| 151 | 169 | public VoiceMessageHolder(View itemView) { |
| 152 | 170 | super(itemView); |
| 153 | 171 | voice_user_name = (TextView) itemView.findViewById(R.id.voice_user_name); |
| 154 | - voice_content = (ImageView) itemView.findViewById(R.id.voice_content); | |
| 172 | + voice_content = (TextView) itemView.findViewById(R.id.voice_content); | |
| 173 | + voice_duration = (TextView) itemView.findViewById(R.id.voice_duration); | |
| 155 | 174 | } |
| 156 | 175 | } |
| 157 | 176 | |
| 158 | - | |
| 159 | - | |
| 160 | 177 | } | ... | ... |
app/src/main/java/com/cnlive/im/ui/ChatRoomActivity.java
| ... | ... | @@ -2,23 +2,37 @@ package com.cnlive.im.ui; |
| 2 | 2 | |
| 3 | 3 | import android.Manifest; |
| 4 | 4 | import android.app.Activity; |
| 5 | +import android.content.ContentResolver; | |
| 6 | +import android.content.Context; | |
| 5 | 7 | import android.content.Intent; |
| 6 | 8 | import android.content.pm.PackageManager; |
| 9 | +import android.database.Cursor; | |
| 7 | 10 | import android.net.Uri; |
| 8 | 11 | import android.os.Build; |
| 9 | 12 | import android.os.Bundle; |
| 10 | 13 | import android.os.Handler; |
| 14 | +import android.provider.ContactsContract; | |
| 15 | +import android.provider.MediaStore; | |
| 16 | +import android.support.annotation.NonNull; | |
| 17 | +import android.support.v4.app.ActivityCompat; | |
| 11 | 18 | import android.support.v4.content.ContextCompat; |
| 12 | 19 | import android.support.v7.app.AppCompatActivity; |
| 13 | 20 | import android.support.v7.widget.LinearLayoutManager; |
| 14 | 21 | import android.support.v7.widget.RecyclerView; |
| 22 | +import android.text.Editable; | |
| 23 | +import android.text.TextUtils; | |
| 24 | +import android.text.TextWatcher; | |
| 15 | 25 | import android.util.Log; |
| 26 | +import android.view.Gravity; | |
| 16 | 27 | import android.view.MotionEvent; |
| 17 | 28 | import android.view.View; |
| 29 | +import android.view.inputmethod.InputMethodManager; | |
| 18 | 30 | import android.widget.Button; |
| 19 | 31 | import android.widget.EditText; |
| 32 | +import android.widget.ImageView; | |
| 20 | 33 | import android.widget.LinearLayout; |
| 21 | 34 | import android.widget.RelativeLayout; |
| 35 | +import android.widget.TextView; | |
| 22 | 36 | import android.widget.Toast; |
| 23 | 37 | |
| 24 | 38 | import com.cnlive.im.R; |
| ... | ... | @@ -27,8 +41,11 @@ import com.cnlive.im.adapter.base.VoiceItemClickListener; |
| 27 | 41 | import com.cnlive.im.mode.ImagMessage; |
| 28 | 42 | import com.cnlive.im.mode.StringMessage; |
| 29 | 43 | import com.cnlive.im.mode.VoiceMessage; |
| 44 | +import com.cnlive.im.util.AudioRecordUtil; | |
| 30 | 45 | import com.cnlive.im.util.MediaRecorderUtil; |
| 31 | 46 | import com.cnlive.im.util.MessageType; |
| 47 | +import com.cnlive.im.util.PlayerUtil; | |
| 48 | +import com.cnlive.im.util.TimeUtils; | |
| 32 | 49 | import com.cnlive.libs.util.chat.ChatUtil; |
| 33 | 50 | import com.cnlive.libs.util.chat.base.IChat; |
| 34 | 51 | import com.cnlive.libs.util.chat.model.CNImgMessage; |
| ... | ... | @@ -38,15 +55,18 @@ import com.cnlive.libs.util.chat.model.CNVoiceMessage; |
| 38 | 55 | |
| 39 | 56 | import org.json.JSONException; |
| 40 | 57 | |
| 58 | +import java.io.LineNumberReader; | |
| 41 | 59 | import java.util.ArrayList; |
| 42 | 60 | |
| 61 | +import static android.R.id.edit; | |
| 62 | + | |
| 43 | 63 | |
| 44 | 64 | /** |
| 45 | 65 | * @author 陈硕 |
| 46 | 66 | * @time 2017/3/7 14:36 |
| 47 | 67 | * @desc ${TODD} |
| 48 | 68 | */ |
| 49 | -public class ChatRoomActivity extends AppCompatActivity implements View.OnClickListener, View.OnTouchListener, VoiceItemClickListener { | |
| 69 | +public class ChatRoomActivity extends AppCompatActivity implements View.OnClickListener, VoiceItemClickListener { | |
| 50 | 70 | private static final String TAG = "ChatRoomActivity"; |
| 51 | 71 | private ArrayList<Object> groupChatOneListMy; |
| 52 | 72 | private String roomIdOne = "ChatRoom05"; |
| ... | ... | @@ -57,32 +77,55 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL |
| 57 | 77 | private Button foundChatBtn; |
| 58 | 78 | private Handler mHandler; |
| 59 | 79 | private RelativeLayout re_chat; |
| 60 | - private LinearLayout lin_user; | |
| 61 | - private EditText user_id, user_name; | |
| 80 | +// private LinearLayout lin_user; | |
| 81 | +// private EditText user_id, user_name; | |
| 62 | 82 | private Button exit_chat1; |
| 63 | 83 | public static String user_name_string; |
| 64 | 84 | private boolean isUserLogin = false; |
| 65 | - private Button ima_send; | |
| 66 | - private Button voice_send; | |
| 85 | + private ImageView ima_send; | |
| 86 | + private Button sendVoice; | |
| 87 | + | |
| 88 | + private Context context; | |
| 89 | + private AudioRecordUtil mAudioRecordUtil; | |
| 90 | + private PopupWindowFactory mPop; | |
| 91 | + private ImageView mImageView; | |
| 92 | + private TextView mTextView; | |
| 93 | + private ImageView keybordBtn; | |
| 94 | + | |
| 95 | + private LinearLayout sendMsgLayout; | |
| 96 | + private LinearLayout cancelSendLayout; | |
| 97 | + | |
| 98 | + private boolean isVoiceBtnVisible = false; | |
| 67 | 99 | |
| 68 | 100 | |
| 69 | 101 | public static final int IMG_FROM_PICTURE = 0x1001; |
| 70 | 102 | public static final int VOICE = 0x1002; |
| 71 | 103 | public static final int PICTURE_REQUEST_CODE = 0x1003; |
| 72 | 104 | public static final int VOICE_REQUEST_CODE = 0x1004; |
| 73 | - private MediaRecorderUtil mediaRecorderUtil; | |
| 74 | 105 | private long l; |
| 75 | 106 | int i; |
| 76 | 107 | |
| 108 | + private String mFilePath; | |
| 109 | + | |
| 110 | + private PlayerUtil playerUtil; | |
| 111 | + | |
| 112 | + // 所需的全部权限 | |
| 113 | + static final String[] PERMISSIONS = new String[]{ | |
| 114 | + Manifest.permission.RECORD_AUDIO, | |
| 115 | + Manifest.permission.WRITE_EXTERNAL_STORAGE | |
| 116 | + }; | |
| 117 | + | |
| 77 | 118 | @Override |
| 78 | 119 | protected void onCreate(Bundle savedInstanceState) { |
| 79 | 120 | super.onCreate(savedInstanceState); |
| 80 | 121 | //取消状态栏 |
| 81 | 122 | setContentView(R.layout.activity_groupchat); |
| 123 | + context = this; | |
| 82 | 124 | initUI(); |
| 125 | + mAudioRecordUtil = new AudioRecordUtil(); | |
| 126 | + mAudioRecordUtil.setOnAudioStatusUpdateListener(onAudioStatusUpdateListener); | |
| 83 | 127 | //设置监听 |
| 84 | 128 | mHandler = new Handler(); |
| 85 | - mediaRecorderUtil = new MediaRecorderUtil(); | |
| 86 | 129 | ChatUtil.setOnConnectStatusListener(connectStatusListener); |
| 87 | 130 | ChatUtil.setOnChatRoomActionListener(chatRoomActionListener); |
| 88 | 131 | ChatUtil.setOnReceiveMessageListener(receiveMessageListener); |
| ... | ... | @@ -93,21 +136,30 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL |
| 93 | 136 | if (user_name_string != null) |
| 94 | 137 | ChatUtil.login(new CNUserInfo(user_id_string, user_name_string, ""), connectListener); |
| 95 | 138 | else ChatUtil.logOut(connectListener); |
| 139 | + requestPermission(); | |
| 140 | + playerUtil = new PlayerUtil(this); | |
| 96 | 141 | |
| 97 | 142 | } |
| 98 | 143 | |
| 99 | 144 | |
| 100 | 145 | private void initUI() { |
| 101 | - voice_send = (Button) findViewById(R.id.voice_send); | |
| 102 | - ima_send = (Button) findViewById(R.id.ima_send); | |
| 146 | + | |
| 147 | + final View view = View.inflate(this, R.layout.layout_microphone, null); | |
| 148 | + mPop = new PopupWindowFactory(this, view); | |
| 149 | + mImageView = (ImageView) view.findViewById(R.id.iv_recording_icon); | |
| 150 | + mTextView = (TextView) view.findViewById(R.id.tv_recording_time); | |
| 151 | + sendMsgLayout = (LinearLayout) view.findViewById(R.id.send_layout); | |
| 152 | + cancelSendLayout = (LinearLayout) view.findViewById(R.id.cancel_send_layout); | |
| 153 | + ima_send = (ImageView) findViewById(R.id.ima_send); | |
| 103 | 154 | exit_chat1 = (Button) findViewById(R.id.exit_chat1); |
| 104 | - user_id = (EditText) findViewById(R.id.user_ID); | |
| 105 | - user_name = (EditText) findViewById(R.id.user_name); | |
| 106 | - lin_user = (LinearLayout) findViewById(R.id.lin_user); | |
| 155 | +// user_id = (EditText) findViewById(R.id.user_ID); | |
| 156 | +// user_name = (EditText) findViewById(R.id.user_name); | |
| 157 | +// lin_user = (LinearLayout) findViewById(R.id.lin_user); | |
| 107 | 158 | re_chat = (RelativeLayout) findViewById(R.id.re_chat); |
| 108 | 159 | foundChatBtn = (Button) findViewById(R.id.creatChat); |
| 109 | 160 | listViewOne = (RecyclerView) findViewById(R.id.chat_list_viewOne); |
| 110 | 161 | editText = (EditText) findViewById(R.id.message_content); |
| 162 | + editText.addTextChangedListener(textWatcher); | |
| 111 | 163 | send_messageOneBtn = (Button) findViewById(R.id.send_messageOne); |
| 112 | 164 | ima_send.setOnClickListener(this); |
| 113 | 165 | exit_chat1.setOnClickListener(this); |
| ... | ... | @@ -118,7 +170,15 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL |
| 118 | 170 | chatListAdapterOne.setonVoiceItemClickListener(this); |
| 119 | 171 | listViewOne.setLayoutManager(new LinearLayoutManager(ChatRoomActivity.this)); |
| 120 | 172 | listViewOne.setAdapter(chatListAdapterOne); |
| 121 | - voice_send.setOnTouchListener(this); | |
| 173 | + | |
| 174 | + sendVoice = (Button) findViewById(R.id.send_voice); | |
| 175 | + re_chat = (RelativeLayout) findViewById(R.id.activity_chat_room); | |
| 176 | + keybordBtn = (ImageView) findViewById(R.id.keybord); | |
| 177 | + keybordBtn.setOnClickListener(this); | |
| 178 | + | |
| 179 | + | |
| 180 | + StartListener(); | |
| 181 | + | |
| 122 | 182 | |
| 123 | 183 | } |
| 124 | 184 | |
| ... | ... | @@ -126,7 +186,6 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL |
| 126 | 186 | /** |
| 127 | 187 | * 发送消息监听 |
| 128 | 188 | */ |
| 129 | - | |
| 130 | 189 | private IChat.OnSendMessageListener sendMessageListener = new IChat.OnSendMessageListener() { |
| 131 | 190 | @Override |
| 132 | 191 | public void onAttached(Object o) { |
| ... | ... | @@ -148,14 +207,20 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL |
| 148 | 207 | CNVoiceMessage o1 = (CNVoiceMessage) o; |
| 149 | 208 | VoiceMessage voiceMessage = new VoiceMessage(MessageType.voiceMessage, o1, true); |
| 150 | 209 | chatListAdapterOne.addItem(voiceMessage); |
| 210 | + //发送成功后删除保存在本地的录制文件 | |
| 211 | + mAudioRecordUtil.deleteRecordFile(mFilePath); | |
| 212 | + | |
| 151 | 213 | } |
| 214 | + listViewOne.smoothScrollToPosition(chatListAdapterOne.getItemCount() - 1); | |
| 152 | 215 | } |
| 153 | 216 | }); |
| 154 | 217 | } |
| 155 | 218 | |
| 156 | 219 | @Override |
| 157 | 220 | public void onError(Object o, int i, String s) { |
| 221 | + if (o instanceof CNImgMessage) { | |
| 158 | 222 | |
| 223 | + } | |
| 159 | 224 | } |
| 160 | 225 | }; |
| 161 | 226 | |
| ... | ... | @@ -186,6 +251,7 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL |
| 186 | 251 | VoiceMessage voiceMessage = new VoiceMessage(MessageType.voiceMessage, o1, false); |
| 187 | 252 | chatListAdapterOne.addItem(voiceMessage); |
| 188 | 253 | } |
| 254 | + listViewOne.smoothScrollToPosition(chatListAdapterOne.getItemCount() - 1); | |
| 189 | 255 | } |
| 190 | 256 | }); |
| 191 | 257 | |
| ... | ... | @@ -282,41 +348,24 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL |
| 282 | 348 | case R.id.ima_send: |
| 283 | 349 | fromPicture(); |
| 284 | 350 | break; |
| 351 | + case R.id.keybord: | |
| 352 | + if (!isVoiceBtnVisible) { | |
| 353 | + editText.setVisibility(View.GONE); | |
| 354 | + sendVoice.setVisibility(View.VISIBLE); | |
| 355 | + keybordBtn.setImageResource(R.drawable.keybord); | |
| 356 | + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); | |
| 357 | + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); | |
| 358 | + isVoiceBtnVisible = true; | |
| 359 | + } else { | |
| 360 | + sendVoice.setVisibility(View.GONE); | |
| 361 | + editText.setVisibility(View.VISIBLE); | |
| 362 | + keybordBtn.setImageResource(R.drawable.voice); | |
| 363 | + isVoiceBtnVisible = false; | |
| 364 | + } | |
| 365 | + break; | |
| 285 | 366 | } |
| 286 | 367 | } |
| 287 | 368 | |
| 288 | - public void mediaRecorder() { | |
| 289 | - if (Build.VERSION.SDK_INT >= 23) { | |
| 290 | - int checkCallPhonePermission = ContextCompat.checkSelfPermission(ChatRoomActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE); | |
| 291 | - int checkCallPhonePermission1 = ContextCompat.checkSelfPermission(ChatRoomActivity.this, Manifest.permission.RECORD_AUDIO); | |
| 292 | - | |
| 293 | - if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED || checkCallPhonePermission1 != PackageManager.PERMISSION_GRANTED) { | |
| 294 | - requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO}, VOICE_REQUEST_CODE); | |
| 295 | - return; | |
| 296 | - } else { | |
| 297 | - recorder(); | |
| 298 | - } | |
| 299 | - } else { | |
| 300 | - recorder(); | |
| 301 | - } | |
| 302 | - } | |
| 303 | - | |
| 304 | - | |
| 305 | - public String getRecoderFile() { | |
| 306 | - | |
| 307 | - return mediaRecorderUtil.getRecorderFile(); | |
| 308 | - | |
| 309 | - } | |
| 310 | - | |
| 311 | - public void recorder() { | |
| 312 | - mediaRecorderUtil.record(); | |
| 313 | - | |
| 314 | - } | |
| 315 | - | |
| 316 | - public void releaseRecord() { | |
| 317 | - mediaRecorderUtil.releaseRecord(); | |
| 318 | - | |
| 319 | - } | |
| 320 | 369 | |
| 321 | 370 | public void fromPicture() { |
| 322 | 371 | if (Build.VERSION.SDK_INT >= 23) { |
| ... | ... | @@ -336,31 +385,8 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL |
| 336 | 385 | private void toIntentPicture() { |
| 337 | 386 | Intent intent = new Intent(); |
| 338 | 387 | intent.setType("image/*"); |
| 339 | - intent.setAction(Intent.ACTION_GET_CONTENT); | |
| 340 | - startActivityForResult(intent, IMG_FROM_PICTURE); | |
| 341 | - } | |
| 342 | - | |
| 343 | - | |
| 344 | - @Override | |
| 345 | - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { | |
| 346 | - super.onRequestPermissionsResult(requestCode, permissions, grantResults); | |
| 347 | - switch (requestCode) { | |
| 348 | - case PICTURE_REQUEST_CODE: | |
| 349 | - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { | |
| 350 | - toIntentPicture(); | |
| 351 | - } else { | |
| 352 | - Toast.makeText(ChatRoomActivity.this, "权限已被禁止,请打开,再使用此功能", Toast.LENGTH_LONG).show(); | |
| 353 | - } | |
| 354 | - break; | |
| 355 | - | |
| 356 | - case VOICE_REQUEST_CODE: | |
| 357 | - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { | |
| 358 | - recorder(); | |
| 359 | - } else { | |
| 360 | - Toast.makeText(ChatRoomActivity.this, "权限已被禁止,请打开,再使用此功能", Toast.LENGTH_LONG).show(); | |
| 361 | - } | |
| 362 | - break; | |
| 363 | - } | |
| 388 | + intent.setAction(Intent.ACTION_PICK); | |
| 389 | + startActivityForResult(Intent.createChooser(intent, "Complete action using"), IMG_FROM_PICTURE); | |
| 364 | 390 | } |
| 365 | 391 | |
| 366 | 392 | |
| ... | ... | @@ -370,7 +396,19 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL |
| 370 | 396 | if (resultCode == Activity.RESULT_OK) { |
| 371 | 397 | switch (requestCode) { |
| 372 | 398 | case IMG_FROM_PICTURE: |
| 373 | - Uri uri = data.getData(); | |
| 399 | +// String localImagePath = "/sdcard/test.png"; | |
| 400 | +// Uri selectedImage = Uri.parse("file://" + localImagePath); | |
| 401 | + Uri selectedImage = data.getData(); | |
| 402 | + String[] filePathColumn = {MediaStore.Images.Media.DATA}; | |
| 403 | + | |
| 404 | + Cursor cursor = getContentResolver().query(selectedImage, | |
| 405 | + filePathColumn, null, null, null); | |
| 406 | + cursor.moveToFirst(); | |
| 407 | + | |
| 408 | + int columnIndex = cursor.getColumnIndex(filePathColumn[0]); | |
| 409 | + final String picturePath = cursor.getString(columnIndex); | |
| 410 | + | |
| 411 | + Uri uri = Uri.parse("file://" + picturePath); | |
| 374 | 412 | ChatUtil.sendImaMessage(IChat.CHATROOM, roomIdOne, uri, uri, sendMessageListener); |
| 375 | 413 | break; |
| 376 | 414 | |
| ... | ... | @@ -406,53 +444,169 @@ public class ChatRoomActivity extends AppCompatActivity implements View.OnClickL |
| 406 | 444 | |
| 407 | 445 | |
| 408 | 446 | @Override |
| 409 | - public boolean onTouch(View v, MotionEvent event) { | |
| 447 | + public void onItemClick(Uri uri) { | |
| 448 | + playerUtil.start(uri); | |
| 410 | 449 | |
| 411 | - switch (event.getAction()) { | |
| 412 | - case MotionEvent.ACTION_DOWN: | |
| 413 | - l = System.currentTimeMillis(); | |
| 414 | - mediaRecorder(); | |
| 415 | - break; | |
| 416 | - case MotionEvent.ACTION_UP: | |
| 450 | + } | |
| 451 | + | |
| 452 | + | |
| 453 | + /**************************************************************************/ | |
| 454 | + | |
| 455 | + /** | |
| 456 | + * 开启扫描之前判断权限是否打开 | |
| 457 | + */ | |
| 458 | + private void requestPermission() { | |
| 459 | + //判断是否开启摄像头权限 | |
| 460 | + if ((ContextCompat.checkSelfPermission(context, | |
| 461 | + Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) && | |
| 462 | + (ContextCompat.checkSelfPermission(context, | |
| 463 | + Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) | |
| 464 | + ) { | |
| 465 | + StartListener(); | |
| 466 | + | |
| 467 | + //判断是否开启语音权限 | |
| 468 | + } else { | |
| 469 | + //请求获取摄像头权限 | |
| 470 | + ActivityCompat.requestPermissions((Activity) context, | |
| 471 | + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO}, VOICE_REQUEST_CODE); | |
| 472 | + } | |
| 473 | + } | |
| 417 | 474 | |
| 418 | - if (Build.VERSION.SDK_INT >= 23) { | |
| 419 | - int checkCallPhonePermission = ContextCompat.checkSelfPermission(ChatRoomActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE); | |
| 420 | - int checkCallPhonePermission1 = ContextCompat.checkSelfPermission(ChatRoomActivity.this, Manifest.permission.RECORD_AUDIO); | |
| 475 | + @Override | |
| 476 | + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { | |
| 477 | + super.onRequestPermissionsResult(requestCode, permissions, grantResults); | |
| 478 | + if (requestCode == VOICE_REQUEST_CODE) { | |
| 479 | + if ((grantResults[0] == PackageManager.PERMISSION_GRANTED) && (grantResults[1] == PackageManager.PERMISSION_GRANTED)) { | |
| 480 | + StartListener(); | |
| 481 | + } else { | |
| 482 | + Toast.makeText(context, "已拒绝权限!", Toast.LENGTH_SHORT).show(); | |
| 483 | + } | |
| 484 | + } | |
| 485 | + } | |
| 486 | + | |
| 487 | + float downX; | |
| 488 | + float downY; | |
| 489 | + | |
| 490 | + public void StartListener() { | |
| 491 | + | |
| 492 | + //Button的touch监听 | |
| 493 | + sendVoice.setOnTouchListener(new View.OnTouchListener() { | |
| 494 | + @Override | |
| 495 | + public boolean onTouch(View v, MotionEvent event) { | |
| 496 | + if (lacksPermissions(PERMISSIONS)) { | |
| 497 | + if (lacksPermission(PERMISSIONS[0])) { | |
| 498 | + Toast.makeText(ChatRoomActivity.this, "没有麦克风权限,请前往“设置 - 应用 - 权限”中开启权限", Toast.LENGTH_SHORT).show(); | |
| 499 | + | |
| 500 | + } else if (lacksPermission(PERMISSIONS[1])) { | |
| 501 | + Toast.makeText(ChatRoomActivity.this, "没有文件读写权限,请前往“设置 - 应用 - 权限”中开启权限", Toast.LENGTH_SHORT).show(); | |
| 421 | 502 | |
| 422 | - if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED || checkCallPhonePermission1 != PackageManager.PERMISSION_GRANTED) { | |
| 423 | - requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO}, VOICE_REQUEST_CODE); | |
| 424 | - } else { | |
| 425 | - sendVoice(); | |
| 426 | 503 | } |
| 427 | 504 | } else { |
| 428 | - sendVoice(); | |
| 505 | + | |
| 506 | + switch (event.getAction()) { | |
| 507 | + | |
| 508 | + case MotionEvent.ACTION_DOWN: | |
| 509 | + mPop.showAtLocation(re_chat, Gravity.CENTER, 0, 0); | |
| 510 | + | |
| 511 | + sendVoice.setText("松开发送"); | |
| 512 | + mAudioRecordUtil.startRecord(); | |
| 513 | + downX = event.getX(); | |
| 514 | + downY = event.getY(); | |
| 515 | + | |
| 516 | + break; | |
| 517 | + | |
| 518 | + case MotionEvent.ACTION_UP: | |
| 519 | + | |
| 520 | + if (cancelSendLayout.getVisibility() == View.VISIBLE) { | |
| 521 | + cancelSendLayout.setVisibility(View.GONE); | |
| 522 | + sendMsgLayout.setVisibility(View.VISIBLE); | |
| 523 | + } | |
| 524 | + float moveX = Math.abs(event.getX() - downX); | |
| 525 | + float moveY = Math.abs(event.getY() - downY); | |
| 526 | + if (moveY > 100) { | |
| 527 | +// Toast.makeText(ChatRoomActivity.this, "cancel", Toast.LENGTH_SHORT).show(); | |
| 528 | + mAudioRecordUtil.cancelRecord(); | |
| 529 | + } else { | |
| 530 | + mAudioRecordUtil.stopRecord(); //结束录音(保存录音文件) | |
| 531 | + } | |
| 532 | + mPop.dismiss(); | |
| 533 | + mTextView.setText("00:00"); | |
| 534 | + sendVoice.setText("按住说话"); | |
| 535 | + break; | |
| 536 | + case MotionEvent.ACTION_MOVE: | |
| 537 | + float moveXm = Math.abs(event.getX() - downX); | |
| 538 | + float moveYm = Math.abs(event.getY() - downY); | |
| 539 | + if (moveYm > 100) { | |
| 540 | +// Toast.makeText(ChatRoomActivity.this, "cancel", Toast.LENGTH_SHORT).show(); | |
| 541 | + if (sendMsgLayout.getVisibility() == View.VISIBLE) { | |
| 542 | + sendMsgLayout.setVisibility(View.GONE); | |
| 543 | + cancelSendLayout.setVisibility(View.VISIBLE); | |
| 544 | + } | |
| 545 | + } else { | |
| 546 | + if (cancelSendLayout.getVisibility() == View.VISIBLE) { | |
| 547 | + cancelSendLayout.setVisibility(View.GONE); | |
| 548 | + sendMsgLayout.setVisibility(View.VISIBLE); | |
| 549 | + } | |
| 550 | + } | |
| 551 | + break; | |
| 552 | + } | |
| 429 | 553 | } |
| 554 | + return true; | |
| 555 | + } | |
| 556 | + }); | |
| 430 | 557 | |
| 558 | + } | |
| 431 | 559 | |
| 432 | - break; | |
| 560 | + // 判断权限集合 | |
| 561 | + public boolean lacksPermissions(String... permissions) { | |
| 562 | + for (String permission : permissions) { | |
| 563 | + if (lacksPermission(permission)) { | |
| 564 | + return true; | |
| 565 | + } | |
| 566 | + } | |
| 567 | + return false; | |
| 568 | + } | |
| 433 | 569 | |
| 570 | + // 判断是否缺少权限 | |
| 571 | + private boolean lacksPermission(String permission) { | |
| 572 | + return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_DENIED; | |
| 573 | + } | |
| 434 | 574 | |
| 575 | + private AudioRecordUtil.OnAudioStatusUpdateListener onAudioStatusUpdateListener = new AudioRecordUtil.OnAudioStatusUpdateListener() { | |
| 576 | + @Override | |
| 577 | + public void onUpdate(double db, long time) { | |
| 578 | + mImageView.getDrawable().setLevel((int) (3000 + 6000 * db / 100)); | |
| 579 | + mTextView.setText(TimeUtils.long2String(time)); | |
| 435 | 580 | } |
| 436 | 581 | |
| 437 | - return true; | |
| 438 | - } | |
| 582 | + @Override | |
| 583 | + public void onStop(String filePath) { | |
| 584 | + i = (int) mAudioRecordUtil.getDuration(); | |
| 585 | + mFilePath = filePath; | |
| 586 | + ChatUtil.sendVoiceMessage(IChat.CHATROOM, roomIdOne, Uri.parse(mFilePath), i, sendMessageListener); | |
| 587 | + } | |
| 588 | + }; | |
| 439 | 589 | |
| 440 | - private void sendVoice() { | |
| 441 | - long l1 = System.currentTimeMillis(); | |
| 442 | - long l2 = (l1 - l) / 1000; | |
| 443 | - i = (int) l2; | |
| 444 | - releaseRecord(); | |
| 445 | - String recoderFile = getRecoderFile(); | |
| 446 | - ChatUtil.sendVoiceMessage(IChat.CHATROOM, roomIdOne, Uri.parse(recoderFile), i, sendMessageListener); | |
| 447 | - } | |
| 590 | + private TextWatcher textWatcher = new TextWatcher() { | |
| 591 | + @Override | |
| 592 | + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { | |
| 593 | + } | |
| 448 | 594 | |
| 449 | - @Override | |
| 450 | - public void onItemClick(Uri uri) { | |
| 451 | - plaVoice(uri); | |
| 595 | + @Override | |
| 596 | + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { | |
| 452 | 597 | |
| 453 | - } | |
| 598 | + } | |
| 599 | + | |
| 600 | + @Override | |
| 601 | + public void afterTextChanged(Editable editable) { | |
| 602 | + if (!TextUtils.isEmpty(editable)){ | |
| 603 | + ima_send.setVisibility(View.GONE); | |
| 604 | + send_messageOneBtn.setVisibility(View.VISIBLE); | |
| 605 | + }else { | |
| 606 | + send_messageOneBtn.setVisibility(View.GONE); | |
| 607 | + ima_send.setVisibility(View.VISIBLE); | |
| 608 | + } | |
| 609 | + } | |
| 610 | + }; | |
| 454 | 611 | |
| 455 | - public void plaVoice(Uri uri) { | |
| 456 | - mediaRecorderUtil.plaVoice(uri, this); | |
| 457 | - } | |
| 458 | 612 | } | ... | ... |
app/src/main/java/com/cnlive/im/ui/PopupWindowFactory.java
0 → 100644
| 1 | +package com.cnlive.im.ui; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.graphics.drawable.BitmapDrawable; | |
| 5 | +import android.util.Log; | |
| 6 | +import android.view.KeyEvent; | |
| 7 | +import android.view.MotionEvent; | |
| 8 | +import android.view.View; | |
| 9 | +import android.view.ViewGroup; | |
| 10 | +import android.widget.PopupWindow; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * Created by Lynn on 2017/7/21. | |
| 14 | + */ | |
| 15 | + | |
| 16 | +public class PopupWindowFactory { | |
| 17 | + private Context mContext; | |
| 18 | + private PopupWindow mPop; | |
| 19 | + | |
| 20 | + /** | |
| 21 | + * @param context 上下文 | |
| 22 | + * @param view PopupWindow显示的布局文件 | |
| 23 | + */ | |
| 24 | + public PopupWindowFactory(Context context, View view) { | |
| 25 | + this(context, view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); | |
| 26 | + } | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * @param context 上下文 | |
| 30 | + * @param view PopupWindow显示的布局文件 | |
| 31 | + * @param width PopupWindow的宽 | |
| 32 | + * @param height PopupWindow的高 | |
| 33 | + */ | |
| 34 | + public PopupWindowFactory(Context context, View view, int width, int height) { | |
| 35 | + init(context, view, width, height); | |
| 36 | + } | |
| 37 | + | |
| 38 | + | |
| 39 | + private void init(Context context, View view, int width, int height) { | |
| 40 | + this.mContext = context; | |
| 41 | + | |
| 42 | + //下面这两个必须有 | |
| 43 | + view.setFocusable(true); | |
| 44 | + view.setFocusableInTouchMode(true); | |
| 45 | + | |
| 46 | + //PopupWindow(布局,宽度、高度) | |
| 47 | + mPop = new PopupWindow(view, width, height, true); | |
| 48 | + mPop.setFocusable(true); | |
| 49 | + mPop.setOutsideTouchable(false); | |
| 50 | + | |
| 51 | + //重写onKeyListener,按返回键消失 | |
| 52 | + view.setOnKeyListener(new View.OnKeyListener() { | |
| 53 | + @Override | |
| 54 | + public boolean onKey(View view, int i, KeyEvent keyEvent) { | |
| 55 | + if (i == KeyEvent.KEYCODE_BACK) { | |
| 56 | + mPop.dismiss(); | |
| 57 | + return true; | |
| 58 | + } | |
| 59 | + return false; | |
| 60 | + } | |
| 61 | + }); | |
| 62 | + | |
| 63 | +// 点击其他地方消失 | |
| 64 | + view.setOnTouchListener(new View.OnTouchListener() { | |
| 65 | + @Override | |
| 66 | + public boolean onTouch(View view, MotionEvent motionEvent) { | |
| 67 | + if (mPop != null && mPop.isShowing()) { | |
| 68 | +// mPop.dismiss(); | |
| 69 | + return true; | |
| 70 | + } | |
| 71 | + return false; | |
| 72 | + } | |
| 73 | + }); | |
| 74 | + | |
| 75 | + } | |
| 76 | + | |
| 77 | + public PopupWindow getPopupWindow() { | |
| 78 | + return mPop; | |
| 79 | + } | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * 以触发弹出窗的view为基准,出现在view的内部上面,弹出的pop_view左上角正对view的左上角 | |
| 83 | + * | |
| 84 | + * @param parent view | |
| 85 | + * @param gravity 在view的什么位置Gravity.CENTER、Gravity.TOP...... | |
| 86 | + * @param x 与控件的x坐标距离 | |
| 87 | + * @param y 与控件的y坐标距离 | |
| 88 | + */ | |
| 89 | + public void showAtLocation(View parent, int gravity, int x, int y) { | |
| 90 | + if (mPop.isShowing()) { | |
| 91 | + return; | |
| 92 | + } | |
| 93 | + mPop.showAtLocation(parent, gravity, x, y); | |
| 94 | + } | |
| 95 | + | |
| 96 | + /** | |
| 97 | + * 以触发弹出窗的view为基准,出现在view的正下方,弹出的pop_view左上角正对view的左下角 | |
| 98 | + * | |
| 99 | + * @param anchor view | |
| 100 | + */ | |
| 101 | + public void showAsDropDown(View anchor) { | |
| 102 | + showAsDropDown(anchor, 0, 0); | |
| 103 | + } | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * 以触发弹出窗的view为基准,出现在view的正下方,弹出的pop_view左上角正对view的左下角 | |
| 107 | + * | |
| 108 | + * @param anchor view | |
| 109 | + * @param xoff 与view的x坐标距离 | |
| 110 | + * @param yoff 与view的y坐标距离 | |
| 111 | + */ | |
| 112 | + public void showAsDropDown(View anchor, int xoff, int yoff) { | |
| 113 | + if (mPop.isShowing()) { | |
| 114 | + return; | |
| 115 | + } | |
| 116 | + | |
| 117 | + mPop.showAsDropDown(anchor, xoff, yoff); | |
| 118 | + } | |
| 119 | + | |
| 120 | + /** | |
| 121 | + * 隐藏popupwindow | |
| 122 | + */ | |
| 123 | + public void dismiss() { | |
| 124 | + if (mPop.isShowing()) { | |
| 125 | + mPop.dismiss(); | |
| 126 | + } | |
| 127 | + } | |
| 128 | +} | ... | ... |
app/src/main/java/com/cnlive/im/ui/UserLoginActivity.java
| ... | ... | @@ -50,7 +50,7 @@ public class UserLoginActivity extends AppCompatActivity implements View.OnClick |
| 50 | 50 | doIntentChatRoom(ChatRoomActivity.class); |
| 51 | 51 | break; |
| 52 | 52 | case R.id.private_chat: |
| 53 | - // doIntentChatRoom(PrivateChatActivity.class); | |
| 53 | + doIntentChatRoom(PrivateChatActivity.class); | |
| 54 | 54 | |
| 55 | 55 | break; |
| 56 | 56 | } | ... | ... |
app/src/main/java/com/cnlive/im/util/AudioRecordUtil.java
0 → 100644
| 1 | +package com.cnlive.im.util; | |
| 2 | + | |
| 3 | +import android.media.MediaRecorder; | |
| 4 | +import android.os.Environment; | |
| 5 | +import android.os.Handler; | |
| 6 | +import android.util.Log; | |
| 7 | + | |
| 8 | +import java.io.File; | |
| 9 | +import java.io.IOException; | |
| 10 | +import java.text.SimpleDateFormat; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * Created by Lynn on 2017/7/20. | |
| 14 | + */ | |
| 15 | + | |
| 16 | +public class AudioRecordUtil { | |
| 17 | + //文件路径 | |
| 18 | + private String filePath; | |
| 19 | + //文件夹路径 | |
| 20 | + private String FolderPath; | |
| 21 | + | |
| 22 | + private MediaRecorder mMediaRecorder; | |
| 23 | + private final String TAG = "fan"; | |
| 24 | + public static final int MAX_LENGTH = 1000 * 60 * 10;// 最大录音时长1000*60*10; | |
| 25 | + | |
| 26 | + private OnAudioStatusUpdateListener audioStatusUpdateListener; | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 文件存储默认sdcard/record | |
| 30 | + */ | |
| 31 | + public AudioRecordUtil() { | |
| 32 | + | |
| 33 | + //默认保存路径为/sdcard/record/下 | |
| 34 | + this(Environment.getExternalStorageDirectory() + "/record/"); | |
| 35 | + } | |
| 36 | + | |
| 37 | + public AudioRecordUtil(String filePath) { | |
| 38 | + | |
| 39 | + File path = new File(filePath); | |
| 40 | + if (!path.exists()) | |
| 41 | + path.mkdirs(); | |
| 42 | + | |
| 43 | + this.FolderPath = filePath; | |
| 44 | + } | |
| 45 | + | |
| 46 | + private long startTime; | |
| 47 | + private long endTime; | |
| 48 | + | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * 开始录音 使用amr格式 | |
| 52 | + * 录音文件 | |
| 53 | + * | |
| 54 | + * @return | |
| 55 | + */ | |
| 56 | + public void startRecord() { | |
| 57 | + // 开始录音 | |
| 58 | + /* ①Initial:实例化MediaRecorder对象 */ | |
| 59 | + if (mMediaRecorder == null) | |
| 60 | + mMediaRecorder = new MediaRecorder(); | |
| 61 | + try { | |
| 62 | + /* ②setAudioSource/setVedioSource */ | |
| 63 | + mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置麦克风 | |
| 64 | + /* ②设置音频文件的编码:AAC/AMR_NB/AMR_MB/Default 声音的(波形)的采样 */ | |
| 65 | + mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); | |
| 66 | + /* | |
| 67 | + * ②设置输出文件的格式:THREE_GPP/MPEG-4/RAW_AMR/Default THREE_GPP(3gp格式 | |
| 68 | + * ,H263视频/ARM音频编码)、MPEG-4、RAW_AMR(只支持音频且音频编码要求为AMR_NB) | |
| 69 | + */ | |
| 70 | + mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); | |
| 71 | + | |
| 72 | + filePath = FolderPath + getCurrentTime() + ".amr"; | |
| 73 | + /* ③准备 */ | |
| 74 | + mMediaRecorder.setOutputFile(filePath); | |
| 75 | + mMediaRecorder.setMaxDuration(MAX_LENGTH); | |
| 76 | + mMediaRecorder.prepare(); | |
| 77 | + /* ④开始 */ | |
| 78 | + mMediaRecorder.start(); | |
| 79 | + // AudioRecord audioRecord. | |
| 80 | + /* 获取开始时间* */ | |
| 81 | + startTime = System.currentTimeMillis(); | |
| 82 | + updateMicStatus(); | |
| 83 | + Log.e("fan", "startTime" + startTime); | |
| 84 | + } catch (IllegalStateException e) { | |
| 85 | + Log.i(TAG, "call startAmr(File mRecAudioFile) failed!" + e.getMessage()); | |
| 86 | + } catch (IOException e) { | |
| 87 | + Log.i(TAG, "call startAmr(File mRecAudioFile) failed!" + e.getMessage()); | |
| 88 | + } | |
| 89 | + } | |
| 90 | + | |
| 91 | + /** | |
| 92 | + * 停止录音 | |
| 93 | + */ | |
| 94 | + public void stopRecord() { | |
| 95 | + if (mMediaRecorder == null) | |
| 96 | + return; | |
| 97 | + endTime = System.currentTimeMillis(); | |
| 98 | + | |
| 99 | + //有一些网友反应在5.0以上在调用stop的时候会报错,翻阅了一下谷歌文档发现上面确实写的有可能会报错的情况,捕获异常清理一下就行了,感谢大家反馈! | |
| 100 | + try { | |
| 101 | + mMediaRecorder.stop(); | |
| 102 | + mMediaRecorder.reset(); | |
| 103 | + mMediaRecorder.release(); | |
| 104 | + mMediaRecorder = null; | |
| 105 | + | |
| 106 | + audioStatusUpdateListener.onStop(filePath); | |
| 107 | + filePath = ""; | |
| 108 | + | |
| 109 | + } catch (RuntimeException e) { | |
| 110 | + mMediaRecorder.reset(); | |
| 111 | + mMediaRecorder.release(); | |
| 112 | + mMediaRecorder = null; | |
| 113 | + | |
| 114 | + File file = new File(filePath); | |
| 115 | + if (file.exists()) | |
| 116 | + file.delete(); | |
| 117 | + | |
| 118 | + filePath = ""; | |
| 119 | + | |
| 120 | + } | |
| 121 | +// return endTime - startTime; | |
| 122 | + } | |
| 123 | + | |
| 124 | + public long getDuration(){ | |
| 125 | + return (endTime - startTime) / 1000; | |
| 126 | + } | |
| 127 | + | |
| 128 | + /** | |
| 129 | + * 取消录音 | |
| 130 | + */ | |
| 131 | + public void cancelRecord() { | |
| 132 | + | |
| 133 | + try { | |
| 134 | + | |
| 135 | + mMediaRecorder.stop(); | |
| 136 | + mMediaRecorder.reset(); | |
| 137 | + mMediaRecorder.release(); | |
| 138 | + mMediaRecorder = null; | |
| 139 | + | |
| 140 | + } catch (RuntimeException e) { | |
| 141 | + mMediaRecorder.reset(); | |
| 142 | + mMediaRecorder.release(); | |
| 143 | + mMediaRecorder = null; | |
| 144 | + } | |
| 145 | + File file = new File(filePath); | |
| 146 | + if (file.exists()) | |
| 147 | + file.delete(); | |
| 148 | + | |
| 149 | + filePath = ""; | |
| 150 | + | |
| 151 | + } | |
| 152 | + | |
| 153 | + private final Handler mHandler = new Handler(); | |
| 154 | + private Runnable mUpdateMicStatusTimer = new Runnable() { | |
| 155 | + public void run() { | |
| 156 | + updateMicStatus(); | |
| 157 | + } | |
| 158 | + }; | |
| 159 | + | |
| 160 | + | |
| 161 | + private int BASE = 1; | |
| 162 | + private int SPACE = 100;// 间隔取样时间 | |
| 163 | + | |
| 164 | + public void setOnAudioStatusUpdateListener(OnAudioStatusUpdateListener audioStatusUpdateListener) { | |
| 165 | + this.audioStatusUpdateListener = audioStatusUpdateListener; | |
| 166 | + } | |
| 167 | + | |
| 168 | + /** | |
| 169 | + * 更新麦克状态 | |
| 170 | + */ | |
| 171 | + private void updateMicStatus() { | |
| 172 | + | |
| 173 | + if (mMediaRecorder != null) { | |
| 174 | + double ratio = (double) mMediaRecorder.getMaxAmplitude() / BASE; | |
| 175 | + double db = 0;// 分贝 | |
| 176 | + if (ratio > 1) { | |
| 177 | + db = 20 * Math.log10(ratio); | |
| 178 | + if (null != audioStatusUpdateListener) { | |
| 179 | + audioStatusUpdateListener.onUpdate(db, System.currentTimeMillis() - startTime); | |
| 180 | + } | |
| 181 | + } | |
| 182 | + mHandler.postDelayed(mUpdateMicStatusTimer, SPACE); | |
| 183 | + } | |
| 184 | + } | |
| 185 | + | |
| 186 | + /** | |
| 187 | + * 删除本地录制的文件 | |
| 188 | + * @param filePath | |
| 189 | + */ | |
| 190 | + public void deleteRecordFile(String filePath) { | |
| 191 | + File file = new File(filePath); | |
| 192 | + if (file.exists()) | |
| 193 | + file.delete(); | |
| 194 | + } | |
| 195 | + | |
| 196 | + public interface OnAudioStatusUpdateListener { | |
| 197 | + /** | |
| 198 | + * 录音中... | |
| 199 | + * | |
| 200 | + * @param db 当前声音分贝 | |
| 201 | + * @param time 录音时长 | |
| 202 | + */ | |
| 203 | + public void onUpdate(double db, long time); | |
| 204 | + | |
| 205 | + /** | |
| 206 | + * 停止录音 | |
| 207 | + * | |
| 208 | + * @param filePath 保存路径 | |
| 209 | + */ | |
| 210 | + public void onStop(String filePath); | |
| 211 | + } | |
| 212 | + | |
| 213 | + private String getCurrentTime() { | |
| 214 | + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); | |
| 215 | + return sdf.format(System.currentTimeMillis()); | |
| 216 | + } | |
| 217 | +} | ... | ... |
app/src/main/java/com/cnlive/im/util/IVoiceManager.java
0 → 100644
app/src/main/java/com/cnlive/im/util/PlayerUtil.java
0 → 100644
| 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/java/com/cnlive/im/util/TimeUtils.java
0 → 100644
| 1 | +package com.cnlive.im.util; | |
| 2 | + | |
| 3 | + | |
| 4 | +import java.text.SimpleDateFormat; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * Created by fan on 2016/6/23. | |
| 8 | + */ | |
| 9 | +public class TimeUtils { | |
| 10 | + | |
| 11 | + //毫秒转秒 | |
| 12 | + public static String long2String(long time){ | |
| 13 | + | |
| 14 | + //毫秒转秒 | |
| 15 | + int sec = (int) time / 1000 ; | |
| 16 | + int min = sec / 60 ; //分钟 | |
| 17 | + sec = sec % 60 ; //秒 | |
| 18 | + if(min < 10){ //分钟补0 | |
| 19 | + if(sec < 10){ //秒补0 | |
| 20 | + return "0"+min+":0"+sec; | |
| 21 | + }else{ | |
| 22 | + return "0"+min+":"+sec; | |
| 23 | + } | |
| 24 | + }else{ | |
| 25 | + if(sec < 10){ //秒补0 | |
| 26 | + return min+":0"+sec; | |
| 27 | + }else{ | |
| 28 | + return min+":"+sec; | |
| 29 | + } | |
| 30 | + } | |
| 31 | + | |
| 32 | + } | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 返回当前时间的格式为 yyyy-MM-dd HH:mm:ss | |
| 36 | + * @return | |
| 37 | + */ | |
| 38 | + public static String getCurrentTime() { | |
| 39 | + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); | |
| 40 | + return sdf.format(System.currentTimeMillis()); | |
| 41 | + } | |
| 42 | + | |
| 43 | + | |
| 44 | +} | ... | ... |
app/src/main/res/drawable-hdpi/keybord.png
0 → 100644
1.07 KB
app/src/main/res/drawable-hdpi/pic.png
0 → 100644
1.09 KB
app/src/main/res/drawable-hdpi/record_bottom.png
0 → 100644
5.5 KB
app/src/main/res/drawable-hdpi/record_top.png
0 → 100644
6.13 KB
app/src/main/res/drawable-hdpi/send_cancel.png
0 → 100644
788 Bytes
app/src/main/res/drawable-hdpi/voice.png
0 → 100644
1.2 KB
app/src/main/res/drawable-hdpi/voice_bg_left.png
0 → 100644
618 Bytes
app/src/main/res/drawable-hdpi/voice_bg_right.png
0 → 100644
607 Bytes
app/src/main/res/drawable-hdpi/voice_msg_left.png deleted
100644 → 0
1.2 KB
app/src/main/res/drawable-hdpi/voice_msg_right.9.png deleted
100644 → 0
1.19 KB
app/src/main/res/drawable/record_microphone.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > | |
| 3 | + <item android:id="@android:id/background" android:drawable="@drawable/record_top" /> | |
| 4 | + <item android:id="@android:id/progress" > | |
| 5 | + <clip android:drawable="@drawable/record_bottom" android:gravity="bottom" android:clipOrientation="vertical" /> | |
| 6 | + </item> | |
| 7 | +</layer-list> | |
| 0 | 8 | \ No newline at end of file | ... | ... |
app/src/main/res/drawable/record_microphone_bj.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<shape xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + android:shape="rectangle"> | |
| 4 | + | |
| 5 | + <corners | |
| 6 | + android:radius="8dp" /> | |
| 7 | + | |
| 8 | + <solid | |
| 9 | + android:color="@color/colorGray" /> | |
| 10 | + | |
| 11 | +</shape> | |
| 0 | 12 | \ No newline at end of file | ... | ... |
app/src/main/res/drawable/voice_bg.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | + | |
| 3 | +<shape xmlns:android="http://schemas.android.com/apk/res/android"> | |
| 4 | + <solid android:color="#ffffff" /> | |
| 5 | + <corners | |
| 6 | + android:bottomLeftRadius="10dp" | |
| 7 | + android:bottomRightRadius="10dp" | |
| 8 | + android:topLeftRadius="10dp" | |
| 9 | + android:topRightRadius="10dp" /> | |
| 10 | + <stroke | |
| 11 | + android:width="1dp" | |
| 12 | + android:color="#8a8a8a" /> | |
| 13 | +</shape> | |
| 0 | 14 | \ No newline at end of file | ... | ... |
app/src/main/res/layout/activity_groupchat.xml
| ... | ... | @@ -11,7 +11,8 @@ |
| 11 | 11 | android:layout_alignParentLeft="true" |
| 12 | 12 | android:layout_alignParentStart="true" |
| 13 | 13 | android:layout_alignParentTop="true" |
| 14 | - android:visibility="visible"> | |
| 14 | + android:visibility="visible" | |
| 15 | + android:clickable="true"> | |
| 15 | 16 | |
| 16 | 17 | <LinearLayout |
| 17 | 18 | android:id="@+id/listVIewTop" |
| ... | ... | @@ -30,7 +31,7 @@ |
| 30 | 31 | <android.support.v7.widget.RecyclerView |
| 31 | 32 | android:id="@+id/chat_list_viewOne" |
| 32 | 33 | android:layout_width="fill_parent" |
| 33 | - android:layout_height="170dp" | |
| 34 | + android:layout_height="200dp" | |
| 34 | 35 | android:layout_above="@+id/edit_layout" |
| 35 | 36 | android:divider="@null" |
| 36 | 37 | android:fastScrollEnabled="true" |
| ... | ... | @@ -45,13 +46,39 @@ |
| 45 | 46 | android:layout_alignParentBottom="true" |
| 46 | 47 | android:orientation="horizontal"> |
| 47 | 48 | |
| 49 | + <ImageView | |
| 50 | + android:id="@+id/keybord" | |
| 51 | + android:layout_width="0dp" | |
| 52 | + android:layout_height="wrap_content" | |
| 53 | + android:layout_gravity="center_vertical" | |
| 54 | + android:layout_weight="0.1" | |
| 55 | + android:src="@drawable/voice" /> | |
| 56 | + | |
| 48 | 57 | <EditText |
| 49 | 58 | android:id="@+id/message_content" |
| 50 | 59 | android:layout_width="0dp" |
| 51 | 60 | android:layout_height="wrap_content" |
| 52 | 61 | android:layout_gravity="center" |
| 53 | - android:layout_weight="0.7" /> | |
| 62 | + android:layout_weight="0.6" /> | |
| 54 | 63 | |
| 64 | + <Button | |
| 65 | + android:id="@+id/send_voice" | |
| 66 | + android:layout_width="0dp" | |
| 67 | + android:layout_height="40dp" | |
| 68 | + android:layout_margin="10dp" | |
| 69 | + android:layout_weight="0.6" | |
| 70 | + android:background="@drawable/voice_bg" | |
| 71 | + android:text="按住说话" | |
| 72 | + android:visibility="gone" /> | |
| 73 | + | |
| 74 | + <ImageView | |
| 75 | + android:id="@+id/ima_send" | |
| 76 | + android:layout_width="0dp" | |
| 77 | + android:layout_height="wrap_content" | |
| 78 | + android:layout_gravity="center_vertical" | |
| 79 | + android:layout_weight="0.1" | |
| 80 | + android:src="@drawable/pic" | |
| 81 | + android:visibility="visible"/> | |
| 55 | 82 | |
| 56 | 83 | <Button |
| 57 | 84 | android:id="@+id/send_messageOne" |
| ... | ... | @@ -59,7 +86,8 @@ |
| 59 | 86 | android:layout_height="wrap_content" |
| 60 | 87 | android:layout_gravity="center" |
| 61 | 88 | android:layout_weight="0.2" |
| 62 | - android:text="发送" /> | |
| 89 | + android:text="发送" | |
| 90 | + android:visibility="gone"/> | |
| 63 | 91 | |
| 64 | 92 | </LinearLayout> |
| 65 | 93 | |
| ... | ... | @@ -80,18 +108,11 @@ |
| 80 | 108 | android:layout_height="wrap_content" |
| 81 | 109 | android:text="加入聊天室" /> |
| 82 | 110 | |
| 83 | - <Button | |
| 84 | - android:id="@+id/ima_send" | |
| 85 | - android:layout_width="wrap_content" | |
| 86 | - android:layout_height="wrap_content" | |
| 87 | - android:text="图片" /> | |
| 88 | - | |
| 89 | - <Button | |
| 90 | - android:id="@+id/voice_send" | |
| 91 | - android:layout_width="wrap_content" | |
| 92 | - android:layout_height="wrap_content" | |
| 93 | - android:text="语音" /> | |
| 94 | - | |
| 111 | + <!--<Button--> | |
| 112 | + <!--android:id="@+id/ima_send"--> | |
| 113 | + <!--android:layout_width="wrap_content"--> | |
| 114 | + <!--android:layout_height="wrap_content"--> | |
| 115 | + <!--android:text="图片" />--> | |
| 95 | 116 | |
| 96 | 117 | <Button |
| 97 | 118 | android:id="@+id/exit_chat1" | ... | ... |
app/src/main/res/layout/imag_layout_item_oppsite.xml
| ... | ... | @@ -2,7 +2,9 @@ |
| 2 | 2 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| 3 | 3 | android:layout_width="match_parent" |
| 4 | 4 | android:layout_height="match_parent" |
| 5 | - android:orientation="vertical"> | |
| 5 | + android:orientation="vertical" | |
| 6 | + android:paddingBottom="10dp" | |
| 7 | + android:paddingTop="10dp"> | |
| 6 | 8 | |
| 7 | 9 | |
| 8 | 10 | <RelativeLayout | ... | ... |
app/src/main/res/layout/imag_layout_item_user.xml
| ... | ... | @@ -2,7 +2,9 @@ |
| 2 | 2 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| 3 | 3 | android:layout_width="match_parent" |
| 4 | 4 | android:layout_height="match_parent" |
| 5 | - android:orientation="vertical"> | |
| 5 | + android:orientation="vertical" | |
| 6 | + android:paddingBottom="10dp" | |
| 7 | + android:paddingTop="10dp"> | |
| 6 | 8 | |
| 7 | 9 | <RelativeLayout |
| 8 | 10 | android:layout_width="wrap_content" | ... | ... |
app/src/main/res/layout/layout_microphone.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 | + | |
| 7 | + <LinearLayout | |
| 8 | + android:id="@+id/send_layout" | |
| 9 | + android:layout_width="wrap_content" | |
| 10 | + android:layout_height="wrap_content" | |
| 11 | + android:background="@drawable/record_microphone_bj" | |
| 12 | + android:gravity="center" | |
| 13 | + android:orientation="vertical" | |
| 14 | + android:padding="16dp" | |
| 15 | + android:layout_centerInParent="true"> | |
| 16 | + | |
| 17 | + <ImageView | |
| 18 | + android:id="@+id/iv_recording_icon" | |
| 19 | + android:layout_width="48dp" | |
| 20 | + android:layout_height="48dp" | |
| 21 | + android:src="@drawable/record_microphone" /> | |
| 22 | + | |
| 23 | + <TextView | |
| 24 | + android:id="@+id/tv_recording_time" | |
| 25 | + android:layout_width="114dp" | |
| 26 | + android:layout_height="wrap_content" | |
| 27 | + android:layout_marginTop="6dp" | |
| 28 | + android:gravity="center" | |
| 29 | + android:text="00:00" | |
| 30 | + android:textColor="#FFFFFF" | |
| 31 | + android:textSize="16sp" /> | |
| 32 | + | |
| 33 | + <TextView | |
| 34 | + android:layout_width="wrap_content" | |
| 35 | + android:layout_height="wrap_content" | |
| 36 | + android:text="上滑取消发送" | |
| 37 | + android:textColor="@android:color/white" | |
| 38 | + android:textSize="16sp" /> | |
| 39 | + </LinearLayout> | |
| 40 | + | |
| 41 | + <LinearLayout | |
| 42 | + android:id="@+id/cancel_send_layout" | |
| 43 | + android:layout_width="wrap_content" | |
| 44 | + android:layout_height="wrap_content" | |
| 45 | + android:background="@drawable/record_microphone_bj" | |
| 46 | + android:gravity="center" | |
| 47 | + android:orientation="vertical" | |
| 48 | + android:padding="16dp" | |
| 49 | + android:visibility="gone" | |
| 50 | + android:layout_centerInParent="true"> | |
| 51 | + | |
| 52 | + <ImageView | |
| 53 | + android:layout_width="48dp" | |
| 54 | + android:layout_height="48dp" | |
| 55 | + android:src="@drawable/send_cancel" /> | |
| 56 | + | |
| 57 | + <TextView | |
| 58 | + android:layout_width="wrap_content" | |
| 59 | + android:layout_height="wrap_content" | |
| 60 | + android:text="松开手指,取消发送" | |
| 61 | + android:textColor="#ffffff" | |
| 62 | + android:textSize="16sp" /> | |
| 63 | + </LinearLayout> | |
| 64 | +</RelativeLayout> | |
| 0 | 65 | \ No newline at end of file | ... | ... |
app/src/main/res/layout/string_layout_item_oppsite.xml
| ... | ... | @@ -2,7 +2,9 @@ |
| 2 | 2 | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| 3 | 3 | android:layout_width="wrap_content" |
| 4 | 4 | android:layout_height="wrap_content" |
| 5 | - android:orientation="vertical"> | |
| 5 | + android:orientation="vertical" | |
| 6 | + android:paddingTop="10dp" | |
| 7 | + android:paddingBottom="10dp"> | |
| 6 | 8 | |
| 7 | 9 | <RelativeLayout |
| 8 | 10 | android:id="@+id/re_chat_room" |
| ... | ... | @@ -25,7 +27,8 @@ |
| 25 | 27 | android:layout_toRightOf="@id/user_name" |
| 26 | 28 | android:text="vfgfgf" |
| 27 | 29 | android:textColor="@android:color/black" |
| 28 | - android:textSize="15sp" /> | |
| 30 | + android:textSize="15sp" | |
| 31 | + android:layout_marginLeft="5dp"/> | |
| 29 | 32 | </RelativeLayout> |
| 30 | 33 | |
| 31 | 34 | </RelativeLayout> |
| 32 | 35 | \ No newline at end of file | ... | ... |
app/src/main/res/layout/string_layout_item_user.xml
| 1 | 1 | <?xml version="1.0" encoding="utf-8"?> |
| 2 | 2 | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| 3 | 3 | android:layout_width="wrap_content" |
| 4 | - android:layout_height="wrap_content"> | |
| 4 | + android:layout_height="wrap_content" | |
| 5 | + android:paddingBottom="10dp" | |
| 6 | + android:paddingTop="10dp"> | |
| 5 | 7 | |
| 6 | 8 | <RelativeLayout |
| 7 | 9 | android:id="@+id/re_chat_room" |
| ... | ... | @@ -25,7 +27,8 @@ |
| 25 | 27 | android:layout_toLeftOf="@id/user_name" |
| 26 | 28 | android:text="vfgfgf" |
| 27 | 29 | android:textColor="@android:color/black" |
| 28 | - android:textSize="15sp" /> | |
| 30 | + android:textSize="15sp" | |
| 31 | + android:layout_marginRight="5dp"/> | |
| 29 | 32 | </RelativeLayout> |
| 30 | 33 | |
| 31 | 34 | ... | ... |
app/src/main/res/layout/voice_layout_item_oppsite.xml
| 1 | 1 | <?xml version="1.0" encoding="utf-8"?> |
| 2 | 2 | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| 3 | 3 | android:layout_width="wrap_content" |
| 4 | - android:layout_height="wrap_content"> | |
| 4 | + android:layout_height="wrap_content" | |
| 5 | + android:paddingBottom="10dp" | |
| 6 | + android:paddingTop="10dp"> | |
| 5 | 7 | |
| 6 | 8 | |
| 7 | 9 | <RelativeLayout |
| ... | ... | @@ -16,12 +18,20 @@ |
| 16 | 18 | android:layout_centerVertical="true" |
| 17 | 19 | android:text="游客" /> |
| 18 | 20 | |
| 19 | - <ImageView | |
| 21 | + <TextView | |
| 20 | 22 | android:id="@+id/voice_content" |
| 21 | 23 | android:layout_width="wrap_content" |
| 22 | - android:layout_height="wrap_content" | |
| 24 | + android:layout_height="50dp" | |
| 23 | 25 | android:layout_toRightOf="@+id/voice_user_name" |
| 24 | - android:src="@drawable/voice_msg_left" /> | |
| 26 | + android:background="@drawable/voice_bg_left" | |
| 27 | + android:layout_marginLeft="5dp"/> | |
| 28 | + | |
| 29 | + <TextView | |
| 30 | + android:id="@+id/voice_duration" | |
| 31 | + android:layout_width="wrap_content" | |
| 32 | + android:layout_height="wrap_content" | |
| 33 | + android:layout_centerVertical="true" | |
| 34 | + android:layout_toRightOf="@id/voice_content" /> | |
| 25 | 35 | |
| 26 | 36 | |
| 27 | 37 | </RelativeLayout> | ... | ... |
app/src/main/res/layout/voice_layout_item_user.xml
| 1 | 1 | <?xml version="1.0" encoding="utf-8"?> |
| 2 | 2 | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| 3 | 3 | android:layout_width="wrap_content" |
| 4 | - android:layout_height="wrap_content"> | |
| 4 | + android:layout_height="wrap_content" | |
| 5 | + android:paddingBottom="10dp" | |
| 6 | + android:paddingTop="10dp"> | |
| 5 | 7 | |
| 6 | 8 | <RelativeLayout |
| 7 | 9 | android:layout_width="wrap_content" |
| ... | ... | @@ -15,12 +17,20 @@ |
| 15 | 17 | android:layout_centerVertical="true" |
| 16 | 18 | android:text="游客" /> |
| 17 | 19 | |
| 18 | - <ImageView | |
| 20 | + <TextView | |
| 19 | 21 | android:id="@+id/voice_content" |
| 20 | 22 | android:layout_width="wrap_content" |
| 21 | - android:layout_height="wrap_content" | |
| 23 | + android:layout_height="50dp" | |
| 22 | 24 | android:layout_toLeftOf="@+id/voice_user_name" |
| 23 | - android:src="@drawable/voice_msg_right" /> | |
| 25 | + android:background="@drawable/voice_bg_right" | |
| 26 | + android:layout_marginRight="5dp"/> | |
| 27 | + | |
| 28 | + <TextView | |
| 29 | + android:id="@+id/voice_duration" | |
| 30 | + android:layout_width="wrap_content" | |
| 31 | + android:layout_height="wrap_content" | |
| 32 | + android:layout_centerVertical="true" | |
| 33 | + android:layout_toLeftOf="@id/voice_content" /> | |
| 24 | 34 | |
| 25 | 35 | </RelativeLayout> |
| 26 | 36 | ... | ... |