Kontak profil kerja

Panduan developer ini menjelaskan cara meningkatkan kualitas aplikasi Anda untuk menggunakan kontak data dari profil kerja. Jika Anda belum menggunakan API kontak Android sebelumnya, baca Penyedia Kontak untuk memahami API.

Ringkasan

Perangkat dengan profil kerja menyimpan kontak di kontak lokal terpisah direktori untuk profil kerja dan pribadi. Secara default, saat aplikasi berjalan di profil pribadi, tidak akan menampilkan kontak bisnis. Namun, aplikasi dapat mengakses informasi kontak dari profil kerja. Misalnya, aplikasi yang melakukan ini adalah aplikasi Kontak Android Google yang menampilkan data pribadi dan kontak direktori kerja di hasil penelusuran.

Pengguna sering kali ingin menggunakan perangkat dan aplikasi pribadi mereka untuk bekerja. Dengan menggunakan kontak profil kerja, aplikasi Anda dapat menjadi bagian dari hari kerja pengguna.

Pengalaman pengguna

Pertimbangkan bagaimana aplikasi dapat menyajikan informasi kontak dari profil kerja. Pendekatan terbaik bergantung pada sifat aplikasi Anda dan alasan pengguna menggunakannya, tetapi pertimbangkan hal-hal berikut:

  • Haruskah aplikasi Anda menyertakan kontak profil kerja secara default atau apakah pengguna harus memilih ikut serta?
  • Bagaimana mencampur atau memisahkan kontak kerja dan profil pribadi akan mempengaruhi di alur pengguna?
  • Apa dampak mengetuk kontak profil kerja secara tidak sengaja?
  • Yang terjadi pada antarmuka aplikasi jika kontak profil kerja tidak tersedia?

Aplikasi Anda harus menunjukkan kontak profil kerja dengan jelas. Mungkin Anda dapat memasang badge kontak menggunakan ikon kerja yang familier—seperti koper.

Screenshot yang menampilkan hasil penelusuran dalam daftar
Gambar 1. Cara aplikasi Google Kontak memisahkan profil kerja kontak

Sebagai contoh, aplikasi Google Kontak (ditunjukkan pada gambar 1) melakukan hal berikut untuk mencantumkan campuran kontak profil kerja dan pribadi:

  1. Menyisipkan subheader untuk memisahkan bagian pekerjaan dan pribadi dari daftar.
  2. Lencana kontak kerja dengan ikon koper.
  3. Membuka kontak kerja di profil kerja saat diketuk.

Jika pengguna perangkat menonaktifkan profil kerja, aplikasi Anda tidak dapat mencari informasi kontak dari profil kerja atau jarak jauh organisasi direktori kontak. Bergantung pada cara Anda menggunakan kontak profil kerja, Anda dapat mengabaikan kontak ini secara diam-diam atau Anda mungkin perlu menonaktifkan antarmuka pengguna kontrol.

Izin

Jika aplikasi Anda sudah berfungsi dengan kontak pengguna, Anda akan mendapatkan READ_CONTACTS (atau mungkin WRITE_CONTACTS) yang Anda minta di file manifes aplikasi Anda. Karena orang yang sama menggunakan profil pribadi dan pekerjaannya profil ini, Anda tidak memerlukan izin lebih lanjut untuk mengakses data kontak dari kantor untuk profil.

Admin IT dapat blokir profil kerja yang berbagi informasi kontak dengan profil pribadi. Jika staf IT jika admin memblokir akses, penelusuran kontak Anda ditampilkan sebagai hasil kosong. Nama aplikasi tidak perlu menangani error tertentu jika pengguna mematikan pekerjaan untuk profil. Penyedia konten direktori terus mengembalikan informasi tentang direktori kontak kerja pengguna (lihat bagian Direktori). Untuk menguji izin ini, lihat Pengembangan dan pengujian bagian.

Penelusuran kontak

Anda dapat memperoleh kontak dari profil kerja menggunakan API dan proses yang sama seperti yang digunakan aplikasi Anda untuk mendapatkan kontak di profil pribadi. URI perusahaan untuk kontak didukung dalam Android 7.0 (API level 24) atau yang lebih tinggi. Anda perlu membuat penyesuaian berikut pada URI:

  1. Menetapkan URI penyedia konten ke Contacts.ENTERPRISE_CONTENT_FILTER_URI, dan memberikan nama kontak sebagai string kueri.
  2. Setel direktori kontak yang akan ditelusuri. Misalnya, ENTERPRISE_DEFAULT menemukan kontak di kantor toko lokal di profil Anda.

Mengubah URI dapat berfungsi dengan mekanisme penyedia konten apa pun seperti CursorLoader—cocok untuk memuat data kontak ke dalam antarmuka pengguna karena akses data terjadi di thread pekerja. Untuk lebih mudahnya, contoh dalam panggilan pemandu ContentResolver.query(). Berikut adalah cara menemukan kontak di direktori kontak lokal profil kerja:

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();
}

Direktori

Banyak organisasi menggunakan direktori jarak jauh, seperti Microsoft Exchange atau LDAP, yang berisi informasi kontak untuk seluruh organisasi. Aplikasi Anda dapat membantu pengguna berkomunikasi dan berbagi dengan rekan kerja yang ada di lingkungan organisasi mereka saat ini. Perhatikan bahwa direktori ini biasanya berisi ribuan kontak, dan aplikasi Anda juga memerlukan koneksi jaringan aktif untuk menelusurinya. Anda dapat menggunakan penyedia konten Directory untuk mendapatkan direktori yang digunakan oleh akun pengguna dan mencari tahu lebih lanjut tentang direktori individual.

Mengkueri Directory.ENTERPRISE_CONTENT_URI penyedia konten untuk mendapatkan direktori dari profil pribadi dan karya profil yang ditampilkan. Penelusuran direktori profil kerja didukung di Android 7.0 (level API 24) atau yang lebih tinggi. Aplikasi Anda masih membutuhkan pengguna untuk memberi READ_CONTACTS izin untuk bekerja dengan kontak mereka direktori.

Karena Android menyimpan informasi kontak dalam berbagai jenis direktori jarak jauh, class Directory memiliki metode yang dapat Anda panggil untuk menemukan tentang direktori:

isEnterpriseDirectoryId()
Panggil metode ini untuk mengetahui apakah direktori tersebut berasal dari akun profil kerja. Perlu diingat bahwa penyedia konten ENTERPRISE_CONTENT_URI akan menampilkan kontak direktori untuk profil pribadi dan kerja bersama-sama.
isRemoteDirectoryId()
Panggil metode ini untuk mengetahui apakah direktori tersebut jarak jauh. Direktori jarak jauh bisa jadi toko kontak perusahaan atau bisa berupa jejaring sosial pengguna.

Contoh berikut menunjukkan cara menggunakan metode ini untuk memfilter profil kerja direktori:

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();
}

Contoh ini mengambil ID dan nama paket untuk direktori. Untuk menampilkan pengguna yang membantu pengguna memilih sumber direktori kontak, Anda mungkin perlu mengambil informasi selengkapnya tentang direktori. Untuk melihat isian {i>metadata <i}lain yang mungkin tersedia, baca referensi class Directory.

Pencarian ponsel

Aplikasi dapat mengkueri PhoneLookup.CONTENT_FILTER_URI untuk secara efisien mencari data kontak untuk nomor telepon. Anda bisa mendapatkan hasil pencarian dari penyedia kontak pribadi dan profil kerja jika Anda mengganti URI ini dengan PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI URI konten profil kerja ini tersedia di Android 5.0 (API level 21) atau lebih tinggi.

Contoh berikut menampilkan aplikasi yang melakukan kueri URI konten profil kerja untuk mengonfigurasi antarmuka pengguna untuk panggilan masuk:

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;
}

Pencarian email

Aplikasi Anda dapat memperoleh data kontak pribadi atau kerja untuk alamat email dengan membuat kueri Email.ENTERPRISE_CONTENT_LOOKUP_URI Meminta URL ini terlebih dahulu akan menelusuri kontak pribadi untuk pencocokan persis. Jika penyedia tersebut tidak cocok dengan kontak pribadi mana pun, penyedia kemudian mencari kontak kerja untuk mendapatkan kecocokan. URI ini tersedia di Android 6.0 (API level 23) atau yang lebih tinggi.

Berikut adalah cara mencari informasi kontak untuk alamat 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();
}

Menampilkan kontak kantor

Aplikasi yang berjalan dalam profil pribadi dapat menampilkan kartu kontak di profil kerja. Telepon ContactsContract.QuickContact.showQuickContact() inci Android 5.0 atau yang lebih tinggi untuk meluncurkan aplikasi Kontak di profil kerja dan menampilkan kartu kontak.

Agar dapat membuat URI yang benar untuk profil kerja, Anda harus memanggil ContactsContract.Contacts.getLookupUri() dan teruskan ID kontak dan kunci pencarian. Contoh berikut menunjukkan cara mendapatkan URI lalu tampilkan kartu:

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();
}

Ketersediaan

Tabel berikut merangkum versi Android mana yang mendukung profil kerja data kontak di profil pribadi:

Versi Android Dukungan
5.0 (API Level 21) Cari nama kontak kantor untuk nomor telepon menggunakan PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI.
6.0 (level API 23) Cari nama kontak kantor untuk alamat email menggunakan Email.ENTERPRISE_CONTENT_LOOKUP_URI.
7.0 (level API 24) Buat kueri nama kontak kerja dari direktori kerja menggunakan Contacts.ENTERPRISE_CONTENT_FILTER_URI.
Cantumkan semua direktori di profil kerja dan pribadi menggunakan Directory.ENTERPRISE_CONTENT_URI.

Pengembangan dan pengujian

Untuk membuat profil kerja, ikuti langkah-langkah berikut:

  1. Instal aplikasi Test DPC kami.
  2. Buka aplikasi Siapkan DPC Pengujian (bukan ikon aplikasi Test DPC).
  3. Ikuti petunjuk di layar untuk menyiapkan profil terkelola.
  4. Di profil kerja, buka aplikasi Contacts dan tambahkan beberapa contoh kontak.

Untuk menyimulasikan admin IT yang memblokir akses ke kontak profil kerja, ikuti langkah-langkah berikut:

  1. Di profil kerja, buka aplikasi Test DPC.
  2. Telusuri setelan Nonaktifkan penelusuran kontak antar-profil atau Nonaktifkan ID penelepon antar-profil.
  3. Setel setelan ke Aktif.

Untuk mempelajari lebih lanjut cara menguji aplikasi dengan profil kerja, baca Menguji Aplikasi untuk Kompatibilitas dengan Profil Kerja.

Referensi lainnya

Untuk mempelajari kontak atau profil kerja lebih lanjut, lihat referensi berikut: