Skip to content
This repository has been archived by the owner on May 3, 2023. It is now read-only.

Read email addresses, phone numbers, postal addresses and instant messaging #9

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.DS_Store
.atom/
.idea
.vscode
.packages
.dart_tool/
.pub/
Expand Down
7 changes: 3 additions & 4 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ buildscript {
}

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

Expand All @@ -26,12 +26,11 @@ rootProject.allprojects {
apply plugin: 'com.android.library'

android {
compileSdkVersion 25
buildToolsVersion '25.0.3'
compileSdkVersion 27

defaultConfig {
minSdkVersion 16
targetSdkVersion 25
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
Expand Down
5 changes: 4 additions & 1 deletion android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.goderbauer.flutter.contactpicker">
package="net.goderbauer.flutter.contactpicker">

<uses-permission android:name="android.permission.READ_CONTACTS"/>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
import android.net.Uri;
import android.provider.ContactsContract;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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.MethodCall;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.Registrar;

Expand All @@ -29,9 +32,9 @@ public static void registerWith(Registrar registrar) {
channel.setMethodCallHandler(instance);
}

private ContactPickerPlugin(Activity activity) {
this.activity = activity;
}
private ContactPickerPlugin(Activity activity) {
this.activity = activity;
}

private static int PICK_CONTACT = 2015;

Expand All @@ -47,7 +50,7 @@ public void onMethodCall(MethodCall call, Result result) {
}
pendingResult = result;

Intent i = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
Intent i = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
activity.startActivityForResult(i, PICK_CONTACT);
} else {
result.notImplemented();
Expand All @@ -59,31 +62,121 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != PICK_CONTACT) {
return false;
}
if (resultCode != RESULT_OK) {

if (resultCode != RESULT_OK || data.getData() == null) {
pendingResult.success(null);
pendingResult = null;
return true;
}

Uri contactUri = data.getData();
Cursor cursor = activity.getContentResolver().query(contactUri, null, null, null, null);
cursor.moveToFirst();
Cursor cursor = null;

try {
cursor = activity.getContentResolver()
.query(contactUri, null, null, null, null);

if (cursor == null || !cursor.moveToFirst()) {
pendingResult.success(null);
pendingResult = null;
return true;
}

long contactId = cursor.getLong(cursor.getColumnIndex(ContactsContract.Contacts._ID));

List<Map<String, Object>> ims = new ArrayList<>();
List<Map<String, Object>> emails = new ArrayList<>();
List<Map<String, Object>> phones = new ArrayList<>();
List<Map<String, Object>> addresses = new ArrayList<>();

Cursor rawCursor = null;
try {
rawCursor = activity.getContentResolver()
.query(ContactsContract.RawContactsEntity.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", new String[]{Long.toString(contactId)}, null, null);

if (rawCursor != null && rawCursor.moveToFirst()) {
do {
Map<String, Object> row = new HashMap<>();

String mimeType = rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.RawContactsEntity.MIMETYPE));
switch (mimeType) {
case ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE: {
int type = rawCursor.getInt(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.TYPE));
String customLabel = rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.LABEL));

row.put("label", ContactsContract.CommonDataKinds.Im.getTypeLabel(activity.getResources(), type, customLabel));
row.put("im", rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)));

int protocol = rawCursor.getInt(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.PROTOCOL));
String customProtocol = rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL));
row.put("protocol", ContactsContract.CommonDataKinds.Im.getProtocolLabel(activity.getResources(), protocol, customProtocol));

ims.add(row);
break;
}
case ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE: {
int type = rawCursor.getInt(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE));
String customLabel = rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.LABEL));

row.put("label", ContactsContract.CommonDataKinds.Email.getTypeLabel(activity.getResources(), type, customLabel));
row.put("email", rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS)));

emails.add(row);
break;
}
case ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE: {
int type = rawCursor.getInt(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
String customLabel = rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.LABEL));

row.put("label", ContactsContract.CommonDataKinds.Phone.getTypeLabel(activity.getResources(), type, customLabel));
row.put("phone", rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));

phones.add(row);
break;
}
case ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE: {
int type = rawCursor.getInt(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.TYPE));
String customLabel = rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.LABEL));

row.put("label", ContactsContract.CommonDataKinds.StructuredPostal.getTypeLabel(activity.getResources(), type, customLabel));
row.put("street", rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET)));
row.put("pobox", rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POBOX)));
row.put("neighborhood", rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.NEIGHBORHOOD)));
row.put("city", rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY)));
row.put("region", rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION)));
row.put("postcode", rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)));
row.put("country", rawCursor.getString(rawCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY)));

addresses.add(row);
break;
}
}
} while (rawCursor.moveToNext());
}
} finally {
if (rawCursor != null) {
rawCursor.close();
}
}

int phoneType = cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
String customLabel = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.LABEL));
String label = (String) ContactsContract.CommonDataKinds.Email.getTypeLabel(activity.getResources(), phoneType, customLabel);
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String fullName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String fullName = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));

HashMap<String, Object> phoneNumber = new HashMap<>();
phoneNumber.put("number", number);
phoneNumber.put("label", label);
HashMap<String, Object> contact = new HashMap<>();
contact.put("fullName", fullName);

HashMap<String, Object> contact = new HashMap<>();
contact.put("fullName", fullName);
contact.put("phoneNumber", phoneNumber);
contact.put("emails", emails);
contact.put("phones", phones);
contact.put("addresses", addresses);
contact.put("ims", ims);

pendingResult.success(contact);
pendingResult = null;
pendingResult.success(contact);
pendingResult = null;
} finally {
if (cursor != null) {
cursor.close();
}
}
return true;
}

}
11 changes: 5 additions & 6 deletions example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
compileSdkVersion 25
buildToolsVersion '25.0.3'
compileSdkVersion 27

lintOptions {
disable 'InvalidPackage'
Expand All @@ -26,7 +25,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.yourcompany.contactpickerexample"
minSdkVersion 16
targetSdkVersion 25
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
Expand All @@ -46,7 +45,7 @@ flutter {
}

dependencies {
androidTestCompile 'com.android.support:support-annotations:25.4.0'
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test:rules:0.5'
androidTestImplementation 'com.android.support:support-annotations:27.1.1'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);



GeneratedPluginRegistrant.registerWith(this);
}
}
3 changes: 2 additions & 1 deletion example/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ buildscript {
maven {
url "https://maven.google.com"
}
google()
}

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

Expand Down
4 changes: 2 additions & 2 deletions example/android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
#Tue Jun 26 18:52:58 CST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
3 changes: 3 additions & 0 deletions example/ios/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ build/
GeneratedPluginRegistrant.h
GeneratedPluginRegistrant.m

.generated/

*.pbxuser
*.mode1v3
*.mode2v3
Expand Down Expand Up @@ -40,3 +42,4 @@ Icon?
/ServiceDefinitions.json

Pods/
.symlinks/
79 changes: 54 additions & 25 deletions example/ios/Podfile
Original file line number Diff line number Diff line change
@@ -1,36 +1,65 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
platform :ios, '10.0'

if ENV['FLUTTER_FRAMEWORK_DIR'] == nil
abort('Please set FLUTTER_FRAMEWORK_DIR to the directory containing Flutter.framework')
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
pods_ary = []
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_ary.push({:name => podname, :path => podpath});
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_ary
end

target 'Runner' do
# Pods for Runner

# Flutter Pods
pod 'Flutter', :path => ENV['FLUTTER_FRAMEWORK_DIR']

if File.exists? '../.flutter-plugins'
flutter_root = File.expand_path('..')
File.foreach('../.flutter-plugins') { |line|
plugin = line.split(pattern='=')
if plugin.length == 2
name = plugin[0].strip()
path = plugin[1].strip()
resolved_path = File.expand_path("#{path}/ios", flutter_root)
pod name, :path => resolved_path
else
puts "Invalid plugin specification: #{line}"
end
use_frameworks!

# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')

# Flutter Pods
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
if generated_xcode_build_settings.empty?
puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
end
generated_xcode_build_settings.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join('.symlinks', 'flutter')
File.symlink(File.dirname(p[:path]), symlink)
pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
end
}

# Plugin Pods
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p|
symlink = File.join('.symlinks', 'plugins', p[:name])
File.symlink(p[:path], symlink)
pod p[:name], :path => File.join(symlink, 'ios')
}
end
end

post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end
end
Loading