manniru
8/29/2014 - 9:38 AM

AccountUtils.java

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:paddingTop="8dp"
              android:paddingLeft="@dimen/page_padding"
              android:paddingRight="@dimen/page_padding"
              android:orientation="vertical"
              android:gravity="center">
    <TextView style="?android:listSeparatorTextViewStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:paddingTop="8dp"
        android:paddingBottom="8dp"
        android:singleLine="true"
        android:paddingLeft="13dp"
        android:text="account" />
    <AutoCompleteTextView
            android:id="@+id/email_address"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/view_margin"
            android:layout_marginRight="@dimen/view_margin"
            android:singleLine="true"
            android:inputType="textEmailAddress"
            android:imeOptions="actionNext"
            android:hint="email address" />
    <EditText
        android:id="@+id/password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/view_margin"
        android:layout_marginBottom="@dimen/view_margin"
        android:singleLine="true"
        android:inputType="textPassword"
        android:hint="password" />
    <TextView style="?android:listSeparatorTextViewStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="left"
            android:paddingTop="8dp"
            android:paddingBottom="8dp"
            android:singleLine="true"
            android:paddingLeft="13dp"
            android:text="information" />
    <AutoCompleteTextView
        android:id="@+id/full_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/view_margin"
        android:singleLine="true"
        android:inputType="textPersonName"
        android:imeOptions="actionNext"
        android:capitalize="words"
        android:hint="full name" />
    <AutoCompleteTextView
        android:id="@+id/phone_number"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/view_margin"
        android:layout_marginBottom="@dimen/view_margin"
        android:singleLine="true"
        android:phoneNumber="true"
        android:inputType="phone"
        android:imeOptions="actionNext"
        android:hint="phone number" />
    <ImageButton style="?android:attr/borderlessButtonStyle"
        android:id="@+id/photo_picker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/view_margin"
        android:layout_marginBottom="@dimen/view_margin"
        android:maxHeight="128dp"
        android:src="@drawable/anonymous_image_2"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        android:cropToPadding="true"
        android:contentDescription="choose an avatar picture, this is the picture set for user by default."
        android:onClick="startPhotoPicker" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/view_margin"
        android:text="create account"
        android:onClick="startHomeScreen" />
</LinearLayout>
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;

/**
 * A custom {@link android.support.v4.content.Loader} that retrieves the {@link AccountUtils.UserProfile} asynchronously.
 * @author Dandré Allison
 */
public class UserProfileLoader extends AsyncTaskLoader<AccountUtils.UserProfile> {

    public UserProfileLoader(Context context) {
        super(context);
    }

    @Override
    public AccountUtils.UserProfile loadInBackground() {
        return AccountUtils.getUserProfile(getContext());
    }

    @Override
    public void deliverResult(AccountUtils.UserProfile user_profile) {
        _user_profile = user_profile;

        if (isStarted())
            // If the Loader is currently started, we can immediately
            // deliver its results.
            super.deliverResult(user_profile);
    }

    @Override
    protected void onStartLoading() {
        if (_user_profile != null)
            // Delivers the result immediately when it's already available
            deliverResult(_user_profile);

        if (takeContentChanged() || _user_profile == null) {
            // If the data has changed since the last time it was loaded
            // or is not currently available, start a load.
            forceLoad();
        }
    }

    @Override
    protected void onStopLoading() {
        // Attempts to cancel the current load task if possible.
        cancelLoad();
    }

    /**
     * Handles a request to completely reset the Loader.
     */
    @Override protected void onReset() {
        super.onReset();

        // Ensures the loader is stopped
        onStopLoading();

        // Clears the stored list
        if (_user_profile != null)
            _user_profile = null;
    }

    /** The list of the user's possible email address and name */
    private AccountUtils.UserProfile _user_profile;
}
public class CreateAccountActivity extends FragmentActivity
                                   implements LoaderManager.LoaderCallbacks<AccountUtils.UserProfile> {

    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        // ...
        getSupportLoaderManager().initLoader(0, Bundle.EMPTY, this);
    }

    @Override
    public Loader<AccountUtils.UserProfile> onCreateLoader(int _, Bundle __) {
        return new UserProfileLoader(this);
    }

    @Override
    public void onLoadFinished(Loader<AccountUtils.UserProfile> loader, AccountUtils.UserProfile user_profile) {
        final List<String> possible_emails = user_profile.possibleEmails();
        final List<String> possible_names = user_profile.possibleNames();
        final List<String> possible_phone_numbers = user_profile.possiblePhoneNumbers();
        final String primary_email = user_profile.primaryEmail();
        final String primary_phone_number = user_profile.primaryPhoneNumber();
        // Sets the text to the likely possibility, this is the user defined primary possibility or the first possibility if there
        // isn't a primary possibility
        if (possible_emails.size() > 0) _email_address.setText(primary_email == null ? possible_emails.get(0) :
                                                                       primary_email);
        if (possible_names.size() > 0) _full_name.setText(possible_names.get(0));
        if (possible_phone_numbers.size() > 0) _phone_number.setText(primary_phone_number == null? possible_phone_numbers.get(0) : primary_phone_number);
        _photo_picker.setImageURI(user_profile.possiblePhoto());

        _email_address.setAdapter(new ArrayAdapter<String>(this,
                                                           android.R.layout.simple_dropdown_item_1line,
                                                           possible_emails));
        _full_name.setAdapter(new ArrayAdapter<String>(this,
                                                       android.R.layout.simple_dropdown_item_1line,
                                                       possible_names));
        _phone_number.setAdapter(new ArrayAdapter<String>(this,
                                                          android.R.layout.simple_dropdown_item_1line,
                                                          possible_phone_numbers));
    }

    @Override
    public void onLoaderReset(Loader<AccountUtils.UserProfile> loader) { }
}
/**
 * A collection of authentication and account connection utilities. With strong inspiration from the Google IO session
 * app.
 * @author Dandré Allison
 */
public class AccountUtils {  

    /**
     * Interface for interacting with the result of {@link AccountUtils#getUserProfile}.
     */
    public static class UserProfile {

        /**
         * Adds an email address to the list of possible email addresses for the user
         * @param email the possible email address
         */
        public void addPossibleEmail(String email) {
            addPossibleEmail(email, false);
        }

        /**
         * Adds an email address to the list of possible email addresses for the user. Retains information about whether this
         * email address is the primary email address of the user.
         * @param email the possible email address
         * @param is_primary whether the email address is the primary email address
         */
        public void addPossibleEmail(String email, boolean is_primary) {
            if (email == null) return;
            if (is_primary) {
                _primary_email = email;
                _possible_emails.add(email);
            } else
                _possible_emails.add(email);
        }

        /**
         * Adds a name to the list of possible names for the user.
         * @param name the possible name
         */
        public void addPossibleName(String name) {
           if (name != null) _possible_names.add(name);
        }

        /**
         * Adds a phone number to the list of possible phone numbers for the user.
         * @param phone_number the possible phone number
         */
        public void addPossiblePhoneNumber(String phone_number) {
            if (phone_number != null) _possible_phone_numbers.add(phone_number);
        }

        /**
         * Adds a phone number to the list of possible phone numbers for the user.  Retains information about whether this
         * phone number is the primary phone number of the user.
         * @param phone_number the possible phone number
         * @param is_primary whether the phone number is teh primary phone number
         */
        public void addPossiblePhoneNumber(String phone_number, boolean is_primary) {
            if (phone_number == null) return;
            if (is_primary) {
                _primary_phone_number = phone_number;
                _possible_phone_numbers.add(phone_number);
            } else
                _possible_phone_numbers.add(phone_number);
        }

        /**
         * Sets the possible photo for the user.
         * @param photo the possible photo
         */
        public void addPossiblePhoto(Uri photo) {
            if (photo != null) _possible_photo = photo;
        }

        /**
         * Retrieves the list of possible email addresses.
         * @return the list of possible email addresses
         */
        public List<String> possibleEmails() {
            return _possible_emails;
        }

        /**
         * Retrieves the list of possible names.
         * @return the list of possible names
         */
        public List<String> possibleNames() {
            return _possible_names;
        }

        /**
         * Retrieves the list of possible phone numbers
         * @return the list of possible phone numbers
         */
        public List<String> possiblePhoneNumbers() {
            return _possible_phone_numbers;
        }

        /**
         * Retrieves the possible photo.
         * @return the possible photo
         */
        public Uri possiblePhoto() {
            return _possible_photo;
        }

        /**
         * Retrieves the primary email address.
         * @return the primary email address
         */
        public String primaryEmail() {
            return _primary_email;
        }

        /**
         * Retrieves the primary phone number
         * @return the primary phone number
         */
        public String primaryPhoneNumber() {
            return _primary_phone_number;
        }

        /** The primary email address */
        private String _primary_email;
        /** The primary name */
        private String _primary_name;
        /** The primary phone number */
        private String _primary_phone_number;
        /** A list of possible email addresses for the user */
        private List<String> _possible_emails = Lists.newArrayList();
        /** A list of possible names for the user */
        private List<String> _possible_names = Lists.newArrayList();
        /** A list of possible phone numbers for the user */
        private List<String> _possible_phone_numbers = Lists.newArrayList();
        /** A possible photo for the user */
        private Uri _possible_photo;
    }

    /**
     * Retrieves the user profile information.
     * @param context the context from which to retrieve the user profile
     * @return the user profile
     */
    public static UserProfile getUserProfile(Context context) {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH
                ? getUserProfileOnIcsDevice(context)
                : getUserProfileOnGingerbreadDevice(context);
    }

    /**
     * Retrieves the user profile information in a manner supported by Gingerbread devices.
     * @param context the context from which to retrieve the user's email address and name
     * @return a list of the possible user's email address and name
     */
    private static UserProfile getUserProfileOnGingerbreadDevice(Context context) {
        // Other that using Patterns (API level 8) this works on devices down to API level 5
        final Matcher valid_email_address = Patterns.EMAIL_ADDRESS.matcher("");
        final Account[] accounts = AccountManager.get(context).getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
        final UserProfile user_profile = new UserProfile();
        // As far as I can tell, there is no way to get the real name or phone number from the Google account
        for (Account account : accounts) {
            if (valid_email_address.reset(account.name).matches())
                user_profile.addPossibleEmail(account.name);
        }
        // Gets the phone number of the device is the device has one
        if (context.getPackageManager().hasSystemFeature(TELEPHONY_SERVICE)) {
            final TelephonyManager telephony = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
            user_profile.addPossiblePhoneNumber(telephony.getLine1Number());
        }

        return user_profile;
    }

    /**
     * Retrieves the user profile information in a manner supported by Ice Cream Sandwich devices.
     * @param context the context from which to retrieve the user's email address and name
     * @return  a list of the possible user's email address and name
     */
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    private static UserProfile getUserProfileOnIcsDevice(Context context) {
        final ContentResolver content = context.getContentResolver();
        final Cursor cursor = content.query(
                // Retrieves data rows for the device user's 'profile' contact
                Uri.withAppendedPath(
                                     ContactsContract.Profile.CONTENT_URI,
                                     ContactsContract.Contacts.Data.CONTENT_DIRECTORY),
                                     ProfileQuery.PROJECTION,

                                     // Selects only email addresses or names
                                     ContactsContract.Contacts.Data.MIMETYPE + "=? OR "
                                     + ContactsContract.Contacts.Data.MIMETYPE + "=? OR "
                                     + ContactsContract.Contacts.Data.MIMETYPE + "=? OR "
                                     + ContactsContract.Contacts.Data.MIMETYPE + "=?",
                                     new String[]{
                                             ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
                                             ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE,
                                             ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
                                             ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
                                     },

                                     // Show primary rows first. Note that there won't be a primary email address if the
                                     // user hasn't specified one.
                                     ContactsContract.Contacts.Data.IS_PRIMARY + " DESC"
        );

        final UserProfile user_profile = new UserProfile();
        String mime_type;
        while (cursor.moveToNext()) {
            mime_type = cursor.getString(ProfileQuery.MIME_TYPE);
            if (mime_type.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE))
                user_profile.addPossibleEmail(cursor.getString(ProfileQuery.EMAIL),
                                              cursor.getInt(ProfileQuery.IS_PRIMARY_EMAIL) > 0);
            else if (mime_type.equals(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE))
                user_profile.addPossibleName(cursor.getString(ProfileQuery.GIVEN_NAME) + " " + cursor.getString(ProfileQuery.FAMILY_NAME));
            else if (mime_type.equals(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE))
                user_profile.addPossiblePhoneNumber(cursor.getString(ProfileQuery.PHONE_NUMBER),
                                                    cursor.getInt(ProfileQuery.IS_PRIMARY_PHONE_NUMBER) > 0);
            else if (mime_type.equals(ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE))
                user_profile.addPossiblePhoto(Uri.parse(cursor.getString(ProfileQuery.PHOTO)));
        }

        cursor.close();

        return user_profile;
    }

    /**
     * Contacts user profile query interface.
     */
    private interface ProfileQuery {
        /** The set of columns to extract from the profile query results */
        String[] PROJECTION = {
                                ContactsContract.CommonDataKinds.Email.ADDRESS,
                                ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
                                ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME,
                                ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,
                                ContactsContract.CommonDataKinds.Phone.NUMBER,
                                ContactsContract.CommonDataKinds.Phone.IS_PRIMARY,
                                ContactsContract.CommonDataKinds.Photo.PHOTO_URI,
                                ContactsContract.Contacts.Data.MIMETYPE
        };

        /** Column index for the email address in the profile query results */
        int EMAIL = 0;
        /** Column index for the primary email address indicator in the profile query results */
        int IS_PRIMARY_EMAIL = 1;
        /** Column index for the family name in the profile query results */
        int FAMILY_NAME = 2;
        /** Column index for the given name in the profile query results */
        int GIVEN_NAME = 3;
        /** Column index for the phone number in the profile query results */
        int PHONE_NUMBER = 4;
        /** Column index for the primary phone number in the profile query results */
        int IS_PRIMARY_PHONE_NUMBER = 5;
        /** Column index for the photo in the profile query results */
        int PHOTO = 6;
        /** Column index for the MIME type in the profile query results */
        int MIME_TYPE = 7;
    }
}