• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 package com.android.mail.content;
17 
18 import android.database.CharArrayBuffer;
19 import android.database.Cursor;
20 import android.database.CursorWrapper;
21 import android.os.Bundle;
22 
23 import com.android.mail.providers.UIProvider;
24 import com.android.mail.utils.LogTag;
25 import com.android.mail.utils.LogUtils;
26 
27 public class ThreadSafeCursorWrapper extends CursorWrapper {
28     private static final String LOG_TAG = LogTag.getLogTag();
29 
30     private final ThreadLocal<Integer> mPosition;
31     private final Object mLock = new Object();
32 
ThreadSafeCursorWrapper(Cursor cursor)33     public ThreadSafeCursorWrapper(Cursor cursor) {
34         super(cursor);
35 
36         mPosition = new ThreadLocal<Integer>() {
37             @Override
38             protected Integer initialValue() {
39                 return Integer.valueOf(-1);
40             }
41         };
42     }
43 
44     @Override
getString(int column)45     public String getString(int column) {
46         synchronized (mLock) {
47             moveToCurrent();
48             return super.getString(column);
49         }
50     }
51 
52     @Override
getShort(int column)53     public short getShort(int column) {
54         synchronized (mLock) {
55             moveToCurrent();
56             return super.getShort(column);
57         }
58     }
59 
60     @Override
getInt(int column)61     public int getInt(int column) {
62         synchronized (mLock) {
63             moveToCurrent();
64             return super.getInt(column);
65         }
66     }
67 
68     @Override
getLong(int column)69     public long getLong(int column) {
70         synchronized (mLock) {
71             moveToCurrent();
72             return super.getLong(column);
73         }
74     }
75 
76     @Override
getFloat(int column)77     public float getFloat(int column) {
78         synchronized (mLock) {
79             moveToCurrent();
80             return super.getFloat(column);
81         }
82     }
83 
84     @Override
getDouble(int column)85     public double getDouble(int column) {
86         synchronized (mLock) {
87             moveToCurrent();
88             return super.getDouble(column);
89         }
90     }
91 
92     @Override
getBlob(int column)93     public byte[] getBlob(int column) {
94         synchronized (mLock) {
95             moveToCurrent();
96             return super.getBlob(column);
97         }
98     }
99 
100     @Override
respond(Bundle extras)101     public Bundle respond(Bundle extras) {
102         final int opts = extras.getInt(UIProvider.ConversationCursorCommand.COMMAND_KEY_OPTIONS);
103         if ((opts & UIProvider.ConversationCursorCommand.OPTION_MOVE_POSITION) != 0) {
104             synchronized (mLock) {
105                 moveToCurrent();
106                 return super.respond(extras);
107             }
108         } else {
109             return super.respond(extras);
110         }
111     }
112 
113     @Override
copyStringToBuffer(int columnIndex, CharArrayBuffer buffer)114     public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
115         synchronized (mLock) {
116             moveToCurrent();
117             super.copyStringToBuffer(columnIndex, buffer);
118         }
119     }
120 
121     @Override
isNull(int column)122     public boolean isNull(int column){
123         synchronized (mLock) {
124             moveToCurrent();
125             return super.isNull(column);
126         }
127     }
128 
moveToCurrent()129     private void moveToCurrent() {
130         final int pos = mPosition.get();
131         final boolean result = super.moveToPosition(pos);
132 
133         // AbstractCursor returns false on negative positions, although Cursor documentation
134         // states that -1 is a valid input. Let's just log positive values as failures.
135         if (!result && pos >= 0) {
136             LogUtils.e(LOG_TAG, "Unexpected failure to move to current position, pos=%d", pos);
137         }
138     }
139 
140     @Override
move(int offset)141     public boolean move(int offset) {
142         final int curPos = mPosition.get();
143         return moveToPosition(curPos + offset);
144     }
145 
146     @Override
moveToFirst()147     public boolean moveToFirst() {
148         return moveToPosition(0);
149     }
150 
151     @Override
moveToLast()152     public boolean moveToLast() {
153         return moveToPosition(getCount() - 1);
154     }
155 
156     @Override
moveToNext()157     public boolean moveToNext() {
158         final int curPos = mPosition.get();
159         return moveToPosition(curPos + 1);
160     }
161 
162     @Override
moveToPosition(int position)163     public boolean moveToPosition(int position) {
164         // Make sure position isn't past the end of the cursor
165         final int count = getCount();
166         if (position >= count) {
167             mPosition.set(count);
168             return false;
169         }
170 
171         // Make sure position isn't before the beginning of the cursor
172         if (position < 0) {
173             mPosition.set(-1);
174             return false;
175         }
176 
177         final int curPos = mPosition.get();
178         // Check for no-op moves, and skip the rest of the work for them
179         if (position == curPos) {
180             return true;
181         }
182 
183         // Save this thread's current position.
184         mPosition.set(position);
185         return true;
186     }
187 
188     @Override
moveToPrevious()189     public boolean moveToPrevious() {
190         final int curPos = mPosition.get();
191         return moveToPosition(curPos - 1);
192     }
193 
194     @Override
getPosition()195     public int getPosition() {
196         return mPosition.get();
197     }
198 }
199