Home | History | Annotate | Download | only in contacts
      1 /*
      2 * Copyright 2015 The Android Open Source Project
      3 *
      4 * Licensed under the Apache License, Version 2.0 (the "License");
      5 * you may not use this file except in compliance with the License.
      6 * You may obtain a copy of the License at
      7 *
      8 *     http://www.apache.org/licenses/LICENSE-2.0
      9 *
     10 * Unless required by applicable law or agreed to in writing, software
     11 * distributed under the License is distributed on an "AS IS" BASIS,
     12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 * See the License for the specific language governing permissions and
     14 * limitations under the License.
     15 */
     16 
     17 package com.example.android.system.runtimepermissions.contacts;
     18 
     19 import com.example.android.common.logger.Log;
     20 import com.example.android.system.runtimepermissions.R;
     21 
     22 import android.content.ContentProviderOperation;
     23 import android.content.ContentResolver;
     24 import android.content.OperationApplicationException;
     25 import android.database.Cursor;
     26 import android.os.Bundle;
     27 import android.os.RemoteException;
     28 import android.provider.ContactsContract;
     29 import android.support.annotation.Nullable;
     30 import android.support.v4.app.Fragment;
     31 import android.support.v4.app.LoaderManager;
     32 import android.support.v4.content.CursorLoader;
     33 import android.support.v4.content.Loader;
     34 import android.view.LayoutInflater;
     35 import android.view.View;
     36 import android.view.ViewGroup;
     37 import android.widget.Button;
     38 import android.widget.TextView;
     39 
     40 import java.util.ArrayList;
     41 
     42 /**
     43  * Displays the first contact stored on the device and contains an option to add a dummy contact.
     44  * <p>
     45  * This Fragment is only used to illustrate that access to the Contacts ContentProvider API has
     46  * been granted (or denied) as part of the runtime permissions model. It is not relevant for the
     47  * use
     48  * of the permissions API.
     49  * <p>
     50  * This fragments demonstrates a basic use case for accessing the Contacts Provider. The
     51  * implementation is based on the training guide available here:
     52  * https://developer.android.com/training/contacts-provider/retrieve-names.html
     53  */
     54 public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
     55 
     56     private static final String TAG = "Contacts";
     57     private TextView mMessageText = null;
     58 
     59     private static String DUMMY_CONTACT_NAME = "__DUMMY CONTACT from runtime permissions sample";
     60 
     61     /**
     62      * Projection for the content provider query includes the id and primary name of a contact.
     63      */
     64     private static final String[] PROJECTION = {ContactsContract.Contacts._ID,
     65             ContactsContract.Contacts.DISPLAY_NAME_PRIMARY};
     66     /**
     67      * Sort order for the query. Sorted by primary name in ascending order.
     68      */
     69     private static final String ORDER = ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " ASC";
     70 
     71 
     72     /**
     73      * Creates a new instance of a ContactsFragment.
     74      */
     75     public static ContactsFragment newInstance() {
     76         return new ContactsFragment();
     77     }
     78 
     79 
     80     @Nullable
     81     @Override
     82     public View onCreateView(LayoutInflater inflater, ViewGroup container,
     83             Bundle savedInstanceState) {
     84         View rootView = inflater.inflate(R.layout.fragment_contacts, container, false);
     85 
     86         mMessageText = (TextView) rootView.findViewById(R.id.contact_message);
     87 
     88         // Register a listener to add a dummy contact when a button is clicked.
     89         Button button = (Button) rootView.findViewById(R.id.contact_add);
     90         button.setOnClickListener(new View.OnClickListener() {
     91             @Override
     92             public void onClick(View view) {
     93                 insertDummyContact();
     94             }
     95         });
     96 
     97         // Register a listener to display the first contact when a button is clicked.
     98         button = (Button) rootView.findViewById(R.id.contact_load);
     99         button.setOnClickListener(new View.OnClickListener() {
    100             @Override
    101             public void onClick(View view) {
    102                 loadContact();
    103             }
    104         });
    105         return rootView;
    106     }
    107 
    108     /**
    109      * Restart the Loader to query the Contacts content provider to display the first contact.
    110      */
    111     private void loadContact() {
    112         getLoaderManager().restartLoader(0, null, this);
    113     }
    114 
    115     /**
    116      * Initialises a new {@link CursorLoader} that queries the {@link ContactsContract}.
    117      */
    118     @Override
    119     public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
    120         return new CursorLoader(getActivity(), ContactsContract.Contacts.CONTENT_URI, PROJECTION,
    121                 null, null, ORDER);
    122     }
    123 
    124 
    125     /**
    126      * Dislays either the name of the first contact or a message.
    127      */
    128     @Override
    129     public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    130 
    131         if (cursor != null) {
    132             final int totalCount = cursor.getCount();
    133             if (totalCount > 0) {
    134                 cursor.moveToFirst();
    135                 String name = cursor
    136                         .getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
    137                 mMessageText.setText(
    138                         getResources().getString(R.string.contacts_string, totalCount, name));
    139                 Log.d(TAG, "First contact loaded: " + name);
    140                 Log.d(TAG, "Total number of contacts: " + totalCount);
    141                 Log.d(TAG, "Total number of contacts: " + totalCount);
    142             } else {
    143                 Log.d(TAG, "List of contacts is empty.");
    144                 mMessageText.setText(R.string.contacts_empty);
    145             }
    146         }
    147     }
    148 
    149     @Override
    150     public void onLoaderReset(Loader<Cursor> loader) {
    151         mMessageText.setText(R.string.contacts_empty);
    152     }
    153 
    154     /**
    155      * Accesses the Contacts content provider directly to insert a new contact.
    156      * <p>
    157      * The contact is called "__DUMMY ENTRY" and only contains a name.
    158      */
    159     private void insertDummyContact() {
    160         // Two operations are needed to insert a new contact.
    161         ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(2);
    162 
    163         // First, set up a new raw contact.
    164         ContentProviderOperation.Builder op =
    165                 ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
    166                         .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
    167                         .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null);
    168         operations.add(op.build());
    169 
    170         // Next, set the name for the contact.
    171         op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
    172                 .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
    173                 .withValue(ContactsContract.Data.MIMETYPE,
    174                         ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
    175                 .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
    176                         DUMMY_CONTACT_NAME);
    177         operations.add(op.build());
    178 
    179         // Apply the operations.
    180         ContentResolver resolver = getActivity().getContentResolver();
    181         try {
    182             resolver.applyBatch(ContactsContract.AUTHORITY, operations);
    183         } catch (RemoteException e) {
    184             Log.d(TAG, "Could not add a new contact: " + e.getMessage());
    185         } catch (OperationApplicationException e) {
    186             Log.d(TAG, "Could not add a new contact: " + e.getMessage());
    187         }
    188     }
    189 }
    190