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. | |
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. | 107 // Flag indicating whether we are bound to the service. |
126 boolean mBound; | 108 boolean mBound; |
127 | 109 |
128 // The inbound messenger used by the remote service to communicate with us. | 110 private Context mContext; |
Robert Sesek
2017/06/20 20:49:43
final?
| |
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 ThreadUtils.runOnUiThread(new Runnable() { | |
169 @Override | |
170 public void run() { | |
171 // Read the reply back from the service. | |
172 String filePath = payload.getString(DecoderService.KEY_FILE_PATH ); | |
173 Boolean success = payload.getBoolean(DecoderService.KEY_SUCCESS) ; | |
174 Bitmap bitmap = success | |
175 ? (Bitmap) payload.getParcelable(DecoderService.KEY_IMAG E_BITMAP) | |
176 : null; | |
177 long decodeTime = payload.getLong(DecoderService.KEY_DECODE_TIME ); | |
178 closeRequest(filePath, bitmap, decodeTime); | |
179 } | |
180 }); | |
181 } | |
182 | |
184 /** | 183 /** |
185 * Ties up all the loose ends from the decoding request (communicates the re sults of the | 184 * 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 | 185 * decoding process back to the client, and takes care of house-keeping chor es regarding |
187 * the request queue). | 186 * the request queue). |
188 * @param filePath The path to the image that was just decoded. | 187 * @param filePath The path to the image that was just decoded. |
189 * @param bitmap The resulting decoded bitmap. | 188 * @param bitmap The resulting decoded bitmap. |
190 * @param decodeTime The length of time it took to decode the bitmap. | 189 * @param decodeTime The length of time it took to decode the bitmap. |
191 */ | 190 */ |
192 public void closeRequest(String filePath, Bitmap bitmap, long decodeTime) { | 191 public void closeRequest(String filePath, Bitmap bitmap, long decodeTime) { |
193 DecoderServiceParams params = getRequests().get(filePath); | 192 DecoderServiceParams params = getRequests().get(filePath); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
241 if (inputFile != null) inputFile.close(); | 240 if (inputFile != null) inputFile.close(); |
242 } catch (IOException e) { | 241 } catch (IOException e) { |
243 Log.e(TAG, "Unable to close inputFile: " + e); | 242 Log.e(TAG, "Unable to close inputFile: " + e); |
244 } | 243 } |
245 StrictMode.setThreadPolicy(oldPolicy); | 244 StrictMode.setThreadPolicy(oldPolicy); |
246 } | 245 } |
247 | 246 |
248 if (pfd == null) return; | 247 if (pfd == null) return; |
249 | 248 |
250 // Prepare and send the data over. | 249 // 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); | 250 bundle.putString(DecoderService.KEY_FILE_PATH, filePath); |
254 bundle.putInt(DecoderService.KEY_SIZE, size); | 251 bundle.putInt(DecoderService.KEY_SIZE, size); |
255 payload.setData(bundle); | |
256 try { | 252 try { |
257 mService.send(payload); | 253 mIRemoteService.decodeImage(bundle, this); |
Theresa
2017/06/20 16:53:12
Does the service automatically run this on a diffe
Finnur
2017/06/20 20:55:05
No, no problem. This is exactly the kind of thing
Theresa
2017/06/21 14:58:36
Thanks for the link, that is very helpful.
So thi
Finnur
2017/06/21 15:20:34
Yes. Done.
| |
258 pfd.close(); | 254 pfd.close(); |
259 } catch (RemoteException e) { | 255 } catch (RemoteException e) { |
260 Log.e(TAG, "Communications failed (Remote): " + e); | 256 Log.e(TAG, "Communications failed (Remote): " + e); |
261 closeRequest(filePath, null, -1); | 257 closeRequest(filePath, null, -1); |
262 } catch (IOException e) { | 258 } catch (IOException e) { |
263 Log.e(TAG, "Communications failed (IO): " + e); | 259 Log.e(TAG, "Communications failed (IO): " + e); |
264 closeRequest(filePath, null, -1); | 260 closeRequest(filePath, null, -1); |
265 } | 261 } |
266 } | 262 } |
267 | 263 |
268 /** | 264 /** |
269 * Cancels a request to decode an image (if it hasn't already been dispatche d). | 265 * 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. | 266 * @param filePath The path to the image to cancel decoding. |
271 */ | 267 */ |
272 public void cancelDecodeImage(String filePath) { | 268 public void cancelDecodeImage(String filePath) { |
273 mRequests.remove(filePath); | 269 mRequests.remove(filePath); |
274 } | 270 } |
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 } | 271 } |
OLD | NEW |