Commit 11faf12d authored by aelias's avatar aelias Committed by Commit bot

Revert of Photo Picker Dialog: Use sandboxed utility process for decoding...

Revert of Photo Picker Dialog: Use sandboxed utility process for decoding images. (patchset #11 id:240001 of https://codereview.chromium.org/2816733002/ )

Reason for revert:
generate_orderfiles.py fails due to AndroidManifest.xml change (see http://crbug.com/717071 )

BUG=717071

Original issue's description:
> Photo Picker Dialog: Use sandboxed utility process for decoding images.
>
> BUG=656015
>
> Review-Url: https://codereview.chromium.org/2816733002
> Cr-Commit-Position: refs/heads/master@{#468209}
> Committed: https://chromium.googlesource.com/chromium/src/+/83c9f3f4faeb35a3a2607446def65f1a8da7aa49

TBR=twellington@chromium.org,yusufo@chromium.org,tedchoc@chromium.org,finnur@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=656015

Review-Url: https://codereview.chromium.org/2853793003
Cr-Commit-Position: refs/heads/master@{#468330}
parent 5ac2cb3b
......@@ -632,14 +632,6 @@ by a child template that "extends" this file.
android:exported="false">
</service>
<!-- Service for decoding images in a sandboxed process. -->
<service
android:description="@string/decoder_description"
android:name="org.chromium.chrome.browser.photo_picker.DecoderService"
android:exported="false"
android:isolatedProcess="true"
android:process=":decoder_service" />
<!-- Providers for chrome data. -->
<provider android:name="org.chromium.chrome.browser.provider.ChromeBrowserProvider"
android:authorities="{{ manifest_package }}.ChromeBrowserProvider;{{ manifest_package }}.browser;{{ manifest_package }}"
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.photo_picker;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.FileDescriptor;
/**
* A collection of utility functions for dealing with bitmaps.
*/
class BitmapUtils {
/**
* Takes a |bitmap| and returns a square thumbnail of |size|x|size| from the center of the
* bitmap specified.
* @param bitmap The bitmap to adjust.
* @param size The desired size (width and height).
* @return The new bitmap thumbnail.
*/
private static Bitmap sizeBitmap(Bitmap bitmap, int size) {
// TODO(finnur): Investigate options that require fewer bitmaps to be created.
bitmap = ensureMinSize(bitmap, size);
bitmap = cropToSquare(bitmap, size);
return bitmap;
}
/**
* Given a FileDescriptor, decodes the contents and returns a bitmap of
* dimensions |size|x|size|.
* @param descriptor The FileDescriptor for the file to read.
* @param size The width and height of the bitmap to return.
* @return The resulting bitmap.
*/
public static Bitmap decodeBitmapFromFileDescriptor(FileDescriptor descriptor, int size) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(descriptor, null, options);
options.inSampleSize = calculateInSampleSize(options.outWidth, options.outHeight, size);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFileDescriptor(descriptor, null, options);
if (bitmap == null) return null;
return sizeBitmap(bitmap, size);
}
/**
* Calculates the sub-sampling factor {@link BitmapFactory#inSampleSize} option for a given
* image dimensions, which will be used to create a bitmap of a pre-determined size (as small as
* possible without either dimension shrinking below |minSize|.
* @param width The calculated width of the image to decode.
* @param height The calculated height of the image to decode.
* @param minSize The maximum size the image should be (in either dimension).
* @return The sub-sampling factor (power of two: 1 = no change, 2 = half-size, etc).
*/
private static int calculateInSampleSize(int width, int height, int minSize) {
int inSampleSize = 1;
if (width > minSize && height > minSize) {
inSampleSize = Math.min(width, height) / minSize;
}
return inSampleSize;
}
/**
* Ensures a |bitmap| is at least |size| in both width and height.
* @param bitmap The bitmap to modify.
* @param size The minimum size (width and height).
* @return The resulting (scaled) bitmap.
*/
private static Bitmap ensureMinSize(Bitmap bitmap, int size) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
if (width >= size && height >= size) return bitmap;
if (width < size) {
float scale = (float) size / width;
width = size;
height *= scale;
}
if (height < size) {
float scale = (float) size / height;
height = size;
width *= scale;
}
return Bitmap.createScaledBitmap(bitmap, width, height, true);
}
/**
* Crops a |bitmap| to a certain square |size|
* @param bitmap The bitmap to crop.
* @param size The size desired (width and height).
* @return The resulting (square) bitmap.
*/
private static Bitmap cropToSquare(Bitmap bitmap, int size) {
int x = 0;
int y = 0;
int width = bitmap.getWidth();
int height = bitmap.getHeight();
if (width == size && height == size) return bitmap;
if (width > size) x = (width - size) / 2;
if (height > size) y = (height - size) / 2;
return Bitmap.createBitmap(bitmap, x, y, size, size);
}
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.photo_picker;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import org.chromium.base.Log;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* A service to accept requests to take image file contents and decode them.
*/
public class DecoderService extends Service {
// Message ids for communicating with the client.
// A message sent by the client to decode an image.
static final int MSG_DECODE_IMAGE = 1;
// A message sent by the server to notify the client of the results of the decoding.
static final int MSG_IMAGE_DECODED_REPLY = 2;
// The keys for the bundle when passing data to and from this service.
static final String KEY_FILE_DESCRIPTOR = "file_descriptor";
static final String KEY_FILE_PATH = "file_path";
static final String KEY_IMAGE_BITMAP = "image_bitmap";
static final String KEY_IMAGE_BYTE_COUNT = "image_byte_count";
static final String KEY_IMAGE_DESCRIPTOR = "image_descriptor";
static final String KEY_SIZE = "size";
static final String KEY_SUCCESS = "success";
// A tag for logging error messages.
private static final String TAG = "ImageDecoder";
/**
* Handler for incoming messages from clients.
*/
static class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DECODE_IMAGE:
Bundle bundle = null;
Messenger client = null;
String filePath = "";
int size = 0;
try {
Bundle payload = msg.getData();
client = msg.replyTo;
filePath = payload.getString(KEY_FILE_PATH);
ParcelFileDescriptor pfd = payload.getParcelable(KEY_FILE_DESCRIPTOR);
size = payload.getInt(KEY_SIZE);
// Setup a minimum viable response to parent process. Will be fleshed out
// further below.
bundle = new Bundle();
bundle.putString(KEY_FILE_PATH, filePath);
bundle.putBoolean(KEY_SUCCESS, false);
FileDescriptor fd = pfd.getFileDescriptor();
Bitmap bitmap = BitmapUtils.decodeBitmapFromFileDescriptor(fd, size);
try {
pfd.close();
} catch (IOException e) {
Log.e(TAG, "Closing failed " + filePath + " (size: " + size + ") " + e);
}
if (bitmap == null) {
Log.e(TAG, "Decode failed " + filePath + " (size: " + size + ")");
sendReply(client, bundle); // Sends SUCCESS == false;
return;
}
// The most widely supported, easiest, and reasonably efficient method is to
// decode to an immutable bitmap and just return the bitmap over binder. It
// will internally memcpy itself to ashmem and then just send over the file
// descriptor. In the receiving process it will just leave the bitmap on
// ashmem since it's immutable and carry on.
bundle.putParcelable(KEY_IMAGE_BITMAP, bitmap);
bundle.putBoolean(KEY_SUCCESS, true);
sendReply(client, bundle);
bitmap.recycle();
} catch (Exception e) {
// This service has no UI and maintains no state so if it crashes on
// decoding a photo, it is better UX to eat the exception instead of showing
// a crash dialog and discarding other requests that have already been sent.
Log.e(TAG,
"Unexpected error during decoding " + filePath + " (size: " + size
+ ") " + e);
if (bundle != null && client != null) sendReply(client, bundle);
}
break;
default:
super.handleMessage(msg);
}
}
private void sendReply(Messenger client, Bundle bundle) {
Message reply = Message.obtain(null, MSG_IMAGE_DECODED_REPLY);
reply.setData(bundle);
try {
client.send(reply);
} catch (RemoteException remoteException) {
Log.e(TAG, "Remote error while replying: " + remoteException);
}
}
}
/**
* The target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.photo_picker;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.StrictMode;
import org.chromium.base.Log;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.LinkedHashMap;
/**
* A class to communicate with the {@link DecoderService}.
*/
public class DecoderServiceHost {
// A tag for logging error messages.
private static final String TAG = "ImageDecoderHost";
/**
* Interface for notifying clients of the service being ready.
*/
public interface ServiceReadyCallback {
/**
* A function to define to receive a notification once the service is up and running.
*/
void serviceReady();
}
/**
* An interface notifying clients when an image has finished decoding.
*/
public interface ImageDecodedCallback {
/**
* A function to define to receive a notification that an image has been decoded.
* @param filePath The file path for the newly decoded image.
* @param bitmap The results of the decoding (or placeholder image, if failed).
*/
void imageDecodedCallback(String filePath, Bitmap bitmap);
}
/**
* Class for interacting with the main interface of the service.
*/
private class DecoderServiceConnection implements ServiceConnection {
// The callback to use to notify the service being ready.
private ServiceReadyCallback mCallback;
public DecoderServiceConnection(ServiceReadyCallback callback) {
mCallback = callback;
}
// Called when a connection to the service has been established.
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger(service);
mBound = true;
mCallback.serviceReady();
}
// Called when a connection to the service has been lost.
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
}
/**
* Class for keeping track of the data involved with each request.
*/
private static class DecoderServiceParams {
// The path to the file containing the bitmap to decode.
public String mFilePath;
// The requested size (width and height) of the bitmap, once decoded.
public int mSize;
// The callback to use to communicate the results of the decoding.
ImageDecodedCallback mCallback;
public DecoderServiceParams(String filePath, int size, ImageDecodedCallback callback) {
mFilePath = filePath;
mSize = size;
mCallback = callback;
}
}
// Map of file paths to decoder parameters in order of request.
private LinkedHashMap<String, DecoderServiceParams> mRequests = new LinkedHashMap<>();
LinkedHashMap<String, DecoderServiceParams> getRequests() {
return mRequests;
}
// The callback used to notify the client when the service is ready.
private ServiceReadyCallback mCallback;
// Messenger for communicating with the remote service.
Messenger mService = null;
// Our service connection to the {@link DecoderService}.
private DecoderServiceConnection mConnection;
// Flag indicating whether we are bound to the service.
boolean mBound;
// The inbound messenger used by the remote service to communicate with us.
final Messenger mMessenger = new Messenger(new IncomingHandler(this));
/**
* The DecoderServiceHost constructor.
* @param callback The callback to use when communicating back to the client.
*/
public DecoderServiceHost(ServiceReadyCallback callback) {
mCallback = callback;
}
/**
* Initiate binding with the {@link DecoderService}.
* @param context The context to use.
*/
public void bind(Context context) {
mConnection = new DecoderServiceConnection(mCallback);
Intent intent = new Intent(context, DecoderService.class);
context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
/**
* Unbind from the {@link DecoderService}.
* @param context The context to use.
*/
public void unbind(Context context) {
if (mBound) {
context.unbindService(mConnection);
mBound = false;
}
}
/**
* Accepts a request to decode a single image. Queues up the request and reports back
* asynchronously on |callback|.
* @param filePath The path to the file to decode.
* @param size The requested size (width and height) of the resulting bitmap.
* @param callback The callback to use to communicate the decoding results.
*/
public void decodeImage(String filePath, int size, ImageDecodedCallback callback) {
DecoderServiceParams params = new DecoderServiceParams(filePath, size, callback);
mRequests.put(filePath, params);
if (mRequests.size() == 1) dispatchNextDecodeImageRequest();
}
/**
* Dispatches the next image for decoding (from the queue).
*/
private void dispatchNextDecodeImageRequest() {
if (mRequests.entrySet().iterator().hasNext()) {
DecoderServiceParams params = mRequests.entrySet().iterator().next().getValue();
dispatchDecodeImageRequest(params.mFilePath, params.mSize);
}
}
/**
* Ties up all the loose ends from the decoding request (communicates the results of the
* decoding process back to the client, and takes care of house-keeping chores regarding
* the request queue).
* @param filePath The path to the image that was just decoded.
* @param bitmap The resulting decoded bitmap.
*/
public void closeRequest(String filePath, Bitmap bitmap) {
DecoderServiceParams params = getRequests().get(filePath);
if (params != null) {
params.mCallback.imageDecodedCallback(filePath, bitmap);
getRequests().remove(filePath);
}
dispatchNextDecodeImageRequest();
}
/**
* Communicates with the server to decode a single bitmap.
* @param filePath The path to the image on disk.
* @param size The requested width and height of the resulting bitmap.
*/
private void dispatchDecodeImageRequest(String filePath, int size) {
// Obtain a file descriptor to send over to the sandboxed process.
File file = new File(filePath);
FileInputStream inputFile = null;
ParcelFileDescriptor pfd = null;
Bundle bundle = new Bundle();
// The restricted utility process can't open the file to read the
// contents, so we need to obtain a file descriptor to pass over.
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
try {
inputFile = new FileInputStream(file);
FileDescriptor fd = inputFile.getFD();
pfd = ParcelFileDescriptor.dup(fd);
bundle.putParcelable(DecoderService.KEY_FILE_DESCRIPTOR, pfd);
} catch (IOException e) {
Log.e(TAG, "Unable to obtain FileDescriptor: " + e);
closeRequest(filePath, null);
}
} finally {
try {
if (inputFile != null) inputFile.close();
} catch (IOException e) {
Log.e(TAG, "Unable to close inputFile: " + e);
}
StrictMode.setThreadPolicy(oldPolicy);
}
if (pfd == null) return;
// Prepare and send the data over.
Message payload = Message.obtain(null, DecoderService.MSG_DECODE_IMAGE);
payload.replyTo = mMessenger;
bundle.putString(DecoderService.KEY_FILE_PATH, filePath);
bundle.putInt(DecoderService.KEY_SIZE, size);
payload.setData(bundle);
try {
mService.send(payload);
pfd.close();
} catch (RemoteException e) {
Log.e(TAG, "Communications failed (Remote): " + e);
closeRequest(filePath, null);
} catch (IOException e) {
Log.e(TAG, "Communications failed (IO): " + e);
closeRequest(filePath, null);
}
}
/**
* Cancels a request to decode an image (if it hasn't already been dispatched).
* @param filePath The path to the image to cancel decoding.
*/
public void cancelDecodeImage(String filePath) {
mRequests.remove(filePath);
}
/**
* A class for handling communications from the service to us.
*/
static class IncomingHandler extends Handler {
// The DecoderServiceHost object to communicate with.
private final WeakReference<DecoderServiceHost> mHost;
/**
* Constructor for IncomingHandler.
* @param host The DecoderServiceHost object to communicate with.
*/
IncomingHandler(DecoderServiceHost host) {
mHost = new WeakReference<DecoderServiceHost>(host);
}
@Override
public void handleMessage(Message msg) {
DecoderServiceHost host = mHost.get();
if (host == null) {
super.handleMessage(msg);
return;
}
switch (msg.what) {
case DecoderService.MSG_IMAGE_DECODED_REPLY:
Bundle payload = msg.getData();
// Read the reply back from the service.
String filePath = payload.getString(DecoderService.KEY_FILE_PATH);
Boolean success = payload.getBoolean(DecoderService.KEY_SUCCESS);
Bitmap bitmap = success
? (Bitmap) payload.getParcelable(DecoderService.KEY_IMAGE_BITMAP)
: null;
host.closeRequest(filePath, bitmap);
break;
default:
super.handleMessage(msg);
}
}
}
}
......@@ -10,7 +10,6 @@ import android.webkit.MimeTypeMap;
import java.io.File;
import java.io.FileFilter;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
/**
......@@ -24,12 +23,13 @@ class MimeTypeFileFilter implements FileFilter {
/**
* Contructs a MimeTypeFileFilter object.
* @param mimeTypes A list of MIME types this filter accepts.
* @param acceptAttr A comma seperated list of MIME types this filter accepts.
* For example: images/gif, video/*.
*/
public MimeTypeFileFilter(@NonNull List<String> mimeTypes) {
for (String field : mimeTypes) {
field = field.trim().toLowerCase(Locale.US);
// TODO(finnur): Convert param to List.
public MimeTypeFileFilter(@NonNull String acceptAttr) {
for (String field : acceptAttr.toLowerCase(Locale.US).split(",")) {
field = field.trim();
if (field.startsWith(".")) {
mExtensions.add(field.substring(1));
} else if (field.endsWith("/*")) {
......
......@@ -189,13 +189,8 @@ public class PickerBitmapView extends SelectableItemView<PickerBitmap> {
mBitmapDetails = bitmapDetails;
setItem(bitmapDetails);
if (isCameraTile() || isGalleryTile()) {
initializeSpecialTile(mBitmapDetails);
mImageLoaded = true;
} else {
setThumbnailBitmap(thumbnail);
mImageLoaded = !placeholder;
}
updateSelectionState();
}
......@@ -222,6 +217,8 @@ public class PickerBitmapView extends SelectableItemView<PickerBitmap> {
mSpecialTile, null, image, null, null);
mSpecialTile.setText(labelStringId);
initialize(bitmapDetails, null, false);
// Reset visibility, since #initialize() sets mSpecialTile visibility to GONE.
mSpecialTile.setVisibility(View.VISIBLE);
}
......@@ -269,7 +266,6 @@ public class PickerBitmapView extends SelectableItemView<PickerBitmap> {
* re-used.
*/
private void resetTile() {
mIconView.setImageBitmap(null);
mUnselectedView.setVisibility(View.GONE);
mSelectedView.setVisibility(View.GONE);
mScrim.setVisibility(View.GONE);
......@@ -327,14 +323,15 @@ public class PickerBitmapView extends SelectableItemView<PickerBitmap> {
}
private boolean isGalleryTile() {
return mBitmapDetails.type() == PickerBitmap.GALLERY;
// TODO(finnur): Remove the null checks here and below.
return mBitmapDetails != null && mBitmapDetails.type() == PickerBitmap.GALLERY;
}
private boolean isCameraTile() {
return mBitmapDetails.type() == PickerBitmap.CAMERA;
return mBitmapDetails != null && mBitmapDetails.type() == PickerBitmap.CAMERA;
}
private boolean isPictureTile() {
return mBitmapDetails.type() == PickerBitmap.PICTURE;
return mBitmapDetails == null || mBitmapDetails.type() == PickerBitmap.PICTURE;
}
}
......@@ -5,6 +5,9 @@
package org.chromium.chrome.browser.photo_picker;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.TextUtils;
......@@ -13,8 +16,7 @@ import java.util.List;
/**
* Holds on to a {@link PickerBitmapView} that displays information about a picker bitmap.
*/
public class PickerBitmapViewHolder
extends ViewHolder implements DecoderServiceHost.ImageDecodedCallback {
public class PickerBitmapViewHolder extends ViewHolder {
// Our parent category.
private PickerCategoryView mCategoryView;
......@@ -33,9 +35,11 @@ public class PickerBitmapViewHolder
mItemView = itemView;
}
// DecoderServiceHost.ImageDecodedCallback
@Override
/**
* The notification handler for when an image has been decoded.
* @param filePath The file path for the newly decoded image.
* @param bitmap The results of the decoding (or placeholder image, if failed).
*/
public void imageDecodedCallback(String filePath, Bitmap bitmap) {
if (bitmap == null || bitmap.getWidth() == 0 || bitmap.getHeight() == 0) {
return;
......@@ -61,16 +65,31 @@ public class PickerBitmapViewHolder
if (mBitmapDetails.type() == PickerBitmap.CAMERA
|| mBitmapDetails.type() == PickerBitmap.GALLERY) {
mItemView.initialize(mBitmapDetails, null, false);
mItemView.initializeSpecialTile(mBitmapDetails);
return;
}
// TODO(finnur): Use cached image, if available.
mItemView.initialize(mBitmapDetails, null, true);
// TODO(finnur): Use decoder instead.
int size = mCategoryView.getImageSize();
mCategoryView.getDecoderServiceHost().decodeImage(mBitmapDetails.getFilePath(), size, this);
imageDecodedCallback(mBitmapDetails.getFilePath(), createPlaceholderBitmap(size, size));
}
/**
* Creates a placeholder bitmap.
* @param width The requested width of the resulting bitmap.
* @param height The requested height of the resulting bitmap.
* @return Placeholder bitmap.
*/
// TODO(finnur): Remove once the decoder is in place.
private Bitmap createPlaceholderBitmap(int width, int height) {
Bitmap placeholder = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(placeholder);
Paint paint = new Paint();
paint.setColor(Color.GRAY);
canvas.drawRect(0, 0, (float) width, (float) height, paint);
return placeholder;
}
/**
......
......@@ -20,7 +20,6 @@ import org.chromium.chrome.browser.widget.selection.SelectableListLayout;
import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
import org.chromium.ui.PhotoPickerListener;
import java.util.Arrays;
import java.util.List;
/**
......@@ -28,8 +27,7 @@ import java.util.List;
* the photo picker, for example the RecyclerView and the bitmap caches.
*/
public class PickerCategoryView extends RelativeLayout
implements FileEnumWorkerTask.FilesEnumeratedCallback, RecyclerView.RecyclerListener,
DecoderServiceHost.ServiceReadyCallback, OnMenuItemClickListener {
implements FileEnumWorkerTask.FilesEnumeratedCallback, OnMenuItemClickListener {
// The dialog that owns us.
private PhotoPickerDialog mDialog;
......@@ -48,9 +46,6 @@ public class PickerCategoryView extends RelativeLayout
// The callback to notify the listener of decisions reached in the picker.
private PhotoPickerListener mListener;
// The host class for the decoding service.
private DecoderServiceHost mDecoderServiceHost;
// The RecyclerView showing the images.
private RecyclerView mRecyclerView;
......@@ -76,9 +71,6 @@ public class PickerCategoryView extends RelativeLayout
// A worker task for asynchronously enumerating files off the main thread.
private FileEnumWorkerTask mWorkerTask;
// Whether the connection to the service has been established.
private boolean mServiceReady;
public PickerCategoryView(Context context) {
super(context);
postConstruction(context);
......@@ -92,11 +84,6 @@ public class PickerCategoryView extends RelativeLayout
private void postConstruction(Context context) {
mContext = context;
mDecoderServiceHost = new DecoderServiceHost(this);
mDecoderServiceHost.bind(mContext);
enumerateBitmaps();
mSelectionDelegate = new SelectionDelegate<PickerBitmap>();
View root = LayoutInflater.from(context).inflate(R.layout.photo_picker_dialog, this);
......@@ -120,21 +107,18 @@ public class PickerCategoryView extends RelativeLayout
mRecyclerView.addItemDecoration(new GridSpacingItemDecoration(mColumns, mPadding));
// TODO(finnur): Implement caching.
// TODO(finnur): Remove this once the decoder service is in place.
prepareBitmaps();
}
/**
* Severs the connection to the decoding utility process and cancels any outstanding requests.
* Cancels any outstanding requests.
*/
public void onDialogDismissed() {
if (mWorkerTask != null) {
mWorkerTask.cancel(true);
mWorkerTask = null;
}
if (mDecoderServiceHost != null) {
mDecoderServiceHost.unbind(mContext);
mDecoderServiceHost = null;
}
}
/**
......@@ -157,25 +141,8 @@ public class PickerCategoryView extends RelativeLayout
@Override
public void filesEnumeratedCallback(List<PickerBitmap> files) {
mPickerBitmaps = files;
processBitmaps();
}
// DecoderServiceHost.ServiceReadyCallback:
@Override
public void serviceReady() {
mServiceReady = true;
processBitmaps();
}
// RecyclerView.RecyclerListener:
@Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
PickerBitmapViewHolder bitmapHolder = (PickerBitmapViewHolder) holder;
String filePath = bitmapHolder.getFilePath();
if (filePath != null) {
getDecoderServiceHost().cancelDecodeImage(filePath);
if (files != null && files.size() > 0) {
mPickerAdapter.notifyDataSetChanged();
}
}
......@@ -195,16 +162,6 @@ public class PickerCategoryView extends RelativeLayout
return false;
}
/**
* Start loading of bitmaps, once files have been enumerated and service is
* ready to decode.
*/
private void processBitmaps() {
if (mServiceReady && mPickerBitmaps != null) {
mPickerAdapter.notifyDataSetChanged();
}
}
// Simple accessors:
public int getImageSize() {
......@@ -219,10 +176,6 @@ public class PickerCategoryView extends RelativeLayout
return mPickerBitmaps;
}
public DecoderServiceHost getDecoderServiceHost() {
return mDecoderServiceHost;
}
public boolean isMultiSelectAllowed() {
return mMultiSelectionAllowed;
}
......@@ -259,15 +212,14 @@ public class PickerCategoryView extends RelativeLayout
}
/**
* Asynchronously enumerates bitmaps on disk.
* Prepares bitmaps for loading.
*/
private void enumerateBitmaps() {
private void prepareBitmaps() {
if (mWorkerTask != null) {
mWorkerTask.cancel(true);
}
mWorkerTask =
new FileEnumWorkerTask(this, new MimeTypeFileFilter(Arrays.asList("image/*")));
mWorkerTask = new FileEnumWorkerTask(this, new MimeTypeFileFilter("image/*"));
mWorkerTask.execute();
}
......
......@@ -2816,11 +2816,6 @@ You must have Bluetooth and Location turned on in order to use the Physical Web.
<ph name="BEGIN_LINK">&lt;link&gt;</ph>Get help<ph name="END_LINK">&lt;/link&gt;</ph>
</message>
<!-- Photo Picker strings -->
<message name="IDS_DECODER_DESCRIPTION" desc="The title for the image decoder utility service.">
Image decoder
</message>
<!-- Migration strings -->
<message name="IDS_TAB_SWITCHER_CALLOUT_BODY" desc="Indicates that clicking the tab switcher button gives you quick access to your tabs.">
Tap this button for quick access to your tabs.
......
......@@ -785,9 +785,6 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/permissions/PermissionDialogController.java",
"java/src/org/chromium/chrome/browser/permissions/PermissionDialogDelegate.java",
"java/src/org/chromium/chrome/browser/physicalweb/BitmapHttpRequest.java",
"java/src/org/chromium/chrome/browser/photo_picker/BitmapUtils.java",
"java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java",
"java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java",
"java/src/org/chromium/chrome/browser/photo_picker/FileEnumWorkerTask.java",
"java/src/org/chromium/chrome/browser/photo_picker/MimeTypeFileFilter.java",
"java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialog.java",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment