I modify the example from Android SDK example so user can add and save contact person details in phone, while introducing a new photo entity called “geotag photo”. User are given two options (gallery or camera) to import image.
BUT the apps crash when user select image from gallery, ALSO if user taking a photo.
below is my class:
package com.example.android.contactmanager;
public final class ContactAdder extends Activity implements OnAccountsUpdateListener
{
public static final String TAG = "ContactsAdder";
public static final String ACCOUNT_NAME =
"com.example.android.contactmanager.ContactsAdder.ACCOUNT_NAME";
public static final String ACCOUNT_TYPE =
"com.example.android.contactmanager.ContactsAdder.ACCOUNT_TYPE";
private final int CAMERA_PICTURE = 1;
private final int GALLERY_PICTURE = 2;
private ImageView userPictureImageView;
private Intent pictureActionIntent = null;
private ArrayList<AccountData> mAccounts;
private AccountAdapter mAccountAdapter;
private Spinner mAccountSpinner;
private EditText mContactEmailEditText;
private ArrayList<Integer> mContactEmailTypes;
private Spinner mContactEmailTypeSpinner;
private EditText mContactNameEditText;
private EditText mContactPhoneEditText;
private ArrayList<Integer> mContactPhoneTypes;
private Spinner mContactPhoneTypeSpinner;
private Button mContactSaveButton;
private AccountData mSelectedAccount;
private EditText mContactGeoPhotoEditText;
/**
* Called when the activity is first created. Responsible for initializing the UI.
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
Log.v(TAG, "Activity State: onCreate()");
super.onCreate(savedInstanceState);
setContentView(R.layout.contact_adder);
Button buttonLoadImage = (Button) findViewById(R.id.buttonLoadPicture);
buttonLoadImage.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startDialog();
}
});
// Obtain handles to UI objects
mAccountSpinner = (Spinner) findViewById(R.id.accountSpinner);
mContactNameEditText = (EditText) findViewById(R.id.contactNameEditText);
mContactPhoneEditText = (EditText) findViewById(R.id.contactPhoneEditText);
mContactEmailEditText = (EditText) findViewById(R.id.contactEmailEditText);
mContactPhoneTypeSpinner = (Spinner) findViewById(R.id.contactPhoneTypeSpinner);
mContactEmailTypeSpinner = (Spinner) findViewById(R.id.contactEmailTypeSpinner);
mContactSaveButton = (Button) findViewById(R.id.contactSaveButton);
mContactGeoPhotoEditText = (EditText) findViewById(R.id.PhotoLocation);
mContactPhoneTypes = new ArrayList<Integer>();
mContactPhoneTypes.add(ContactsContract.CommonDataKinds.Phone.TYPE_HOME);
mContactPhoneTypes.add(ContactsContract.CommonDataKinds.Phone.TYPE_WORK);
mContactPhoneTypes.add(ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
mContactPhoneTypes.add(ContactsContract.CommonDataKinds.Phone.TYPE_OTHER);
mContactEmailTypes = new ArrayList<Integer>();
mContactEmailTypes.add(ContactsContract.CommonDataKinds.Email.TYPE_HOME);
mContactEmailTypes.add(ContactsContract.CommonDataKinds.Email.TYPE_WORK);
mContactEmailTypes.add(ContactsContract.CommonDataKinds.Email.TYPE_MOBILE);
mContactEmailTypes.add(ContactsContract.CommonDataKinds.Email.TYPE_OTHER);
// Prepare model for account spinner
mAccounts = new ArrayList<AccountData>();
mAccountAdapter = new AccountAdapter(this, mAccounts);
mAccountSpinner.setAdapter(mAccountAdapter);
// Populate list of account types for phone
ArrayAdapter<String> adapter;
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Iterator<Integer> iter;
iter = mContactPhoneTypes.iterator();
while (iter.hasNext()) {
adapter.add(ContactsContract.CommonDataKinds.Phone.getTypeLabel(
this.getResources(),
iter.next(),
getString(R.string.undefinedTypeLabel)).toString());
}
mContactPhoneTypeSpinner.setAdapter(adapter);
mContactPhoneTypeSpinner.setPrompt(getString(R.string.selectLabel));
// Populate list of account types for email
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
iter = mContactEmailTypes.iterator();
while (iter.hasNext()) {
adapter.add(ContactsContract.CommonDataKinds.Email.getTypeLabel(
this.getResources(),
iter.next(),
getString(R.string.undefinedTypeLabel)).toString());
}
mContactEmailTypeSpinner.setAdapter(adapter);
mContactEmailTypeSpinner.setPrompt(getString(R.string.selectLabel));
AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
// Register handlers for UI elements
mAccountSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long i) {
updateAccountSelection();
}
public void onNothingSelected(AdapterView<?> parent) {
// We don't need to worry about nothing being selected, since Spinners don't allow
// this.
}
});
mContactSaveButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
onSaveButtonClicked();
}
});
}
@Override
//working original
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
//try with integrated
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GALLERY_PICTURE)
{
Uri selectedImage = data.getData();
if (selectedImage != null)
{
// User had pick an image.
Cursor cursor = getContentResolver().query(selectedImage, new String[] { android.provider.MediaStore.Images.ImageColumns.DATA }, null, null, null);
cursor.moveToFirst();
// Link to the image
final String imageFilePath = cursor.getString(0);
File photos = new File(imageFilePath);
Toast picturePath = Toast.makeText(this, imageFilePath, Toast.LENGTH_LONG);
picturePath.show();
Bitmap b = decodeFile(photos);
b = Bitmap.createScaledBitmap(b, 150, 150, true);
userPictureImageView.setImageBitmap(b);
cursor.close();
// ImageView imageView = (ImageView) findViewById(R.id.imgView);
// imageView.setImageBitmap(BitmapFactory.decodeFile(imageFilePath));
}
else
{
Toast toast = Toast.makeText(this, "No Image is selected.", Toast.LENGTH_LONG);
toast.show();
}
}
else if (requestCode == CAMERA_PICTURE) {
CheckEnableGPS();
if (data.getExtras() != null) {
// here is the image from camera
Bitmap bitmap = (Bitmap) data.getExtras().get("data");
userPictureImageView.setImageBitmap(bitmap);
ImageView imageView = (ImageView) findViewById(R.id.imgView);
}
}
}
private Bitmap decodeFile(File f) {
try {
// decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 70;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale++;
}
// decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
}
catch (FileNotFoundException e) {
}
return null;
}
private void startDialog() {
AlertDialog.Builder myAlertDialog = new AlertDialog.Builder(this);
myAlertDialog.setTitle("Select Pictures Option");
myAlertDialog.setMessage("How do you want to set your picture?");
myAlertDialog.setPositiveButton("Gallery", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
pictureActionIntent = new Intent(Intent.ACTION_GET_CONTENT, null);
pictureActionIntent.setType("image/*");
pictureActionIntent.putExtra("return-data", true);
startActivityForResult(pictureActionIntent, GALLERY_PICTURE);
}
});
myAlertDialog.setNegativeButton("Camera", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
pictureActionIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(pictureActionIntent, CAMERA_PICTURE);
}
});
myAlertDialog.show();
}
private void CheckEnableGPS()
{
String provider = Settings.Secure.getString(getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if(!provider.equals("")){
//GPS Enabled
Toast.makeText(ContactAdder.this, "GPS Enabled: " + provider, Toast.LENGTH_LONG).show();
}
else
{
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this);
dlgAlert.setMessage("Please make sure that you turn on the GPS setting and have a clear view of the sky.");
dlgAlert.setTitle("Kindly Remind That...");
dlgAlert.setPositiveButton("OK", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface arg0, int arg1)
{
try
{
Intent intent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
startActivity(intent);
}//end try
catch(Exception e)
{
Toast.makeText(getBaseContext(), "", Toast.LENGTH_LONG).show();
}//end catch
}//end onClick()
}).create();
dlgAlert.setCancelable(true);
dlgAlert.create().show();
}
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
private void geoTag(String absolutePath, double latitude, double longitude) {
// TODO Auto-generated method stub
}
/**
* Actions for when the Save button is clicked. Creates a contact entry and terminates the
* activity.
*/
private void onSaveButtonClicked() {
Log.v(TAG, "Save button clicked");
createContactEntry();
finish();
}
/**
* Creates a contact entry from the current UI values in the account named by mSelectedAccount.
*/
protected void createContactEntry() {
// Get values from UI
String name = mContactNameEditText.getText().toString();
String phone = mContactPhoneEditText.getText().toString();
String email = mContactEmailEditText.getText().toString();
int phoneType = mContactPhoneTypes.get(
mContactPhoneTypeSpinner.getSelectedItemPosition());
int emailType = mContactEmailTypes.get(
mContactEmailTypeSpinner.getSelectedItemPosition());
// String geotagPhoto = mContactGeoPhotoEditText.getText().toString() ;
// Prepare contact creation request
//
// Note: We use RawContacts because this data must be associated with a particular account.
// The system will aggregate this with any other data for this contact and create a
// corresponding entry in the ContactsContract.Contacts provider for us.
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType())
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName())
.build());
ops.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, name)
.build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType)
.build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Email.DATA, email)
.withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType)
.build());
// ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
// .withValue(ContactsContract.CommonDataKinds.Note.DATA1, geotagPhoto)
// .build());
// Ask the Contact provider to create a new contact
Log.i(TAG,"Selected account: " + mSelectedAccount.getName() + " (" + mSelectedAccount.getType() + ")");
Log.i(TAG,"Creating contact: " + name);
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (Exception e) {
// Display warning
Context ctx = getApplicationContext();
CharSequence txt = getString(R.string.contactCreationFailure);
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(ctx, txt, duration);
toast.show();
// Log exception
Log.e(TAG, "Exceptoin encoutered while inserting contact: " + e);
}
}
/**
* Called when this activity is about to be destroyed by the system.
*/
@Override
public void onDestroy() {
// Remove AccountManager callback
AccountManager.get(this).removeOnAccountsUpdatedListener(this);
super.onDestroy();
}
/**
* Updates account list spinner when the list of Accounts on the system changes. Satisfies
* OnAccountsUpdateListener implementation.
*/
public void onAccountsUpdated(Account[] a) {
Log.i(TAG, "Account list update detected");
// Clear out any old data to prevent duplicates
mAccounts.clear();
// Get account data from system
AuthenticatorDescription[] accountTypes = AccountManager.get(this).getAuthenticatorTypes();
// Populate tables
for (int i = 0; i < a.length; i++) {
// The user may have multiple accounts with the same name, so we need to construct a
// meaningful display name for each.
String systemAccountType = a[i].type;
AuthenticatorDescription ad = getAuthenticatorDescription(systemAccountType,
accountTypes);
AccountData data = new AccountData(a[i].name, ad);
mAccounts.add(data);
}
// Update the account spinner
mAccountAdapter.notifyDataSetChanged();
}
/**
* Obtain the AuthenticatorDescription for a given account type.
* @param type The account type to locate.
* @param dictionary An array of AuthenticatorDescriptions, as returned by AccountManager.
* @return The description for the specified account type.
*/
private static AuthenticatorDescription getAuthenticatorDescription(String type,
AuthenticatorDescription[] dictionary) {
for (int i = 0; i < dictionary.length; i++) {
if (dictionary[i].type.equals(type)) {
return dictionary[i];
}
}
// No match found
throw new RuntimeException("Unable to find matching authenticator");
}
/**
* Update account selection. If NO_ACCOUNT is selected, then we prohibit inserting new contacts.
*/
private void updateAccountSelection() {
// Read current account selection
mSelectedAccount = (AccountData) mAccountSpinner.getSelectedItem();
}
/**
* A container class used to represent all known information about an account.
*/
private class AccountData {
private String mName;
private String mType;
private CharSequence mTypeLabel;
private Drawable mIcon;
/**
* @param name The name of the account. This is usually the user's email address or
* username.
* @param description The description for this account. This will be dictated by the
* type of account returned, and can be obtained from the system AccountManager.
*/
public AccountData(String name, AuthenticatorDescription description) {
mName = name;
if (description != null) {
mType = description.type;
// The type string is stored in a resource, so we need to convert it into something
// human readable.
String packageName = description.packageName;
PackageManager pm = getPackageManager();
if (description.labelId != 0) {
mTypeLabel = pm.getText(packageName, description.labelId, null);
if (mTypeLabel == null) {
throw new IllegalArgumentException("LabelID provided, but label not found");
}
} else {
mTypeLabel = "";
}
if (description.iconId != 0) {
mIcon = pm.getDrawable(packageName, description.iconId, null);
if (mIcon == null) {
throw new IllegalArgumentException("IconID provided, but drawable not " +
"found");
}
} else {
mIcon = getResources().getDrawable(android.R.drawable.sym_def_app_icon);
}
}
}
public String getName() {
return mName;
}
public String getType() {
return mType;
}
public CharSequence getTypeLabel() {
return mTypeLabel;
}
public Drawable getIcon() {
return mIcon;
}
public String toString() {
return mName;
}
}
/**
* Custom adapter used to display account icons and descriptions in the account spinner.
*/
private class AccountAdapter extends ArrayAdapter<AccountData> {
public AccountAdapter(Context context, ArrayList<AccountData> accountData) {
super(context, android.R.layout.simple_spinner_item, accountData);
setDropDownViewResource(R.layout.account_entry);
}
public View getDropDownView(int position, View convertView, ViewGroup parent) {
// Inflate a view template
if (convertView == null) {
LayoutInflater layoutInflater = getLayoutInflater();
convertView = layoutInflater.inflate(R.layout.account_entry, parent, false);
}
TextView firstAccountLine = (TextView) convertView.findViewById(R.id.firstAccountLine);
TextView secondAccountLine = (TextView) convertView.findViewById(R.id.secondAccountLine);
ImageView accountIcon = (ImageView) convertView.findViewById(R.id.accountIcon);
// Populate template
AccountData data = getItem(position);
firstAccountLine.setText(data.getName());
secondAccountLine.setText(data.getTypeLabel());
Drawable icon = data.getIcon();
if (icon == null) {
icon = getResources().getDrawable(android.R.drawable.ic_menu_search);
}
accountIcon.setImageDrawable(icon);
return convertView;
}
}
}
the logcat as below:
12-26 15:15:13.628: V/ContactManager(377): Activity State: onCreate()
12-26 15:15:13.878: W/Resources(377): Converting to string: TypedValue{t=0x12/d=0x0 a=2 r=0x7f05000d}
12-26 15:28:33.378: V/ContactManager(410): Activity State: onCreate()
12-26 15:28:33.698: W/Resources(410): Converting to string: TypedValue{t=0x12/d=0x0 a=2 r=0x7f05000d}
12-26 15:29:17.698: I/TAG(410): You clicked item 1 at position 0
12-26 15:29:17.718: I/Show Contact Clicked:(410): Tan Chi WeeEmail: null
12-26 15:29:17.827: D/dalvikvm(410): GC_EXTERNAL_ALLOC freed 72K, 49% free 2782K/5379K, external 2032K/2137K, paused 53ms
12-26 15:29:20.018: W/KeyCharacterMap(410): No keyboard for id 0
12-26 15:29:20.018: W/KeyCharacterMap(410): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
12-26 15:29:20.158: W/Resources(410): Converting to string: TypedValue{t=0x12/d=0x0 a=2 r=0x7f05000d}
12-26 15:29:21.578: D/ContactManager(410): mAddAccountButton clicked
12-26 15:29:21.648: V/ContactsAdder(410): Activity State: onCreate()
12-26 15:29:21.758: I/ContactsAdder(410): Account list update detected
12-26 15:29:26.408: W/IInputConnectionWrapper(410): showStatusIcon on inactive InputConnection
12-26 15:29:29.348: D/AndroidRuntime(410): Shutting down VM
12-26 15:29:29.348: W/dalvikvm(410): threadid=1: thread exiting with uncaught exception (group=0x40015560)
12-26 15:29:29.359: E/AndroidRuntime(410): FATAL EXCEPTION: main
12-26 15:29:29.359: E/AndroidRuntime(410): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=2, result=-1, data=Intent { dat=content://media/external/images/media/1 (has extras) }} to activity {com.example.android.contactmanager/com.example.android.contactmanager.ContactAdder}: java.lang.NullPointerException
12-26 15:29:29.359: E/AndroidRuntime(410): at android.app.ActivityThread.deliverResults(ActivityThread.java:2532)
12-26 15:29:29.359: E/AndroidRuntime(410): at android.app.ActivityThread.handleSendResult(ActivityThread.java:2574)
12-26 15:29:29.359: E/AndroidRuntime(410): at android.app.ActivityThread.access$2000(ActivityThread.java:117)
12-26 15:29:29.359: E/AndroidRuntime(410): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:961)
12-26 15:29:29.359: E/AndroidRuntime(410): at android.os.Handler.dispatchMessage(Handler.java:99)
12-26 15:29:29.359: E/AndroidRuntime(410): at android.os.Looper.loop(Looper.java:130)
12-26 15:29:29.359: E/AndroidRuntime(410): at android.app.ActivityThread.main(ActivityThread.java:3683)
12-26 15:29:29.359: E/AndroidRuntime(410): at java.lang.reflect.Method.invokeNative(Native Method)
12-26 15:29:29.359: E/AndroidRuntime(410): at java.lang.reflect.Method.invoke(Method.java:507)
12-26 15:29:29.359: E/AndroidRuntime(410): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
12-26 15:29:29.359: E/AndroidRuntime(410): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
12-26 15:29:29.359: E/AndroidRuntime(410): at dalvik.system.NativeStart.main(Native Method)
12-26 15:29:29.359: E/AndroidRuntime(410): Caused by: java.lang.NullPointerException
12-26 15:29:29.359: E/AndroidRuntime(410): at com.example.android.contactmanager.ContactAdder.onActivityResult(ContactAdder.java:221)
12-26 15:29:29.359: E/AndroidRuntime(410): at android.app.Activity.dispatchActivityResult(Activity.java:3908)
12-26 15:29:29.359: E/AndroidRuntime(410): at android.app.ActivityThread.deliverResults(ActivityThread.java:2528)
12-26 15:29:29.359: E/AndroidRuntime(410): ... 11 more
12-26 15:29:31.818: I/Process(410): Sending signal. PID: 410 SIG: 9
As mentioned in the comments, your crash is on this line:
This means that
userPictureImageViewis null. A quick look through your code confirms this: You define it in the class (as a member variable), but never define it.You need to do so in
onCreate()with the others:Side note: Learn to read LogCat logs: