Skip to content

Instantly share code, notes, and snippets.

@imminent
Created November 12, 2012 19:55
Show Gist options
  • Star 34 You must be signed in to star a gist
  • Fork 11 You must be signed in to fork a gist
  • Save imminent/4061516 to your computer and use it in GitHub Desktop.
Save imminent/4061516 to your computer and use it in GitHub Desktop.
Utility to retrieve user profile on Android device
/**
* 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;
}
}
<?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>
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) { }
}
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;
}
@mhdtouban
Copy link

java.lang.RuntimeException: An error occured while executing doInBackground() at android.support.v4.content.ModernAsyncTask$3.done(ModernAsyncTask.java:137) at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352) at java.util.concurrent.FutureTask.setException(FutureTask.java:219) at java.util.concurrent.FutureTask.run(FutureTask.java:239) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573) at java.lang.Thread.run(Thread.java:841) Caused by: java.lang.NullPointerException: uriString at android.net.Uri$StringUri.<init>(Uri.java:468) at android.net.Uri$StringUri.<init>(Uri.java:458) at android.net.Uri.parse(Uri.java:430) at smart.taxi.pmu.common.AccountUtils.getUserProfileOnIcsDevice(AccountUtils.java:236) at smart.taxi.pmu.common.AccountUtils.getUserProfile(AccountUtils.java:163) at smart.taxi.pmu.common.UserProfileLoader.loadInBackground(UserProfileLoader.java:18) at smart.taxi.pmu.common.UserProfileLoader.loadInBackground(UserProfileLoader.java:1) at android.support.v4.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:242) at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:51) at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:40) at android.support.v4.content.ModernAsyncTask$2.call(ModernAsyncTask.java:123) at java.util.concurrent.FutureTask.run(FutureTask.java:234) ... 3 more

@goldilock
Copy link

how to initialize these, do i have to create main activity or createaccount activity will be default activity?
in short
How to use this utility properly???

_email_address
_full_name
_phone_number
_photo_picker
if (possible_emails.size() > 0) _email_address.setText(primary_email == null ? possible_emails.get(0) :

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

@flavius-mester
Copy link

do we need any permissions with this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment