blob: 1696a12f29af1590673a619324bf2847b6d8e6d5 [file] [log] [blame]
/*
* Copyright (C) 2015 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.editor;
import com.android.contacts.R;
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
import com.android.contacts.util.SchedulingUtils;
import com.android.contacts.widget.QuickContactImageView;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.net.Uri;
import android.provider.ContactsContract;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
/**
* Displays a photo and calls the host back when the user clicks it.
*/
public class CompactPhotoEditorView extends RelativeLayout implements View.OnClickListener {
/**
* Callbacks for the host of this view.
*/
public interface Listener {
/**
* Invoked when the user wants to change their photo.
*/
void onPhotoEditorViewClicked();
}
private Listener mListener;
private final float mLandscapePhotoRatio;
private final float mPortraitPhotoRatio;
private final boolean mIsTwoPanel;
private final int mActionBarHeight;
private final int mStatusBarHeight;
private QuickContactImageView mPhotoImageView;
private View mPhotoIcon;
private View mPhotoIconOverlay;
private View mPhotoTouchInterceptOverlay;
private boolean mReadOnly;
private boolean mIsNonDefaultPhotoBound;
public CompactPhotoEditorView(Context context) {
this(context, null);
}
public CompactPhotoEditorView(Context context, AttributeSet attrs) {
super(context, attrs);
mLandscapePhotoRatio = getTypedFloat(R.dimen.quickcontact_landscape_photo_ratio);
mPortraitPhotoRatio = getTypedFloat(R.dimen.editor_portrait_photo_ratio);
mIsTwoPanel = getResources().getBoolean(R.bool.quickcontact_two_panel);
final TypedArray styledAttributes = getContext().getTheme().obtainStyledAttributes(
new int[] { android.R.attr.actionBarSize });
mActionBarHeight = (int) styledAttributes.getDimension(0, 0);
styledAttributes.recycle();
final int resourceId = getResources().getIdentifier(
"status_bar_height", "dimen", "android");
mStatusBarHeight = resourceId > 0 ? getResources().getDimensionPixelSize(resourceId) : 0;
}
private float getTypedFloat(int resourceId) {
final TypedValue typedValue = new TypedValue();
getResources().getValue(resourceId, typedValue, /* resolveRefs =*/ true);
return typedValue.getFloat();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mPhotoImageView = (QuickContactImageView) findViewById(R.id.photo);
mPhotoIcon = findViewById(R.id.photo_icon);
mPhotoIconOverlay = findViewById(R.id.photo_icon_overlay);
mPhotoTouchInterceptOverlay = findViewById(R.id.photo_touch_intercept_overlay);
}
public void setListener(Listener listener) {
mListener = listener;
}
public void setReadOnly(boolean readOnly) {
mReadOnly = readOnly;
if (mReadOnly) {
mPhotoIcon.setVisibility(View.GONE);
mPhotoIconOverlay.setVisibility(View.GONE);
} else {
mPhotoTouchInterceptOverlay.setOnClickListener(this);
}
}
/**
* Tries to bind a full size photo or a bitmap loaded from the given ValuesDelta,
* and falls back to the default avatar, tinted using the given MaterialPalette (if it's not
* null);
*/
public void setPhoto(ValuesDelta valuesDelta, MaterialPalette materialPalette) {
// Check if we can update to the full size photo immediately
final Long photoFileId = EditorUiUtils.getPhotoFileId(valuesDelta);
if (photoFileId != null) {
final Uri photoUri = ContactsContract.DisplayPhoto.CONTENT_URI.buildUpon()
.appendPath(photoFileId.toString()).build();
setFullSizedPhoto(photoUri);
adjustDimensions();
return;
}
// Use the bitmap image from the values delta
final Bitmap bitmap = EditorUiUtils.getPhotoBitmap(valuesDelta);
if (bitmap != null) {
setPhoto(bitmap);
adjustDimensions();
return;
}
setDefaultPhoto(materialPalette);
adjustDimensions();
}
private void adjustDimensions() {
// Follow the same logic as MultiShrinkScroll.initialize
SchedulingUtils.doOnPreDraw(this, /* drawNextFrame =*/ false, new Runnable() {
@Override
public void run() {
final int photoHeight, photoWidth;
if (mIsTwoPanel) {
photoHeight = getContentViewHeight();
photoWidth = (int) (photoHeight * mLandscapePhotoRatio);
} else {
// Make the photo slightly shorter that it is wide
photoWidth = getContentViewWidth();
photoHeight = (int) (photoWidth / mPortraitPhotoRatio);
}
final ViewGroup.LayoutParams layoutParams = getLayoutParams();
layoutParams.height = photoHeight;
layoutParams.width = photoWidth;
setLayoutParams(layoutParams);
}
});
}
private int getContentViewWidth() {
final Activity activity = (Activity) getContext();
final DisplayMetrics displayMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
// We're calculating the height the hard way because using the height of the content view
// (found using android.view.Window.ID_ANDROID_CONTENT) with the soft keyboard up when
// going from portrait to landscape mode results in a very small height value.
// See b/20526470
private int getContentViewHeight() {
final Activity activity = (Activity) getContext();
final DisplayMetrics displayMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.heightPixels - mActionBarHeight - mStatusBarHeight;
}
/**
* Whether a removable, non-default photo is bound to this view.
*/
public boolean isWritablePhotoSet() {
return !mReadOnly && mIsNonDefaultPhotoBound;
}
/**
* Binds the given bitmap.
*/
private void setPhoto(Bitmap bitmap) {
mPhotoImageView.setImageBitmap(bitmap);
mIsNonDefaultPhotoBound = true;
}
private void setDefaultPhoto(MaterialPalette materialPalette) {
EditorUiUtils.setDefaultPhoto(mPhotoImageView, getResources(), materialPalette);
}
/**
* Binds a full size photo loaded from the given Uri.
*/
public void setFullSizedPhoto(Uri photoUri) {
EditorUiUtils.loadPhoto(ContactPhotoManager.getInstance(getContext()),
mPhotoImageView, photoUri);
mIsNonDefaultPhotoBound = true;
}
/**
* Removes the current bound photo bitmap.
*/
public void removePhoto() {
mPhotoImageView.setImageBitmap(/* bitmap =*/ null);
mIsNonDefaultPhotoBound = false;
setDefaultPhoto(/* materialPalette =*/ null);
}
@Override
public void onClick(View view) {
if (mListener != null) {
mListener.onPhotoEditorViewClicked();
}
}
}