获取通话记录

This commit is contained in:
GYJ 2024-11-23 15:22:23 +08:00
parent 87c41341fd
commit a82e726d5f
21 changed files with 430 additions and 6 deletions

View File

@ -21,14 +21,13 @@ android {
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.czg.cashier_reserve"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
minSdkVersion 26
targetSdkVersion 33
}
buildTypes {
@ -43,3 +42,8 @@ android {
flutter {
source = "../.."
}
dependencies {
implementation(name:'callmodule-release',ext:'aar')
implementation('com.android.support:appcompat-v7:28.0.0')
}

Binary file not shown.

View File

@ -1,7 +1,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<application
android:label="cashier_reserve"
android:name="${applicationName}"
android:name=".CzgApplication"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"

View File

@ -0,0 +1,36 @@
package com.czg.cashier_reserve;
import android.content.Context;
import io.flutter.plugin.common.BinaryMessenger;
public class ContextHolder {
private static ContextHolder instance;
private Context context;
private BinaryMessenger binaryMessenger;
private ContextHolder() {}
public static ContextHolder getInstance() {
if (instance == null) {
instance = new ContextHolder();
}
return instance;
}
public void setContext(Context context) {
this.context = context;
}
public Context getContext() {
return context;
}
public void setBinaryMessenger(BinaryMessenger binaryMessenger) {
this.binaryMessenger = binaryMessenger;
}
public BinaryMessenger getBinaryMessenger() {
return binaryMessenger;
}
}

View File

@ -0,0 +1,13 @@
package com.czg.cashier_reserve;
import cn.kaer.callmodule.KeSdk;
import io.flutter.Log;
import io.flutter.app.FlutterApplication;
public class CzgApplication extends FlutterApplication {
@Override
public void onCreate() {
super.onCreate();
}
}

View File

@ -1,6 +1,46 @@
package com.czg.cashier_reserve;
import android.os.Bundle;
import androidx.annotation.NonNull;
import com.czg.cashier_reserve.channel.ChannelManager;
import cn.kaer.callmodule.KeSdk;
import io.flutter.Log;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getFlutterEngine()!= null && getFlutterEngine().getDartExecutor().getBinaryMessenger()!= null) {
Log.i("MainActivity","onCreate +++ " + this);
} else {
Log.e("MainActivity", "FlutterEngine or BinaryMessenger is null, cannot setup EventChannel.");
}
}
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
Log.i("MainActivity","configureFlutterEngine +++ " + this);
ContextHolder.getInstance().setContext(this);
ContextHolder.getInstance().setBinaryMessenger(flutterEngine.getDartExecutor().getBinaryMessenger());
KeSdk.get().init(new KeSdk.Builder().setContext(this)//必选
.setClz(MainActivity.class)//可选 设置拉起通话页面
.setPstnIncomingDelay(2000)//可选 设置有线振铃延迟时间默认1500
.setAutoAnswerByHookoff(true)//可选 设置来电摘手柄自动接听默认false
.setRingPlayAuto(true)//可选 设置来电自动播放铃声默认true
.setPstnRingType(0)//可选 pstn设置铃声 0系统铃声 1和弦铃声
.setAutoTermByHookon(true)//可选 设置放手柄自动挂断默认false
.setAutoChangeChannelByHookoff(true));//可选 设置通话中摘手柄自动切换到手柄通道默认false
ChannelManager.createChannel(flutterEngine.getDartExecutor().getBinaryMessenger());
}
}

View File

@ -0,0 +1,70 @@
package com.czg.cashier_reserve.call;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.provider.CallLog;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.czg.cashier_reserve.ContextHolder;
import com.czg.cashier_reserve.channel.EventChannelManager;
import org.json.JSONArray;
import org.json.JSONObject;
import java.text.SimpleDateFormat;
import java.util.Date;
import io.flutter.Log;
public class CallManager {
private static final String[] columns = {CallLog.Calls.CACHED_NAME// 通话记录的联系人
, CallLog.Calls.NUMBER// 通话记录的电话号码
, CallLog.Calls.DATE// 通话记录的日期
, CallLog.Calls.DURATION// 通话时长
, CallLog.Calls.TYPE};// 通话类型}
public static void loadCallLog() {
Context mainActivityContext = ContextHolder.getInstance().getContext();
Log.i("CallManager","loadCallLog -- " + mainActivityContext);
Cursor cursor = mainActivityContext.getContentResolver().query(CallLog.Calls.CONTENT_URI,
columns, null, null, null);
JSONArray callLogArray = new JSONArray();
Log.i("CallManager","cursor count:" + cursor.getCount());
while (cursor.moveToNext()) {
@SuppressLint("Range") String name = cursor.getString(cursor.getColumnIndex(CallLog.Calls.CACHED_NAME)); //姓名
@SuppressLint("Range") String number = cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER)); //号码
@SuppressLint("Range") long dateLong = cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DATE)); //获取通话日期
@SuppressLint("SimpleDateFormat") String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(dateLong));
// @SuppressLint("SimpleDateFormat") String time = new SimpleDateFormat("HH:mm").format(new Date(dateLong));
@SuppressLint("Range") int duration = cursor.getInt(cursor.getColumnIndex(CallLog.Calls.DURATION));//获取通话时长值为多少秒
@SuppressLint("Range") int type = cursor.getInt(cursor.getColumnIndex(CallLog.Calls.TYPE)); //获取通话类型1.呼入2.呼出3.未接
// @SuppressLint("SimpleDateFormat") String dayCurrent = new SimpleDateFormat("dd").format(new Date());
// @SuppressLint("SimpleDateFormat") String dayRecord = new SimpleDateFormat("dd").format(new Date(dateLong));
JSONObject callLog = new JSONObject();
try {
callLog.put("name", name);
callLog.put("number", number);
callLog.put("date", date);
callLog.put("duration", duration);
callLog.put("type", type);
} catch (Exception e) {
e.printStackTrace();
}
callLogArray.put(callLog);
}
Log.i("CallManager", "callLogArray: " + callLogArray);
Intent broad = new Intent(EventChannelManager.Action.GET_CALL_LOG_FINISH);
broad.putExtra("callLog", callLogArray.toString());
mainActivityContext.sendBroadcast(broad);
Log.i("CallManager", "send broadcast");
}
}

View File

@ -0,0 +1,10 @@
package com.czg.cashier_reserve.channel;
import io.flutter.plugin.common.BinaryMessenger;
public class ChannelManager {
public static void createChannel(BinaryMessenger messenger) {
MessageChannel.addMessageChannel(messenger);
EventChannelManager.addEventChannel(messenger);
}
}

View File

@ -0,0 +1,13 @@
package com.czg.cashier_reserve.channel;
public class ChannelNames {
public static final String BASE_NAME = "com.czg.cashier_reserve/";
public static final String GET_CALL_LOG = "getCallLog";
public static final String CALL_LOG_CALLBACK = "callLogCallback";
public static String getChannelName(String name) {
return BASE_NAME + name;
}
}

View File

@ -0,0 +1,89 @@
package com.czg.cashier_reserve.channel;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import androidx.annotation.RequiresApi;
import com.czg.cashier_reserve.ContextHolder;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.Log;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
public class EventChannelManager {
public static Map<String, BroadcastReceiver> receiverMap = new HashMap<>();
public static List<BroadcastReceiver> broadcastReceiverList = new ArrayList<>();
private static EventChannel callLogChannel;
public static void addEventChannel(BinaryMessenger messenger) {
getCallLogCallback(messenger);
}
public static void getCallLogCallback(BinaryMessenger messenger) {
if (messenger == null) {
return;
}
Log.i("EventChannelManager", "getCallLogCallback");
callLogChannel = new EventChannel(messenger, ChannelNames.getChannelName(ChannelNames.CALL_LOG_CALLBACK));
callLogChannel.setStreamHandler(new EventChannel.StreamHandler() {
private BroadcastReceiver broadCast;
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
Log.i("EventChannelManager", "onListen");
broadCast = EventChannelManager.getBroadCast(eventSink);
Context context = ContextHolder.getInstance().getContext();
IntentFilter intentFilter = new IntentFilter(EventChannelManager.Action.GET_CALL_LOG_FINISH);
context.registerReceiver(broadCast, intentFilter);
receiverMap.put(EventChannelManager.Action.GET_CALL_LOG_FINISH, broadCast);
}
@Override
public void onCancel(Object o) {
Context context = ContextHolder.getInstance().getContext();
context.unregisterReceiver(broadCast);
broadcastReceiverList.remove(broadCast);
broadCast = null;
}
});
}
public static BroadcastReceiver getBroadCast(EventChannel.EventSink eventSink) {
BroadcastReceiver b = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("EventChannelManager", "onReceive");
String action = intent.getAction();
Log.i("EventChannelManager", "action name == " + action);
if (Action.GET_CALL_LOG_FINISH.equals(action)) {
String extra = intent.getStringExtra("callLog");
eventSink.success(extra);
} else {
eventSink.error("没有该事件", null, null);
}
}
};
broadcastReceiverList.add(b);
return b;
}
// 这里假设Action是一个定义了相关常量的类示例如下你可以根据实际情况调整
public static class Action {
public static final String GET_CALL_LOG_FINISH = ChannelNames.BASE_NAME + "get_call_log_finish";
}
}

View File

@ -0,0 +1,29 @@
package com.czg.cashier_reserve.channel;
import com.czg.cashier_reserve.call.CallManager;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodChannel;
public class MessageChannel {
public static void addMessageChannel(BinaryMessenger messenger) {
callLogChannel(messenger);
}
public static void callLogChannel(BinaryMessenger messenger) {
if (messenger == null) {
return;
}
MethodChannel methodChannel = new MethodChannel(messenger, ChannelNames.getChannelName(ChannelNames.GET_CALL_LOG));
methodChannel.setMethodCallHandler((call, result) -> {
System.out.println("call.method: " + call.method);
if (call.method.equals(ChannelNames.GET_CALL_LOG)) {
System.out.println("加载通话记录");
result.success(null);
CallManager.loadCallLog();
};
});
}
}

View File

@ -15,4 +15,13 @@
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
<style name="DialerDigit" parent="@android:style/TextAppearance.Medium">
<item name="android:padding">5dp</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_centerInParent">true</item>
<item name="android:soundEffectsEnabled">false</item>
<!-- <item name="android:background">@drawable/keyboard_numb_bg</item>-->
</style>
</resources>

View File

@ -1,10 +1,33 @@
allprojects {
repositories {
flatDir {
dirs 'libs'
}
google()
mavenCentral()
}
}
subprojects {
afterEvaluate { project ->
if (project.plugins.hasPlugin('com.android.library') || project.plugins.hasPlugin('com.android.application')) {
println "project: ${project.name} Namespace get: ${project.android.namespace}"
def packageName = project.android.namespace ?: project.android.defaultConfig.applicationId ?: project.android.sourceSets.main.manifest.srcFile.text.find(/package="([^"]*)"/) ?: project.group
// project.android.namespace = packageName
// println "Namespace set to: ${packageName} for project: ${project.name}"
// "com.baidu"
if (!packageName.contains('com.baidu')) {
project.android.namespace = packageName
println "Namespace set to: ${packageName} for project: ${project.name}"
} else {
println "Skipping namespace setting for project ${project.name} as the package name contains 'com.baidu'"
}
}
}
}
rootProject.buildDir = "../build"
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"

View File

@ -0,0 +1,27 @@
import 'package:cashier_reserve/common/print/print.dart';
import 'package:flutter/services.dart';
import 'names.dart';
class MyEventChannel {
static void startListener() {
onGetCallLogResult();
}
static void onGetCallLogResult() {
EventChannel channel = EventChannel(getChannelName(kCallLogCallback));
channel.receiveBroadcastStream().listen((Object? o) {
yjPrint("onGetCallLogResult");
yjPrint(o);
// AlipayPayResultEvent event = AlipayPayResultEvent();
// if (o is int) {
// event.resultStatus = o;
// } else {
// event.resultStatus = int.parse(o as String);
// }
// EventManager.postEvent(event);
}, onError: (Object error) {
yjPrint("onGetCallLogResult error");
});
}
}

View File

@ -0,0 +1,16 @@
import 'package:flutter/services.dart';
import '../print/print.dart';
import 'names.dart';
class ChannelManager {
static Future<void> getCallLog(String param) async {
MethodChannel channel = MethodChannel(getChannelName(kGetCallLog));
try {
final result = await channel.invokeMethod(kGetCallLog, param);
yjPrint(result);
} on PlatformException catch (e) {
yjPrint('$kGetCallLog 发生异常:$e');
}
}
}

View File

@ -0,0 +1,9 @@
const String kChannelBaseName = 'com.czg.cashier_reserve/';
const String kGetCallLog = 'getCallLog';
const String kCallLogCallback = 'callLogCallback';
String getChannelName(name) {
return kChannelBaseName + name;
}

View File

@ -0,0 +1,10 @@
import 'package:flutter/services.dart';
import '../channel/channel_event.dart';
class AppManager {
static Future<void> initThirdPackage() async {
MyEventChannel.startListener();
}
}

View File

@ -0,0 +1,8 @@
import 'package:flutter/foundation.dart';
void yjPrint(Object? object) {
if (kDebugMode) {
print(object);
}
}

View File

@ -77,7 +77,9 @@ class ReserveView extends BaseUI {
width: 5,
),
InkWell(
onTap: () {},
onTap: () {
provider.loadCallLog();
},
child: const SizedBox(
width: 40,
height: 40,

View File

@ -1,4 +1,5 @@
import 'package:cashier_reserve/common/base/ui_model.dart';
import 'package:cashier_reserve/common/channel/channel_manager.dart';
class ReserveViewModel extends BaseUIModel {
Map<int, String> weekdayMap = {
@ -16,6 +17,14 @@ class ReserveViewModel extends BaseUIModel {
1: "",
2: "",
};
// ReserveViewModel() {
// loadData();
// }
void loadCallLog() {
ChannelManager.getCallLog("getCallLog");
}
String getCurrentDate() {
DateTime now = DateTime.now();

View File

@ -1,5 +1,6 @@
import 'dart:io';
import 'package:cashier_reserve/common/manager/app_manager.dart';
import 'package:cashier_reserve/root_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -8,7 +9,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
import 'common/base/widgets.dart';
import 'common/local/cupertino_localizations_delegate.dart';
void main() {
void main() async {
WidgetsFlutterBinding.ensureInitialized();
///
@ -16,6 +17,9 @@ void main() {
statusBarColor: Colors.transparent,
statusBarIconBrightness: getAppBrightness(false),
statusBarBrightness: getAppBrightness(false)));
await AppManager.initThirdPackage();
runApp(const MyApp());
}