blob: 885046bf199540b03c967aac3574f11105289126 [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.database;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.os.Bundle;
Jeff Hamilton7cd51ef2010-05-12 17:30:27 -050020import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.util.Log;
22
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023/**
Jeff Brownd2183652011-10-09 12:39:53 -070024 * Adapts an {@link IBulkCursor} to a {@link Cursor} for use in the local process.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025 *
26 * {@hide}
27 */
28public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor {
29 private static final String TAG = "BulkCursor";
30
Jeff Brownd2183652011-10-09 12:39:53 -070031 private SelfContentObserver mObserverBridge = new SelfContentObserver(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032 private IBulkCursor mBulkCursor;
33 private int mCount;
34 private String[] mColumns;
35 private boolean mWantsAllOnMoveCalls;
36
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 /**
Jeff Brownd2183652011-10-09 12:39:53 -070038 * Initializes the adaptor.
39 * Must be called before first use.
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -080040 */
Jeff Brown0cde89f2011-10-10 14:50:10 -070041 public void initialize(IBulkCursor bulkCursor, int count, int idIndex,
42 boolean wantsAllOnMoveCalls) {
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -080043 mBulkCursor = bulkCursor;
44 mColumns = null; // lazily retrieved
45 mCount = count;
46 mRowIdColumnIndex = idIndex;
Jeff Brown0cde89f2011-10-10 14:50:10 -070047 mWantsAllOnMoveCalls = wantsAllOnMoveCalls;
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -080048 }
49
50 /**
51 * Returns column index of "_id" column, or -1 if not found.
52 */
53 public static int findRowIdColumnIndex(String[] columnNames) {
54 int length = columnNames.length;
55 for (int i = 0; i < length; i++) {
56 if (columnNames[i].equals("_id")) {
57 return i;
58 }
59 }
60 return -1;
61 }
62
63 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 * Gets a SelfDataChangeOberserver that can be sent to a remote
65 * process to receive change notifications over IPC.
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -080066 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 * @return A SelfContentObserver hooked up to this Cursor
68 */
Jeff Brownd2183652011-10-09 12:39:53 -070069 public IContentObserver getObserver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 return mObserverBridge.getContentObserver();
71 }
72
Jeff Brownd2183652011-10-09 12:39:53 -070073 private void throwIfCursorIsClosed() {
74 if (mBulkCursor == null) {
75 throw new StaleDataException("Attempted to access a cursor after it has been closed.");
76 }
77 }
78
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 @Override
80 public int getCount() {
Jeff Brownd2183652011-10-09 12:39:53 -070081 throwIfCursorIsClosed();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 return mCount;
83 }
84
85 @Override
86 public boolean onMove(int oldPosition, int newPosition) {
Jeff Brownd2183652011-10-09 12:39:53 -070087 throwIfCursorIsClosed();
88
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 try {
90 // Make sure we have the proper window
Jeff Brown0cde89f2011-10-10 14:50:10 -070091 if (mWindow == null
92 || newPosition < mWindow.getStartPosition()
93 || newPosition >= mWindow.getStartPosition() + mWindow.getNumRows()) {
Jeff Brownd2183652011-10-09 12:39:53 -070094 setWindow(mBulkCursor.getWindow(newPosition));
Jeff Brown0cde89f2011-10-10 14:50:10 -070095 } else if (mWantsAllOnMoveCalls) {
96 mBulkCursor.onMove(newPosition);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 }
98 } catch (RemoteException ex) {
99 // We tried to get a window and failed
100 Log.e(TAG, "Unable to get window because the remote process is dead");
101 return false;
102 }
103
104 // Couldn't obtain a window, something is wrong
105 if (mWindow == null) {
106 return false;
107 }
108
109 return true;
110 }
111
112 @Override
113 public void deactivate() {
114 // This will call onInvalidated(), so make sure to do it before calling release,
115 // which is what actually makes the data set invalid.
116 super.deactivate();
117
Jeff Brownd2183652011-10-09 12:39:53 -0700118 if (mBulkCursor != null) {
119 try {
120 mBulkCursor.deactivate();
121 } catch (RemoteException ex) {
122 Log.w(TAG, "Remote process exception when deactivating");
123 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 }
126
127 @Override
128 public void close() {
129 super.close();
Jeff Brownd2183652011-10-09 12:39:53 -0700130
131 if (mBulkCursor != null) {
132 try {
133 mBulkCursor.close();
134 } catch (RemoteException ex) {
135 Log.w(TAG, "Remote process exception when closing");
136 } finally {
137 mBulkCursor = null;
138 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 }
141
142 @Override
143 public boolean requery() {
Jeff Brownd2183652011-10-09 12:39:53 -0700144 throwIfCursorIsClosed();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145
Jeff Brownd2183652011-10-09 12:39:53 -0700146 try {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700147 mCount = mBulkCursor.requery(getObserver());
148 if (mCount != -1) {
149 mPos = -1;
150 closeWindow();
Jeff Brownd2183652011-10-09 12:39:53 -0700151
Jeff Brown0cde89f2011-10-10 14:50:10 -0700152 // super.requery() will call onChanged. Do it here instead of relying on the
153 // observer from the far side so that observers can see a correct value for mCount
154 // when responding to onChanged.
155 super.requery();
156 return true;
157 } else {
158 deactivate();
159 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 }
161 } catch (Exception ex) {
162 Log.e(TAG, "Unable to requery because the remote process exception " + ex.getMessage());
163 deactivate();
164 return false;
165 }
166 }
167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 @Override
169 public String[] getColumnNames() {
Jeff Brownd2183652011-10-09 12:39:53 -0700170 throwIfCursorIsClosed();
171
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -0800172 if (mColumns == null) {
173 try {
174 mColumns = mBulkCursor.getColumnNames();
175 } catch (RemoteException ex) {
176 Log.e(TAG, "Unable to fetch column names because the remote process is dead");
177 return null;
178 }
179 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 return mColumns;
181 }
182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 @Override
184 public Bundle getExtras() {
Jeff Brownd2183652011-10-09 12:39:53 -0700185 throwIfCursorIsClosed();
186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 try {
188 return mBulkCursor.getExtras();
189 } catch (RemoteException e) {
190 // This should never happen because the system kills processes that are using remote
191 // cursors when the provider process is killed.
192 throw new RuntimeException(e);
193 }
194 }
195
196 @Override
197 public Bundle respond(Bundle extras) {
Jeff Brownd2183652011-10-09 12:39:53 -0700198 throwIfCursorIsClosed();
199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 try {
201 return mBulkCursor.respond(extras);
202 } catch (RemoteException e) {
Karl Rosaen6dc0ef02009-06-22 12:51:35 -0700203 // the system kills processes that are using remote cursors when the provider process
204 // is killed, but this can still happen if this is being called from the system process,
205 // so, better to log and return an empty bundle.
206 Log.w(TAG, "respond() threw RemoteException, returning an empty bundle.", e);
207 return Bundle.EMPTY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 }
209 }
210}