CursorToBulkCursorAdaptor.java revision 43a17654cf4bfe7f1ec22bd8b7b32daccdf27c09
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.Bundle; 20import android.os.IBinder; 21import android.os.RemoteException; 22import android.util.Log; 23 24 25/** 26 * Wraps a BulkCursor around an existing Cursor making it remotable. 27 * 28 * {@hide} 29 */ 30public final class CursorToBulkCursorAdaptor extends BulkCursorNative 31 implements IBinder.DeathRecipient { 32 private static final String TAG = "Cursor"; 33 private final CrossProcessCursor mCursor; 34 private CursorWindow mWindow; 35 private final String mProviderName; 36 private ContentObserverProxy mObserver; 37 38 private static final class ContentObserverProxy extends ContentObserver 39 { 40 protected IContentObserver mRemote; 41 42 public ContentObserverProxy(IContentObserver remoteObserver, DeathRecipient recipient) { 43 super(null); 44 mRemote = remoteObserver; 45 try { 46 remoteObserver.asBinder().linkToDeath(recipient, 0); 47 } catch (RemoteException e) { 48 // Do nothing, the far side is dead 49 } 50 } 51 52 public boolean unlinkToDeath(DeathRecipient recipient) { 53 return mRemote.asBinder().unlinkToDeath(recipient, 0); 54 } 55 56 @Override 57 public boolean deliverSelfNotifications() { 58 // The far side handles the self notifications. 59 return false; 60 } 61 62 @Override 63 public void onChange(boolean selfChange) { 64 try { 65 mRemote.onChange(selfChange); 66 } catch (RemoteException ex) { 67 // Do nothing, the far side is dead 68 } 69 } 70 } 71 72 public CursorToBulkCursorAdaptor(Cursor cursor, IContentObserver observer, String providerName, 73 boolean allowWrite, CursorWindow window) { 74 try { 75 mCursor = (CrossProcessCursor) cursor; 76 if (mCursor instanceof AbstractWindowedCursor) { 77 AbstractWindowedCursor windowedCursor = (AbstractWindowedCursor) cursor; 78 if (windowedCursor.hasWindow()) { 79 if (Log.isLoggable(TAG, Log.VERBOSE) || false) { 80 Log.v(TAG, "Cross process cursor has a local window before setWindow in " 81 + providerName, new RuntimeException()); 82 } 83 } 84 windowedCursor.setWindow(window); 85 } else { 86 mWindow = window; 87 mCursor.fillWindow(0, window); 88 } 89 } catch (ClassCastException e) { 90 // TODO Implement this case. 91 throw new UnsupportedOperationException( 92 "Only CrossProcessCursor cursors are supported across process for now", e); 93 } 94 mProviderName = providerName; 95 96 createAndRegisterObserverProxy(observer); 97 } 98 99 public void binderDied() { 100 mCursor.close(); 101 if (mWindow != null) { 102 mWindow.close(); 103 } 104 } 105 106 public CursorWindow getWindow(int startPos) { 107 mCursor.moveToPosition(startPos); 108 109 if (mWindow != null) { 110 if (startPos < mWindow.getStartPosition() || 111 startPos >= (mWindow.getStartPosition() + mWindow.getNumRows())) { 112 mCursor.fillWindow(startPos, mWindow); 113 } 114 return mWindow; 115 } else { 116 return ((AbstractWindowedCursor)mCursor).getWindow(); 117 } 118 } 119 120 public void onMove(int position) { 121 mCursor.onMove(mCursor.getPosition(), position); 122 } 123 124 public int count() { 125 return mCursor.getCount(); 126 } 127 128 public String[] getColumnNames() { 129 return mCursor.getColumnNames(); 130 } 131 132 public void deactivate() { 133 maybeUnregisterObserverProxy(); 134 mCursor.deactivate(); 135 } 136 137 public void close() { 138 maybeUnregisterObserverProxy(); 139 mCursor.close(); 140 } 141 142 public int requery(IContentObserver observer, CursorWindow window) { 143 if (mWindow == null) { 144 ((AbstractWindowedCursor)mCursor).setWindow(window); 145 } 146 try { 147 if (!mCursor.requery()) { 148 return -1; 149 } 150 } catch (IllegalStateException e) { 151 IllegalStateException leakProgram = new IllegalStateException( 152 mProviderName + " Requery misuse db, mCursor isClosed:" + 153 mCursor.isClosed(), e); 154 throw leakProgram; 155 } 156 157 if (mWindow != null) { 158 mCursor.fillWindow(0, window); 159 mWindow = window; 160 } 161 maybeUnregisterObserverProxy(); 162 createAndRegisterObserverProxy(observer); 163 return mCursor.getCount(); 164 } 165 166 public boolean getWantsAllOnMoveCalls() { 167 return mCursor.getWantsAllOnMoveCalls(); 168 } 169 170 /** 171 * Create a ContentObserver from the observer and register it as an observer on the 172 * underlying cursor. 173 * @param observer the IContentObserver that wants to monitor the cursor 174 * @throws IllegalStateException if an observer is already registered 175 */ 176 private void createAndRegisterObserverProxy(IContentObserver observer) { 177 if (mObserver != null) { 178 throw new IllegalStateException("an observer is already registered"); 179 } 180 mObserver = new ContentObserverProxy(observer, this); 181 mCursor.registerContentObserver(mObserver); 182 } 183 184 /** Unregister the observer if it is already registered. */ 185 private void maybeUnregisterObserverProxy() { 186 if (mObserver != null) { 187 mCursor.unregisterContentObserver(mObserver); 188 mObserver.unlinkToDeath(this); 189 mObserver = null; 190 } 191 } 192 193 public Bundle getExtras() { 194 return mCursor.getExtras(); 195 } 196 197 public Bundle respond(Bundle extras) { 198 return mCursor.respond(extras); 199 } 200} 201