15635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov/*
25635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * Copyright (C) 2009 The Android Open Source Project
35635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov *
45635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License");
55635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * you may not use this file except in compliance with the License.
65635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * You may obtain a copy of the License at
75635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov *
85635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov *      http://www.apache.org/licenses/LICENSE-2.0
95635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov *
105635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * Unless required by applicable law or agreed to in writing, software
115635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS,
125635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * See the License for the specific language governing permissions and
145635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * limitations under the License.
155635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov */
165635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
175635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikovpackage com.example.android.businesscard;
185635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
195635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikovimport android.app.Activity;
205635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikovimport android.content.Intent;
215635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikovimport android.net.Uri;
225635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikovimport android.os.AsyncTask;
235635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikovimport android.os.Bundle;
245635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikovimport android.view.View;
255635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikovimport android.view.View.OnClickListener;
265635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikovimport android.widget.Button;
275635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikovimport android.widget.TextView;
285635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
295635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov/**
305635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * A simple activity that shows a "Pick Contact" button and two fields: contact's name
315635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * and phone number.  The user taps on the Pick Contact button to bring up
325635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * the contact chooser.  Once this activity receives the result from contact picker,
335635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * it launches an asynchronous query (queries should always be asynchronous) to load
345635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * contact's name and phone number. When the query completes, the activity displays
355635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov * the loaded data.
365635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov */
375635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikovpublic class BusinessCardActivity extends Activity  {
385635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
395635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    // Request code for the contact picker activity
405635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    private static final int PICK_CONTACT_REQUEST = 1;
415635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
425635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    /**
435635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     * An SDK-specific instance of {@link ContactAccessor}.  The activity does not need
445635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     * to know what SDK it is running in: all idiosyncrasies of different SDKs are
455635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     * encapsulated in the implementations of the ContactAccessor class.
465635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     */
475635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    private final ContactAccessor mContactAccessor = ContactAccessor.getInstance();
485635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
495635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    /**
505635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     * Called with the activity is first created.
515635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     */
525635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    @Override
535635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    public void onCreate(Bundle savedInstanceState) {
545635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        super.onCreate(savedInstanceState);
555635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
565635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        setContentView(R.layout.business_card);
575635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
585635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        // Install a click handler on the Pick Contact button
595635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        Button pickContact = (Button)findViewById(R.id.pick_contact_button);
605635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        pickContact.setOnClickListener(new OnClickListener() {
615635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
625635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov            public void onClick(View v) {
635635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov                pickContact();
645635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov            }
655635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        });
665635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    }
675635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
685635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    /**
695635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     * Click handler for the Pick Contact button.  Invokes a contact picker activity.
705635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     * The specific intent used to bring up that activity differs between versions
715635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     * of the SDK, which is why we delegate the creation of the intent to ContactAccessor.
725635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     */
735635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    protected void pickContact() {
745635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        startActivityForResult(mContactAccessor.getPickContactIntent(), PICK_CONTACT_REQUEST);
755635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    }
765635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
775635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    /**
785635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     * Invoked when the contact picker activity is finished. The {@code contactUri} parameter
795635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     * will contain a reference to the contact selected by the user. We will treat it as
805635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     * an opaque URI and allow the SDK-specific ContactAccessor to handle the URI accordingly.
815635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     */
825635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    @Override
835635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
845635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        if (requestCode == PICK_CONTACT_REQUEST && resultCode == RESULT_OK) {
855635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov            loadContactInfo(data.getData());
865635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        }
875635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    }
885635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
895635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    /**
905635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     * Load contact information on a background thread.
915635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     */
925635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    private void loadContactInfo(Uri contactUri) {
935635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
945635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        /*
955635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov         * We should always run database queries on a background thread. The database may be
965635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov         * locked by some process for a long time.  If we locked up the UI thread while waiting
975635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov         * for the query to come back, we might get an "Application Not Responding" dialog.
985635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov         */
995635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        AsyncTask<Uri, Void, ContactInfo> task = new AsyncTask<Uri, Void, ContactInfo>() {
1005635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
1015635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov            @Override
1025635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov            protected ContactInfo doInBackground(Uri... uris) {
1035635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov                return mContactAccessor.loadContact(getContentResolver(), uris[0]);
1045635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov            }
1055635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
1065635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov            @Override
1075635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov            protected void onPostExecute(ContactInfo result) {
1085635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov                bindView(result);
1095635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov            }
1105635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        };
1115635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
1125635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        task.execute(contactUri);
1135635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    }
1145635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
1155635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    /**
1165635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     * Displays contact information: name and phone number.
1175635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov     */
1185635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    protected void bindView(ContactInfo contactInfo) {
1195635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        TextView displayNameView = (TextView) findViewById(R.id.display_name_text_view);
1205635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        displayNameView.setText(contactInfo.getDisplayName());
1215635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov
1225635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        TextView phoneNumberView = (TextView) findViewById(R.id.phone_number_text_view);
1235635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov        phoneNumberView.setText(contactInfo.getPhoneNumber());
1245635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov    }
1255635cf46c1d8df9a2a3bda2538a1ab813237dc3cDmitri Plotnikov}
126