diff options
Diffstat (limited to 'src/com/android/settings/users/EditUserPhotoController.java')
-rw-r--r-- | src/com/android/settings/users/EditUserPhotoController.java | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/src/com/android/settings/users/EditUserPhotoController.java b/src/com/android/settings/users/EditUserPhotoController.java new file mode 100644 index 0000000..82e550e --- /dev/null +++ b/src/com/android/settings/users/EditUserPhotoController.java @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2013 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.settings.users; + +import android.app.Activity; +import android.app.Fragment; +import android.content.ClipData; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Bitmap.Config; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.AsyncTask; +import android.provider.MediaStore; +import android.provider.ContactsContract.DisplayPhoto; +import android.support.v4.content.FileProvider; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.ListAdapter; +import android.widget.ListPopupWindow; + +import com.android.settings.R; +import com.android.settings.drawable.CircleFramedDrawable; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +public class EditUserPhotoController { + private static final String TAG = "EditUserPhotoController"; + + private static final int POPUP_LIST_ITEM_ID_CHOOSE_PHOTO = 1; + private static final int POPUP_LIST_ITEM_ID_TAKE_PHOTO = 2; + + // It seems that this class generates custom request codes and they may + // collide with ours, these values are very unlikely to have a conflict. + private static final int REQUEST_CODE_CHOOSE_PHOTO = 1001; + private static final int REQUEST_CODE_TAKE_PHOTO = 1002; + private static final int REQUEST_CODE_CROP_PHOTO = 1003; + + private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg"; + private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto2.jpg"; + + private final int mPhotoSize; + + private final Context mContext; + private final Fragment mFragment; + private final ImageView mImageView; + + private final Uri mCropPictureUri; + private final Uri mTakePictureUri; + + private Bitmap mNewUserPhotoBitmap; + private Drawable mNewUserPhotoDrawable; + + public EditUserPhotoController(Fragment fragment, ImageView view, + Bitmap bitmap, Drawable drawable, boolean waiting) { + mContext = view.getContext(); + mFragment = fragment; + mImageView = view; + mCropPictureUri = createTempImageUri(mContext, CROP_PICTURE_FILE_NAME, !waiting); + mTakePictureUri = createTempImageUri(mContext, TAKE_PICTURE_FILE_NAME, !waiting); + mPhotoSize = getPhotoSize(mContext); + mImageView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + showUpdatePhotoPopup(); + } + }); + mNewUserPhotoBitmap = bitmap; + mNewUserPhotoDrawable = drawable; + } + + public boolean onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode != Activity.RESULT_OK) { + return false; + } + final Uri pictureUri = data != null && data.getData() != null + ? data.getData() : mTakePictureUri; + switch (requestCode) { + case REQUEST_CODE_CROP_PHOTO: + onPhotoCropped(pictureUri, true); + return true; + case REQUEST_CODE_TAKE_PHOTO: + case REQUEST_CODE_CHOOSE_PHOTO: + cropPhoto(pictureUri); + return true; + } + return false; + } + + public Bitmap getNewUserPhotoBitmap() { + return mNewUserPhotoBitmap; + } + + public Drawable getNewUserPhotoDrawable() { + return mNewUserPhotoDrawable; + } + + private void showUpdatePhotoPopup() { + final boolean canTakePhoto = canTakePhoto(); + final boolean canChoosePhoto = canChoosePhoto(); + + if (!canTakePhoto && !canChoosePhoto) { + return; + } + + Context context = mImageView.getContext(); + final List<EditUserPhotoController.AdapterItem> items = new ArrayList<EditUserPhotoController.AdapterItem>(); + + if (canTakePhoto()) { + String title = mImageView.getContext().getString( R.string.user_image_take_photo); + EditUserPhotoController.AdapterItem item = new AdapterItem(title, POPUP_LIST_ITEM_ID_TAKE_PHOTO); + items.add(item); + } + + if (canChoosePhoto) { + String title = context.getString(R.string.user_image_choose_photo); + EditUserPhotoController.AdapterItem item = new AdapterItem(title, POPUP_LIST_ITEM_ID_CHOOSE_PHOTO); + items.add(item); + } + + final ListPopupWindow listPopupWindow = new ListPopupWindow(context); + + listPopupWindow.setAnchorView(mImageView); + listPopupWindow.setModal(true); + listPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED); + + ListAdapter adapter = new ArrayAdapter<EditUserPhotoController.AdapterItem>(context, + R.layout.edit_user_photo_popup_item, items); + listPopupWindow.setAdapter(adapter); + + final int width = Math.max(mImageView.getWidth(), context.getResources() + .getDimensionPixelSize(R.dimen.update_user_photo_popup_min_width)); + listPopupWindow.setWidth(width); + + listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + EditUserPhotoController.AdapterItem item = items.get(position); + switch (item.id) { + case POPUP_LIST_ITEM_ID_CHOOSE_PHOTO: { + choosePhoto(); + listPopupWindow.dismiss(); + } break; + case POPUP_LIST_ITEM_ID_TAKE_PHOTO: { + takePhoto(); + listPopupWindow.dismiss(); + } break; + } + } + }); + + listPopupWindow.show(); + } + + private boolean canTakePhoto() { + return mImageView.getContext().getPackageManager().queryIntentActivities( + new Intent(MediaStore.ACTION_IMAGE_CAPTURE), + PackageManager.MATCH_DEFAULT_ONLY).size() > 0; + } + + private boolean canChoosePhoto() { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("image/*"); + return mImageView.getContext().getPackageManager().queryIntentActivities( + intent, 0).size() > 0; + } + + private void takePhoto() { + Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + appendOutputExtra(intent, mTakePictureUri); + mFragment.startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO); + } + + private void choosePhoto() { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); + intent.setType("image/*"); + appendOutputExtra(intent, mTakePictureUri); + mFragment.startActivityForResult(intent, REQUEST_CODE_CHOOSE_PHOTO); + } + + private void cropPhoto(Uri pictureUri) { + // TODO: Use a public intent, when there is one. + Intent intent = new Intent("com.android.camera.action.CROP"); + intent.setDataAndType(pictureUri, "image/*"); + appendOutputExtra(intent, mCropPictureUri); + appendCropExtras(intent); + if (intent.resolveActivity(mContext.getPackageManager()) != null) { + mFragment.startActivityForResult(intent, REQUEST_CODE_CROP_PHOTO); + } else { + onPhotoCropped(pictureUri, false); + } + } + + private void appendOutputExtra(Intent intent, Uri pictureUri) { + intent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri); + intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION + | Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setClipData(ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, pictureUri)); + } + + private void appendCropExtras(Intent intent) { + intent.putExtra("crop", "true"); + intent.putExtra("scale", true); + intent.putExtra("scaleUpIfNeeded", true); + intent.putExtra("aspectX", 1); + intent.putExtra("aspectY", 1); + intent.putExtra("outputX", mPhotoSize); + intent.putExtra("outputY", mPhotoSize); + } + + private void onPhotoCropped(final Uri data, final boolean cropped) { + new AsyncTask<Void, Void, Bitmap>() { + @Override + protected Bitmap doInBackground(Void... params) { + if (cropped) { + InputStream imageStream = null; + try { + imageStream = mContext.getContentResolver() + .openInputStream(data); + return BitmapFactory.decodeStream(imageStream); + } catch (FileNotFoundException fe) { + Log.w(TAG, "Cannot find image file", fe); + return null; + } finally { + if (imageStream != null) { + try { + imageStream.close(); + } catch (IOException ioe) { + Log.w(TAG, "Cannot close image stream", ioe); + } + } + } + } else { + // Scale and crop to a square aspect ratio + Bitmap croppedImage = Bitmap.createBitmap(mPhotoSize, mPhotoSize, + Config.ARGB_8888); + Canvas canvas = new Canvas(croppedImage); + Bitmap fullImage = null; + try { + InputStream imageStream = mContext.getContentResolver() + .openInputStream(data); + fullImage = BitmapFactory.decodeStream(imageStream); + } catch (FileNotFoundException fe) { + return null; + } + if (fullImage != null) { + final int squareSize = Math.min(fullImage.getWidth(), + fullImage.getHeight()); + final int left = (fullImage.getWidth() - squareSize) / 2; + final int top = (fullImage.getHeight() - squareSize) / 2; + Rect rectSource = new Rect(left, top, + left + squareSize, top + squareSize); + Rect rectDest = new Rect(0, 0, mPhotoSize, mPhotoSize); + Paint paint = new Paint(); + canvas.drawBitmap(fullImage, rectSource, rectDest, paint); + return croppedImage; + } else { + // Bah! Got nothin. + return null; + } + } + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (bitmap != null) { + mNewUserPhotoBitmap = bitmap; + mNewUserPhotoDrawable = CircleFramedDrawable + .getInstance(mImageView.getContext(), mNewUserPhotoBitmap); + mImageView.setImageDrawable(mNewUserPhotoDrawable); + } + new File(mContext.getCacheDir(), TAKE_PICTURE_FILE_NAME).delete(); + new File(mContext.getCacheDir(), CROP_PICTURE_FILE_NAME).delete(); + } + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); + } + + private static int getPhotoSize(Context context) { + Cursor cursor = context.getContentResolver().query( + DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI, + new String[]{DisplayPhoto.DISPLAY_MAX_DIM}, null, null, null); + try { + cursor.moveToFirst(); + return cursor.getInt(0); + } finally { + cursor.close(); + } + } + + private Uri createTempImageUri(Context context, String fileName, boolean purge) { + final File folder = context.getCacheDir(); + folder.mkdirs(); + final File fullPath = new File(folder, fileName); + if (purge) { + fullPath.delete(); + } + final Uri fileUri = + FileProvider.getUriForFile(context, RestrictedProfileSettings.FILE_PROVIDER_AUTHORITY, fullPath); + return fileUri; + } + + private static final class AdapterItem { + final String title; + final int id; + + public AdapterItem(String title, int id) { + this.title = title; + this.id = id; + } + + @Override + public String toString() { + return title; + } + } +}
\ No newline at end of file |