diff options
Diffstat (limited to 'src/com/android/gallery3d/ingest/ui')
5 files changed, 666 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/ingest/ui/DateTileView.java b/src/com/android/gallery3d/ingest/ui/DateTileView.java new file mode 100644 index 000000000..52fe9b85b --- /dev/null +++ b/src/com/android/gallery3d/ingest/ui/DateTileView.java @@ -0,0 +1,107 @@ +/* + * 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.gallery3d.ingest.ui; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.FrameLayout; +import android.widget.TextView; + +import com.android.gallery3d.R; +import com.android.gallery3d.ingest.SimpleDate; + +import java.text.DateFormatSymbols; +import java.util.Locale; + +public class DateTileView extends FrameLayout { + private static String[] sMonthNames = DateFormatSymbols.getInstance().getShortMonths(); + private static Locale sLocale; + + static { + refreshLocale(); + } + + public static boolean refreshLocale() { + Locale currentLocale = Locale.getDefault(); + if (!currentLocale.equals(sLocale)) { + sLocale = currentLocale; + sMonthNames = DateFormatSymbols.getInstance(sLocale).getShortMonths(); + return true; + } else { + return false; + } + } + + private TextView mDateTextView; + private TextView mMonthTextView; + private TextView mYearTextView; + private int mMonth = -1; + private int mYear = -1; + private int mDate = -1; + private String[] mMonthNames = sMonthNames; + + public DateTileView(Context context) { + super(context); + } + + public DateTileView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public DateTileView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Force this to be square + super.onMeasure(widthMeasureSpec, widthMeasureSpec); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mDateTextView = (TextView) findViewById(R.id.date_tile_day); + mMonthTextView = (TextView) findViewById(R.id.date_tile_month); + mYearTextView = (TextView) findViewById(R.id.date_tile_year); + } + + public void setDate(SimpleDate date) { + setDate(date.getDay(), date.getMonth(), date.getYear()); + } + + public void setDate(int date, int month, int year) { + if (date != mDate) { + mDate = date; + mDateTextView.setText(mDate > 9 ? Integer.toString(mDate) : "0" + mDate); + } + if (mMonthNames != sMonthNames) { + mMonthNames = sMonthNames; + if (month == mMonth) { + mMonthTextView.setText(mMonthNames[mMonth]); + } + } + if (month != mMonth) { + mMonth = month; + mMonthTextView.setText(mMonthNames[mMonth]); + } + if (year != mYear) { + mYear = year; + mYearTextView.setText(Integer.toString(mYear)); + } + } +} diff --git a/src/com/android/gallery3d/ingest/ui/IngestGridView.java b/src/com/android/gallery3d/ingest/ui/IngestGridView.java new file mode 100644 index 000000000..c821259fe --- /dev/null +++ b/src/com/android/gallery3d/ingest/ui/IngestGridView.java @@ -0,0 +1,58 @@ +/* + * 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.gallery3d.ingest.ui; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.GridView; + +/** + * This just extends GridView with the ability to listen for calls + * to clearChoices() + */ +public class IngestGridView extends GridView { + + public interface OnClearChoicesListener { + public void onClearChoices(); + } + + private OnClearChoicesListener mOnClearChoicesListener = null; + + public IngestGridView(Context context) { + super(context); + } + + public IngestGridView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public IngestGridView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public void setOnClearChoicesListener(OnClearChoicesListener l) { + mOnClearChoicesListener = l; + } + + @Override + public void clearChoices() { + super.clearChoices(); + if (mOnClearChoicesListener != null) { + mOnClearChoicesListener.onClearChoices(); + } + } +} diff --git a/src/com/android/gallery3d/ingest/ui/MtpFullscreenView.java b/src/com/android/gallery3d/ingest/ui/MtpFullscreenView.java new file mode 100644 index 000000000..8d3884dc6 --- /dev/null +++ b/src/com/android/gallery3d/ingest/ui/MtpFullscreenView.java @@ -0,0 +1,115 @@ +/* + * 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.gallery3d.ingest.ui; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.CheckBox; +import android.widget.Checkable; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.RelativeLayout; + +import com.android.gallery3d.R; +import com.android.gallery3d.ingest.adapter.CheckBroker; + +public class MtpFullscreenView extends RelativeLayout implements Checkable, + CompoundButton.OnCheckedChangeListener, CheckBroker.OnCheckedChangedListener { + + private MtpImageView mImageView; + private CheckBox mCheckbox; + private int mPosition = -1; + private CheckBroker mBroker; + + public MtpFullscreenView(Context context) { + super(context); + } + + public MtpFullscreenView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public MtpFullscreenView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mImageView = (MtpImageView) findViewById(R.id.ingest_fullsize_image); + mCheckbox = (CheckBox) findViewById(R.id.ingest_fullsize_image_checkbox); + mCheckbox.setOnCheckedChangeListener(this); + } + + @Override + public boolean isChecked() { + return mCheckbox.isChecked(); + } + + @Override + public void setChecked(boolean checked) { + mCheckbox.setChecked(checked); + } + + @Override + public void toggle() { + mCheckbox.toggle(); + } + + @Override + public void onDetachedFromWindow() { + setPositionAndBroker(-1, null); + super.onDetachedFromWindow(); + } + + public MtpImageView getImageView() { + return mImageView; + } + + public int getPosition() { + return mPosition; + } + + public void setPositionAndBroker(int position, CheckBroker b) { + if (mBroker != null) { + mBroker.unregisterOnCheckedChangeListener(this); + } + mPosition = position; + mBroker = b; + if (mBroker != null) { + setChecked(mBroker.isItemChecked(position)); + mBroker.registerOnCheckedChangeListener(this); + } + } + + @Override + public void onCheckedChanged(CompoundButton arg0, boolean isChecked) { + if (mBroker != null) mBroker.setItemChecked(mPosition, isChecked); + } + + @Override + public void onCheckedChanged(int position, boolean isChecked) { + if (position == mPosition) { + setChecked(isChecked); + } + } + + @Override + public void onBulkCheckedChanged() { + if(mBroker != null) setChecked(mBroker.isItemChecked(mPosition)); + } +} diff --git a/src/com/android/gallery3d/ingest/ui/MtpImageView.java b/src/com/android/gallery3d/ingest/ui/MtpImageView.java new file mode 100644 index 000000000..80c105126 --- /dev/null +++ b/src/com/android/gallery3d/ingest/ui/MtpImageView.java @@ -0,0 +1,280 @@ +/* + * 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.gallery3d.ingest.ui; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.drawable.Drawable; +import android.mtp.MtpDevice; +import android.mtp.MtpObjectInfo; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.util.AttributeSet; +import android.widget.ImageView; + +import com.android.gallery3d.R; +import com.android.gallery3d.ingest.MtpDeviceIndex; +import com.android.gallery3d.ingest.data.BitmapWithMetadata; +import com.android.gallery3d.ingest.data.MtpBitmapFetch; + +import java.lang.ref.WeakReference; + +public class MtpImageView extends ImageView { + // We will use the thumbnail for images larger than this threshold + private static final int MAX_FULLSIZE_PREVIEW_SIZE = 8388608; // 8 megabytes + + private int mObjectHandle; + private int mGeneration; + + private WeakReference<MtpImageView> mWeakReference = new WeakReference<MtpImageView>(this); + private Object mFetchLock = new Object(); + private boolean mFetchPending = false; + private MtpObjectInfo mFetchObjectInfo; + private MtpDevice mFetchDevice; + private Object mFetchResult; + private Drawable mOverlayIcon; + private boolean mShowOverlayIcon; + + private static final FetchImageHandler sFetchHandler = FetchImageHandler.createOnNewThread(); + private static final ShowImageHandler sFetchCompleteHandler = new ShowImageHandler(); + + private void init() { + showPlaceholder(); + } + + public MtpImageView(Context context) { + super(context); + init(); + } + + public MtpImageView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public MtpImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void showPlaceholder() { + setImageResource(android.R.color.transparent); + } + + public void setMtpDeviceAndObjectInfo(MtpDevice device, MtpObjectInfo object, int gen) { + int handle = object.getObjectHandle(); + if (handle == mObjectHandle && gen == mGeneration) { + return; + } + cancelLoadingAndClear(); + showPlaceholder(); + mGeneration = gen; + mObjectHandle = handle; + mShowOverlayIcon = MtpDeviceIndex.SUPPORTED_VIDEO_FORMATS.contains(object.getFormat()); + if (mShowOverlayIcon && mOverlayIcon == null) { + mOverlayIcon = getResources().getDrawable(R.drawable.ic_control_play); + updateOverlayIconBounds(); + } + synchronized (mFetchLock) { + mFetchObjectInfo = object; + mFetchDevice = device; + if (mFetchPending) return; + mFetchPending = true; + sFetchHandler.sendMessage( + sFetchHandler.obtainMessage(0, mWeakReference)); + } + } + + protected Object fetchMtpImageDataFromDevice(MtpDevice device, MtpObjectInfo info) { + if (info.getCompressedSize() <= MAX_FULLSIZE_PREVIEW_SIZE + && MtpDeviceIndex.SUPPORTED_IMAGE_FORMATS.contains(info.getFormat())) { + return MtpBitmapFetch.getFullsize(device, info); + } else { + return new BitmapWithMetadata(MtpBitmapFetch.getThumbnail(device, info), 0); + } + } + + private float mLastBitmapWidth; + private float mLastBitmapHeight; + private int mLastRotationDegrees; + private Matrix mDrawMatrix = new Matrix(); + + private void updateDrawMatrix() { + mDrawMatrix.reset(); + float dwidth; + float dheight; + float vheight = getHeight(); + float vwidth = getWidth(); + float scale; + boolean rotated90 = (mLastRotationDegrees % 180 != 0); + if (rotated90) { + dwidth = mLastBitmapHeight; + dheight = mLastBitmapWidth; + } else { + dwidth = mLastBitmapWidth; + dheight = mLastBitmapHeight; + } + if (dwidth <= vwidth && dheight <= vheight) { + scale = 1.0f; + } else { + scale = Math.min(vwidth / dwidth, vheight / dheight); + } + mDrawMatrix.setScale(scale, scale); + if (rotated90) { + mDrawMatrix.postTranslate(-dheight * scale * 0.5f, + -dwidth * scale * 0.5f); + mDrawMatrix.postRotate(mLastRotationDegrees); + mDrawMatrix.postTranslate(dwidth * scale * 0.5f, + dheight * scale * 0.5f); + } + mDrawMatrix.postTranslate((vwidth - dwidth * scale) * 0.5f, + (vheight - dheight * scale) * 0.5f); + if (!rotated90 && mLastRotationDegrees > 0) { + // rotated by a multiple of 180 + mDrawMatrix.postRotate(mLastRotationDegrees, vwidth / 2, vheight / 2); + } + setImageMatrix(mDrawMatrix); + } + + private static final int OVERLAY_ICON_SIZE_DENOMINATOR = 4; + + private void updateOverlayIconBounds() { + int iheight = mOverlayIcon.getIntrinsicHeight(); + int iwidth = mOverlayIcon.getIntrinsicWidth(); + int vheight = getHeight(); + int vwidth = getWidth(); + float scale_height = ((float) vheight) / (iheight * OVERLAY_ICON_SIZE_DENOMINATOR); + float scale_width = ((float) vwidth) / (iwidth * OVERLAY_ICON_SIZE_DENOMINATOR); + if (scale_height >= 1f && scale_width >= 1f) { + mOverlayIcon.setBounds((vwidth - iwidth) / 2, + (vheight - iheight) / 2, + (vwidth + iwidth) / 2, + (vheight + iheight) / 2); + } else { + float scale = Math.min(scale_height, scale_width); + mOverlayIcon.setBounds((int) (vwidth - scale * iwidth) / 2, + (int) (vheight - scale * iheight) / 2, + (int) (vwidth + scale * iwidth) / 2, + (int) (vheight + scale * iheight) / 2); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed && getScaleType() == ScaleType.MATRIX) { + updateDrawMatrix(); + } + if (mShowOverlayIcon && changed && mOverlayIcon != null) { + updateOverlayIconBounds(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (mShowOverlayIcon && mOverlayIcon != null) { + mOverlayIcon.draw(canvas); + } + } + + protected void onMtpImageDataFetchedFromDevice(Object result) { + BitmapWithMetadata bitmapWithMetadata = (BitmapWithMetadata)result; + if (getScaleType() == ScaleType.MATRIX) { + mLastBitmapHeight = bitmapWithMetadata.bitmap.getHeight(); + mLastBitmapWidth = bitmapWithMetadata.bitmap.getWidth(); + mLastRotationDegrees = bitmapWithMetadata.rotationDegrees; + updateDrawMatrix(); + } else { + setRotation(bitmapWithMetadata.rotationDegrees); + } + setAlpha(0f); + setImageBitmap(bitmapWithMetadata.bitmap); + animate().alpha(1f); + } + + protected void cancelLoadingAndClear() { + synchronized (mFetchLock) { + mFetchDevice = null; + mFetchObjectInfo = null; + mFetchResult = null; + } + animate().cancel(); + setImageResource(android.R.color.transparent); + } + + @Override + public void onDetachedFromWindow() { + cancelLoadingAndClear(); + super.onDetachedFromWindow(); + } + + private static class FetchImageHandler extends Handler { + public FetchImageHandler(Looper l) { + super(l); + } + + public static FetchImageHandler createOnNewThread() { + HandlerThread t = new HandlerThread("MtpImageView Fetch"); + t.start(); + return new FetchImageHandler(t.getLooper()); + } + + @Override + public void handleMessage(Message msg) { + @SuppressWarnings("unchecked") + MtpImageView parent = ((WeakReference<MtpImageView>) msg.obj).get(); + if (parent == null) return; + MtpObjectInfo objectInfo; + MtpDevice device; + synchronized (parent.mFetchLock) { + parent.mFetchPending = false; + device = parent.mFetchDevice; + objectInfo = parent.mFetchObjectInfo; + } + if (device == null) return; + Object result = parent.fetchMtpImageDataFromDevice(device, objectInfo); + if (result == null) return; + synchronized (parent.mFetchLock) { + if (parent.mFetchObjectInfo != objectInfo) return; + parent.mFetchResult = result; + parent.mFetchDevice = null; + parent.mFetchObjectInfo = null; + sFetchCompleteHandler.sendMessage( + sFetchCompleteHandler.obtainMessage(0, parent.mWeakReference)); + } + } + } + + private static class ShowImageHandler extends Handler { + @Override + public void handleMessage(Message msg) { + @SuppressWarnings("unchecked") + MtpImageView parent = ((WeakReference<MtpImageView>) msg.obj).get(); + if (parent == null) return; + Object result; + synchronized (parent.mFetchLock) { + result = parent.mFetchResult; + } + if (result == null) return; + parent.onMtpImageDataFetchedFromDevice(result); + } + } +} diff --git a/src/com/android/gallery3d/ingest/ui/MtpThumbnailTileView.java b/src/com/android/gallery3d/ingest/ui/MtpThumbnailTileView.java new file mode 100644 index 000000000..3307e78aa --- /dev/null +++ b/src/com/android/gallery3d/ingest/ui/MtpThumbnailTileView.java @@ -0,0 +1,106 @@ +/* + * 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.gallery3d.ingest.ui; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.mtp.MtpDevice; +import android.mtp.MtpObjectInfo; +import android.util.AttributeSet; +import android.widget.Checkable; + +import com.android.gallery3d.R; +import com.android.gallery3d.ingest.data.MtpBitmapFetch; + + +public class MtpThumbnailTileView extends MtpImageView implements Checkable { + + private Paint mForegroundPaint; + private boolean mIsChecked; + private Bitmap mBitmap; + + private void init() { + mForegroundPaint = new Paint(); + mForegroundPaint.setColor(getResources().getColor(R.color.ingest_highlight_semitransparent)); + } + + public MtpThumbnailTileView(Context context) { + super(context); + init(); + } + + public MtpThumbnailTileView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public MtpThumbnailTileView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Force this to be square + super.onMeasure(widthMeasureSpec, widthMeasureSpec); + } + + @Override + protected Object fetchMtpImageDataFromDevice(MtpDevice device, MtpObjectInfo info) { + return MtpBitmapFetch.getThumbnail(device, info); + } + + @Override + protected void onMtpImageDataFetchedFromDevice(Object result) { + mBitmap = (Bitmap)result; + setImageBitmap(mBitmap); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + if (isChecked()) { + canvas.drawRect(canvas.getClipBounds(), mForegroundPaint); + } + } + + @Override + public boolean isChecked() { + return mIsChecked; + } + + @Override + public void setChecked(boolean checked) { + mIsChecked = checked; + } + + @Override + public void toggle() { + setChecked(!mIsChecked); + } + + @Override + protected void cancelLoadingAndClear() { + super.cancelLoadingAndClear(); + if (mBitmap != null) { + MtpBitmapFetch.recycleThumbnail(mBitmap); + mBitmap = null; + } + } +} |