Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.photo_picker; | 5 package org.chromium.chrome.browser.photo_picker; |
| 6 | 6 |
| 7 import android.content.ComponentName; | 7 import android.content.ComponentName; |
| 8 import android.content.Context; | 8 import android.content.Context; |
| 9 import android.content.Intent; | 9 import android.content.Intent; |
| 10 import android.content.ServiceConnection; | 10 import android.content.ServiceConnection; |
| 11 import android.graphics.Bitmap; | 11 import android.graphics.Bitmap; |
| 12 import android.os.Bundle; | 12 import android.os.Bundle; |
| 13 import android.os.Handler; | |
| 14 import android.os.IBinder; | 13 import android.os.IBinder; |
| 15 import android.os.Message; | 14 import android.os.Message; |
| 16 import android.os.Messenger; | |
| 17 import android.os.ParcelFileDescriptor; | 15 import android.os.ParcelFileDescriptor; |
| 18 import android.os.RemoteException; | 16 import android.os.RemoteException; |
| 19 import android.os.StrictMode; | 17 import android.os.StrictMode; |
| 20 import android.os.SystemClock; | 18 import android.os.SystemClock; |
| 21 | 19 |
| 22 import org.chromium.base.Log; | 20 import org.chromium.base.Log; |
| 21 import org.chromium.base.ThreadUtils; | |
| 23 import org.chromium.base.metrics.RecordHistogram; | 22 import org.chromium.base.metrics.RecordHistogram; |
| 24 import org.chromium.chrome.browser.util.ConversionUtils; | 23 import org.chromium.chrome.browser.util.ConversionUtils; |
| 25 | 24 |
| 26 import java.io.File; | 25 import java.io.File; |
| 27 import java.io.FileDescriptor; | 26 import java.io.FileDescriptor; |
| 28 import java.io.FileInputStream; | 27 import java.io.FileInputStream; |
| 29 import java.io.IOException; | 28 import java.io.IOException; |
| 30 import java.lang.ref.WeakReference; | |
| 31 import java.util.LinkedHashMap; | 29 import java.util.LinkedHashMap; |
| 32 import java.util.concurrent.TimeUnit; | 30 import java.util.concurrent.TimeUnit; |
| 33 | 31 |
| 34 /** | 32 /** |
| 35 * A class to communicate with the {@link DecoderService}. | 33 * A class to communicate with the {@link DecoderServiceImpl}. |
| 36 */ | 34 */ |
| 37 public class DecoderServiceHost { | 35 public class DecoderServiceHost extends IDecoderServiceListener.Stub { |
| 38 // A tag for logging error messages. | 36 // A tag for logging error messages. |
| 39 private static final String TAG = "ImageDecoderHost"; | 37 private static final String TAG = "ImageDecoderHost"; |
| 40 | 38 |
| 39 IDecoderService mIRemoteService; | |
| 40 private ServiceConnection mConnection = new ServiceConnection() { | |
| 41 public void onServiceConnected(ComponentName className, IBinder service) { | |
| 42 mIRemoteService = IDecoderService.Stub.asInterface(service); | |
| 43 mBound = true; | |
| 44 mCallback.serviceReady(); | |
| 45 } | |
| 46 | |
| 47 public void onServiceDisconnected(ComponentName className) { | |
| 48 Log.e(TAG, "Service has unexpectedly disconnected"); | |
|
Robert Sesek
2017/06/20 02:09:47
This will be called if you ever unbindService(), w
Finnur
2017/06/20 12:20:57
I do call unbindService but I do not see this func
| |
| 49 mIRemoteService = null; | |
| 50 mBound = false; | |
| 51 } | |
| 52 }; | |
| 53 | |
| 41 /** | 54 /** |
| 42 * Interface for notifying clients of the service being ready. | 55 * Interface for notifying clients of the service being ready. |
| 43 */ | 56 */ |
| 44 public interface ServiceReadyCallback { | 57 public interface ServiceReadyCallback { |
| 45 /** | 58 /** |
| 46 * A function to define to receive a notification once the service is up and running. | 59 * A function to define to receive a notification once the service is up and running. |
| 47 */ | 60 */ |
| 48 void serviceReady(); | 61 void serviceReady(); |
| 49 } | 62 } |
| 50 | 63 |
| 51 /** | 64 /** |
| 52 * An interface notifying clients when an image has finished decoding. | 65 * An interface notifying clients when an image has finished decoding. |
| 53 */ | 66 */ |
| 54 public interface ImageDecodedCallback { | 67 public interface ImageDecodedCallback { |
| 55 /** | 68 /** |
| 56 * A function to define to receive a notification that an image has been decoded. | 69 * A function to define to receive a notification that an image has been decoded. |
| 57 * @param filePath The file path for the newly decoded image. | 70 * @param filePath The file path for the newly decoded image. |
| 58 * @param bitmap The results of the decoding (or placeholder image, if f ailed). | 71 * @param bitmap The results of the decoding (or placeholder image, if f ailed). |
| 59 */ | 72 */ |
| 60 void imageDecodedCallback(String filePath, Bitmap bitmap); | 73 void imageDecodedCallback(String filePath, Bitmap bitmap); |
| 61 } | 74 } |
| 62 | 75 |
| 63 /** | 76 /** |
| 64 * Class for interacting with the main interface of the service. | |
| 65 */ | |
| 66 private class DecoderServiceConnection implements ServiceConnection { | |
| 67 // The callback to use to notify the service being ready. | |
| 68 private ServiceReadyCallback mCallback; | |
| 69 | |
| 70 public DecoderServiceConnection(ServiceReadyCallback callback) { | |
| 71 mCallback = callback; | |
| 72 } | |
| 73 | |
| 74 // Called when a connection to the service has been established. | |
| 75 public void onServiceConnected(ComponentName name, IBinder service) { | |
| 76 mService = new Messenger(service); | |
| 77 mBound = true; | |
| 78 mCallback.serviceReady(); | |
| 79 } | |
| 80 | |
| 81 // Called when a connection to the service has been lost. | |
| 82 public void onServiceDisconnected(ComponentName name) { | |
| 83 mBound = false; | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 /** | |
| 88 * Class for keeping track of the data involved with each request. | 77 * Class for keeping track of the data involved with each request. |
| 89 */ | 78 */ |
| 90 private static class DecoderServiceParams { | 79 private static class DecoderServiceParams { |
| 91 // The path to the file containing the bitmap to decode. | 80 // The path to the file containing the bitmap to decode. |
| 92 public String mFilePath; | 81 public String mFilePath; |
| 93 | 82 |
| 94 // The requested size (width and height) of the bitmap, once decoded. | 83 // The requested size (width and height) of the bitmap, once decoded. |
| 95 public int mSize; | 84 public int mSize; |
| 96 | 85 |
| 97 // The callback to use to communicate the results of the decoding. | 86 // The callback to use to communicate the results of the decoding. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 109 | 98 |
| 110 // Map of file paths to decoder parameters in order of request. | 99 // Map of file paths to decoder parameters in order of request. |
| 111 private LinkedHashMap<String, DecoderServiceParams> mRequests = new LinkedHa shMap<>(); | 100 private LinkedHashMap<String, DecoderServiceParams> mRequests = new LinkedHa shMap<>(); |
| 112 LinkedHashMap<String, DecoderServiceParams> getRequests() { | 101 LinkedHashMap<String, DecoderServiceParams> getRequests() { |
| 113 return mRequests; | 102 return mRequests; |
| 114 } | 103 } |
| 115 | 104 |
| 116 // The callback used to notify the client when the service is ready. | 105 // The callback used to notify the client when the service is ready. |
| 117 private ServiceReadyCallback mCallback; | 106 private ServiceReadyCallback mCallback; |
| 118 | 107 |
| 119 // Messenger for communicating with the remote service. | |
| 120 Messenger mService = null; | |
| 121 | |
| 122 // Our service connection to the {@link DecoderService}. | |
| 123 private DecoderServiceConnection mConnection; | |
| 124 | |
| 125 // Flag indicating whether we are bound to the service. | 108 // Flag indicating whether we are bound to the service. |
| 126 boolean mBound; | 109 boolean mBound; |
| 127 | 110 |
| 128 // The inbound messenger used by the remote service to communicate with us. | 111 private Context mContext; |
| 129 final Messenger mMessenger = new Messenger(new IncomingHandler(this)); | |
| 130 | 112 |
| 131 /** | 113 /** |
| 132 * The DecoderServiceHost constructor. | 114 * The DecoderServiceHost constructor. |
| 133 * @param callback The callback to use when communicating back to the client . | 115 * @param callback The callback to use when communicating back to the client . |
| 134 */ | 116 */ |
| 135 public DecoderServiceHost(ServiceReadyCallback callback) { | 117 public DecoderServiceHost(ServiceReadyCallback callback, Context context) { |
| 136 mCallback = callback; | 118 mCallback = callback; |
| 119 mContext = context; | |
| 137 } | 120 } |
| 138 | 121 |
| 139 /** | 122 /** |
| 140 * Initiate binding with the {@link DecoderService}. | 123 * Initiate binding with the {@link DecoderServiceImpl}. |
| 141 * @param context The context to use. | 124 * @param context The context to use. |
| 142 */ | 125 */ |
| 143 public void bind(Context context) { | 126 public void bind(Context context) { |
| 144 mConnection = new DecoderServiceConnection(mCallback); | 127 Intent intent = new Intent(mContext, DecoderServiceImpl.class); |
| 145 Intent intent = new Intent(context, DecoderService.class); | 128 intent.setAction(IDecoderService.class.getName()); |
| 146 context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); | 129 mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); |
| 147 } | 130 } |
| 148 | 131 |
| 149 /** | 132 /** |
| 150 * Unbind from the {@link DecoderService}. | 133 * Unbind from the {@link DecoderServiceImpl}. |
| 151 * @param context The context to use. | 134 * @param context The context to use. |
| 152 */ | 135 */ |
| 153 public void unbind(Context context) { | 136 public void unbind(Context context) { |
| 154 if (mBound) { | 137 if (mBound) { |
| 155 context.unbindService(mConnection); | 138 context.unbindService(mConnection); |
| 156 mBound = false; | 139 mBound = false; |
| 157 } | 140 } |
| 158 } | 141 } |
| 159 | 142 |
| 160 /** | 143 /** |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 174 * Dispatches the next image for decoding (from the queue). | 157 * Dispatches the next image for decoding (from the queue). |
| 175 */ | 158 */ |
| 176 private void dispatchNextDecodeImageRequest() { | 159 private void dispatchNextDecodeImageRequest() { |
| 177 if (mRequests.entrySet().iterator().hasNext()) { | 160 if (mRequests.entrySet().iterator().hasNext()) { |
| 178 DecoderServiceParams params = mRequests.entrySet().iterator().next() .getValue(); | 161 DecoderServiceParams params = mRequests.entrySet().iterator().next() .getValue(); |
| 179 params.mTimestamp = SystemClock.elapsedRealtime(); | 162 params.mTimestamp = SystemClock.elapsedRealtime(); |
| 180 dispatchDecodeImageRequest(params.mFilePath, params.mSize); | 163 dispatchDecodeImageRequest(params.mFilePath, params.mSize); |
| 181 } | 164 } |
| 182 } | 165 } |
| 183 | 166 |
| 167 @Override | |
| 168 public void onDecodeImageDone(final Bundle payload) { | |
| 169 ThreadUtils.runOnUiThread(new Runnable() { | |
| 170 @Override | |
| 171 public void run() { | |
| 172 // Read the reply back from the service. | |
| 173 String filePath = payload.getString(DecoderServiceImpl.KEY_FILE_ PATH); | |
| 174 Boolean success = payload.getBoolean(DecoderServiceImpl.KEY_SUCC ESS); | |
| 175 Bitmap bitmap = success | |
| 176 ? (Bitmap) payload.getParcelable(DecoderServiceImpl.KEY_ IMAGE_BITMAP) | |
| 177 : null; | |
| 178 long decodeTime = payload.getLong(DecoderServiceImpl.KEY_DECODE_ TIME); | |
| 179 closeRequest(filePath, bitmap, decodeTime); | |
| 180 } | |
| 181 }); | |
| 182 } | |
| 183 | |
| 184 /** | 184 /** |
| 185 * Ties up all the loose ends from the decoding request (communicates the re sults of the | 185 * Ties up all the loose ends from the decoding request (communicates the re sults of the |
| 186 * decoding process back to the client, and takes care of house-keeping chor es regarding | 186 * decoding process back to the client, and takes care of house-keeping chor es regarding |
| 187 * the request queue). | 187 * the request queue). |
| 188 * @param filePath The path to the image that was just decoded. | 188 * @param filePath The path to the image that was just decoded. |
| 189 * @param bitmap The resulting decoded bitmap. | 189 * @param bitmap The resulting decoded bitmap. |
| 190 * @param decodeTime The length of time it took to decode the bitmap. | 190 * @param decodeTime The length of time it took to decode the bitmap. |
| 191 */ | 191 */ |
| 192 public void closeRequest(String filePath, Bitmap bitmap, long decodeTime) { | 192 public void closeRequest(String filePath, Bitmap bitmap, long decodeTime) { |
| 193 DecoderServiceParams params = getRequests().get(filePath); | 193 DecoderServiceParams params = getRequests().get(filePath); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 224 Bundle bundle = new Bundle(); | 224 Bundle bundle = new Bundle(); |
| 225 | 225 |
| 226 // The restricted utility process can't open the file to read the | 226 // The restricted utility process can't open the file to read the |
| 227 // contents, so we need to obtain a file descriptor to pass over. | 227 // contents, so we need to obtain a file descriptor to pass over. |
| 228 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); | 228 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); |
| 229 try { | 229 try { |
| 230 try { | 230 try { |
| 231 inputFile = new FileInputStream(file); | 231 inputFile = new FileInputStream(file); |
| 232 FileDescriptor fd = inputFile.getFD(); | 232 FileDescriptor fd = inputFile.getFD(); |
| 233 pfd = ParcelFileDescriptor.dup(fd); | 233 pfd = ParcelFileDescriptor.dup(fd); |
| 234 bundle.putParcelable(DecoderService.KEY_FILE_DESCRIPTOR, pfd); | 234 bundle.putParcelable(DecoderServiceImpl.KEY_FILE_DESCRIPTOR, pfd ); |
| 235 } catch (IOException e) { | 235 } catch (IOException e) { |
| 236 Log.e(TAG, "Unable to obtain FileDescriptor: " + e); | 236 Log.e(TAG, "Unable to obtain FileDescriptor: " + e); |
| 237 closeRequest(filePath, null, -1); | 237 closeRequest(filePath, null, -1); |
| 238 } | 238 } |
| 239 } finally { | 239 } finally { |
| 240 try { | 240 try { |
| 241 if (inputFile != null) inputFile.close(); | 241 if (inputFile != null) inputFile.close(); |
| 242 } catch (IOException e) { | 242 } catch (IOException e) { |
| 243 Log.e(TAG, "Unable to close inputFile: " + e); | 243 Log.e(TAG, "Unable to close inputFile: " + e); |
| 244 } | 244 } |
| 245 StrictMode.setThreadPolicy(oldPolicy); | 245 StrictMode.setThreadPolicy(oldPolicy); |
| 246 } | 246 } |
| 247 | 247 |
| 248 if (pfd == null) return; | 248 if (pfd == null) return; |
| 249 | 249 |
| 250 // Prepare and send the data over. | 250 // Prepare and send the data over. |
| 251 Message payload = Message.obtain(null, DecoderService.MSG_DECODE_IMAGE); | 251 Message payload = Message.obtain(); |
| 252 payload.replyTo = mMessenger; | 252 bundle.putString(DecoderServiceImpl.KEY_FILE_PATH, filePath); |
| 253 bundle.putString(DecoderService.KEY_FILE_PATH, filePath); | 253 bundle.putInt(DecoderServiceImpl.KEY_SIZE, size); |
| 254 bundle.putInt(DecoderService.KEY_SIZE, size); | |
| 255 payload.setData(bundle); | 254 payload.setData(bundle); |
| 256 try { | 255 try { |
| 257 mService.send(payload); | 256 mIRemoteService.decodeImage(bundle, this); |
| 258 pfd.close(); | 257 pfd.close(); |
| 259 } catch (RemoteException e) { | 258 } catch (RemoteException e) { |
| 260 Log.e(TAG, "Communications failed (Remote): " + e); | 259 Log.e(TAG, "Communications failed (Remote): " + e); |
| 261 closeRequest(filePath, null, -1); | 260 closeRequest(filePath, null, -1); |
| 262 } catch (IOException e) { | 261 } catch (IOException e) { |
| 263 Log.e(TAG, "Communications failed (IO): " + e); | 262 Log.e(TAG, "Communications failed (IO): " + e); |
| 264 closeRequest(filePath, null, -1); | 263 closeRequest(filePath, null, -1); |
| 265 } | 264 } |
| 266 } | 265 } |
| 267 | 266 |
| 268 /** | 267 /** |
| 269 * Cancels a request to decode an image (if it hasn't already been dispatche d). | 268 * Cancels a request to decode an image (if it hasn't already been dispatche d). |
| 270 * @param filePath The path to the image to cancel decoding. | 269 * @param filePath The path to the image to cancel decoding. |
| 271 */ | 270 */ |
| 272 public void cancelDecodeImage(String filePath) { | 271 public void cancelDecodeImage(String filePath) { |
| 273 mRequests.remove(filePath); | 272 mRequests.remove(filePath); |
| 274 } | 273 } |
| 275 | |
| 276 /** | |
| 277 * A class for handling communications from the service to us. | |
| 278 */ | |
| 279 static class IncomingHandler extends Handler { | |
| 280 // The DecoderServiceHost object to communicate with. | |
| 281 private final WeakReference<DecoderServiceHost> mHost; | |
| 282 | |
| 283 /** | |
| 284 * Constructor for IncomingHandler. | |
| 285 * @param host The DecoderServiceHost object to communicate with. | |
| 286 */ | |
| 287 IncomingHandler(DecoderServiceHost host) { | |
| 288 mHost = new WeakReference<DecoderServiceHost>(host); | |
| 289 } | |
| 290 | |
| 291 @Override | |
| 292 public void handleMessage(Message msg) { | |
| 293 DecoderServiceHost host = mHost.get(); | |
| 294 if (host == null) { | |
| 295 super.handleMessage(msg); | |
| 296 return; | |
| 297 } | |
| 298 | |
| 299 switch (msg.what) { | |
| 300 case DecoderService.MSG_IMAGE_DECODED_REPLY: | |
| 301 Bundle payload = msg.getData(); | |
| 302 | |
| 303 // Read the reply back from the service. | |
| 304 String filePath = payload.getString(DecoderService.KEY_FILE_ PATH); | |
| 305 Boolean success = payload.getBoolean(DecoderService.KEY_SUCC ESS); | |
| 306 Bitmap bitmap = success | |
| 307 ? (Bitmap) payload.getParcelable(DecoderService.KEY_ IMAGE_BITMAP) | |
| 308 : null; | |
| 309 long decodeTime = payload.getLong(DecoderService.KEY_DECODE_ TIME); | |
| 310 host.closeRequest(filePath, bitmap, decodeTime); | |
| 311 break; | |
| 312 default: | |
| 313 super.handleMessage(msg); | |
| 314 } | |
| 315 } | |
| 316 } | |
| 317 } | 274 } |
| OLD | NEW |