Skip to content
This repository was archived by the owner on Mar 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/phone_log/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## [0.0.2] - June 11th, 2018.
Update README and several fixes.

## [0.0.1] - June 11th, 2018.
Initial the plugin package.
21 changes: 21 additions & 0 deletions packages/phone_log/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 Google Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
41 changes: 41 additions & 0 deletions packages/phone_log/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# phone_log

A flutter plugin project to access the device phone log (Android only).

Currently only fetching the following 5 fields:
CallLog.Calls.CACHED_FORMATTED_NUMBER
CallLog.Calls.CACHED_MATCHED_NUMBER
CallLog.Calls.TYPE
CallLog.Calls.DATE
CallLog.Calls.DURATION

For iOS it is not possible to extract the call log programmatically. Apple officially does not expose any public API to access the call log. So all the method will return null on iOS.

## Getting Started

Make sure you add the permission below to your Android Manifest Permission:

```xml
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
```
## Usage in Dart

Import the relevant file:

```
import 'package:phone_log/phone_log.dart';
```

### Methods
```dart
/// Check phone log permission and return a [Future] with the result
Future<bool> checkPermission(Permission permission);

/// Request phone log permission and return a [Future] with the result
Future<bool> requestPermission(Permission permission);

/// Fetch the call log from Android device with a [startDate] and a
/// minimum [duration]. If startDate == null, all the data will be
/// fetched out. If duration == null, there will be no duration limit.
Future<Iterable<CallRecord>> getPhoneLogs();
```
34 changes: 34 additions & 0 deletions packages/phone_log/android/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
group 'com.jiajiabingcheng.phonelog'
version '1.0-SNAPSHOT'

buildscript {
repositories {
google()
jcenter()
}

dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
}

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

apply plugin: 'com.android.library'

android {
compileSdkVersion 27

defaultConfig {
minSdkVersion 16
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
}
}
1 change: 1 addition & 0 deletions packages/phone_log/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.gradle.jvmargs=-Xmx1536M
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#Wed Jun 13 15:42:51 PDT 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
1 change: 1 addition & 0 deletions packages/phone_log/android/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = 'phone_log'
4 changes: 4 additions & 0 deletions packages/phone_log/android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jiajiabingcheng.phonelog">
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.jiajiabingcheng.phonelog;

import java.util.HashMap;

class CallRecord {

CallRecord() {}

String formattedNumber;
String number;
String callType;
int dateYear;
int dateMonth;
int dateDay;
int dateHour;
int dateMinute;
int dateSecond;
long duration;

HashMap<String, Object> toMap() {
HashMap<String, Object> recordMap = new HashMap<>();
recordMap.put("formattedNumber", formattedNumber);
recordMap.put("number", number);
recordMap.put("callType", callType);
recordMap.put("dateYear", dateYear);
recordMap.put("dateMonth", dateMonth);
recordMap.put("dateDay", dateDay);
recordMap.put("dateHour", dateHour);
recordMap.put("dateMinute", dateMinute);
recordMap.put("dateSecond", dateSecond);
recordMap.put("duration", duration);

return recordMap;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
package com.jiajiabingcheng.phonelog;

import android.Manifest;
import android.annotation.TargetApi;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Build;
import android.provider.CallLog;
import android.util.Log;

import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.Registrar;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;

/**
* PhoneLogPlugin
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class PhoneLogPlugin implements MethodCallHandler,
PluginRegistry.RequestPermissionsResultListener {
private final Registrar registrar;
private Result pendingResult;

private PhoneLogPlugin(Registrar registrar) {
this.registrar = registrar;
}

public static void registerWith(Registrar registrar) {
final MethodChannel channel =
new MethodChannel(registrar.messenger(), "github.com/jiajiabingcheng/phone_log");
PhoneLogPlugin phoneLogPlugin = new PhoneLogPlugin(registrar);
channel.setMethodCallHandler(phoneLogPlugin);
registrar.addRequestPermissionsResultListener(phoneLogPlugin);
}

@Override
public void onMethodCall(MethodCall call, Result result) {
if (pendingResult != null) {
pendingResult.error("multiple_requests", "Cancelled by a second request.", null);
pendingResult = null;
}
pendingResult = result;
switch (call.method) {
case "checkPermission":
pendingResult.success(checkPermission());
pendingResult = null;
break;
case "requestPermission":
requestPermission();
break;
case "getPhoneLogs":
String startDate = call.argument("startDate");
String duration = call.argument("duration");
fetchCallRecords(startDate, duration);
break;
default:
result.notImplemented();
}
}

private void requestPermission() {
Log.i("PhoneLogPlugin", "Requesting permission : " + Manifest.permission.READ_CALL_LOG);
String[] perm = {Manifest.permission.READ_CALL_LOG};
registrar.activity().requestPermissions(perm, 0);
}

private boolean checkPermission() {
Log.i("PhoneLogPlugin", "Checking permission : " + Manifest.permission.READ_CALL_LOG);
return PackageManager.PERMISSION_GRANTED
== registrar.activity().checkSelfPermission(Manifest.permission.READ_CALL_LOG);
}

@Override
public boolean onRequestPermissionsResult(int requestCode,
String[] strings,
int[] grantResults) {
boolean res = false;
if (requestCode == 0 && grantResults.length > 0) {
res = grantResults[0] == PackageManager.PERMISSION_GRANTED;
pendingResult.success(res);
pendingResult = null;
}
return res;
}

private static final String[] PROJECTION =
{CallLog.Calls.CACHED_FORMATTED_NUMBER,
CallLog.Calls.CACHED_MATCHED_NUMBER,
CallLog.Calls.TYPE,
CallLog.Calls.DATE,
CallLog.Calls.DURATION,};

@TargetApi(Build.VERSION_CODES.M)
private void fetchCallRecords(String startDate, String duration) {
if (registrar.activity().checkSelfPermission(Manifest.permission.READ_CALL_LOG)
== PackageManager.PERMISSION_GRANTED) {
String selectionCondition = null;
if (startDate != null) {
selectionCondition = CallLog.Calls.DATE + "> " + startDate;
}
if (duration != null) {
String durationSelection = CallLog.Calls.DURATION + "> " + duration;
if (selectionCondition != null) {
selectionCondition = selectionCondition + " AND " + durationSelection;
} else {
selectionCondition = durationSelection;
}
}
Cursor cursor = registrar.context().getContentResolver().query(
CallLog.Calls.CONTENT_URI, PROJECTION,
selectionCondition,
null, CallLog.Calls.DATE + " DESC");

try {
ArrayList<HashMap<String, Object>> records = getCallRecordMaps(cursor);
pendingResult.success(records);
pendingResult = null;
} catch (Exception e) {
Log.e("PhoneLog", "Error on fetching call record" + e);
pendingResult.error("PhoneLog", e.getMessage(), null);
pendingResult = null;
} finally {
if (cursor != null) {
cursor.close();
}
}

} else {
pendingResult.error("PhoneLog", "Permission is not granted", null);
pendingResult = null;
}
}


/**
* Builds the list of call record maps from the cursor
*
* @param cursor
* @return the list of maps
*/
private ArrayList<HashMap<String, Object>> getCallRecordMaps(Cursor cursor) {
ArrayList<HashMap<String, Object>> records = new ArrayList<>();

while (cursor != null && cursor.moveToNext()) {
CallRecord record = new CallRecord();
record.formattedNumber = cursor.getString(0);
record.number = cursor.getString(1);
record.callType = getCallType(cursor.getInt(2));

Date date = new Date(cursor.getLong(3));
Calendar cal = Calendar.getInstance();
cal.setTime(date);
record.dateYear = cal.get(Calendar.YEAR);
record.dateMonth = cal.get(Calendar.MONTH);
record.dateDay = cal.get(Calendar.DAY_OF_MONTH);
record.dateHour = cal.get(Calendar.HOUR_OF_DAY);
record.dateMinute = cal.get(Calendar.MINUTE);
record.dateSecond = cal.get(Calendar.SECOND);
record.duration = cursor.getLong(4);

records.add(record.toMap());
}
return records;
}

private String getCallType(int anInt) {
switch (anInt) {
case CallLog.Calls.INCOMING_TYPE:
return "INCOMING_TYPE";
case CallLog.Calls.OUTGOING_TYPE:
return "OUTGOING_TYPE";
case CallLog.Calls.MISSED_TYPE:
return "MISSED_TYPE";
default:
break;
}
return null;
}
}
8 changes: 8 additions & 0 deletions packages/phone_log/example/.metadata
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.

version:
revision: 44b7e7d3f42f050a79712daab253af06e9daf530
channel: beta
8 changes: 8 additions & 0 deletions packages/phone_log/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# phone_log_example

Demonstrates how to use the phone_log plugin.

## Getting Started

For help getting started with Flutter, view our online
[documentation](https://flutter.io/).
Loading