1/*
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.database;
18
19import android.os.Binder;
20import android.os.Bundle;
21import android.os.IBinder;
22import android.os.Parcel;
23import android.os.Parcelable;
24import android.os.RemoteException;
25
26/**
27 * Native implementation of the bulk cursor. This is only for use in implementing
28 * IPC, application code should use the Cursor interface.
29 *
30 * {@hide}
31 */
32public abstract class BulkCursorNative extends Binder implements IBulkCursor
33{
34    public BulkCursorNative()
35    {
36        attachInterface(this, descriptor);
37    }
38
39    /**
40     * Cast a Binder object into a content resolver interface, generating
41     * a proxy if needed.
42     */
43    static public IBulkCursor asInterface(IBinder obj)
44    {
45        if (obj == null) {
46            return null;
47        }
48        IBulkCursor in = (IBulkCursor)obj.queryLocalInterface(descriptor);
49        if (in != null) {
50            return in;
51        }
52
53        return new BulkCursorProxy(obj);
54    }
55
56    @Override
57    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
58            throws RemoteException {
59        try {
60            switch (code) {
61                case GET_CURSOR_WINDOW_TRANSACTION: {
62                    data.enforceInterface(IBulkCursor.descriptor);
63                    int startPos = data.readInt();
64                    CursorWindow window = getWindow(startPos);
65                    reply.writeNoException();
66                    if (window == null) {
67                        reply.writeInt(0);
68                    } else {
69                        reply.writeInt(1);
70                        window.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
71                    }
72                    return true;
73                }
74
75                case DEACTIVATE_TRANSACTION: {
76                    data.enforceInterface(IBulkCursor.descriptor);
77                    deactivate();
78                    reply.writeNoException();
79                    return true;
80                }
81
82                case CLOSE_TRANSACTION: {
83                    data.enforceInterface(IBulkCursor.descriptor);
84                    close();
85                    reply.writeNoException();
86                    return true;
87                }
88
89                case REQUERY_TRANSACTION: {
90                    data.enforceInterface(IBulkCursor.descriptor);
91                    IContentObserver observer =
92                            IContentObserver.Stub.asInterface(data.readStrongBinder());
93                    int count = requery(observer);
94                    reply.writeNoException();
95                    reply.writeInt(count);
96                    reply.writeBundle(getExtras());
97                    return true;
98                }
99
100                case ON_MOVE_TRANSACTION: {
101                    data.enforceInterface(IBulkCursor.descriptor);
102                    int position = data.readInt();
103                    onMove(position);
104                    reply.writeNoException();
105                    return true;
106                }
107
108                case GET_EXTRAS_TRANSACTION: {
109                    data.enforceInterface(IBulkCursor.descriptor);
110                    Bundle extras = getExtras();
111                    reply.writeNoException();
112                    reply.writeBundle(extras);
113                    return true;
114                }
115
116                case RESPOND_TRANSACTION: {
117                    data.enforceInterface(IBulkCursor.descriptor);
118                    Bundle extras = data.readBundle();
119                    Bundle returnExtras = respond(extras);
120                    reply.writeNoException();
121                    reply.writeBundle(returnExtras);
122                    return true;
123                }
124            }
125        } catch (Exception e) {
126            DatabaseUtils.writeExceptionToParcel(reply, e);
127            return true;
128        }
129
130        return super.onTransact(code, data, reply, flags);
131    }
132
133    public IBinder asBinder()
134    {
135        return this;
136    }
137}
138
139
140final class BulkCursorProxy implements IBulkCursor {
141    private IBinder mRemote;
142    private Bundle mExtras;
143
144    public BulkCursorProxy(IBinder remote)
145    {
146        mRemote = remote;
147        mExtras = null;
148    }
149
150    public IBinder asBinder()
151    {
152        return mRemote;
153    }
154
155    public CursorWindow getWindow(int position) throws RemoteException
156    {
157        Parcel data = Parcel.obtain();
158        Parcel reply = Parcel.obtain();
159        try {
160            data.writeInterfaceToken(IBulkCursor.descriptor);
161            data.writeInt(position);
162
163            mRemote.transact(GET_CURSOR_WINDOW_TRANSACTION, data, reply, 0);
164            DatabaseUtils.readExceptionFromParcel(reply);
165
166            CursorWindow window = null;
167            if (reply.readInt() == 1) {
168                window = CursorWindow.newFromParcel(reply);
169            }
170            return window;
171        } finally {
172            data.recycle();
173            reply.recycle();
174        }
175    }
176
177    public void onMove(int position) throws RemoteException {
178        Parcel data = Parcel.obtain();
179        Parcel reply = Parcel.obtain();
180        try {
181            data.writeInterfaceToken(IBulkCursor.descriptor);
182            data.writeInt(position);
183
184            mRemote.transact(ON_MOVE_TRANSACTION, data, reply, 0);
185            DatabaseUtils.readExceptionFromParcel(reply);
186        } finally {
187            data.recycle();
188            reply.recycle();
189        }
190    }
191
192    public void deactivate() throws RemoteException
193    {
194        Parcel data = Parcel.obtain();
195        Parcel reply = Parcel.obtain();
196        try {
197            data.writeInterfaceToken(IBulkCursor.descriptor);
198
199            mRemote.transact(DEACTIVATE_TRANSACTION, data, reply, 0);
200            DatabaseUtils.readExceptionFromParcel(reply);
201        } finally {
202            data.recycle();
203            reply.recycle();
204        }
205    }
206
207    public void close() throws RemoteException
208    {
209        Parcel data = Parcel.obtain();
210        Parcel reply = Parcel.obtain();
211        try {
212            data.writeInterfaceToken(IBulkCursor.descriptor);
213
214            mRemote.transact(CLOSE_TRANSACTION, data, reply, 0);
215            DatabaseUtils.readExceptionFromParcel(reply);
216        } finally {
217            data.recycle();
218            reply.recycle();
219        }
220    }
221
222    public int requery(IContentObserver observer) throws RemoteException {
223        Parcel data = Parcel.obtain();
224        Parcel reply = Parcel.obtain();
225        try {
226            data.writeInterfaceToken(IBulkCursor.descriptor);
227            data.writeStrongInterface(observer);
228
229            boolean result = mRemote.transact(REQUERY_TRANSACTION, data, reply, 0);
230            DatabaseUtils.readExceptionFromParcel(reply);
231
232            int count;
233            if (!result) {
234                count = -1;
235            } else {
236                count = reply.readInt();
237                mExtras = reply.readBundle();
238            }
239            return count;
240        } finally {
241            data.recycle();
242            reply.recycle();
243        }
244    }
245
246    public Bundle getExtras() throws RemoteException {
247        if (mExtras == null) {
248            Parcel data = Parcel.obtain();
249            Parcel reply = Parcel.obtain();
250            try {
251                data.writeInterfaceToken(IBulkCursor.descriptor);
252
253                mRemote.transact(GET_EXTRAS_TRANSACTION, data, reply, 0);
254                DatabaseUtils.readExceptionFromParcel(reply);
255
256                mExtras = reply.readBundle();
257            } finally {
258                data.recycle();
259                reply.recycle();
260            }
261        }
262        return mExtras;
263    }
264
265    public Bundle respond(Bundle extras) throws RemoteException {
266        Parcel data = Parcel.obtain();
267        Parcel reply = Parcel.obtain();
268        try {
269            data.writeInterfaceToken(IBulkCursor.descriptor);
270            data.writeBundle(extras);
271
272            mRemote.transact(RESPOND_TRANSACTION, data, reply, 0);
273            DatabaseUtils.readExceptionFromParcel(reply);
274
275            Bundle returnExtras = reply.readBundle();
276            return returnExtras;
277        } finally {
278            data.recycle();
279            reply.recycle();
280        }
281    }
282}
283
284