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