blob: b7af99f4b35e04eff2d27bbf93039acdda3c8956 [file] [log] [blame]
/*
* Copyright 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.system.runtimepermissions.contacts
import android.content.ContentProviderOperation
import android.content.OperationApplicationException
import android.database.Cursor
import android.os.Bundle
import android.os.RemoteException
import android.provider.ContactsContract
import android.support.design.widget.Snackbar
import android.support.v4.app.Fragment
import android.support.v4.app.LoaderManager
import android.support.v4.content.CursorLoader
import android.support.v4.content.Loader
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.android.system.runtimepermissions.R
import kotlinx.android.synthetic.main.fragment_contacts.*
import java.util.ArrayList
/**
* Displays the first contact stored on the device and contains an option to add a dummy contact.
*
*
* This Fragment is only used to illustrate that access to the Contacts ContentProvider API has
* been granted (or denied) as part of the runtime permissions model. It is not relevant for the
* use
* of the permissions API.
*
*
* This fragments demonstrates a basic use case for accessing the Contacts Provider. The
* implementation is based on the training guide available here:
* https://developer.android.com/training/contacts-provider/retrieve-names.html
*/
class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View =
inflater.inflate(R.layout.fragment_contacts, container, false).apply {
// Register a listener to add a dummy contact when a button is clicked.
contactAddButton.setOnClickListener { insertDummyContact() }
// Register a listener to display the first contact when a button is clicked.
contactLoadButton.setOnClickListener { loadContact() }
}
/**
* Restart the Loader to query the Contacts content provider to display the first contact.
*/
private fun loadContact() {
loaderManager.restartLoader(0, Bundle(), this)
}
/**
* Initialises a new [CursorLoader] that queries the [ContactsContract].
*/
override fun onCreateLoader(i: Int, bundle: Bundle): Loader<Cursor> =
CursorLoader(activity, ContactsContract.Contacts.CONTENT_URI, PROJECTION, null, null,
ORDER)
/**
* Dislays either the name of the first contact or a message.
*/
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor?) {
cursor?.run {
if (count > 0) {
moveToFirst()
val name = getString(getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
contactMessage.text = resources.getString(R.string.contacts_string, count, name)
} else {
contactMessage.text = resources.getString(R.string.contacts_empty)
}
}
}
override fun onLoaderReset(loader: Loader<Cursor>) {
contactMessage.text = getString(R.string.contacts_empty)
}
/**
* Accesses the Contacts content provider directly to insert a new contact.
*
*
* The contact is called "__DUMMY ENTRY" and only contains a name.
*/
private fun insertDummyContact() {
// Two operations are needed to insert a new contact.
val operations = ArrayList<ContentProviderOperation>(2)
// First, set up a new raw contact.
operations.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
.build())
// Next, set the name for the contact.
operations.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
DUMMY_CONTACT_NAME)
.build())
// Apply the operations.
try {
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
} catch (e: RemoteException) {
Snackbar.make(contactMessage.rootView, "Could not add a new contact: " + e.message,
Snackbar.LENGTH_LONG)
} catch (e: OperationApplicationException) {
Snackbar.make(contactMessage.rootView, "Could not add a new contact: " + e.message,
Snackbar.LENGTH_LONG)
}
}
companion object {
/**
* Projection for the content provider query includes the id and primary name of a contact.
*/
@JvmField val PROJECTION = arrayOf(ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)
/**
* Sort order for the query. Sorted by primary name in ascending order.
*/
const val ORDER = ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " ASC"
const val DUMMY_CONTACT_NAME = "__DUMMY CONTACT from runtime permissions sample"
/**
* Creates a new instance of a ContactsFragment.
*/
fun newInstance() = ContactsFragment()
}
}