diff --git a/app/build.gradle b/app/build.gradle
index cd87bba..c4889a3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -45,5 +45,6 @@ dependencies {
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:support-v4:25.3.1'
compile 'com.google.android:flexbox:0.3.0'
+ compile 'com.android.support:recyclerview-v7:25.3.1'
testCompile 'junit:junit:4.12'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 273569a..c7afcc6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -25,10 +25,11 @@
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
- android:windowSoftInputMode="stateHidden"
- android:screenOrientation="portrait">
+ android:screenOrientation="portrait"
+ android:windowSoftInputMode="stateHidden">
+
diff --git a/app/src/main/java/com/example/zhiruili/videoconf/MainActivity.java b/app/src/main/java/com/example/zhiruili/videoconf/MainActivity.java
index fcf9014..c15bb6e 100644
--- a/app/src/main/java/com/example/zhiruili/videoconf/MainActivity.java
+++ b/app/src/main/java/com/example/zhiruili/videoconf/MainActivity.java
@@ -3,7 +3,6 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.support.design.widget.BottomNavigationView;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
@@ -13,12 +12,10 @@
import android.view.MenuItem;
import android.view.ViewGroup;
-import com.example.zhiruili.utils.ViewUtils;
import com.example.zhiruili.videoconf.call.account.ILiveHelper;
import com.example.zhiruili.videoconf.call.constants.CallResultCode;
import com.tencent.callsdk.ILVCallConfig;
import com.tencent.callsdk.ILVCallConstants;
-import com.tencent.callsdk.ILVCallListener;
import com.tencent.callsdk.ILVCallManager;
import com.tencent.callsdk.ILVCallNotification;
import com.tencent.callsdk.ILVCallNotificationListener;
@@ -38,11 +35,14 @@ public final class MainActivity
extends AppCompatActivity
implements
ToCallBufferFragment.OnFragmentInteractionListener,
- ILVCallNotificationListener, ILVIncomingListener, ILVCallListener {
+ RecentCallsFragment.OnFragmentInteractionListener,
+ ILVCallNotificationListener, ILVIncomingListener {
private static final String TAG = MainActivity.class.getSimpleName();
private ViewGroup mMainContainer;
+ private ToCallBufferFragment mToCallBuffer;
+ private RecentCallsFragment mRecentCallsList;
private static final class RequestCode {
public static final int REQ_CALL = 0;
@@ -50,26 +50,6 @@ private static final class RequestCode {
// 是否登录
private boolean mHasLogin = false;
- // 当前导航 tab id
- private int mCurrNavItemId = -1;
- // 导航 tab 点击事件监听器
- private BottomNavigationView.OnNavigationItemSelectedListener
- mOnNavigationItemSelectedListener = item -> {
-
- Log.d(TAG, "Select item " + item.getItemId());
- int itemId = item.getItemId();
- if (itemId == mCurrNavItemId) {
- return false;
- }
- if (itemId == R.id.navigation_recent_calls) {
-
- } else if (itemId == R.id.navigation_contacts) {
-
- } else {
- return false;
- }
- return true;
- };
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -86,7 +66,6 @@ protected void onCreate(Bundle savedInstanceState) {
mHasLogin = intent.getBooleanExtra(getString(R.string.intent_extra_has_login), false);
if (mHasLogin) {
Log.v(TAG, "User has login");
- initViews();
initCallSdk();
return;
}
@@ -105,7 +84,6 @@ protected void onCreate(Bundle savedInstanceState) {
_ignore -> {
Log.v(TAG, "login success");
mHasLogin = true;
- initViews();
initCallSdk();
},
err -> {
@@ -115,13 +93,8 @@ protected void onCreate(Bundle savedInstanceState) {
gotoLogin();
});
}
- ViewUtils.hideKeyboard(this);
- }
-
- private void initViews() {
- BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
- navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
- navigation.setSelectedItemId(R.id.navigation_recent_calls);
+ mToCallBuffer = (ToCallBufferFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_to_call_buffer);
+ mRecentCallsList = (RecentCallsFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_recent_calls_list);
}
@Override
@@ -146,11 +119,9 @@ private void initCallSdk() {
private void registerCallSdkListeners() {
ILVCallManager.getInstance().addIncomingListener(this);
- ILVCallManager.getInstance().addCallListener(this);
}
private void unregisterCallSdkListeners() {
- ILVCallManager.getInstance().removeCallListener(this);
ILVCallManager.getInstance().removeIncomingListener(this);
}
@@ -274,6 +245,11 @@ public void onStartCalling(ArrayList calledIds) {
gotoCall(ILiveLoginManager.getInstance().getMyUserId(), 0, ILVCallConstants.CALL_TYPE_VIDEO, calledIds);
}
+ @Override
+ public void onListItemClick(String callId) {
+ mToCallBuffer.addIdToBuffer(callId);
+ }
+
@Override
public void onRecvNotification(int callId, ILVCallNotification notification) {
Log.d(TAG, "onRecvNotification, callId: " + callId);
@@ -282,17 +258,20 @@ public void onRecvNotification(int callId, ILVCallNotification notification) {
@Override
public void onNewIncomingCall(int callId, int callType, ILVIncomingNotification notification) {
Log.d(TAG, "onNewIncomingCall, callId: " + callId + ", callType: " + callType);
- Log.d(TAG, "onNewIncomingCall, sponsorId: " + notification.getSponsorId() + ", sender: " + notification.getSender() + ", members: " + notification.getMembersString());
+ Log.d(TAG, "onNewIncomingCall, sponsorId: " + notification.getSponsorId() +
+ ", sender: " + notification.getSender() +
+ ", members: " + notification.getMembersString());
final String membersMsg;
if (notification.getMembersString() == null) {
membersMsg = "";
} else {
- membersMsg = "\n其他参与者:" + notification.getMembersString();
+ membersMsg = "\n参与者:" + notification.getMembersString();
}
new AlertDialog.Builder(this)
.setTitle("新会议请求")
.setMessage("会议发起人:" + notification.getSponsorId() + membersMsg)
- .setNegativeButton("拒绝", null)
+ .setNegativeButton("拒绝",
+ (dialog, which) -> ILVCallManager.getInstance().rejectCall(callId))
.setPositiveButton("接受", (dialog, which) -> {
final ArrayList members = new ArrayList<>();
if (notification.getMembers() != null) {
@@ -304,21 +283,13 @@ public void onNewIncomingCall(int callId, int callType, ILVIncomingNotification
}
private void gotoCall(String sponsor, int callId, int callType, ArrayList members) {
- startActivityForResult(CallActivity.createIntent(this, callId, callType, sponsor, members), RequestCode.REQ_CALL);
- }
-
- @Override
- public void onCallEstablish(int callId) {
- Log.d(TAG, "onCallEstablish, callId: " + callId);
- }
-
- @Override
- public void onCallEnd(int callId, int endResult, String endInfo) {
- Log.d(TAG, "onCallEnd, callId: " + callId + ", endResult: " + endResult);
- }
-
- @Override
- public void onException(int iExceptionId, int errCode, String errMsg) {
- Log.d(TAG, "onException, exceptionId: " + iExceptionId + ", errorCode: " + errCode + ", errMsg: " + errMsg);
+// mRecentCallsList
+// .updateCalls(members, callId != 0)
+// .subscribeOn(Schedulers.io())
+// .observeOn(AndroidSchedulers.mainThread())
+// .subscribe(success -> {
+// Log.d(TAG, "gotoCall success = " + success);
+ startActivityForResult(CallActivity.createIntent(this, callId, callType, sponsor, members), RequestCode.REQ_CALL);
+// });
}
}
diff --git a/app/src/main/java/com/example/zhiruili/videoconf/RecentCallsFragment.java b/app/src/main/java/com/example/zhiruili/videoconf/RecentCallsFragment.java
new file mode 100644
index 0000000..d368289
--- /dev/null
+++ b/app/src/main/java/com/example/zhiruili/videoconf/RecentCallsFragment.java
@@ -0,0 +1,117 @@
+package com.example.zhiruili.videoconf;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.example.zhiruili.videoconf.data.RecentCallsDbHelper;
+import com.example.zhiruili.videoconf.data.RecentCallsListContract.*;
+import com.example.zhiruili.videoconf.data.TestHelper;
+
+import java.util.List;
+
+import io.reactivex.Single;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+public class RecentCallsFragment extends Fragment {
+
+ private OnFragmentInteractionListener mInteractionListener;
+ private RecentCallsListAdapter mListAdapter = null;
+ private SQLiteDatabase mDb;
+
+ public RecentCallsFragment() { }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View rootView = inflater.inflate(R.layout.fragment_recent_calls, container, false);
+ final RecyclerView callsListView = (RecyclerView) rootView.findViewById(R.id.rv_recent_calls_list);
+ callsListView.setLayoutManager(new LinearLayoutManager(rootView.getContext()));
+
+ Single
+ .fromCallable(() -> new RecentCallsDbHelper(getActivity()).getWritableDatabase())
+ .doOnSuccess(db -> mDb = db)
+ // .doOnSuccess(TestHelper::insertFakeData)
+ .map(_ignore -> getAllRecentCalls())
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .map(cursor -> new RecentCallsListAdapter(rootView.getContext(), cursor, mInteractionListener::onListItemClick))
+ .doOnSuccess(adapter -> mListAdapter = adapter)
+ .doOnSuccess(callsListView::setAdapter)
+ .doOnError(Throwable::printStackTrace)
+ .subscribe();
+
+ return rootView;
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof OnFragmentInteractionListener) {
+ mInteractionListener = (OnFragmentInteractionListener) context;
+ } else {
+ throw new RuntimeException(context.toString()
+ + " must implement OnFragmentInteractionListener");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mInteractionListener = null;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ }
+
+ public interface OnFragmentInteractionListener {
+ void onListItemClick(String callId);
+ }
+
+ public Single updateCalls(List callIds, boolean isCallIn) {
+ return Single
+ .fromCallable(() -> {
+ mDb.beginTransaction();
+ for (String id : callIds) {
+ mDb.delete(RecentCallsListEntry.TABLE_NAME, RecentCallsListEntry.COLUMN_PERSON_ID + "=?", new String[] { id });
+ }
+ for (String id : callIds) {
+ ContentValues cv = new ContentValues();
+ cv.put(RecentCallsListEntry.COLUMN_PERSON_ID, id);
+ cv.put(RecentCallsListEntry.COLUMN_IS_CALL_IN, isCallIn);
+ mDb.insert(RecentCallsListEntry.TABLE_NAME, null, cv);
+ }
+ mDb.setTransactionSuccessful();
+ return true;
+ })
+ .doFinally(() -> mDb.endTransaction())
+ .map(_ignore -> getAllRecentCalls())
+ .doOnError(Throwable::printStackTrace)
+ .subscribeOn(Schedulers.io())
+ .doOnSuccess(mListAdapter::swapCursor)
+ .subscribeOn(AndroidSchedulers.mainThread())
+ .map(_ignore -> true)
+ .onErrorReturn(err -> {
+ err.printStackTrace();
+ return false;
+ });
+ }
+
+ public Cursor getAllRecentCalls() {
+ return mDb.query(
+ RecentCallsListEntry.TABLE_NAME,
+ null, null, null, null, null,
+ RecentCallsListEntry.COLUMN_CALL_TIME + " DESC");
+ }
+}
diff --git a/app/src/main/java/com/example/zhiruili/videoconf/RecentCallsListAdapter.java b/app/src/main/java/com/example/zhiruili/videoconf/RecentCallsListAdapter.java
new file mode 100644
index 0000000..2fe6c23
--- /dev/null
+++ b/app/src/main/java/com/example/zhiruili/videoconf/RecentCallsListAdapter.java
@@ -0,0 +1,76 @@
+package com.example.zhiruili.videoconf;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.example.zhiruili.videoconf.data.RecentCallsListContract.*;
+
+public class RecentCallsListAdapter extends RecyclerView.Adapter {
+
+ private Context mContext;
+ private Cursor mCursor;
+ private OnItemClickListener mClickListener;
+
+ public RecentCallsListAdapter(Context context, Cursor cursor, OnItemClickListener listener) {
+ mContext = context;
+ mCursor = cursor;
+ mClickListener = listener;
+ }
+
+ @Override
+ public RecentCallViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ View view = inflater.inflate(R.layout.recent_calls_list_item, parent, false);
+ return new RecentCallViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(RecentCallViewHolder holder, int position) {
+ if (!mCursor.moveToPosition(position)) {
+ return;
+ }
+ int idxCallId = mCursor.getColumnIndex(RecentCallsListEntry.COLUMN_PERSON_ID);
+ String callId = mCursor.getString(idxCallId);
+ int idxIsCallIn = mCursor.getColumnIndex(RecentCallsListEntry.COLUMN_IS_CALL_IN);
+ boolean isCallIn = mCursor.getInt(idxIsCallIn) != 0;
+ int idxCallTime = mCursor.getColumnIndex(RecentCallsListEntry.COLUMN_CALL_TIME);
+ String callTimeString = mCursor.getString(idxCallTime);
+ holder.callId.setText(callId);
+ holder.callTime.setText(callTimeString);
+ holder.callInOrOut.setText(isCallIn ? mContext.getString(R.string.label_call_in) : mContext.getString(R.string.label_call_out));
+ }
+
+ void swapCursor(Cursor newCursor) {
+ mCursor = newCursor;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getItemCount() {
+ return mCursor.getCount();
+ }
+
+ class RecentCallViewHolder extends RecyclerView.ViewHolder {
+
+ TextView callId;
+ TextView callTime;
+ TextView callInOrOut;
+
+ public RecentCallViewHolder(View itemView) {
+ super(itemView);
+ callId = (TextView) itemView.findViewById(R.id.tv_call_id);
+ callTime = (TextView) itemView.findViewById(R.id.tv_call_time);
+ callInOrOut = (TextView) itemView.findViewById(R.id.tv_call_in_or_out);
+ itemView.setOnClickListener(v -> mClickListener.onClick(callId.getText().toString()));
+ }
+ }
+
+ public interface OnItemClickListener {
+ void onClick(String callId);
+ }
+}
diff --git a/app/src/main/java/com/example/zhiruili/videoconf/data/RecentCallsDbHelper.java b/app/src/main/java/com/example/zhiruili/videoconf/data/RecentCallsDbHelper.java
new file mode 100644
index 0000000..0108ce2
--- /dev/null
+++ b/app/src/main/java/com/example/zhiruili/videoconf/data/RecentCallsDbHelper.java
@@ -0,0 +1,36 @@
+package com.example.zhiruili.videoconf.data;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+import com.example.zhiruili.videoconf.data.RecentCallsListContract.*;
+
+public class RecentCallsDbHelper extends SQLiteOpenHelper {
+
+ private static final String DATABASE_NAME = "recent_calls.db";
+
+ private static final int DATABASE_VERSION = 1;
+
+ public RecentCallsDbHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ final String sqlCreateTable =
+ "CREATE TABLE " + RecentCallsListEntry.TABLE_NAME + "(" +
+ RecentCallsListEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ RecentCallsListEntry.COLUMN_PERSON_ID + " TEXT NOT NULL, " +
+ RecentCallsListEntry.COLUMN_IS_CALL_IN + " INTEGER NOT NULL, " +
+ RecentCallsListEntry.COLUMN_CALL_TIME + " TIMESTAMP DEFAULT CURRENT_TIMESTAMP" +
+ ");";
+ db.execSQL(sqlCreateTable);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL("DROP TABLE IF EXISTS " + RecentCallsListEntry.TABLE_NAME);
+ onCreate(db);
+ }
+}
diff --git a/app/src/main/java/com/example/zhiruili/videoconf/data/RecentCallsListContract.java b/app/src/main/java/com/example/zhiruili/videoconf/data/RecentCallsListContract.java
new file mode 100644
index 0000000..f7eaf9e
--- /dev/null
+++ b/app/src/main/java/com/example/zhiruili/videoconf/data/RecentCallsListContract.java
@@ -0,0 +1,16 @@
+package com.example.zhiruili.videoconf.data;
+
+import android.provider.BaseColumns;
+
+public class RecentCallsListContract {
+
+ private RecentCallsListContract() { }
+
+ public static final class RecentCallsListEntry implements BaseColumns {
+
+ public static final String TABLE_NAME = "recent_calls_list";
+ public static final String COLUMN_PERSON_ID = "person_id";
+ public static final String COLUMN_CALL_TIME = "call_time";
+ public static final String COLUMN_IS_CALL_IN = "is_call_in";
+ }
+}
diff --git a/app/src/main/java/com/example/zhiruili/videoconf/data/TestHelper.java b/app/src/main/java/com/example/zhiruili/videoconf/data/TestHelper.java
new file mode 100644
index 0000000..0072fe9
--- /dev/null
+++ b/app/src/main/java/com/example/zhiruili/videoconf/data/TestHelper.java
@@ -0,0 +1,38 @@
+package com.example.zhiruili.videoconf.data;
+
+import android.content.ContentValues;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+
+import com.example.zhiruili.videoconf.data.RecentCallsListContract.*;
+
+import java.util.ArrayList;
+
+public final class TestHelper {
+
+ public static void insertFakeData(SQLiteDatabase db) {
+
+ ArrayList list = new ArrayList() {{
+ for (int i = 10; i < 60; ++i) {
+ ContentValues cv = new ContentValues();
+ cv.put(RecentCallsListEntry.COLUMN_PERSON_ID, "alonglongid_" + i);
+ cv.put(RecentCallsListEntry.COLUMN_IS_CALL_IN, i % 3 == 0);
+ cv.put(RecentCallsListEntry.COLUMN_CALL_TIME, "2017-01-01 12:14:" + i);
+ add(cv);
+ }
+ }};
+ try {
+ db.beginTransaction();
+ db.delete(RecentCallsListEntry.TABLE_NAME, null, null);
+ for (ContentValues v : list) {
+ db.insert(RecentCallsListEntry.TABLE_NAME, null, v);
+ }
+ db.setTransactionSuccessful();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ } finally {
+ db.endTransaction();
+ }
+
+ }
+}
diff --git a/app/src/main/res/drawable/ic_format_list_bulleted_black_24dp.xml b/app/src/main/res/drawable/ic_format_list_bulleted_black_24dp.xml
deleted file mode 100644
index 6cb93c6..0000000
--- a/app/src/main/res/drawable/ic_format_list_bulleted_black_24dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_group_black_24dp.xml b/app/src/main/res/drawable/ic_group_black_24dp.xml
deleted file mode 100644
index 4cfd869..0000000
--- a/app/src/main/res/drawable/ic_group_black_24dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index b17cb5f..245a3ff 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -19,25 +19,21 @@
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:layout_width="0dp"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ tools:layout="@layout/fragment_to_call_buffer" />
-
-
-
diff --git a/app/src/main/res/layout/fragment_recent_calls.xml b/app/src/main/res/layout/fragment_recent_calls.xml
new file mode 100644
index 0000000..33ecb73
--- /dev/null
+++ b/app/src/main/res/layout/fragment_recent_calls.xml
@@ -0,0 +1,7 @@
+
diff --git a/app/src/main/res/layout/recent_calls_list_item.xml b/app/src/main/res/layout/recent_calls_list_item.xml
new file mode 100644
index 0000000..c031d6e
--- /dev/null
+++ b/app/src/main/res/layout/recent_calls_list_item.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/navigation.xml b/app/src/main/res/menu/navigation.xml
deleted file mode 100644
index 090a972..0000000
--- a/app/src/main/res/menu/navigation.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index f0426a8..c1c42ce 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -3,4 +3,5 @@
16dp
68dp
46dp
+ 16dp
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index df484b5..ad3da3c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -42,4 +42,7 @@
注销成功
无法添加更多的会议成员
+ 呼入
+ 呼出
+