Hướng dẫn dành cho nhà phát triển này giải thích cách bạn có thể cải thiện ứng dụng của mình để sử dụng danh bạ khỏi hồ sơ công việc. Nếu bạn chưa sử dụng API danh bạ của Android trước đó, hãy đọc Nhà cung cấp danh bạ để làm quen với các API.
Tổng quan
Các thiết bị có hồ sơ công việc lưu trữ danh bạ trong các thiết bị cục bộ riêng biệt cho hồ sơ công việc và hồ sơ cá nhân. Theo mặc định, khi một ứng dụng chạy trong hồ sơ cá nhân, hồ sơ cá nhân sẽ không hiển thị danh bạ công việc. Tuy nhiên, một ứng dụng có thể truy cập thông tin liên hệ từ hồ sơ công việc. Ví dụ: một ứng dụng đây là ứng dụng Danh bạ Android của Google, hiển thị cả thông tin cá nhân và người liên hệ trong thư mục công việc trong kết quả tìm kiếm.
Người dùng thường muốn sử dụng các ứng dụng và thiết bị cá nhân cho công việc. Bằng cách sử dụng địa chỉ liên hệ trong hồ sơ công việc, ứng dụng của bạn có thể trở thành một phần trong ngày làm việc của người dùng.
Trải nghiệm người dùng
Cân nhắc cách ứng dụng của bạn có thể trình bày thông tin liên hệ từ hồ sơ công việc. Phương pháp tiếp cận tốt nhất phụ thuộc vào bản chất của ứng dụng và lý do khiến mọi người sử dụng thư viện này, nhưng hãy nghĩ đến những điều sau:
- Ứng dụng của bạn nên bao gồm danh bạ trong hồ sơ công việc theo mặc định hay người dùng nên chọn sử dụng không?
- Việc kết hợp hoặc tách riêng thông tin liên hệ trong hồ sơ cá nhân và công việc sẽ ảnh hưởng như thế nào đến luồng của người dùng?
- Ảnh hưởng của việc vô tình nhấn vào một người liên hệ trong hồ sơ công việc là gì?
- Điều gì sẽ xảy ra với giao diện của ứng dụng khi người liên hệ trong hồ sơ công việc không ở có sẵn không?
Ứng dụng của bạn phải chỉ rõ một người liên hệ trong hồ sơ công việc. Bạn có thể gắn huy hiệu người liên hệ đó bằng cách dùng biểu tượng công việc quen thuộc, chẳng hạn như một chiếc cặp tài liệu.
Ví dụ: ứng dụng Danh bạ Google (minh hoạ trong hình 1) thực hiện những việc sau để liệt kê cả thông tin liên hệ trên hồ sơ công việc và hồ sơ cá nhân:
- Chèn tiêu đề phụ để phân tách các phần công việc và cá nhân trong danh sách.
- Huy hiệu liên hệ công việc bằng biểu tượng cặp tài liệu.
- Mở một địa chỉ liên hệ công việc trong hồ sơ công việc khi được nhấn.
Nếu người sử dụng thiết bị tắt hồ sơ công việc, thì ứng dụng của bạn không thể tra cứu thông tin liên hệ trên hồ sơ công việc hoặc điều khiển từ xa của tổ chức danh bạ. Tuỳ thuộc vào cách bạn sử dụng danh bạ trong hồ sơ công việc, bạn có thể để yên tâm liên lạc với những người liên hệ này hoặc bạn có thể cần phải tắt giao diện người dùng .
Quyền
Nếu ứng dụng của bạn đang làm việc với danh bạ của người dùng, bạn sẽ có
READ_CONTACTS
(hoặc có thể
WRITE_CONTACTS
) mà bạn đã yêu cầu trong
tệp kê khai ứng dụng. Bởi vì cùng một người sử dụng hồ sơ cá nhân và công việc
hồ sơ khác, bạn không cần có thêm quyền để truy cập vào dữ liệu người liên hệ trong
hồ sơ.
Quản trị viên CNTT có thể chặn hồ sơ công việc chia sẻ thông tin liên hệ với hồ sơ cá nhân. Nếu đội ngũ CNTT quản trị viên chặn quyền truy cập, các tìm kiếm địa chỉ liên hệ của bạn được trả về dưới dạng kết quả trống. Thông tin ứng dụng không cần xử lý các lỗi cụ thể nếu người dùng tắt ứng dụng hồ sơ. Trình cung cấp nội dung thư mục tiếp tục trả về thông tin về danh bạ công việc của người dùng (xem phần Thư mục). Để kiểm tra các quyền này, hãy xem phần Phát triển và kiểm thử .
Tìm kiếm người liên hệ
Bạn có thể lấy danh bạ từ hồ sơ công việc bằng cách sử dụng cùng các API và quy trình ứng dụng của bạn dùng để tải danh bạ trong hồ sơ cá nhân. URI doanh nghiệp cho danh bạ được hỗ trợ trong Android 7.0 (API cấp 24) trở lên. Bạn cần thực hiện các điều chỉnh sau đây đối với URI:
- Đặt URI của trình cung cấp nội dung thành
Contacts.ENTERPRISE_CONTENT_FILTER_URI
! và cung cấp tên của địa chỉ liên hệ dưới dạng chuỗi truy vấn. - Thiết lập một danh bạ để tìm kiếm. Ví dụ:
ENTERPRISE_DEFAULT
tìm người liên hệ trong cơ quan cửa hàng địa phương của hồ sơ.
Việc thay đổi URI sẽ hoạt động với bất kỳ cơ chế nào của trình cung cấp nội dung, chẳng hạn như
CursorLoader
– lý tưởng để tải dữ liệu liên hệ vào giao diện người dùng vì
hoạt động truy cập dữ liệu diễn ra trên một luồng worker. Để cho đơn giản, các ví dụ trong
lệnh gọi hướng dẫn ContentResolver.query()
. Sau đây là cách bạn có thể tìm thấy
người liên hệ trong danh bạ cục bộ của hồ sơ công việc:
Kotlin
// First confirm the device user has given permission for the personal profile. // There isn't a separate work permission, but an IT admin can block access. val readContactsPermission = ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.READ_CONTACTS) if (readContactsPermission != PackageManager.PERMISSION_GRANTED) { return } // Fetch Jackie, James, & Jason (and anyone else whose names begin with "ja"). val nameQuery = Uri.encode("ja") // Build the URI to look up work profile contacts whose name matches. Query // the default work profile directory which is the locally-stored contacts. val contentFilterUri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI .buildUpon() .appendPath(nameQuery) .appendQueryParameter( ContactsContract.DIRECTORY_PARAM_KEY, ContactsContract.Directory.ENTERPRISE_DEFAULT.toString() ) .build() // Query the content provider using the generated URI. var cursor = getContentResolver() .query( contentFilterUri, arrayOf( ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY, ContactsContract.Contacts.DISPLAY_NAME_PRIMARY ), null, null, null ) // Print any results found using the work profile contacts' display name. cursor?.use { while (it.moveToNext()) { Log.i(TAG, "Work profile contact: ${it.getString(2)}") } }
Java
// First confirm the device user has given permission for the personal profile. // There isn't a separate work permission, but an IT admin can block access. int readContactsPermission = ContextCompat.checkSelfPermission( getBaseContext(), Manifest.permission.READ_CONTACTS); if (readContactsPermission != PackageManager.PERMISSION_GRANTED) { return; } // Fetch Jackie, James, & Jason (and anyone else whose names begin with "ja"). String nameQuery = Uri.encode("ja"); // Build the URI to look up work profile contacts whose name matches. Query // the default work profile directory which is the locally stored contacts. Uri contentFilterUri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI .buildUpon() .appendPath(nameQuery) .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(ContactsContract.Directory.ENTERPRISE_DEFAULT)) .build(); // Query the content provider using the generated URI. Cursor cursor = getContentResolver().query( contentFilterUri, new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY, ContactsContract.Contacts.DISPLAY_NAME_PRIMARY }, null, null, null); if (cursor == null) { return; } // Print any results found using the work profile contacts' display name. try { while (cursor.moveToNext()) { Log.i(TAG, "Work profile contact: " + cursor.getString(2)); } } finally { cursor.close(); }
Thư mục
Nhiều tổ chức sử dụng thư mục từ xa, chẳng hạn như Microsoft Exchange hoặc LDAP,
chứa thông tin liên hệ của toàn bộ tổ chức. Ứng dụng của bạn có thể giúp bạn
người dùng giao tiếp và chia sẻ với đồng nghiệp trong tổ chức của họ
thư mục. Xin lưu ý rằng các thư mục này thường chứa hàng nghìn địa chỉ liên hệ,
và ứng dụng của bạn cũng cần kết nối mạng đang hoạt động để tìm kiếm chúng. Bạn có thể sử dụng
trình cung cấp nội dung Directory
để lấy các thư mục mà
tài khoản của người dùng và tìm hiểu thêm về từng thư mục.
Truy vấn Directory.ENTERPRISE_CONTENT_URI
trình cung cấp nội dung để nhận các thư mục từ hồ sơ cá nhân và công việc
hồ sơ được trả về cùng nhau. Tính năng tìm thư mục hồ sơ công việc được hỗ trợ trong
Android 7.0 (API cấp 24) trở lên. Ứng dụng của bạn vẫn cần người dùng cho phép
READ_CONTACTS
quyền làm việc với người liên hệ của họ
.
Vì Android lưu trữ thông tin liên hệ ở nhiều loại tệp địa phương và
các thư mục từ xa, thì lớp Directory
có các phương thức mà bạn có thể gọi để tìm thêm
về một thư mục:
isEnterpriseDirectoryId()
- Gọi phương thức này để tìm hiểu xem thư mục có phải từ tài khoản hồ sơ công việc hay không.
Lưu ý rằng trình cung cấp nội dung
ENTERPRISE_CONTENT_URI
trả về thông tin liên hệ cả thư mục cho hồ sơ cá nhân và hồ sơ công việc. isRemoteDirectoryId()
- Gọi phương thức này để tìm hiểu xem thư mục có từ xa hay không. Thư mục từ xa có thể là cửa hàng liên hệ của doanh nghiệp hoặc có thể là mạng xã hội của người dùng.
Ví dụ sau cho thấy cách bạn có thể sử dụng các phương pháp này để lọc hồ sơ công việc thư mục:
Kotlin
// First, confirm the device user has given READ_CONTACTS permission. // This permission is still needed for directory listings ... // Query the content provider to get directories for BOTH the personal and // work profiles. val cursor = getContentResolver() .query( ContactsContract.Directory.ENTERPRISE_CONTENT_URI, arrayOf(ContactsContract.Directory._ID, ContactsContract.Directory.PACKAGE_NAME), null, null, null ) // Print the package name of the work profile's local or remote contact directories. cursor?.use { while (it.moveToNext()) { val directoryId = it.getLong(0) if (ContactsContract.Directory.isEnterpriseDirectoryId(directoryId)) { Log.i(TAG, "Directory: ${it.getString(1)}") } } }
Java
// First, confirm the device user has given READ_CONTACTS permission. // This permission is still needed for directory listings ... // Query the content provider to get directories for BOTH the personal and // work profiles. Cursor cursor = getContentResolver().query( ContactsContract.Directory.ENTERPRISE_CONTENT_URI, new String[]{ ContactsContract.Directory._ID, ContactsContract.Directory.PACKAGE_NAME }, null, null, null); if (cursor == null) { return; } // Print the package name of the work profile's local or remote contact directories. try { while (cursor.moveToNext()) { long directoryId = cursor.getLong(0); if (ContactsContract.Directory.isEnterpriseDirectoryId(directoryId)) { Log.i(TAG, "Directory: " + cursor.getString(1)); } } } finally { cursor.close(); }
Ví dụ này tìm nạp mã nhận dạng và tên gói cho thư mục. Để hiển thị người dùng
giúp người dùng chọn một nguồn thư mục liên hệ, bạn có thể cần phải
tìm nạp thêm thông tin về thư mục. Để xem các trường siêu dữ liệu khác
có thể có sẵn, hãy đọc tài liệu tham khảo về lớp Directory
.
Tra cứu điện thoại
Các ứng dụng có thể truy vấn
PhoneLookup.CONTENT_FILTER_URI
để đến một cách hiệu quả
tra cứu dữ liệu liên hệ cho một số điện thoại. Bạn có thể nhận kết quả tra cứu từ
nhà cung cấp danh bạ cho cả hồ sơ cá nhân lẫn hồ sơ công việc nếu bạn thay thế URI này bằng
PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI
.
URI nội dung hồ sơ công việc này có trong Android 5.0 (API cấp 21) hoặc
cao hơn.
Ví dụ sau đây cho thấy một ứng dụng truy vấn URI nội dung hồ sơ công việc để định cấu hình giao diện người dùng cho cuộc gọi đến:
Kotlin
fun onCreateIncomingConnection( connectionManagerPhoneAccount: PhoneAccountHandle, request: ConnectionRequest ): Connection { var request = request // Get the telephone number from the incoming request URI. val phoneNumber = this.extractTelephoneNumber(request.address) var displayName = "Unknown caller" var isCallerInWorkProfile = false // Look up contact details for the caller in the personal and work profiles. val lookupUri = Uri.withAppendedPath( ContactsContract.PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, Uri.encode(phoneNumber) ) val cursor = getContentResolver() .query( lookupUri, arrayOf( ContactsContract.PhoneLookup._ID, ContactsContract.PhoneLookup.DISPLAY_NAME, ContactsContract.PhoneLookup.CUSTOM_RINGTONE ), null, null, null ) // Use the first contact found and check if they're from the work profile. cursor?.use { if (it.moveToFirst() == true) { displayName = it.getString(1) isCallerInWorkProfile = ContactsContract.Contacts.isEnterpriseContactId(it.getLong(0)) } } // Return a configured connection object for the incoming call. val connection = MyAudioConnection() connection.setCallerDisplayName(displayName, TelecomManager.PRESENTATION_ALLOWED) // Our app's activity uses this value to decide whether to show a work badge. connection.setIsCallerInWorkProfile(isCallerInWorkProfile) // Configure the connection further ... return connection }
Java
public Connection onCreateIncomingConnection ( PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) { // Get the telephone number from the incoming request URI. String phoneNumber = this.extractTelephoneNumber(request.getAddress()); String displayName = "Unknown caller"; boolean isCallerInWorkProfile = false; // Look up contact details for the caller in the personal and work profiles. Uri lookupUri = Uri.withAppendedPath( ContactsContract.PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI, Uri.encode(phoneNumber)); Cursor cursor = getContentResolver().query( lookupUri, new String[]{ ContactsContract.PhoneLookup._ID, ContactsContract.PhoneLookup.DISPLAY_NAME, ContactsContract.PhoneLookup.CUSTOM_RINGTONE }, null, null, null); // Use the first contact found and check if they're from the work profile. if (cursor != null) { try { if (cursor.moveToFirst() == true) { displayName = cursor.getString(1); isCallerInWorkProfile = ContactsContract.Contacts.isEnterpriseContactId(cursor.getLong(0)); } } finally { cursor.close(); } } // Return a configured connection object for the incoming call. MyConnection connection = new MyConnection(); connection.setCallerDisplayName(displayName, TelecomManager.PRESENTATION_ALLOWED); // Our app's activity uses this value to decide whether to show a work badge. connection.setIsCallerInWorkProfile(isCallerInWorkProfile); // Configure the connection further ... return connection; }
Tra cứu email
Ứng dụng của bạn có thể lấy dữ liệu liên hệ cá nhân hoặc công việc cho một địa chỉ email bằng cách truy vấn
Email.ENTERPRISE_CONTENT_LOOKUP_URI
.
Truy vấn URL này trước tiên sẽ tìm kiếm danh bạ cá nhân để tìm kết quả khớp chính xác. Nếu
nhà cung cấp không khớp với bất kỳ người liên hệ cá nhân nào, nhà cung cấp sẽ tìm kiếm
địa chỉ liên hệ công việc để tìm thông tin trùng khớp. URI này có trong Android 6.0 (API cấp 23)
trở lên.
Sau đây là cách bạn có thể tra cứu thông tin liên hệ của một địa chỉ email:
Kotlin
// Build the URI to look up contacts from the personal and work profiles that // are an exact (case-insensitive) match for the email address. val emailAddress = "somebody@example.com" val contentFilterUri = Uri.withAppendedPath( ContactsContract.CommonDataKinds.Email.ENTERPRISE_CONTENT_LOOKUP_URI, Uri.encode(emailAddress) ) // Query the content provider to first try to match personal contacts and, // if none are found, then try to match the work contacts. val cursor = contentResolver.query( contentFilterUri, arrayOf( ContactsContract.CommonDataKinds.Email.CONTACT_ID, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.Contacts.DISPLAY_NAME ), null, null, null ) ?: return // Print the name of the matching contact. If we want to work-badge contacts, // we can call ContactsContract.Contacts.isEnterpriseContactId() with the ID. cursor.use { while (it.moveToNext()) { Log.i(TAG, "Matching contact: ${it.getString(2)}") } }
Java
// Build the URI to look up contacts from the personal and work profiles that // are an exact (case-insensitive) match for the email address. String emailAddress = "somebody@example.com"; Uri contentFilterUri = Uri.withAppendedPath( ContactsContract.CommonDataKinds.Email.ENTERPRISE_CONTENT_LOOKUP_URI, Uri.encode(emailAddress)); // Query the content provider to first try to match personal contacts and, // if none are found, then try to match the work contacts. Cursor cursor = getContentResolver().query( contentFilterUri, new String[]{ ContactsContract.CommonDataKinds.Email.CONTACT_ID, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.Contacts.DISPLAY_NAME }, null, null, null); if (cursor == null) { return; } // Print the name of the matching contact. If we want to work-badge contacts, // we can call ContactsContract.Contacts.isEnterpriseContactId() with the ID. try { while (cursor.moveToNext()) { Log.i(TAG, "Matching contact: " + cursor.getString(2)); } } finally { cursor.close(); }
Hiện một người liên hệ công việc
Các ứng dụng chạy trong hồ sơ cá nhân có thể hiển thị thẻ liên hệ trong hồ sơ công việc.
Gọi điện
ContactsContract.QuickContact.showQuickContact()
inch
Android 5.0 trở lên để khởi chạy ứng dụng Danh bạ trong hồ sơ công việc và hiển thị
thẻ của người liên hệ đó.
Để tạo URI chính xác cho hồ sơ công việc, bạn cần gọi
ContactsContract.Contacts.getLookupUri()
rồi truyền một
mã liên hệ và khoá tra cứu. Ví dụ sau cho thấy cách lấy URI
rồi hiện thẻ:
Kotlin
// Query the content provider using the ENTERPRISE_CONTENT_FILTER_URI address. // We use the _ID and LOOKUP_KEY columns to generate a work-profile URI. val cursor = getContentResolver() .query( contentFilterUri, arrayOf(ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY), null, null ) // Show the contact details card in the work profile's Contacts app. The URI // must be created with getLookupUri(). cursor?.use { if (it.moveToFirst() == true) { val uri = ContactsContract.Contacts.getLookupUri(it.getLong(0), it.getString(1)) ContactsContract.QuickContact.showQuickContact( activity, Rect(20, 20, 100, 100), uri, ContactsContract.QuickContact.MODE_LARGE, null ) } }
Java
// Query the content provider using the ENTERPRISE_CONTENT_FILTER_URI address. // We use the _ID and LOOKUP_KEY columns to generate a work-profile URI. Cursor cursor = getContentResolver().query( contentFilterUri, new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY, }, null, null, null); if (cursor == null) { return; } // Show the contact details card in the work profile's Contacts app. The URI // must be created with getLookupUri(). try { if (cursor.moveToFirst() == true) { Uri uri = ContactsContract.Contacts.getLookupUri( cursor.getLong(0), cursor.getString(1)); ContactsContract.QuickContact.showQuickContact( getActivity(), new Rect(20, 20, 100, 100), uri, ContactsContract.QuickContact.MODE_LARGE, null); } } finally { cursor.close(); }
Phạm vi cung cấp
Bảng sau đây tóm tắt những phiên bản Android hỗ trợ hồ sơ công việc dữ liệu liên hệ trong hồ sơ cá nhân:
Phiên bản Android | Hỗ trợ |
---|---|
5.0 (API cấp 21) | Tra cứu tên liên hệ công việc cho các số điện thoại bằng PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI . |
6.0 (API cấp 23) | Tra cứu tên người liên hệ công việc cho các địa chỉ email bằng Email.ENTERPRISE_CONTENT_LOOKUP_URI . |
7.0 (API cấp 24) | Truy vấn tên người liên hệ công việc từ các thư mục công việc bằng cách sử dụng Contacts.ENTERPRISE_CONTENT_FILTER_URI .Liệt kê tất cả thư mục trong hồ sơ công việc và hồ sơ cá nhân bằng Directory.ENTERPRISE_CONTENT_URI . |
Phát triển và kiểm thử
Để tạo hồ sơ công việc, hãy làm theo các bước sau:
- Cài đặt ứng dụng Kiểm thử DPC.
- Mở ứng dụng Thiết lập DPC Kiểm thử (không phải biểu tượng ứng dụng Kiểm thử DPC).
- Làm theo hướng dẫn trên màn hình để thiết lập hồ sơ được quản lý.
- Trong hồ sơ công việc, hãy mở ứng dụng Danh bạ rồi thêm một số liên hệ mẫu.
Để mô phỏng khi một quản trị viên CNTT chặn quyền truy cập vào danh bạ hồ sơ công việc, hãy làm theo các bước sau:
- Trong hồ sơ công việc, mở ứng dụng Test DPC (Kiểm thử DPC).
- Tìm chế độ cài đặt Tắt tính năng tìm kiếm người liên hệ giữa các hồ sơ hoặc Tắt chế độ cài đặt tên nhận dạng người gọi giữa nhiều hồ sơ.
- Chuyển chế độ cài đặt này sang trạng thái Bật.
Để tìm hiểu thêm về cách kiểm thử ứng dụng bằng hồ sơ công việc, hãy đọc bài viết Kiểm thử ứng dụng bằng hồ sơ công việc Khả năng tương thích với Hồ sơ công việc.
Tài nguyên khác
Để tìm hiểu thêm về danh bạ hoặc hồ sơ công việc, hãy xem các tài nguyên sau:
- Hồ sơ công việc chứa các phương pháp hay nhất khác dành cho công việc hồ sơ.
- Truy xuất danh sách người liên hệ hướng dẫn bạn các bước cần thiết để liệt kê người liên hệ trong một ứng dụng.
- Trình cung cấp danh bạ giải thích cấu trúc của cơ sở dữ liệu danh bạ.