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