blob: 2f7651f6c7ecae20776345904e2ed6b970b14b31 [file] [log] [blame]
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.contacts.activities;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.Loader;
import android.content.Loader.OnLoadCompleteListener;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.DisplayPhoto;
import android.util.Log;
import com.android.contacts.ContactSaveService;
import com.android.contacts.ContactsActivity;
import com.android.contacts.ContactsUtils;
import com.android.contacts.model.Contact;
import com.android.contacts.model.ContactLoader;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.model.RawContactDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.account.AccountType;
import com.android.contacts.util.ContactPhotoUtils;
import java.io.File;
/**
* Provides an external interface for other applications to attach images
* to contacts. It will first present a contact picker and then run the
* image that is handed to it through the cropper to make the image the proper
* size and give the user a chance to use the face detector.
*/
public class AttachPhotoActivity extends ContactsActivity {
private static final String TAG = AttachPhotoActivity.class.getSimpleName();
private static final int REQUEST_PICK_CONTACT = 1;
private static final int REQUEST_CROP_PHOTO = 2;
private static final String KEY_CONTACT_URI = "contact_uri";
private static final String KEY_TEMP_PHOTO_URI = "temp_photo_uri";
private File mTempPhotoFile;
private Uri mTempPhotoUri;
private ContentResolver mContentResolver;
// Height and width (in pixels) to request for the photo - queried from the provider.
private static int mPhotoDim;
private Uri mContactUri;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
if (icicle != null) {
final String uri = icicle.getString(KEY_CONTACT_URI);
mContactUri = (uri == null) ? null : Uri.parse(uri);
mTempPhotoUri = Uri.parse(icicle.getString(KEY_TEMP_PHOTO_URI));
mTempPhotoFile = new File(mTempPhotoUri.getPath());
} else {
mTempPhotoFile = ContactPhotoUtils.generateTempPhotoFile(this);
mTempPhotoUri = Uri.fromFile(mTempPhotoFile);
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(Contacts.CONTENT_TYPE);
startActivityForResult(intent, REQUEST_PICK_CONTACT);
}
mContentResolver = getContentResolver();
// Load the photo dimension to request.
Cursor c = mContentResolver.query(DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
new String[]{DisplayPhoto.DISPLAY_MAX_DIM}, null, null, null);
try {
c.moveToFirst();
mPhotoDim = c.getInt(0);
} finally {
c.close();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mContactUri != null) outState.putString(KEY_CONTACT_URI, mContactUri.toString());
outState.putString(KEY_TEMP_PHOTO_URI, mTempPhotoUri.toString());
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent result) {
if (resultCode != RESULT_OK) {
finish();
return;
}
if (requestCode == REQUEST_PICK_CONTACT) {
// A contact was picked. Launch the cropper to get face detection, the right size, etc.
// TODO: get these values from constants somewhere
Intent myIntent = getIntent();
Intent intent = new Intent("com.android.camera.action.CROP", myIntent.getData());
if (myIntent.getStringExtra("mimeType") != null) {
intent.setDataAndType(myIntent.getData(), myIntent.getStringExtra("mimeType"));
}
ContactPhotoUtils.addGalleryIntentExtras(intent, mTempPhotoUri, mPhotoDim);
startActivityForResult(intent, REQUEST_CROP_PHOTO);
mContactUri = result.getData();
} else if (requestCode == REQUEST_CROP_PHOTO) {
loadContact(mContactUri, new Listener() {
@Override
public void onContactLoaded(Contact contact) {
saveContact(contact);
}
});
}
}
// TODO: consider moving this to ContactLoader, especially if we keep adding similar
// code elsewhere (ViewNotificationService is another case). The only concern is that,
// although this is convenient, it isn't quite as robust as using LoaderManager... for
// instance, the loader doesn't persist across Activity restarts.
private void loadContact(Uri contactUri, final Listener listener) {
final ContactLoader loader = new ContactLoader(this, contactUri, true);
loader.registerListener(0, new OnLoadCompleteListener<Contact>() {
@Override
public void onLoadComplete(
Loader<Contact> loader, Contact contact) {
try {
loader.reset();
}
catch (RuntimeException e) {
Log.e(TAG, "Error resetting loader", e);
}
listener.onContactLoaded(contact);
}
});
loader.startLoading();
}
private interface Listener {
public void onContactLoaded(Contact contact);
}
/**
* If prerequisites have been met, attach the photo to a raw-contact and save.
* The prerequisites are:
* - photo has been cropped
* - contact has been loaded
*/
private void saveContact(Contact contact) {
// Obtain the raw-contact that we will save to.
RawContactDeltaList deltaList = contact.createRawContactDeltaList();
RawContactDelta raw = deltaList.getFirstWritableRawContact(this);
if (raw == null) {
Log.w(TAG, "no writable raw-contact found");
return;
}
// Create a scaled, compressed bitmap to add to the entity-delta list.
final int size = ContactsUtils.getThumbnailSize(this);
final Bitmap bitmap = BitmapFactory.decodeFile(mTempPhotoFile.getAbsolutePath());
final Bitmap scaled = Bitmap.createScaledBitmap(bitmap, size, size, false);
final byte[] compressed = ContactPhotoUtils.compressBitmap(scaled);
if (compressed == null) {
Log.w(TAG, "could not create scaled and compressed Bitmap");
return;
}
// Add compressed bitmap to entity-delta... this allows us to save to
// a new contact; otherwise the entity-delta-list would be empty, and
// the ContactSaveService would not create the new contact, and the
// full-res photo would fail to be saved to the non-existent contact.
AccountType account = raw.getRawContactAccountType(this);
RawContactDelta.ValuesDelta values =
RawContactModifier.ensureKindExists(raw, account, Photo.CONTENT_ITEM_TYPE);
if (values == null) {
Log.w(TAG, "cannot attach photo to this account type");
return;
}
values.setPhoto(compressed);
// Finally, invoke the ContactSaveService.
Log.v(TAG, "all prerequisites met, about to save photo to contact");
Intent intent = ContactSaveService.createSaveContactIntent(
this,
deltaList,
"", 0,
contact.isUserProfile(),
null, null,
raw.getRawContactId(),
mTempPhotoFile.getAbsolutePath());
startService(intent);
finish();
}
}