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; | |
16 import android.os.Messenger; | |
17 import android.os.ParcelFileDescriptor; | 14 import android.os.ParcelFileDescriptor; |
18 import android.os.RemoteException; | 15 import android.os.RemoteException; |
19 import android.os.StrictMode; | 16 import android.os.StrictMode; |
20 import android.os.SystemClock; | 17 import android.os.SystemClock; |
21 | 18 |
22 import org.chromium.base.Log; | 19 import org.chromium.base.Log; |
| 20 import org.chromium.base.ThreadUtils; |
23 import org.chromium.base.metrics.RecordHistogram; | 21 import org.chromium.base.metrics.RecordHistogram; |
24 import org.chromium.chrome.browser.util.ConversionUtils; | 22 import org.chromium.chrome.browser.util.ConversionUtils; |
25 | 23 |
26 import java.io.File; | 24 import java.io.File; |
27 import java.io.FileDescriptor; | 25 import java.io.FileDescriptor; |
28 import java.io.FileInputStream; | 26 import java.io.FileInputStream; |
29 import java.io.IOException; | 27 import java.io.IOException; |
30 import java.lang.ref.WeakReference; | |
31 import java.util.LinkedHashMap; | 28 import java.util.LinkedHashMap; |
32 import java.util.concurrent.TimeUnit; | 29 import java.util.concurrent.TimeUnit; |
33 | 30 |
34 /** | 31 /** |
35 * A class to communicate with the {@link DecoderService}. | 32 * A class to communicate with the {@link DecoderService}. |
36 */ | 33 */ |
37 public class DecoderServiceHost { | 34 public class DecoderServiceHost extends IDecoderServiceCallback.Stub { |
38 // A tag for logging error messages. | 35 // A tag for logging error messages. |
39 private static final String TAG = "ImageDecoderHost"; | 36 private static final String TAG = "ImageDecoderHost"; |
40 | 37 |
| 38 IDecoderService mIRemoteService; |
| 39 private ServiceConnection mConnection = new ServiceConnection() { |
| 40 public void onServiceConnected(ComponentName className, IBinder service)
{ |
| 41 mIRemoteService = IDecoderService.Stub.asInterface(service); |
| 42 mBound = true; |
| 43 mCallback.serviceReady(); |
| 44 } |
| 45 |
| 46 public void onServiceDisconnected(ComponentName className) { |
| 47 Log.e(TAG, "Service has unexpectedly disconnected"); |
| 48 mIRemoteService = null; |
| 49 mBound = false; |
| 50 } |
| 51 }; |
| 52 |
41 /** | 53 /** |
42 * Interface for notifying clients of the service being ready. | 54 * Interface for notifying clients of the service being ready. |
43 */ | 55 */ |
44 public interface ServiceReadyCallback { | 56 public interface ServiceReadyCallback { |
45 /** | 57 /** |
46 * A function to define to receive a notification once the service is up
and running. | 58 * A function to define to receive a notification once the service is up
and running. |
47 */ | 59 */ |
48 void serviceReady(); | 60 void serviceReady(); |
49 } | 61 } |
50 | 62 |
51 /** | 63 /** |
52 * An interface notifying clients when an image has finished decoding. | 64 * An interface notifying clients when an image has finished decoding. |
53 */ | 65 */ |
54 public interface ImageDecodedCallback { | 66 public interface ImageDecodedCallback { |
55 /** | 67 /** |
56 * A function to define to receive a notification that an image has been
decoded. | 68 * 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. | 69 * @param filePath The file path for the newly decoded image. |
58 * @param bitmap The results of the decoding (or placeholder image, if f
ailed). | 70 * @param bitmap The results of the decoding (or placeholder image, if f
ailed). |
59 */ | 71 */ |
60 void imageDecodedCallback(String filePath, Bitmap bitmap); | 72 void imageDecodedCallback(String filePath, Bitmap bitmap); |
61 } | 73 } |
62 | 74 |
63 /** | 75 /** |
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. | 76 * Class for keeping track of the data involved with each request. |
89 */ | 77 */ |
90 private static class DecoderServiceParams { | 78 private static class DecoderServiceParams { |
91 // The path to the file containing the bitmap to decode. | 79 // The path to the file containing the bitmap to decode. |
92 public String mFilePath; | 80 public String mFilePath; |
93 | 81 |
94 // The requested size (width and height) of the bitmap, once decoded. | 82 // The requested size (width and height) of the bitmap, once decoded. |
95 public int mSize; | 83 public int mSize; |
96 | 84 |
97 // The callback to use to communicate the results of the decoding. | 85 // The callback to use to communicate the results of the decoding. |
(...skipping 11 matching lines...) Expand all Loading... |
109 | 97 |
110 // Map of file paths to decoder parameters in order of request. | 98 // Map of file paths to decoder parameters in order of request. |
111 private LinkedHashMap<String, DecoderServiceParams> mRequests = new LinkedHa
shMap<>(); | 99 private LinkedHashMap<String, DecoderServiceParams> mRequests = new LinkedHa
shMap<>(); |
112 LinkedHashMap<String, DecoderServiceParams> getRequests() { | 100 LinkedHashMap<String, DecoderServiceParams> getRequests() { |
113 return mRequests; | 101 return mRequests; |
114 } | 102 } |
115 | 103 |
116 // The callback used to notify the client when the service is ready. | 104 // The callback used to notify the client when the service is ready. |
117 private ServiceReadyCallback mCallback; | 105 private ServiceReadyCallback mCallback; |
118 | 106 |
119 // Messenger for communicating with the remote service. | 107 // Flag indicating whether we are bound to the service. |
120 Messenger mService = null; | 108 private boolean mBound; |
121 | 109 |
122 // Our service connection to the {@link DecoderService}. | 110 private final Context mContext; |
123 private DecoderServiceConnection mConnection; | |
124 | |
125 // Flag indicating whether we are bound to the service. | |
126 boolean mBound; | |
127 | |
128 // The inbound messenger used by the remote service to communicate with us. | |
129 final Messenger mMessenger = new Messenger(new IncomingHandler(this)); | |
130 | 111 |
131 /** | 112 /** |
132 * The DecoderServiceHost constructor. | 113 * The DecoderServiceHost constructor. |
133 * @param callback The callback to use when communicating back to the client
. | 114 * @param callback The callback to use when communicating back to the client
. |
134 */ | 115 */ |
135 public DecoderServiceHost(ServiceReadyCallback callback) { | 116 public DecoderServiceHost(ServiceReadyCallback callback, Context context) { |
136 mCallback = callback; | 117 mCallback = callback; |
| 118 mContext = context; |
137 } | 119 } |
138 | 120 |
139 /** | 121 /** |
140 * Initiate binding with the {@link DecoderService}. | 122 * Initiate binding with the {@link DecoderService}. |
141 * @param context The context to use. | 123 * @param context The context to use. |
142 */ | 124 */ |
143 public void bind(Context context) { | 125 public void bind(Context context) { |
144 mConnection = new DecoderServiceConnection(mCallback); | 126 Intent intent = new Intent(mContext, DecoderService.class); |
145 Intent intent = new Intent(context, DecoderService.class); | 127 intent.setAction(IDecoderService.class.getName()); |
146 context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); | 128 mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); |
147 } | 129 } |
148 | 130 |
149 /** | 131 /** |
150 * Unbind from the {@link DecoderService}. | 132 * Unbind from the {@link DecoderService}. |
151 * @param context The context to use. | 133 * @param context The context to use. |
152 */ | 134 */ |
153 public void unbind(Context context) { | 135 public void unbind(Context context) { |
154 if (mBound) { | 136 if (mBound) { |
155 context.unbindService(mConnection); | 137 context.unbindService(mConnection); |
156 mBound = false; | 138 mBound = false; |
(...skipping 17 matching lines...) Expand all Loading... |
174 * Dispatches the next image for decoding (from the queue). | 156 * Dispatches the next image for decoding (from the queue). |
175 */ | 157 */ |
176 private void dispatchNextDecodeImageRequest() { | 158 private void dispatchNextDecodeImageRequest() { |
177 if (mRequests.entrySet().iterator().hasNext()) { | 159 if (mRequests.entrySet().iterator().hasNext()) { |
178 DecoderServiceParams params = mRequests.entrySet().iterator().next()
.getValue(); | 160 DecoderServiceParams params = mRequests.entrySet().iterator().next()
.getValue(); |
179 params.mTimestamp = SystemClock.elapsedRealtime(); | 161 params.mTimestamp = SystemClock.elapsedRealtime(); |
180 dispatchDecodeImageRequest(params.mFilePath, params.mSize); | 162 dispatchDecodeImageRequest(params.mFilePath, params.mSize); |
181 } | 163 } |
182 } | 164 } |
183 | 165 |
| 166 @Override |
| 167 public void onDecodeImageDone(final Bundle payload) { |
| 168 // As per the Android documentation, AIDL callbacks can (and will) happe
n on any thread, so |
| 169 // make sure the code runs on the UI thread, since further down the call
chain the code will |
| 170 // end up creating UI objects. |
| 171 ThreadUtils.runOnUiThread(new Runnable() { |
| 172 @Override |
| 173 public void run() { |
| 174 // Read the reply back from the service. |
| 175 String filePath = payload.getString(DecoderService.KEY_FILE_PATH
); |
| 176 Boolean success = payload.getBoolean(DecoderService.KEY_SUCCESS)
; |
| 177 Bitmap bitmap = success |
| 178 ? (Bitmap) payload.getParcelable(DecoderService.KEY_IMAG
E_BITMAP) |
| 179 : null; |
| 180 long decodeTime = payload.getLong(DecoderService.KEY_DECODE_TIME
); |
| 181 closeRequest(filePath, bitmap, decodeTime); |
| 182 } |
| 183 }); |
| 184 } |
| 185 |
184 /** | 186 /** |
185 * Ties up all the loose ends from the decoding request (communicates the re
sults of the | 187 * 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 | 188 * decoding process back to the client, and takes care of house-keeping chor
es regarding |
187 * the request queue). | 189 * the request queue). |
188 * @param filePath The path to the image that was just decoded. | 190 * @param filePath The path to the image that was just decoded. |
189 * @param bitmap The resulting decoded bitmap. | 191 * @param bitmap The resulting decoded bitmap. |
190 * @param decodeTime The length of time it took to decode the bitmap. | 192 * @param decodeTime The length of time it took to decode the bitmap. |
191 */ | 193 */ |
192 public void closeRequest(String filePath, Bitmap bitmap, long decodeTime) { | 194 public void closeRequest(String filePath, Bitmap bitmap, long decodeTime) { |
193 DecoderServiceParams params = getRequests().get(filePath); | 195 DecoderServiceParams params = getRequests().get(filePath); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 if (inputFile != null) inputFile.close(); | 243 if (inputFile != null) inputFile.close(); |
242 } catch (IOException e) { | 244 } catch (IOException e) { |
243 Log.e(TAG, "Unable to close inputFile: " + e); | 245 Log.e(TAG, "Unable to close inputFile: " + e); |
244 } | 246 } |
245 StrictMode.setThreadPolicy(oldPolicy); | 247 StrictMode.setThreadPolicy(oldPolicy); |
246 } | 248 } |
247 | 249 |
248 if (pfd == null) return; | 250 if (pfd == null) return; |
249 | 251 |
250 // Prepare and send the data over. | 252 // Prepare and send the data over. |
251 Message payload = Message.obtain(null, DecoderService.MSG_DECODE_IMAGE); | |
252 payload.replyTo = mMessenger; | |
253 bundle.putString(DecoderService.KEY_FILE_PATH, filePath); | 253 bundle.putString(DecoderService.KEY_FILE_PATH, filePath); |
254 bundle.putInt(DecoderService.KEY_SIZE, size); | 254 bundle.putInt(DecoderService.KEY_SIZE, size); |
255 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 |