blob: d1ab8d576412fe136ed85bdee4cc035baa48146c [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content;
18
19import android.content.res.AssetFileDescriptor;
20import android.database.BulkCursorNative;
21import android.database.BulkCursorToCursorAdaptor;
22import android.database.Cursor;
23import android.database.CursorWindow;
24import android.database.DatabaseUtils;
25import android.database.IBulkCursor;
26import android.database.IContentObserver;
27import android.net.Uri;
28import android.os.Binder;
Brad Fitzpatrick1877d012010-03-04 17:48:13 -080029import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.os.RemoteException;
31import android.os.IBinder;
32import android.os.Parcel;
33import android.os.ParcelFileDescriptor;
34import android.os.Parcelable;
35
36import java.io.FileNotFoundException;
Fred Quintana03d94902009-05-22 14:23:31 -070037import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038
39/**
40 * {@hide}
41 */
42abstract public class ContentProviderNative extends Binder implements IContentProvider {
43 private static final String TAG = "ContentProvider";
44
45 public ContentProviderNative()
46 {
47 attachInterface(this, descriptor);
48 }
49
50 /**
51 * Cast a Binder object into a content resolver interface, generating
52 * a proxy if needed.
53 */
54 static public IContentProvider asInterface(IBinder obj)
55 {
56 if (obj == null) {
57 return null;
58 }
59 IContentProvider in =
60 (IContentProvider)obj.queryLocalInterface(descriptor);
61 if (in != null) {
62 return in;
63 }
64
65 return new ContentProviderProxy(obj);
66 }
67
68 @Override
69 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
70 throws RemoteException {
71 try {
72 switch (code) {
73 case QUERY_TRANSACTION:
74 {
75 data.enforceInterface(IContentProvider.descriptor);
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -080076
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 Uri url = Uri.CREATOR.createFromParcel(data);
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -080078
79 // String[] projection
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 int num = data.readInt();
81 String[] projection = null;
82 if (num > 0) {
83 projection = new String[num];
84 for (int i = 0; i < num; i++) {
85 projection[i] = data.readString();
86 }
87 }
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -080088
89 // String selection, String[] selectionArgs...
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 String selection = data.readString();
91 num = data.readInt();
92 String[] selectionArgs = null;
93 if (num > 0) {
94 selectionArgs = new String[num];
95 for (int i = 0; i < num; i++) {
96 selectionArgs[i] = data.readString();
97 }
98 }
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -080099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 String sortOrder = data.readString();
101 IContentObserver observer = IContentObserver.Stub.
102 asInterface(data.readStrongBinder());
103 CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);
104
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -0800105 // Flag for whether caller wants the number of
106 // rows in the cursor and the position of the
107 // "_id" column index (or -1 if non-existent)
108 // Only to be returned if binder != null.
109 boolean wantsCursorMetadata = data.readInt() != 0;
110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 IBulkCursor bulkCursor = bulkQuery(url, projection, selection,
112 selectionArgs, sortOrder, observer, window);
113 reply.writeNoException();
114 if (bulkCursor != null) {
115 reply.writeStrongBinder(bulkCursor.asBinder());
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -0800116
117 if (wantsCursorMetadata) {
118 reply.writeInt(bulkCursor.count());
119 reply.writeInt(BulkCursorToCursorAdaptor.findRowIdColumnIndex(
120 bulkCursor.getColumnNames()));
121 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 } else {
123 reply.writeStrongBinder(null);
124 }
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -0800125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 return true;
127 }
128
129 case GET_TYPE_TRANSACTION:
130 {
131 data.enforceInterface(IContentProvider.descriptor);
132 Uri url = Uri.CREATOR.createFromParcel(data);
133 String type = getType(url);
134 reply.writeNoException();
135 reply.writeString(type);
136
137 return true;
138 }
139
140 case INSERT_TRANSACTION:
141 {
142 data.enforceInterface(IContentProvider.descriptor);
143 Uri url = Uri.CREATOR.createFromParcel(data);
144 ContentValues values = ContentValues.CREATOR.createFromParcel(data);
145
146 Uri out = insert(url, values);
147 reply.writeNoException();
148 Uri.writeToParcel(reply, out);
149 return true;
150 }
151
152 case BULK_INSERT_TRANSACTION:
153 {
154 data.enforceInterface(IContentProvider.descriptor);
155 Uri url = Uri.CREATOR.createFromParcel(data);
156 ContentValues[] values = data.createTypedArray(ContentValues.CREATOR);
157
158 int count = bulkInsert(url, values);
159 reply.writeNoException();
160 reply.writeInt(count);
161 return true;
162 }
163
Fred Quintana89437372009-05-15 15:10:40 -0700164 case APPLY_BATCH_TRANSACTION:
165 {
166 data.enforceInterface(IContentProvider.descriptor);
Fred Quintana03d94902009-05-22 14:23:31 -0700167 final int numOperations = data.readInt();
168 final ArrayList<ContentProviderOperation> operations =
169 new ArrayList<ContentProviderOperation>(numOperations);
170 for (int i = 0; i < numOperations; i++) {
171 operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
172 }
Fred Quintana89437372009-05-15 15:10:40 -0700173 final ContentProviderResult[] results = applyBatch(operations);
174 reply.writeNoException();
175 reply.writeTypedArray(results, 0);
Fred Quintana6a8d5332009-05-07 17:35:38 -0700176 return true;
177 }
178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 case DELETE_TRANSACTION:
180 {
181 data.enforceInterface(IContentProvider.descriptor);
182 Uri url = Uri.CREATOR.createFromParcel(data);
183 String selection = data.readString();
184 String[] selectionArgs = data.readStringArray();
185
186 int count = delete(url, selection, selectionArgs);
187
188 reply.writeNoException();
189 reply.writeInt(count);
190 return true;
191 }
192
193 case UPDATE_TRANSACTION:
194 {
195 data.enforceInterface(IContentProvider.descriptor);
196 Uri url = Uri.CREATOR.createFromParcel(data);
197 ContentValues values = ContentValues.CREATOR.createFromParcel(data);
198 String selection = data.readString();
199 String[] selectionArgs = data.readStringArray();
200
201 int count = update(url, values, selection, selectionArgs);
202
203 reply.writeNoException();
204 reply.writeInt(count);
205 return true;
206 }
207
208 case OPEN_FILE_TRANSACTION:
209 {
210 data.enforceInterface(IContentProvider.descriptor);
211 Uri url = Uri.CREATOR.createFromParcel(data);
212 String mode = data.readString();
213
214 ParcelFileDescriptor fd;
215 fd = openFile(url, mode);
216 reply.writeNoException();
217 if (fd != null) {
218 reply.writeInt(1);
219 fd.writeToParcel(reply,
220 Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
221 } else {
222 reply.writeInt(0);
223 }
224 return true;
225 }
226
227 case OPEN_ASSET_FILE_TRANSACTION:
228 {
229 data.enforceInterface(IContentProvider.descriptor);
230 Uri url = Uri.CREATOR.createFromParcel(data);
231 String mode = data.readString();
232
233 AssetFileDescriptor fd;
234 fd = openAssetFile(url, mode);
235 reply.writeNoException();
236 if (fd != null) {
237 reply.writeInt(1);
238 fd.writeToParcel(reply,
239 Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
240 } else {
241 reply.writeInt(0);
242 }
243 return true;
244 }
Brad Fitzpatrick1877d012010-03-04 17:48:13 -0800245
246 case CALL_TRANSACTION:
247 {
248 data.enforceInterface(IContentProvider.descriptor);
249
250 String method = data.readString();
251 String stringArg = data.readString();
252 Bundle args = data.readBundle();
253
254 Bundle responseBundle = call(method, stringArg, args);
255
256 reply.writeNoException();
257 reply.writeBundle(responseBundle);
258 return true;
259 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700260
261 case GET_STREAM_TYPES_TRANSACTION:
262 {
263 data.enforceInterface(IContentProvider.descriptor);
264 Uri url = Uri.CREATOR.createFromParcel(data);
265 String mimeTypeFilter = data.readString();
266 String[] types = getStreamTypes(url, mimeTypeFilter);
267 reply.writeNoException();
268 reply.writeStringArray(types);
269
270 return true;
271 }
272
273 case OPEN_TYPED_ASSET_FILE_TRANSACTION:
274 {
275 data.enforceInterface(IContentProvider.descriptor);
276 Uri url = Uri.CREATOR.createFromParcel(data);
277 String mimeType = data.readString();
278 Bundle opts = data.readBundle();
279
280 AssetFileDescriptor fd;
281 fd = openTypedAssetFile(url, mimeType, opts);
282 reply.writeNoException();
283 if (fd != null) {
284 reply.writeInt(1);
285 fd.writeToParcel(reply,
286 Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
287 } else {
288 reply.writeInt(0);
289 }
290 return true;
291 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 }
293 } catch (Exception e) {
294 DatabaseUtils.writeExceptionToParcel(reply, e);
295 return true;
296 }
297
298 return super.onTransact(code, data, reply, flags);
299 }
300
301 public IBinder asBinder()
302 {
303 return this;
304 }
305}
306
307
308final class ContentProviderProxy implements IContentProvider
309{
310 public ContentProviderProxy(IBinder remote)
311 {
312 mRemote = remote;
313 }
314
315 public IBinder asBinder()
316 {
317 return mRemote;
318 }
319
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -0800320 // Like bulkQuery() but sets up provided 'adaptor' if not null.
321 private IBulkCursor bulkQueryInternal(
322 Uri url, String[] projection,
323 String selection, String[] selectionArgs, String sortOrder,
324 IContentObserver observer, CursorWindow window,
325 BulkCursorToCursorAdaptor adaptor) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 Parcel data = Parcel.obtain();
327 Parcel reply = Parcel.obtain();
328
329 data.writeInterfaceToken(IContentProvider.descriptor);
330
331 url.writeToParcel(data, 0);
332 int length = 0;
333 if (projection != null) {
334 length = projection.length;
335 }
336 data.writeInt(length);
337 for (int i = 0; i < length; i++) {
338 data.writeString(projection[i]);
339 }
340 data.writeString(selection);
341 if (selectionArgs != null) {
342 length = selectionArgs.length;
343 } else {
344 length = 0;
345 }
346 data.writeInt(length);
347 for (int i = 0; i < length; i++) {
348 data.writeString(selectionArgs[i]);
349 }
350 data.writeString(sortOrder);
351 data.writeStrongBinder(observer.asBinder());
352 window.writeToParcel(data, 0);
353
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -0800354 // Flag for whether or not we want the number of rows in the
355 // cursor and the position of the "_id" column index (or -1 if
356 // non-existent). Only to be returned if binder != null.
357 final boolean wantsCursorMetadata = (adaptor != null);
358 data.writeInt(wantsCursorMetadata ? 1 : 0);
359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
361
362 DatabaseUtils.readExceptionFromParcel(reply);
363
364 IBulkCursor bulkCursor = null;
365 IBinder bulkCursorBinder = reply.readStrongBinder();
366 if (bulkCursorBinder != null) {
367 bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder);
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -0800368
369 if (wantsCursorMetadata) {
370 int rowCount = reply.readInt();
371 int idColumnPosition = reply.readInt();
372 if (bulkCursor != null) {
373 adaptor.set(bulkCursor, rowCount, idColumnPosition);
374 }
375 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 }
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -0800377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 data.recycle();
379 reply.recycle();
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -0800380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 return bulkCursor;
382 }
383
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -0800384 public IBulkCursor bulkQuery(Uri url, String[] projection,
385 String selection, String[] selectionArgs, String sortOrder, IContentObserver observer,
386 CursorWindow window) throws RemoteException {
387 return bulkQueryInternal(
388 url, projection, selection, selectionArgs, sortOrder,
389 observer, window,
390 null /* BulkCursorToCursorAdaptor */);
391 }
392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 public Cursor query(Uri url, String[] projection, String selection,
394 String[] selectionArgs, String sortOrder) throws RemoteException {
395 //TODO make a pool of windows so we can reuse memory dealers
396 CursorWindow window = new CursorWindow(false /* window will be used remotely */);
397 BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -0800398 IBulkCursor bulkCursor = bulkQueryInternal(
399 url, projection, selection, selectionArgs, sortOrder,
400 adaptor.getObserver(), window,
401 adaptor);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 if (bulkCursor == null) {
403 return null;
404 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 return adaptor;
406 }
407
408 public String getType(Uri url) throws RemoteException
409 {
410 Parcel data = Parcel.obtain();
411 Parcel reply = Parcel.obtain();
412
413 data.writeInterfaceToken(IContentProvider.descriptor);
414
415 url.writeToParcel(data, 0);
416
417 mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0);
418
419 DatabaseUtils.readExceptionFromParcel(reply);
420 String out = reply.readString();
421
422 data.recycle();
423 reply.recycle();
424
425 return out;
426 }
427
428 public Uri insert(Uri url, ContentValues values) throws RemoteException
429 {
430 Parcel data = Parcel.obtain();
431 Parcel reply = Parcel.obtain();
432
433 data.writeInterfaceToken(IContentProvider.descriptor);
434
435 url.writeToParcel(data, 0);
436 values.writeToParcel(data, 0);
437
438 mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0);
439
440 DatabaseUtils.readExceptionFromParcel(reply);
441 Uri out = Uri.CREATOR.createFromParcel(reply);
442
443 data.recycle();
444 reply.recycle();
445
446 return out;
447 }
448
449 public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException {
450 Parcel data = Parcel.obtain();
451 Parcel reply = Parcel.obtain();
452
453 data.writeInterfaceToken(IContentProvider.descriptor);
454
455 url.writeToParcel(data, 0);
456 data.writeTypedArray(values, 0);
457
458 mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0);
459
460 DatabaseUtils.readExceptionFromParcel(reply);
461 int count = reply.readInt();
462
463 data.recycle();
464 reply.recycle();
465
466 return count;
467 }
468
Fred Quintana03d94902009-05-22 14:23:31 -0700469 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
Fred Quintana89437372009-05-15 15:10:40 -0700470 throws RemoteException, OperationApplicationException {
Fred Quintana6a8d5332009-05-07 17:35:38 -0700471 Parcel data = Parcel.obtain();
472 Parcel reply = Parcel.obtain();
473
474 data.writeInterfaceToken(IContentProvider.descriptor);
Fred Quintana03d94902009-05-22 14:23:31 -0700475 data.writeInt(operations.size());
476 for (ContentProviderOperation operation : operations) {
477 operation.writeToParcel(data, 0);
478 }
Fred Quintana89437372009-05-15 15:10:40 -0700479 mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0);
Fred Quintana6a8d5332009-05-07 17:35:38 -0700480
Fred Quintana89437372009-05-15 15:10:40 -0700481 DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply);
482 final ContentProviderResult[] results =
483 reply.createTypedArray(ContentProviderResult.CREATOR);
Fred Quintana6a8d5332009-05-07 17:35:38 -0700484
485 data.recycle();
486 reply.recycle();
487
488 return results;
489 }
490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 public int delete(Uri url, String selection, String[] selectionArgs)
492 throws RemoteException {
493 Parcel data = Parcel.obtain();
494 Parcel reply = Parcel.obtain();
495
496 data.writeInterfaceToken(IContentProvider.descriptor);
497
498 url.writeToParcel(data, 0);
499 data.writeString(selection);
500 data.writeStringArray(selectionArgs);
501
502 mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0);
503
504 DatabaseUtils.readExceptionFromParcel(reply);
505 int count = reply.readInt();
506
507 data.recycle();
508 reply.recycle();
509
510 return count;
511 }
512
513 public int update(Uri url, ContentValues values, String selection,
514 String[] selectionArgs) throws RemoteException {
515 Parcel data = Parcel.obtain();
516 Parcel reply = Parcel.obtain();
517
518 data.writeInterfaceToken(IContentProvider.descriptor);
519
520 url.writeToParcel(data, 0);
521 values.writeToParcel(data, 0);
522 data.writeString(selection);
523 data.writeStringArray(selectionArgs);
524
525 mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0);
526
527 DatabaseUtils.readExceptionFromParcel(reply);
528 int count = reply.readInt();
529
530 data.recycle();
531 reply.recycle();
532
533 return count;
534 }
535
536 public ParcelFileDescriptor openFile(Uri url, String mode)
537 throws RemoteException, FileNotFoundException {
538 Parcel data = Parcel.obtain();
539 Parcel reply = Parcel.obtain();
540
541 data.writeInterfaceToken(IContentProvider.descriptor);
542
543 url.writeToParcel(data, 0);
544 data.writeString(mode);
545
546 mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
547
548 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
549 int has = reply.readInt();
550 ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null;
551
552 data.recycle();
553 reply.recycle();
554
555 return fd;
556 }
557
558 public AssetFileDescriptor openAssetFile(Uri url, String mode)
559 throws RemoteException, FileNotFoundException {
560 Parcel data = Parcel.obtain();
561 Parcel reply = Parcel.obtain();
562
563 data.writeInterfaceToken(IContentProvider.descriptor);
564
565 url.writeToParcel(data, 0);
566 data.writeString(mode);
567
568 mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0);
569
570 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
571 int has = reply.readInt();
572 AssetFileDescriptor fd = has != 0
573 ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
574
575 data.recycle();
576 reply.recycle();
577
578 return fd;
579 }
580
Brad Fitzpatrick1877d012010-03-04 17:48:13 -0800581 public Bundle call(String method, String request, Bundle args)
582 throws RemoteException {
583 Parcel data = Parcel.obtain();
584 Parcel reply = Parcel.obtain();
585
586 data.writeInterfaceToken(IContentProvider.descriptor);
587
588 data.writeString(method);
589 data.writeString(request);
590 data.writeBundle(args);
591
592 mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0);
593
594 DatabaseUtils.readExceptionFromParcel(reply);
Brad Fitzpatrickdfb437e2010-03-08 22:11:50 -0800595 Bundle bundle = reply.readBundle();
596
597 data.recycle();
598 reply.recycle();
599
600 return bundle;
Brad Fitzpatrick1877d012010-03-04 17:48:13 -0800601 }
602
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700603 public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException
604 {
605 Parcel data = Parcel.obtain();
606 Parcel reply = Parcel.obtain();
607
608 data.writeInterfaceToken(IContentProvider.descriptor);
609
610 url.writeToParcel(data, 0);
611 data.writeString(mimeTypeFilter);
612
613 mRemote.transact(IContentProvider.GET_STREAM_TYPES_TRANSACTION, data, reply, 0);
614
615 DatabaseUtils.readExceptionFromParcel(reply);
616 String[] out = reply.createStringArray();
617
618 data.recycle();
619 reply.recycle();
620
621 return out;
622 }
623
624 public AssetFileDescriptor openTypedAssetFile(Uri url, String mimeType, Bundle opts)
625 throws RemoteException, FileNotFoundException {
626 Parcel data = Parcel.obtain();
627 Parcel reply = Parcel.obtain();
628
629 data.writeInterfaceToken(IContentProvider.descriptor);
630
631 url.writeToParcel(data, 0);
632 data.writeString(mimeType);
633 data.writeBundle(opts);
634
635 mRemote.transact(IContentProvider.OPEN_TYPED_ASSET_FILE_TRANSACTION, data, reply, 0);
636
637 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
638 int has = reply.readInt();
639 AssetFileDescriptor fd = has != 0
640 ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
641
642 data.recycle();
643 reply.recycle();
644
645 return fd;
646 }
647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 private IBinder mRemote;
649}