Home | History | Annotate | Download | only in database
      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 
     17 package android.database;
     18 
     19 import android.os.Binder;
     20 import android.os.RemoteException;
     21 import android.os.IBinder;
     22 import android.os.Parcel;
     23 import android.os.Bundle;
     24 
     25 import java.util.HashMap;
     26 import java.util.Map;
     27 
     28 /**
     29  * Native implementation of the bulk cursor. This is only for use in implementing
     30  * IPC, application code should use the Cursor interface.
     31  *
     32  * {@hide}
     33  */
     34 public abstract class BulkCursorNative extends Binder implements IBulkCursor
     35 {
     36     public BulkCursorNative()
     37     {
     38         attachInterface(this, descriptor);
     39     }
     40 
     41     /**
     42      * Cast a Binder object into a content resolver interface, generating
     43      * a proxy if needed.
     44      */
     45     static public IBulkCursor asInterface(IBinder obj)
     46     {
     47         if (obj == null) {
     48             return null;
     49         }
     50         IBulkCursor in = (IBulkCursor)obj.queryLocalInterface(descriptor);
     51         if (in != null) {
     52             return in;
     53         }
     54 
     55         return new BulkCursorProxy(obj);
     56     }
     57 
     58     @Override
     59     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
     60             throws RemoteException {
     61         try {
     62             switch (code) {
     63                 case GET_CURSOR_WINDOW_TRANSACTION: {
     64                     data.enforceInterface(IBulkCursor.descriptor);
     65                     int startPos = data.readInt();
     66                     CursorWindow window = getWindow(startPos);
     67                     if (window == null) {
     68                         reply.writeInt(0);
     69                         return true;
     70                     }
     71                     reply.writeNoException();
     72                     reply.writeInt(1);
     73                     window.writeToParcel(reply, 0);
     74                     return true;
     75                 }
     76 
     77                 case COUNT_TRANSACTION: {
     78                     data.enforceInterface(IBulkCursor.descriptor);
     79                     int count = count();
     80                     reply.writeNoException();
     81                     reply.writeInt(count);
     82                     return true;
     83                 }
     84 
     85                 case GET_COLUMN_NAMES_TRANSACTION: {
     86                     data.enforceInterface(IBulkCursor.descriptor);
     87                     String[] columnNames = getColumnNames();
     88                     reply.writeNoException();
     89                     reply.writeInt(columnNames.length);
     90                     int length = columnNames.length;
     91                     for (int i = 0; i < length; i++) {
     92                         reply.writeString(columnNames[i]);
     93                     }
     94                     return true;
     95                 }
     96 
     97                 case DEACTIVATE_TRANSACTION: {
     98                     data.enforceInterface(IBulkCursor.descriptor);
     99                     deactivate();
    100                     reply.writeNoException();
    101                     return true;
    102                 }
    103 
    104                 case CLOSE_TRANSACTION: {
    105                     data.enforceInterface(IBulkCursor.descriptor);
    106                     close();
    107                     reply.writeNoException();
    108                     return true;
    109                 }
    110 
    111                 case REQUERY_TRANSACTION: {
    112                     data.enforceInterface(IBulkCursor.descriptor);
    113                     IContentObserver observer =
    114                         IContentObserver.Stub.asInterface(data.readStrongBinder());
    115                     CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);
    116                     int count = requery(observer, window);
    117                     reply.writeNoException();
    118                     reply.writeInt(count);
    119                     reply.writeBundle(getExtras());
    120                     return true;
    121                 }
    122 
    123                 case UPDATE_ROWS_TRANSACTION: {
    124                     data.enforceInterface(IBulkCursor.descriptor);
    125                     // TODO - what ClassLoader should be passed to readHashMap?
    126                     // TODO - switch to Bundle
    127                     HashMap<Long, Map<String, Object>> values = data.readHashMap(null);
    128                     boolean result = updateRows(values);
    129                     reply.writeNoException();
    130                     reply.writeInt((result == true ? 1 : 0));
    131                     return true;
    132                 }
    133 
    134                 case DELETE_ROW_TRANSACTION: {
    135                     data.enforceInterface(IBulkCursor.descriptor);
    136                     int position = data.readInt();
    137                     boolean result = deleteRow(position);
    138                     reply.writeNoException();
    139                     reply.writeInt((result == true ? 1 : 0));
    140                     return true;
    141                 }
    142 
    143                 case ON_MOVE_TRANSACTION: {
    144                     data.enforceInterface(IBulkCursor.descriptor);
    145                     int position = data.readInt();
    146                     onMove(position);
    147                     reply.writeNoException();
    148                     return true;
    149                 }
    150 
    151                 case WANTS_ON_MOVE_TRANSACTION: {
    152                     data.enforceInterface(IBulkCursor.descriptor);
    153                     boolean result = getWantsAllOnMoveCalls();
    154                     reply.writeNoException();
    155                     reply.writeInt(result ? 1 : 0);
    156                     return true;
    157                 }
    158 
    159                 case GET_EXTRAS_TRANSACTION: {
    160                     data.enforceInterface(IBulkCursor.descriptor);
    161                     Bundle extras = getExtras();
    162                     reply.writeNoException();
    163                     reply.writeBundle(extras);
    164                     return true;
    165                 }
    166 
    167                 case RESPOND_TRANSACTION: {
    168                     data.enforceInterface(IBulkCursor.descriptor);
    169                     Bundle extras = data.readBundle();
    170                     Bundle returnExtras = respond(extras);
    171                     reply.writeNoException();
    172                     reply.writeBundle(returnExtras);
    173                     return true;
    174                 }
    175             }
    176         } catch (Exception e) {
    177             DatabaseUtils.writeExceptionToParcel(reply, e);
    178             return true;
    179         }
    180 
    181         return super.onTransact(code, data, reply, flags);
    182     }
    183 
    184     public IBinder asBinder()
    185     {
    186         return this;
    187     }
    188 }
    189 
    190 
    191 final class BulkCursorProxy implements IBulkCursor {
    192     private IBinder mRemote;
    193     private Bundle mExtras;
    194 
    195     public BulkCursorProxy(IBinder remote)
    196     {
    197         mRemote = remote;
    198         mExtras = null;
    199     }
    200 
    201     public IBinder asBinder()
    202     {
    203         return mRemote;
    204     }
    205 
    206     public CursorWindow getWindow(int startPos) throws RemoteException
    207     {
    208         Parcel data = Parcel.obtain();
    209         Parcel reply = Parcel.obtain();
    210 
    211         data.writeInterfaceToken(IBulkCursor.descriptor);
    212 
    213         data.writeInt(startPos);
    214 
    215         mRemote.transact(GET_CURSOR_WINDOW_TRANSACTION, data, reply, 0);
    216 
    217         DatabaseUtils.readExceptionFromParcel(reply);
    218 
    219         CursorWindow window = null;
    220         if (reply.readInt() == 1) {
    221             window = CursorWindow.newFromParcel(reply);
    222         }
    223 
    224         data.recycle();
    225         reply.recycle();
    226 
    227         return window;
    228     }
    229 
    230     public void onMove(int position) throws RemoteException {
    231         Parcel data = Parcel.obtain();
    232         Parcel reply = Parcel.obtain();
    233 
    234         data.writeInterfaceToken(IBulkCursor.descriptor);
    235 
    236         data.writeInt(position);
    237 
    238         mRemote.transact(ON_MOVE_TRANSACTION, data, reply, 0);
    239 
    240         DatabaseUtils.readExceptionFromParcel(reply);
    241 
    242         data.recycle();
    243         reply.recycle();
    244     }
    245 
    246     public int count() throws RemoteException
    247     {
    248         Parcel data = Parcel.obtain();
    249         Parcel reply = Parcel.obtain();
    250 
    251         data.writeInterfaceToken(IBulkCursor.descriptor);
    252 
    253         boolean result = mRemote.transact(COUNT_TRANSACTION, data, reply, 0);
    254 
    255         DatabaseUtils.readExceptionFromParcel(reply);
    256 
    257         int count;
    258         if (result == false) {
    259             count = -1;
    260         } else {
    261             count = reply.readInt();
    262         }
    263         data.recycle();
    264         reply.recycle();
    265         return count;
    266     }
    267 
    268     public String[] getColumnNames() throws RemoteException
    269     {
    270         Parcel data = Parcel.obtain();
    271         Parcel reply = Parcel.obtain();
    272 
    273         data.writeInterfaceToken(IBulkCursor.descriptor);
    274 
    275         mRemote.transact(GET_COLUMN_NAMES_TRANSACTION, data, reply, 0);
    276 
    277         DatabaseUtils.readExceptionFromParcel(reply);
    278 
    279         String[] columnNames = null;
    280         int numColumns = reply.readInt();
    281         columnNames = new String[numColumns];
    282         for (int i = 0; i < numColumns; i++) {
    283             columnNames[i] = reply.readString();
    284         }
    285 
    286         data.recycle();
    287         reply.recycle();
    288         return columnNames;
    289     }
    290 
    291     public void deactivate() throws RemoteException
    292     {
    293         Parcel data = Parcel.obtain();
    294         Parcel reply = Parcel.obtain();
    295 
    296         data.writeInterfaceToken(IBulkCursor.descriptor);
    297 
    298         mRemote.transact(DEACTIVATE_TRANSACTION, data, reply, 0);
    299         DatabaseUtils.readExceptionFromParcel(reply);
    300 
    301         data.recycle();
    302         reply.recycle();
    303     }
    304 
    305     public void close() throws RemoteException
    306     {
    307         Parcel data = Parcel.obtain();
    308         Parcel reply = Parcel.obtain();
    309 
    310         data.writeInterfaceToken(IBulkCursor.descriptor);
    311 
    312         mRemote.transact(CLOSE_TRANSACTION, data, reply, 0);
    313         DatabaseUtils.readExceptionFromParcel(reply);
    314 
    315         data.recycle();
    316         reply.recycle();
    317     }
    318 
    319     public int requery(IContentObserver observer, CursorWindow window) throws RemoteException {
    320         Parcel data = Parcel.obtain();
    321         Parcel reply = Parcel.obtain();
    322 
    323         data.writeInterfaceToken(IBulkCursor.descriptor);
    324 
    325         data.writeStrongInterface(observer);
    326         window.writeToParcel(data, 0);
    327 
    328         boolean result = mRemote.transact(REQUERY_TRANSACTION, data, reply, 0);
    329 
    330         DatabaseUtils.readExceptionFromParcel(reply);
    331 
    332         int count;
    333         if (!result) {
    334             count = -1;
    335         } else {
    336             count = reply.readInt();
    337             mExtras = reply.readBundle();
    338         }
    339 
    340         data.recycle();
    341         reply.recycle();
    342 
    343         return count;
    344     }
    345 
    346     public boolean updateRows(Map values) throws RemoteException
    347     {
    348         Parcel data = Parcel.obtain();
    349         Parcel reply = Parcel.obtain();
    350 
    351         data.writeInterfaceToken(IBulkCursor.descriptor);
    352 
    353         data.writeMap(values);
    354 
    355         mRemote.transact(UPDATE_ROWS_TRANSACTION, data, reply, 0);
    356 
    357         DatabaseUtils.readExceptionFromParcel(reply);
    358 
    359         boolean result = (reply.readInt() == 1 ? true : false);
    360 
    361         data.recycle();
    362         reply.recycle();
    363 
    364         return result;
    365     }
    366 
    367     public boolean deleteRow(int position) throws RemoteException
    368     {
    369         Parcel data = Parcel.obtain();
    370         Parcel reply = Parcel.obtain();
    371 
    372         data.writeInterfaceToken(IBulkCursor.descriptor);
    373 
    374         data.writeInt(position);
    375 
    376         mRemote.transact(DELETE_ROW_TRANSACTION, data, reply, 0);
    377 
    378         DatabaseUtils.readExceptionFromParcel(reply);
    379 
    380         boolean result = (reply.readInt() == 1 ? true : false);
    381 
    382         data.recycle();
    383         reply.recycle();
    384 
    385         return result;
    386     }
    387 
    388     public boolean getWantsAllOnMoveCalls() throws RemoteException {
    389         Parcel data = Parcel.obtain();
    390         Parcel reply = Parcel.obtain();
    391 
    392         data.writeInterfaceToken(IBulkCursor.descriptor);
    393 
    394         mRemote.transact(WANTS_ON_MOVE_TRANSACTION, data, reply, 0);
    395 
    396         DatabaseUtils.readExceptionFromParcel(reply);
    397 
    398         int result = reply.readInt();
    399         data.recycle();
    400         reply.recycle();
    401         return result != 0;
    402     }
    403 
    404     public Bundle getExtras() throws RemoteException {
    405         if (mExtras == null) {
    406             Parcel data = Parcel.obtain();
    407             Parcel reply = Parcel.obtain();
    408 
    409             data.writeInterfaceToken(IBulkCursor.descriptor);
    410 
    411             mRemote.transact(GET_EXTRAS_TRANSACTION, data, reply, 0);
    412 
    413             DatabaseUtils.readExceptionFromParcel(reply);
    414 
    415             mExtras = reply.readBundle();
    416             data.recycle();
    417             reply.recycle();
    418         }
    419         return mExtras;
    420     }
    421 
    422     public Bundle respond(Bundle extras) throws RemoteException {
    423         Parcel data = Parcel.obtain();
    424         Parcel reply = Parcel.obtain();
    425 
    426         data.writeInterfaceToken(IBulkCursor.descriptor);
    427 
    428         data.writeBundle(extras);
    429 
    430         mRemote.transact(RESPOND_TRANSACTION, data, reply, 0);
    431 
    432         DatabaseUtils.readExceptionFromParcel(reply);
    433 
    434         Bundle returnExtras = reply.readBundle();
    435         data.recycle();
    436         reply.recycle();
    437         return returnExtras;
    438     }
    439 }
    440 
    441