20 | * NOTE: Unfortunately, Android variables are limited in size so this class takes that last 23 (sic) characters
21 | * of the class name if it is larger than 23 characters. For example, if the class is AndroidDatabaseConnection you
22 | * would do:
23 | *
24 | *
36 | *
37 | * @author graywatson
38 | */
39 | public class AndroidLog implements com.j256.ormlite.logger.Log {
40 |
41 | private final static String ALL_LOGS_NAME = "ORMLite";
42 | private final static int REFRESH_LEVEL_CACHE_EVERY = 200;
43 |
44 | private final static int MAX_TAG_LENGTH = 23;
45 | private String className;
46 |
47 | // we do this because supposedly Log.isLoggable() always does IO
48 | private volatile int levelCacheC = 0;
49 | private final boolean levelCache[];
50 |
51 | public AndroidLog(String className) {
52 | // get the last part of the class name
53 | this.className = LoggerFactory.getSimpleClassName(className);
54 | // make sure that our tag length is not too long
55 | int length = this.className.length();
56 | if (length > MAX_TAG_LENGTH) {
57 | this.className = this.className.substring(length - MAX_TAG_LENGTH, length);
58 | }
59 | // find the maximum level value
60 | int maxLevel = 0;
61 | for (com.j256.ormlite.logger.Log.Level level : com.j256.ormlite.logger.Log.Level.values()) {
62 | int androidLevel = levelToAndroidLevel(level);
63 | if (androidLevel > maxLevel) {
64 | maxLevel = androidLevel;
65 | }
66 | }
67 | levelCache = new boolean[maxLevel + 1];
68 | refreshLevelCache();
69 | }
70 |
71 | public boolean isLevelEnabled(Level level) {
72 | // we don't care if this is not synchronized, it will be updated sooner or later and multiple updates are fine.
73 | if (++levelCacheC >= REFRESH_LEVEL_CACHE_EVERY) {
74 | refreshLevelCache();
75 | levelCacheC = 0;
76 | }
77 | int androidLevel = levelToAndroidLevel(level);
78 | if (androidLevel < levelCache.length) {
79 | return levelCache[androidLevel];
80 | } else {
81 | return isLevelEnabledInternal(androidLevel);
82 | }
83 | }
84 |
85 | public void log(Level level, String msg) {
86 | switch (level) {
87 | case TRACE :
88 | Log.v(className, msg);
89 | break;
90 | case DEBUG :
91 | Log.d(className, msg);
92 | break;
93 | case INFO :
94 | Log.i(className, msg);
95 | break;
96 | case WARNING :
97 | Log.w(className, msg);
98 | break;
99 | case ERROR :
100 | Log.e(className, msg);
101 | break;
102 | case FATAL :
103 | Log.e(className, msg);
104 | break;
105 | default :
106 | Log.i(className, msg);
107 | break;
108 | }
109 | }
110 |
111 | public void log(Level level, String msg, Throwable t) {
112 | switch (level) {
113 | case TRACE :
114 | Log.v(className, msg, t);
115 | break;
116 | case DEBUG :
117 | Log.d(className, msg, t);
118 | break;
119 | case INFO :
120 | Log.i(className, msg, t);
121 | break;
122 | case WARNING :
123 | Log.w(className, msg, t);
124 | break;
125 | case ERROR :
126 | Log.e(className, msg, t);
127 | break;
128 | case FATAL :
129 | Log.e(className, msg, t);
130 | break;
131 | default :
132 | Log.i(className, msg, t);
133 | break;
134 | }
135 | }
136 |
137 | private void refreshLevelCache() {
138 | for (com.j256.ormlite.logger.Log.Level level : com.j256.ormlite.logger.Log.Level.values()) {
139 | int androidLevel = levelToAndroidLevel(level);
140 | if (androidLevel < levelCache.length) {
141 | levelCache[androidLevel] = isLevelEnabledInternal(androidLevel);
142 | }
143 | }
144 | }
145 |
146 | private boolean isLevelEnabledInternal(int androidLevel) {
147 | // this is supposedly expensive with an IO operation for each call so we cache them into levelCache[]
148 | return Log.isLoggable(className, androidLevel) || Log.isLoggable(ALL_LOGS_NAME, androidLevel);
149 | }
150 |
151 | private int levelToAndroidLevel(com.j256.ormlite.logger.Log.Level level) {
152 | switch (level) {
153 | case TRACE :
154 | return Log.VERBOSE;
155 | case DEBUG :
156 | return Log.DEBUG;
157 | case INFO :
158 | return Log.INFO;
159 | case WARNING :
160 | return Log.WARN;
161 | case ERROR :
162 | return Log.ERROR;
163 | case FATAL :
164 | return Log.ERROR;
165 | default :
166 | return Log.INFO;
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/sqlcipher-old/src/main/java/com/j256/ormlite/sqlcipher/android/apptools/OpenHelperManager.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.apptools;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 |
6 | import com.j256.ormlite.dao.BaseDaoImpl;
7 | import com.j256.ormlite.dao.DaoManager;
8 | import com.j256.ormlite.logger.Logger;
9 | import com.j256.ormlite.logger.LoggerFactory;
10 |
11 | import net.sqlcipher.database.SQLiteOpenHelper;
12 |
13 | import java.lang.reflect.Constructor;
14 | import java.lang.reflect.ParameterizedType;
15 | import java.lang.reflect.Type;
16 |
17 | /**
18 | * This helps organize and access database connections to optimize connection sharing. There are several schemes to
19 | * manage the database connections in an Android app, but as an app gets more complicated, there are many potential
20 | * places where database locks can occur. This class allows database connection sharing between multiple threads in a
21 | * single app.
22 | *
23 | * This gets injected or called with the {@link OrmLiteSqliteOpenHelper} class that is used to manage the database
24 | * connection. The helper instance will be kept in a static field and only released once its internal usage count goes
25 | * to 0.
26 | *
27 | * The {@link SQLiteOpenHelper} and database classes maintain one connection under the hood, and prevent locks in the
28 | * java code. Creating multiple connections can potentially be a source of trouble. This class shares the same
29 | * connection instance between multiple clients, which will allow multiple activities and services to run at the same
30 | * time.
31 | *
32 | * Every time you use the helper, you should call {@link #getHelper(Context)} or {@link #getHelper(Context, Class)}.
33 | * When you are done with the helper you should call {@link #releaseHelper()}.
34 | *
35 | * @author graywatson, kevingalligan
36 | */
37 | public class OpenHelperManager {
38 |
39 | private static final String HELPER_CLASS_RESOURCE_NAME = "open_helper_classname";
40 | private static Logger logger = LoggerFactory.getLogger(OpenHelperManager.class);
41 |
42 | private static Class extends OrmLiteSqliteOpenHelper> helperClass = null;
43 | private static volatile OrmLiteSqliteOpenHelper helper = null;
44 | private static boolean wasClosed = false;
45 | private static int instanceCount = 0;
46 |
47 | /**
48 | * If you are _not_ using the {@link OrmLiteBaseActivity} type classes then you will need to call this in a static
49 | * method in your code.
50 | */
51 | public static synchronized void setOpenHelperClass(Class extends OrmLiteSqliteOpenHelper> openHelperClass) {
52 | if (openHelperClass == null) {
53 | helperClass = null;
54 | } else {
55 | innerSetHelperClass(openHelperClass);
56 | }
57 | }
58 |
59 | /**
60 | * Set the helper for the manager. This is most likely used for testing purposes and should only be called if you
61 | * _really_ know what you are doing. If you do use it then it should be in a static {} initializing block to make
62 | * sure you have one helper instance for your application.
63 | */
64 | public static synchronized void setHelper(OrmLiteSqliteOpenHelper helper) {
65 | OpenHelperManager.helper = helper;
66 | }
67 |
68 | /**
69 | * Create a static instance of our open helper from the helper class. This has a usage counter on it so make sure
70 | * all calls to this method have an associated call to {@link #releaseHelper()}. This should be called during an
71 | * onCreate() type of method when the application or service is starting. The caller should then keep the helper
72 | * around until it is shutting down when {@link #releaseHelper()} should be called.
73 | */
74 | public static synchronized T getHelper(Context context, Class openHelperClass) {
75 | if (openHelperClass == null) {
76 | throw new IllegalArgumentException("openHelperClass argument is null");
77 | }
78 | innerSetHelperClass(openHelperClass);
79 | return loadHelper(context, openHelperClass);
80 | }
81 |
82 | /**
83 | * Similar to {@link #getHelper(Context, Class)} (which is recommended) except we have to find the helper class
84 | * through other means. This method requires that the Context be a class that extends one of ORMLite's Android base
85 | * classes such as {@link OrmLiteBaseActivity}. Either that or the helper class needs to be set in the strings.xml.
86 | *
87 | *
88 | * To find the helper class, this does the following:
89 | * 1) If the class has been set with a call to {@link #setOpenHelperClass(Class)}, it will be used to construct a
90 | * helper.
91 | * 2) If the resource class name is configured in the strings.xml file it will be used.
92 | * 3) The context class hierarchy is walked looking at the generic parameters for a class extending
93 | * OrmLiteSqliteOpenHelper. This is used by the {@link OrmLiteBaseActivity} and other base classes.
94 | * 4) An exception is thrown saying that it was not able to set the helper class.
95 | *
96 | *
97 | * @deprecated Should use {@link #getHelper(Context, Class)}
98 | */
99 | @Deprecated
100 | public static synchronized OrmLiteSqliteOpenHelper getHelper(Context context) {
101 | if (helperClass == null) {
102 | if (context == null) {
103 | throw new IllegalArgumentException("context argument is null");
104 | }
105 | Context appContext = context.getApplicationContext();
106 | innerSetHelperClass(lookupHelperClass(appContext, context.getClass()));
107 | }
108 | return loadHelper(context, helperClass);
109 | }
110 |
111 | /**
112 | * @deprecated This has been renamed to be {@link #releaseHelper()}.
113 | */
114 | @Deprecated
115 | public static void release() {
116 | releaseHelper();
117 | }
118 |
119 | /**
120 | * Release the helper that was previously returned by a call {@link #getHelper(Context)} or
121 | * {@link #getHelper(Context, Class)}. This will decrement the usage counter and close the helper if the counter is
122 | * 0.
123 | *
124 | *
125 | * WARNING: This should be called in an onDestroy() type of method when your application or service is
126 | * terminating or if your code is no longer going to use the helper or derived DAOs in any way. _Don't_ call this
127 | * method if you expect to call {@link #getHelper(Context)} again before the application terminates.
128 | *
129 | */
130 | public static synchronized void releaseHelper() {
131 | instanceCount--;
132 | logger.trace("releasing helper {}, instance count = {}", helper, instanceCount);
133 | if (instanceCount <= 0) {
134 | if (helper != null) {
135 | logger.trace("zero instances, closing helper {}", helper);
136 | helper.close();
137 | helper = null;
138 | wasClosed = true;
139 | }
140 | if (instanceCount < 0) {
141 | logger.error("too many calls to release helper, instance count = {}", instanceCount);
142 | }
143 | }
144 | }
145 |
146 | /**
147 | * Set the helper class and make sure we aren't changing it to another class.
148 | */
149 | private static void innerSetHelperClass(Class extends OrmLiteSqliteOpenHelper> openHelperClass) {
150 | // make sure if that there are not 2 helper classes in an application
151 | if (openHelperClass == null) {
152 | throw new IllegalStateException("Helper class was trying to be reset to null");
153 | } else if (helperClass == null) {
154 | helperClass = openHelperClass;
155 | } else if (helperClass != openHelperClass) {
156 | throw new IllegalStateException("Helper class was " + helperClass + " but is trying to be reset to "
157 | + openHelperClass);
158 | }
159 | }
160 |
161 | private static T loadHelper(Context context, Class openHelperClass) {
162 | if (helper == null) {
163 | if (wasClosed) {
164 | // this can happen if you are calling get/release and then get again
165 | logger.info("helper was already closed and is being re-opened");
166 | }
167 | if (context == null) {
168 | throw new IllegalArgumentException("context argument is null");
169 | }
170 | Context appContext = context.getApplicationContext();
171 | helper = constructHelper(appContext, openHelperClass);
172 | logger.trace("zero instances, created helper {}", helper);
173 | /*
174 | * Filipe Leandro and I worked on this bug for like 10 hours straight. It's a doosey.
175 | *
176 | * Each ForeignCollection has internal DAO objects that are holding a ConnectionSource. Each Android
177 | * ConnectionSource is tied to a particular database connection. What Filipe was seeing was that when all of
178 | * his views we closed (onDestroy), but his application WAS NOT FULLY KILLED, the first View.onCreate()
179 | * method would open a new connection to the database. Fine. But because he application was still in memory,
180 | * the static BaseDaoImpl default cache had not been cleared and was containing cached objects with
181 | * ForeignCollections. The ForeignCollections still had references to the DAOs that had been opened with old
182 | * ConnectionSource objects and therefore the old database connection. Using those cached collections would
183 | * cause exceptions saying that you were trying to work with a database that had already been close.
184 | *
185 | * Now, whenever we create a new helper object, we must make sure that the internal object caches have been
186 | * fully cleared. This is a good lesson for anyone that is holding objects around after they have closed
187 | * connections to the database or re-created the DAOs on a different connection somehow.
188 | */
189 | BaseDaoImpl.clearAllInternalObjectCaches();
190 | /*
191 | * Might as well do this also since if the helper changes then the ConnectionSource will change so no one is
192 | * going to have a cache hit on the old DAOs anyway. All they are doing is holding memory.
193 | *
194 | * NOTE: we don't want to clear the config map.
195 | */
196 | DaoManager.clearDaoCache();
197 | instanceCount = 0;
198 | }
199 |
200 | instanceCount++;
201 | logger.trace("returning helper {}, instance count = {} ", helper, instanceCount);
202 | @SuppressWarnings("unchecked")
203 | T castHelper = (T) helper;
204 | return castHelper;
205 | }
206 |
207 | /**
208 | * Call the constructor on our helper class.
209 | */
210 | private static OrmLiteSqliteOpenHelper constructHelper(Context context,
211 | Class extends OrmLiteSqliteOpenHelper> openHelperClass) {
212 | Constructor> constructor;
213 | try {
214 | constructor = openHelperClass.getConstructor(Context.class);
215 | } catch (Exception e) {
216 | throw new IllegalStateException(
217 | "Could not find public constructor that has a single (Context) argument for helper class "
218 | + openHelperClass, e);
219 | }
220 | try {
221 | return (OrmLiteSqliteOpenHelper) constructor.newInstance(context);
222 | } catch (Exception e) {
223 | throw new IllegalStateException("Could not construct instance of helper class " + openHelperClass, e);
224 | }
225 | }
226 |
227 | /**
228 | * Lookup the helper class either from the resource string or by looking for a generic parameter.
229 | */
230 | private static Class extends OrmLiteSqliteOpenHelper> lookupHelperClass(Context context, Class> componentClass) {
231 |
232 | // see if we have the magic resource class name set
233 | Resources resources = context.getResources();
234 | int resourceId = resources.getIdentifier(HELPER_CLASS_RESOURCE_NAME, "string", context.getPackageName());
235 | if (resourceId != 0) {
236 | String className = resources.getString(resourceId);
237 | try {
238 | @SuppressWarnings("unchecked")
239 | Class extends OrmLiteSqliteOpenHelper> castClass =
240 | (Class extends OrmLiteSqliteOpenHelper>) Class.forName(className);
241 | return castClass;
242 | } catch (Exception e) {
243 | throw new IllegalStateException("Could not create helper instance for class " + className, e);
244 | }
245 | }
246 |
247 | // try walking the context class to see if we can get the OrmLiteSqliteOpenHelper from a generic parameter
248 | for (Class> componentClassWalk = componentClass; componentClassWalk != null; componentClassWalk =
249 | componentClassWalk.getSuperclass()) {
250 | Type superType = componentClassWalk.getGenericSuperclass();
251 | if (superType == null || !(superType instanceof ParameterizedType)) {
252 | continue;
253 | }
254 | // get the generic type arguments
255 | Type[] types = ((ParameterizedType) superType).getActualTypeArguments();
256 | // defense
257 | if (types == null || types.length == 0) {
258 | continue;
259 | }
260 | for (Type type : types) {
261 | // defense
262 | if (!(type instanceof Class)) {
263 | continue;
264 | }
265 | Class> clazz = (Class>) type;
266 | if (OrmLiteSqliteOpenHelper.class.isAssignableFrom(clazz)) {
267 | @SuppressWarnings("unchecked")
268 | Class extends OrmLiteSqliteOpenHelper> castOpenHelperClass =
269 | (Class extends OrmLiteSqliteOpenHelper>) clazz;
270 | return castOpenHelperClass;
271 | }
272 | }
273 | }
274 | throw new IllegalStateException(
275 | "Could not find OpenHelperClass because none of the generic parameters of class " + componentClass
276 | + " extends OrmLiteSqliteOpenHelper. You should use getHelper(Context, Class) instead.");
277 | }
278 | }
279 |
--------------------------------------------------------------------------------
/sqlcipher-old/src/main/java/com/j256/ormlite/sqlcipher/android/apptools/OrmLiteBaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.apptools;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 |
7 | import com.j256.ormlite.logger.Logger;
8 | import com.j256.ormlite.logger.LoggerFactory;
9 | import com.j256.ormlite.support.ConnectionSource;
10 |
11 | /**
12 | * Base class to use for activities in Android.
13 | *
14 | * You can simply call {@link #getHelper()} to get your helper class, or {@link #getConnectionSource()} to get a
15 | * {@link ConnectionSource}.
16 | *
17 | * The method {@link #getHelper()} assumes you are using the default helper factory -- see {@link OpenHelperManager}. If
18 | * not, you'll need to provide your own helper instances which will need to implement a reference counting scheme. This
19 | * method will only be called if you use the database, and only called once for this activity's life-cycle. 'close' will
20 | * also be called once for each call to createInstance.
21 | *
22 | * @author graywatson, kevingalligan
23 | */
24 | public abstract class OrmLiteBaseActivity extends Activity {
25 |
26 | private volatile H helper;
27 | private volatile boolean created = false;
28 | private volatile boolean destroyed = false;
29 | private static Logger logger = LoggerFactory.getLogger(OrmLiteBaseActivity.class);
30 |
31 | /**
32 | * Get a helper for this action.
33 | */
34 | public H getHelper() {
35 | if (helper == null) {
36 | if (!created) {
37 | throw new IllegalStateException("A call has not been made to onCreate() yet so the helper is null");
38 | } else if (destroyed) {
39 | throw new IllegalStateException(
40 | "A call to onDestroy has already been made and the helper cannot be used after that point");
41 | } else {
42 | throw new IllegalStateException("Helper is null for some unknown reason");
43 | }
44 | } else {
45 | return helper;
46 | }
47 | }
48 |
49 | /**
50 | * Get a connection source for this action.
51 | */
52 | public ConnectionSource getConnectionSource() {
53 | return getHelper().getConnectionSource();
54 | }
55 |
56 | @Override
57 | protected void onCreate(Bundle savedInstanceState) {
58 | if (helper == null) {
59 | helper = getHelperInternal(this);
60 | created = true;
61 | }
62 | super.onCreate(savedInstanceState);
63 | }
64 |
65 | @Override
66 | protected void onDestroy() {
67 | super.onDestroy();
68 | releaseHelper(helper);
69 | destroyed = true;
70 | }
71 |
72 | /**
73 | * This is called internally by the class to populate the helper object instance. This should not be called directly
74 | * by client code unless you know what you are doing. Use {@link #getHelper()} to get a helper instance. If you are
75 | * managing your own helper creation, override this method to supply this activity with a helper instance.
76 | *
77 | *
78 | * NOTE: If you override this method, you most likely will need to override the
79 | * {@link #releaseHelper(OrmLiteSqliteOpenHelper)} method as well.
80 | *
81 | */
82 | protected H getHelperInternal(Context context) {
83 | @SuppressWarnings({ "unchecked", "deprecation" })
84 | H newHelper = (H) OpenHelperManager.getHelper(context);
85 | logger.trace("{}: got new helper {} from OpenHelperManager", this, newHelper);
86 | return newHelper;
87 | }
88 |
89 | /**
90 | * Release the helper instance created in {@link #getHelperInternal(Context)}. You most likely will not need to call
91 | * this directly since {@link #onDestroy()} does it for you.
92 | *
93 | *
94 | * NOTE: If you override this method, you most likely will need to override the
95 | * {@link #getHelperInternal(Context)} method as well.
96 | *
97 | */
98 | protected void releaseHelper(H helper) {
99 | OpenHelperManager.releaseHelper();
100 | logger.trace("{}: helper {} was released, set to null", this, helper);
101 | this.helper = null;
102 | }
103 |
104 | @Override
105 | public String toString() {
106 | return getClass().getSimpleName() + "@" + Integer.toHexString(super.hashCode());
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/sqlcipher-old/src/main/java/com/j256/ormlite/sqlcipher/android/apptools/OrmLiteBaseActivityGroup.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.apptools;
2 |
3 | import android.app.ActivityGroup;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 |
7 | import com.j256.ormlite.support.ConnectionSource;
8 |
9 | /**
10 | * Base class to use for activity groups in Android.
11 | *
12 | * You can simply call {@link #getHelper()} to get your helper class, or {@link #getConnectionSource()} to get a
13 | * {@link ConnectionSource}.
14 | *
15 | * The method {@link #getHelper()} assumes you are using the default helper factory -- see {@link OpenHelperManager}. If
16 | * not, you'll need to provide your own helper instances which will need to implement a reference counting scheme. This
17 | * method will only be called if you use the database, and only called once for this activity's life-cycle. 'close' will
18 | * also be called once for each call to createInstance.
19 | *
20 | * @author graywatson, kevingalligan
21 | */
22 | public abstract class OrmLiteBaseActivityGroup extends ActivityGroup {
23 |
24 | private volatile H helper;
25 | private volatile boolean created = false;
26 | private volatile boolean destroyed = false;
27 |
28 | /**
29 | * Get a helper for this action.
30 | */
31 | public H getHelper() {
32 | if (helper == null) {
33 | if (!created) {
34 | throw new IllegalStateException("A call has not been made to onCreate() yet so the helper is null");
35 | } else if (destroyed) {
36 | throw new IllegalStateException(
37 | "A call to onDestroy has already been made and the helper cannot be used after that point");
38 | } else {
39 | throw new IllegalStateException("Helper is null for some unknown reason");
40 | }
41 | } else {
42 | return helper;
43 | }
44 | }
45 |
46 | /**
47 | * Get a connection source for this action.
48 | */
49 | public ConnectionSource getConnectionSource() {
50 | return getHelper().getConnectionSource();
51 | }
52 |
53 | @Override
54 | protected void onCreate(Bundle savedInstanceState) {
55 | if (helper == null) {
56 | helper = getHelperInternal(this);
57 | created = true;
58 | }
59 | super.onCreate(savedInstanceState);
60 | }
61 |
62 | @Override
63 | protected void onDestroy() {
64 | super.onDestroy();
65 | releaseHelper(helper);
66 | destroyed = true;
67 | }
68 |
69 | /**
70 | * This is called internally by the class to populate the helper object instance. This should not be called directly
71 | * by client code unless you know what you are doing. Use {@link #getHelper()} to get a helper instance. If you are
72 | * managing your own helper creation, override this method to supply this activity with a helper instance.
73 | *
74 | *
75 | * NOTE: If you override this method, you most likely will need to override the
76 | * {@link #releaseHelper(OrmLiteSqliteOpenHelper)} method as well.
77 | *
78 | */
79 | protected H getHelperInternal(Context context) {
80 | @SuppressWarnings({ "unchecked", "deprecation" })
81 | H newHelper = (H) OpenHelperManager.getHelper(context);
82 | return newHelper;
83 | }
84 |
85 | /**
86 | * Release the helper instance created in {@link #getHelperInternal(Context)}. You most likely will not need to call
87 | * this directly since {@link #onDestroy()} does it for you.
88 | *
89 | *
90 | * NOTE: If you override this method, you most likely will need to override the
91 | * {@link #getHelperInternal(Context)} method as well.
92 | *
93 | */
94 | protected void releaseHelper(H helper) {
95 | OpenHelperManager.releaseHelper();
96 | this.helper = null;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/sqlcipher-old/src/main/java/com/j256/ormlite/sqlcipher/android/apptools/OrmLiteBaseListActivity.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.apptools;
2 |
3 | import android.app.ListActivity;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 |
7 | import com.j256.ormlite.support.ConnectionSource;
8 |
9 | /**
10 | * Base class to use for Tab activities in Android.
11 | *
12 | * For more information, see {@link OrmLiteBaseActivity}.
13 | *
14 | * @author graywatson, kevingalligan
15 | */
16 | public abstract class OrmLiteBaseListActivity extends ListActivity {
17 |
18 | private volatile H helper;
19 | private volatile boolean created = false;
20 | private volatile boolean destroyed = false;
21 |
22 | /**
23 | * Get a helper for this action.
24 | */
25 | public H getHelper() {
26 | if (helper == null) {
27 | if (!created) {
28 | throw new IllegalStateException("A call has not been made to onCreate() yet so the helper is null");
29 | } else if (destroyed) {
30 | throw new IllegalStateException(
31 | "A call to onDestroy has already been made and the helper cannot be used after that point");
32 | } else {
33 | throw new IllegalStateException("Helper is null for some unknown reason");
34 | }
35 | } else {
36 | return helper;
37 | }
38 | }
39 |
40 | /**
41 | * Get a connection source for this action.
42 | */
43 | public ConnectionSource getConnectionSource() {
44 | return getHelper().getConnectionSource();
45 | }
46 |
47 | @Override
48 | protected void onCreate(Bundle savedInstanceState) {
49 | if (helper == null) {
50 | helper = getHelperInternal(this);
51 | created = true;
52 | }
53 | super.onCreate(savedInstanceState);
54 | }
55 |
56 | @Override
57 | protected void onDestroy() {
58 | super.onDestroy();
59 | releaseHelper(helper);
60 | destroyed = true;
61 | }
62 |
63 | /**
64 | * This is called internally by the class to populate the helper object instance. This should not be called directly
65 | * by client code unless you know what you are doing. Use {@link #getHelper()} to get a helper instance. If you are
66 | * managing your own helper creation, override this method to supply this activity with a helper instance.
67 | *
68 | *
69 | * NOTE: If you override this method, you most likely will need to override the
70 | * {@link #releaseHelper(OrmLiteSqliteOpenHelper)} method as well.
71 | *
72 | */
73 | protected H getHelperInternal(Context context) {
74 | @SuppressWarnings({ "unchecked", "deprecation" })
75 | H newHelper = (H) OpenHelperManager.getHelper(context);
76 | return newHelper;
77 | }
78 |
79 | /**
80 | * Release the helper instance created in {@link #getHelperInternal(Context)}. You most likely will not need to call
81 | * this directly since {@link #onDestroy()} does it for you.
82 | *
83 | *
84 | * NOTE: If you override this method, you most likely will need to override the
85 | * {@link #getHelperInternal(Context)} method as well.
86 | *
87 | */
88 | protected void releaseHelper(H helper) {
89 | OpenHelperManager.releaseHelper();
90 | this.helper = null;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/sqlcipher-old/src/main/java/com/j256/ormlite/sqlcipher/android/apptools/OrmLiteBaseService.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.apptools;
2 |
3 | import android.app.Service;
4 | import android.content.Context;
5 |
6 | import com.j256.ormlite.support.ConnectionSource;
7 |
8 | /**
9 | * Base class to use for services in Android.
10 | *
11 | * For more information, see {@link OrmLiteBaseActivity}.
12 | *
13 | * @author graywatson, kevingalligan
14 | */
15 | public abstract class OrmLiteBaseService extends Service {
16 |
17 | private volatile H helper;
18 | private volatile boolean created = false;
19 | private volatile boolean destroyed = false;
20 |
21 | /**
22 | * Get a helper for this action.
23 | */
24 | public H getHelper() {
25 | if (helper == null) {
26 | if (!created) {
27 | throw new IllegalStateException("A call has not been made to onCreate() yet so the helper is null");
28 | } else if (destroyed) {
29 | throw new IllegalStateException(
30 | "A call to onDestroy has already been made and the helper cannot be used after that point");
31 | } else {
32 | throw new IllegalStateException("Helper is null for some unknown reason");
33 | }
34 | } else {
35 | return helper;
36 | }
37 | }
38 |
39 | /**
40 | * Get a connection source for this action.
41 | */
42 | public ConnectionSource getConnectionSource() {
43 | return getHelper().getConnectionSource();
44 | }
45 |
46 | @Override
47 | public void onCreate() {
48 | if (helper == null) {
49 | helper = getHelperInternal(this);
50 | created = true;
51 | }
52 | super.onCreate();
53 | }
54 |
55 | @Override
56 | public void onDestroy() {
57 | super.onDestroy();
58 | releaseHelper(helper);
59 | destroyed = true;
60 | }
61 |
62 | /**
63 | * This is called internally by the class to populate the helper object instance. This should not be called directly
64 | * by client code unless you know what you are doing. Use {@link #getHelper()} to get a helper instance. If you are
65 | * managing your own helper creation, override this method to supply this activity with a helper instance.
66 | *
67 | *
68 | * NOTE: If you override this method, you most likely will need to override the
69 | * {@link #releaseHelper(OrmLiteSqliteOpenHelper)} method as well.
70 | *
71 | */
72 | protected H getHelperInternal(Context context) {
73 | @SuppressWarnings({ "unchecked", "deprecation" })
74 | H newHelper = (H) OpenHelperManager.getHelper(context);
75 | return newHelper;
76 | }
77 |
78 | /**
79 | * Release the helper instance created in {@link #getHelperInternal(Context)}. You most likely will not need to call
80 | * this directly since {@link #onDestroy()} does it for you.
81 | *
82 | *
83 | * NOTE: If you override this method, you most likely will need to override the
84 | * {@link #getHelperInternal(Context)} method as well.
85 | *
86 | */
87 | protected void releaseHelper(H helper) {
88 | OpenHelperManager.releaseHelper();
89 | this.helper = null;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/sqlcipher-old/src/main/java/com/j256/ormlite/sqlcipher/android/apptools/OrmLiteBaseTabActivity.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.apptools;
2 |
3 | import android.app.TabActivity;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 |
7 | import com.j256.ormlite.support.ConnectionSource;
8 |
9 | /**
10 | * Base class to use for Tab activities in Android.
11 | *
12 | * For more information, see {@link OrmLiteBaseActivity}.
13 | *
14 | * @author graywatson, kevingalligan
15 | */
16 | public abstract class OrmLiteBaseTabActivity extends TabActivity {
17 |
18 | private volatile H helper;
19 | private volatile boolean created = false;
20 | private volatile boolean destroyed = false;
21 |
22 | /**
23 | * Get a helper for this action.
24 | */
25 | public H getHelper() {
26 | if (helper == null) {
27 | if (!created) {
28 | throw new IllegalStateException("A call has not been made to onCreate() yet so the helper is null");
29 | } else if (destroyed) {
30 | throw new IllegalStateException(
31 | "A call to onDestroy has already been made and the helper cannot be used after that point");
32 | } else {
33 | throw new IllegalStateException("Helper is null for some unknown reason");
34 | }
35 | } else {
36 | return helper;
37 | }
38 | }
39 |
40 | /**
41 | * Get a connection source for this action.
42 | */
43 | public ConnectionSource getConnectionSource() {
44 | return getHelper().getConnectionSource();
45 | }
46 |
47 | @Override
48 | protected void onCreate(Bundle savedInstanceState) {
49 | if (helper == null) {
50 | helper = getHelperInternal(this);
51 | created = true;
52 | }
53 | super.onCreate(savedInstanceState);
54 | }
55 |
56 | @Override
57 | protected void onDestroy() {
58 | super.onDestroy();
59 | releaseHelper(helper);
60 | destroyed = true;
61 | }
62 |
63 | /**
64 | * This is called internally by the class to populate the helper object instance. This should not be called directly
65 | * by client code unless you know what you are doing. Use {@link #getHelper()} to get a helper instance. If you are
66 | * managing your own helper creation, override this method to supply this activity with a helper instance.
67 | *
68 | *
69 | * NOTE: If you override this method, you most likely will need to override the
70 | * {@link #releaseHelper(OrmLiteSqliteOpenHelper)} method as well.
71 | *
72 | *
73 | * @see OpenHelperManager#getHelper(Context)
74 | */
75 | protected H getHelperInternal(Context context) {
76 | @SuppressWarnings({ "unchecked", "deprecation" })
77 | H newHelper = (H) OpenHelperManager.getHelper(context);
78 | return newHelper;
79 | }
80 |
81 | /**
82 | * Release the helper instance created in {@link #getHelperInternal(Context)}. You most likely will not need to call
83 | * this directly since {@link #onDestroy()} does it for you.
84 | *
85 | *
86 | * NOTE: If you override this method, you most likely will need to override the
87 | * {@link #getHelperInternal(Context)} method as well.
88 | *
36 | * With help from the user list and especially Ian Dees, we discovered that calls to annotation methods in Android are
37 | * _very_ expensive because Method.equals() was doing a huge toString(). This was causing folks to see 2-3 seconds
38 | * startup time when configuring 10-15 DAOs because of 1000s of calls to @DatabaseField methods. See this Android bug report.
40 | *
41 | *
42 | *
43 | * I added this utility class which writes a configuration file into the raw resource "res/raw" directory inside of your
44 | * project containing the table and field names and associated details. This file can then be loaded into the
45 | * {@link DaoManager} with the help of the
46 | * {@link OrmLiteSqliteOpenHelper#OrmLiteSqliteOpenHelper(android.content.Context, String, SQLiteDatabase.CursorFactory, int, int)}
47 | * constructor. This means that you can configure your classes _without_ any runtime calls to annotations. It seems
48 | * significantly faster.
49 | *
50 | *
51 | *
52 | * WARNING: Although this is fast, the big problem is that you have to remember to regenerate the config file
53 | * whenever you edit one of your database classes. There is no way that I know of to do this automagically.
54 | *
55 | *
56 | * @author graywatson
57 | */
58 | public class OrmLiteConfigUtil {
59 |
60 | /**
61 | * Resource directory name that we are looking for.
62 | */
63 | protected static final String RESOURCE_DIR_NAME = "res";
64 | /**
65 | * Raw directory name that we are looking for.
66 | */
67 | protected static final String RAW_DIR_NAME = "raw";
68 |
69 | /**
70 | * Maximum recursion level while we are looking for source files.
71 | */
72 | protected static int maxFindSourceLevel = 20;
73 |
74 | private static final DatabaseType databaseType = new SqliteAndroidDatabaseType();
75 |
76 | /**
77 | * A call through to {@link #writeConfigFile(String)} taking the file name from the single command line argument.
78 | */
79 | public static void main(String[] args) throws Exception {
80 | if (args.length != 1) {
81 | throw new IllegalArgumentException("Main can take a single file-name argument.");
82 | }
83 | writeConfigFile(args[0]);
84 | }
85 |
86 | /**
87 | * Finds the annotated classes in the current directory or below and writes a configuration file to the file-name in
88 | * the raw folder.
89 | */
90 | public static void writeConfigFile(String fileName) throws SQLException, IOException {
91 | List> classList = new ArrayList>();
92 | findAnnotatedClasses(classList, new File("."), 0);
93 | writeConfigFile(fileName, classList.toArray(new Class[classList.size()]));
94 | }
95 |
96 | /**
97 | * Writes a configuration fileName in the raw directory with the configuration for classes.
98 | */
99 | public static void writeConfigFile(String fileName, Class>[] classes) throws SQLException, IOException {
100 | File rawDir = findRawDir(new File("."));
101 | if (rawDir == null) {
102 | System.err.println("Could not find " + RAW_DIR_NAME + " directory which is typically in the "
103 | + RESOURCE_DIR_NAME + " directory");
104 | } else {
105 | File configFile = new File(rawDir, fileName);
106 | writeConfigFile(configFile, classes);
107 | }
108 | }
109 |
110 | /**
111 | * Finds the annotated classes in the current directory or below and writes a configuration file.
112 | */
113 | public static void writeConfigFile(File configFile) throws SQLException, IOException {
114 | writeConfigFile(configFile, new File("."));
115 | }
116 |
117 | /**
118 | * Finds the annotated classes in the specified search directory or below and writes a configuration file.
119 | */
120 | public static void writeConfigFile(File configFile, File searchDir) throws SQLException, IOException {
121 | List> classList = new ArrayList>();
122 | findAnnotatedClasses(classList, searchDir, 0);
123 | writeConfigFile(configFile, classList.toArray(new Class[classList.size()]));
124 | }
125 |
126 | /**
127 | * Write a configuration file with the configuration for classes.
128 | */
129 | public static void writeConfigFile(File configFile, Class>[] classes) throws SQLException, IOException {
130 | System.out.println("Writing configurations to " + configFile.getAbsolutePath());
131 | writeConfigFile(new FileOutputStream(configFile), classes);
132 | }
133 |
134 | /**
135 | * Write a configuration file to an output stream with the configuration for classes.
136 | */
137 | public static void writeConfigFile(OutputStream outputStream, File searchDir) throws SQLException, IOException {
138 | List> classList = new ArrayList>();
139 | findAnnotatedClasses(classList, searchDir, 0);
140 | writeConfigFile(outputStream, classList.toArray(new Class[classList.size()]));
141 | }
142 |
143 | /**
144 | * Write a configuration file to an output stream with the configuration for classes.
145 | */
146 | public static void writeConfigFile(OutputStream outputStream, Class>[] classes) throws SQLException, IOException {
147 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream), 4096);
148 | try {
149 | writeHeader(writer);
150 | for (Class> clazz : classes) {
151 | writeConfigForTable(writer, clazz);
152 | }
153 | // NOTE: done is here because this is public
154 | System.out.println("Done.");
155 | } finally {
156 | writer.close();
157 | }
158 | }
159 |
160 | /**
161 | * Look for the resource-directory in the current directory or the directories above. Then look for the
162 | * raw-directory underneath the resource-directory.
163 | */
164 | protected static File findRawDir(File dir) {
165 | for (int i = 0; dir != null && i < 20; i++) {
166 | File rawDir = findResRawDir(dir);
167 | if (rawDir != null) {
168 | return rawDir;
169 | }
170 | dir = dir.getParentFile();
171 | }
172 | return null;
173 | }
174 |
175 | private static void writeHeader(BufferedWriter writer) throws IOException {
176 | writer.append('#');
177 | writer.newLine();
178 | writer.append("# generated on ").append(new SimpleDateFormat("yyyy/MM/dd hh:mm:ss").format(new Date()));
179 | writer.newLine();
180 | writer.append('#');
181 | writer.newLine();
182 | }
183 |
184 | private static void findAnnotatedClasses(List> classList, File dir, int level) throws SQLException,
185 | IOException {
186 | for (File file : dir.listFiles()) {
187 | if (file.isDirectory()) {
188 | // recurse if we aren't deep enough
189 | if (level < maxFindSourceLevel) {
190 | findAnnotatedClasses(classList, file, level + 1);
191 | }
192 | continue;
193 | }
194 | // skip non .java files
195 | if (!file.getName().endsWith(".java")) {
196 | continue;
197 | }
198 | String packageName = getPackageOfClass(file);
199 | if (packageName == null) {
200 | System.err.println("Could not find package name for: " + file);
201 | continue;
202 | }
203 | // get the filename and cut off the .java
204 | String name = file.getName();
205 | name = name.substring(0, name.length() - ".java".length());
206 | String className = packageName + "." + name;
207 | Class> clazz;
208 | try {
209 | clazz = Class.forName(className);
210 | } catch (Throwable t) {
211 | // amazingly, this sometimes throws an Error
212 | System.err.println("Could not load class file for: " + file);
213 | System.err.println(" " + t);
214 | continue;
215 | }
216 | if (classHasAnnotations(clazz)) {
217 | classList.add(clazz);
218 | }
219 | // handle inner classes
220 | try {
221 | for (Class> innerClazz : clazz.getDeclaredClasses()) {
222 | if (classHasAnnotations(innerClazz)) {
223 | classList.add(innerClazz);
224 | }
225 | }
226 | } catch (Throwable t) {
227 | // amazingly, this sometimes throws an Error
228 | System.err.println("Could not load inner classes for: " + clazz);
229 | System.err.println(" " + t);
230 | continue;
231 | }
232 | }
233 | }
234 |
235 | private static void writeConfigForTable(BufferedWriter writer, Class> clazz) throws SQLException, IOException {
236 | String tableName = DatabaseTableConfig.extractTableName(clazz);
237 | List fieldConfigs = new ArrayList();
238 | // walk up the classes finding the fields
239 | try {
240 | for (Class> working = clazz; working != null; working = working.getSuperclass()) {
241 | for (Field field : working.getDeclaredFields()) {
242 | DatabaseFieldConfig fieldConfig = DatabaseFieldConfig.fromField(databaseType, tableName, field);
243 | if (fieldConfig != null) {
244 | fieldConfigs.add(fieldConfig);
245 | }
246 | }
247 | }
248 | } catch (Error e) {
249 | System.err.println("Skipping " + clazz + " because we got an error finding its definition: "
250 | + e.getMessage());
251 | return;
252 | }
253 | if (fieldConfigs.isEmpty()) {
254 | System.out.println("Skipping " + clazz + " because no annotated fields found");
255 | return;
256 | }
257 | @SuppressWarnings({ "rawtypes", "unchecked" })
258 | DatabaseTableConfig> tableConfig = new DatabaseTableConfig(clazz, tableName, fieldConfigs);
259 | DatabaseTableConfigLoader.write(writer, tableConfig);
260 | writer.append("#################################");
261 | writer.newLine();
262 | System.out.println("Wrote config for " + clazz);
263 | }
264 |
265 | private static boolean classHasAnnotations(Class> clazz) {
266 | while (clazz != null) {
267 | if (clazz.getAnnotation(DatabaseTable.class) != null) {
268 | return true;
269 | }
270 | Field[] fields;
271 | try {
272 | fields = clazz.getDeclaredFields();
273 | } catch (Throwable t) {
274 | // amazingly, this sometimes throws an Error
275 | System.err.println("Could not load get delcared fields from: " + clazz);
276 | System.err.println(" " + t);
277 | return false;
278 | }
279 | for (Field field : fields) {
280 | if (field.getAnnotation(DatabaseField.class) != null
281 | || field.getAnnotation(ForeignCollectionField.class) != null) {
282 | return true;
283 | }
284 | }
285 | try {
286 | clazz = clazz.getSuperclass();
287 | } catch (Throwable t) {
288 | // amazingly, this sometimes throws an Error
289 | System.err.println("Could not get super class for: " + clazz);
290 | System.err.println(" " + t);
291 | return false;
292 | }
293 | }
294 |
295 | return false;
296 | }
297 |
298 | /**
299 | * Returns the package name of a file that has one of the annotations we are looking for.
300 | *
301 | * @return Package prefix string or null or no annotations.
302 | */
303 | private static String getPackageOfClass(File file) throws IOException {
304 | BufferedReader reader = new BufferedReader(new FileReader(file));
305 | try {
306 | while (true) {
307 | String line = reader.readLine();
308 | if (line == null) {
309 | return null;
310 | }
311 | if (line.contains("package")) {
312 | String[] parts = line.split("[ \t;]");
313 | if (parts.length > 1 && parts[0].equals("package")) {
314 | return parts[1];
315 | }
316 | }
317 | }
318 | } finally {
319 | reader.close();
320 | }
321 | }
322 |
323 | /**
324 | * Look for the resource directory with raw beneath it.
325 | */
326 | private static File findResRawDir(File dir) {
327 | for (File file : dir.listFiles()) {
328 | if (file.getName().equals(RESOURCE_DIR_NAME) && file.isDirectory()) {
329 | File[] rawFiles = file.listFiles(new FileFilter() {
330 | public boolean accept(File file) {
331 | return file.getName().equals(RAW_DIR_NAME) && file.isDirectory();
332 | }
333 | });
334 | if (rawFiles.length == 1) {
335 | return rawFiles[0];
336 | }
337 | }
338 | }
339 | return null;
340 | }
341 | }
342 |
--------------------------------------------------------------------------------
/sqlcipher-old/src/main/java/com/j256/ormlite/sqlcipher/android/compat/ApiCompatibility.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.compat;
2 |
3 |
4 | import net.sqlcipher.Cursor;
5 | import net.sqlcipher.database.SQLiteDatabase;
6 |
7 | /**
8 | * Compatibility interface to support various different versions of the Android API.
9 | *
10 | * @author graywatson
11 | */
12 | public interface ApiCompatibility {
13 |
14 | /**
15 | * Perform a raw query on a database with an optional cancellation-hook.
16 | */
17 | public Cursor rawQuery(SQLiteDatabase db, String sql, String[] selectionArgs, CancellationHook cancellationHook);
18 |
19 | /**
20 | * Return a cancellation hook object that will be passed to the
21 | * {@link #rawQuery(SQLiteDatabase, String, String[], CancellationHook)}. If not supported then this will return
22 | * null.
23 | */
24 | public CancellationHook createCancellationHook();
25 |
26 | /**
27 | * Cancellation hook class returned by {@link ApiCompatibility#createCancellationHook()}.
28 | */
29 | public interface CancellationHook {
30 | /**
31 | * Cancel the associated query.
32 | */
33 | public void cancel();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/sqlcipher-old/src/main/java/com/j256/ormlite/sqlcipher/android/compat/ApiCompatibilityUtils.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.compat;
2 |
3 | import android.os.Build;
4 |
5 |
6 | /**
7 | * Utility class which loads the various classes based on which API version is being supported.
8 | *
9 | * @author graywatson
10 | */
11 | @SuppressWarnings("unused")
12 | public class ApiCompatibilityUtils {
13 |
14 | private static ApiCompatibility compatibility;
15 |
16 | /**
17 | * Copied from {@link Build.VERSION_CODES}. We don't use those codes because they won't be in certain versions of
18 | * Build.
19 | */
20 | private static final int BASE = 1;
21 | private static final int BASE_1_1 = 2;
22 | private static final int CUPCAKE = 3;
23 | private static final int DONUT = 4;
24 | private static final int ECLAIR = 5;
25 | private static final int ECLAIR_0_1 = 6;
26 | private static final int ECLAIR_MR1 = 7;
27 | private static final int FROYO = 8;
28 | private static final int GINGERBREAD = 9;
29 | private static final int GINGERBREAD_MR1 = 10;
30 | private static final int HONEYCOMB = 11;
31 | private static final int HONEYCOMB_MR1 = 12;
32 | private static final int HONEYCOMB_MR2 = 13;
33 | private static final int ICE_CREAM_SANDWICH = 14;
34 | private static final int ICE_CREAM_SANDWICH_MR1 = 15;
35 | private static final int JELLY_BEAN = 16;
36 | private static final int JELLY_BEAN_MR1 = 17;
37 | private static final int JELLY_BEAN_MR2 = 18;
38 |
39 | static {
40 | if (Build.VERSION.SDK_INT >= JELLY_BEAN) {
41 | compatibility = new com.j256.ormlite.sqlcipher.android.compat.JellyBeanApiCompatibility();
42 | } else {
43 | compatibility = new com.j256.ormlite.sqlcipher.android.compat.BasicApiCompatibility();
44 | }
45 | }
46 |
47 | /**
48 | * Return the compatibility class that matches our build number.
49 | */
50 | public static ApiCompatibility getCompatibility() {
51 | return compatibility;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/sqlcipher-old/src/main/java/com/j256/ormlite/sqlcipher/android/compat/BasicApiCompatibility.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.compat;
2 |
3 |
4 | import net.sqlcipher.Cursor;
5 | import net.sqlcipher.database.SQLiteDatabase;
6 |
7 | /**
8 | * Basic class which provides no-op methods for all Android version.
9 | *
10 | * @author graywatson
11 | */
12 | public class BasicApiCompatibility implements ApiCompatibility {
13 |
14 | public Cursor rawQuery(SQLiteDatabase db, String sql, String[] selectionArgs, CancellationHook cancellationHook) {
15 | // NOTE: cancellationHook will always be null
16 | return db.rawQuery(sql, selectionArgs);
17 | }
18 |
19 | public CancellationHook createCancellationHook() {
20 | return null;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/sqlcipher-old/src/main/java/com/j256/ormlite/sqlcipher/android/compat/JellyBeanApiCompatibility.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.compat;
2 |
3 | import android.annotation.TargetApi;
4 | import android.os.Build;
5 | import android.os.CancellationSignal;
6 |
7 | import net.sqlcipher.Cursor;
8 | import net.sqlcipher.database.SQLiteDatabase;
9 |
10 | /**
11 | * Basic class which provides no-op methods for all Android version.
12 | *
13 | *
14 | * NOTE: Will show as in error if compiled with previous Android versions.
15 | *
16 | *
17 | * @author graywatson
18 | */
19 | public class JellyBeanApiCompatibility extends BasicApiCompatibility {
20 |
21 | @Override
22 | public Cursor rawQuery(SQLiteDatabase db, String sql, String[] selectionArgs, CancellationHook cancellationHook) {
23 | // NOTE: in patched version this is the same as BasicApiCompatibility
24 | // because SqlCipher supports Android version lower than API level 16 (Jelly Bean)
25 | // if (cancellationHook == null) {
26 | return db.rawQuery(sql, selectionArgs);
27 | // } else {
28 | // return db.rawQuery(sql, selectionArgs, ((JellyBeanCancellationHook) cancellationHook).cancellationSignal);
29 | // }
30 | }
31 |
32 | @Override
33 | public CancellationHook createCancellationHook() {
34 | return new JellyBeanCancellationHook();
35 | }
36 |
37 | protected static class JellyBeanCancellationHook implements CancellationHook {
38 |
39 | private final CancellationSignal cancellationSignal;
40 |
41 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
42 | public JellyBeanCancellationHook() {
43 | this.cancellationSignal = new CancellationSignal();
44 | }
45 |
46 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
47 | public void cancel() {
48 | cancellationSignal.cancel();
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/sqlcipher-old/src/main/java/com/j256/ormlite/sqlcipher/db/SqliteAndroidDatabaseType.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.db;
2 |
3 | import com.j256.ormlite.db.BaseSqliteDatabaseType;
4 | import com.j256.ormlite.field.DataPersister;
5 | import com.j256.ormlite.field.FieldConverter;
6 | import com.j256.ormlite.field.FieldType;
7 | import com.j256.ormlite.field.types.DateStringType;
8 | import com.j256.ormlite.sqlcipher.android.DatabaseTableConfigUtil;
9 | import com.j256.ormlite.support.ConnectionSource;
10 | import com.j256.ormlite.table.DatabaseTableConfig;
11 |
12 | import java.sql.SQLException;
13 |
14 | /**
15 | * Sqlite database type information for the Android OS that makes native calls to the Android OS database APIs.
16 | *
17 | * @author graywatson
18 | */
19 | public class SqliteAndroidDatabaseType extends BaseSqliteDatabaseType {
20 |
21 | @Override
22 | public void loadDriver() {
23 | // noop
24 | }
25 |
26 | public boolean isDatabaseUrlThisType(String url, String dbTypePart) {
27 | // not used by the android code
28 | return true;
29 | }
30 |
31 | @Override
32 | protected String getDriverClassName() {
33 | // no driver to load in android-land
34 | return null;
35 | }
36 |
37 | public String getDatabaseName() {
38 | return "Android SQLite";
39 | }
40 |
41 | @Override
42 | protected void appendDateType(StringBuilder sb, FieldType fieldType, int fieldWidth) {
43 | // default is to store the date as a string
44 | appendStringType(sb, fieldType, fieldWidth);
45 | }
46 |
47 | @Override
48 | protected void appendBooleanType(StringBuilder sb, FieldType fieldType, int fieldWidth) {
49 | // we have to convert booleans to numbers
50 | appendShortType(sb, fieldType, fieldWidth);
51 | }
52 |
53 | @Override
54 | public FieldConverter getFieldConverter(DataPersister dataPersister) {
55 | // we are only overriding certain types
56 | switch (dataPersister.getSqlType()) {
57 | case DATE :
58 | return DateStringType.getSingleton();
59 | default :
60 | return super.getFieldConverter(dataPersister);
61 | }
62 | }
63 |
64 | @Override
65 | public boolean isNestedSavePointsSupported() {
66 | return false;
67 | }
68 |
69 | @Override
70 | public boolean isBatchUseTransaction() {
71 | return true;
72 | }
73 |
74 | @Override
75 | public DatabaseTableConfig extractDatabaseTableConfig(ConnectionSource connectionSource, Class clazz)
76 | throws SQLException {
77 | return DatabaseTableConfigUtil.fromClass(connectionSource, clazz);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/sqlcipher-old/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | database
3 |
4 |
--------------------------------------------------------------------------------
/sqlcipher/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sqlcipher/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply from: 'maven_upload.gradle'
3 | apply from: '../config.gradle'
4 |
5 | android {
6 | compileSdkVersion compileSdkVer
7 | buildToolsVersion buildToolsVer
8 |
9 | defaultConfig {
10 | minSdkVersion minSdkVer
11 | targetSdkVersion targetSdkVer
12 | versionCode 1
13 | versionName "1.0"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 |
22 | }
23 |
24 | repositories {
25 | flatDir {
26 | dirs 'libs' //this way we can find the .aar file in libs folder
27 | }
28 | }
29 |
30 | dependencies {
31 | compile 'net.zetetic:android-database-sqlcipher:3.5.4'
32 | compile 'com.j256.ormlite:ormlite-core:4.48'
33 | }
34 |
--------------------------------------------------------------------------------
/sqlcipher/maven_pom.properties:
--------------------------------------------------------------------------------
1 | POM_NAME=android
2 | POM_DESCRIPTION=app sql cipher lib
3 | POM_GROUP=com.xtc.data
4 | POM_ARTIFACT_ID=data-new-sqlcipher
5 | POM_PACKAGING=aar
6 | POM_VERSION=0.0.2-SNAPSHOT
--------------------------------------------------------------------------------
/sqlcipher/maven_upload.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven'
2 |
3 | Properties user_properties = new Properties()
4 | user_properties.load(project.rootProject.file('maven_user.properties').newDataInputStream())
5 | def repoUrl = user_properties.getProperty("repository.url")
6 | def userName = user_properties.getProperty("repository.user")
7 | def userPassword = user_properties.getProperty("repository.password")
8 |
9 | Properties pom_properties = new Properties()
10 | pom_properties.load(project.file('maven_pom.properties').newDataInputStream())
11 | def pom_name = pom_properties.getProperty("POM_NAME")
12 | def pom_description = pom_properties.getProperty("POM_DESCRIPTION")
13 | def pom_group = pom_properties.getProperty("POM_GROUP")
14 | def pom_artifact_id = pom_properties.getProperty("POM_ARTIFACT_ID")
15 | def pom_packaging = pom_properties.getProperty("POM_PACKAGING")
16 | def pom_version = pom_properties.getProperty("POM_VERSION")
17 |
18 |
19 | uploadArchives {
20 |
21 | repositories.mavenDeployer {
22 | repository(url: repoUrl) {
23 | authentication(userName: userName,
24 | password: userPassword)
25 | }
26 |
27 | pom.project {
28 | name pom_name
29 | description pom_description
30 | groupId pom_group
31 | artifactId pom_artifact_id
32 | version pom_version
33 | packaging pom_packaging
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/sqlcipher/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/Stay/develop/android-sdk-mac_x86/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/DatabaseEncrypted.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher;
2 |
3 | import android.app.Application;
4 | import android.util.Log;
5 |
6 | import net.sqlcipher.database.SQLiteDatabase;
7 |
8 | import java.io.File;
9 |
10 |
11 | /**
12 | * 数据库加密
13 | */
14 | public class DatabaseEncrypted {
15 |
16 | private static final String TAG = "DatabaseEncrypted";
17 |
18 | /**
19 | * 将未加密数据库转换为加密数据库
20 | *
21 | * @param application application
22 | * @param unencryptedDbName 未加密数据库名
23 | * @param encryptedDbName 加密数据库名
24 | * @param password 加密数据库密码
25 | */
26 | public static boolean importUnencryptedDatabase(Application application, String unencryptedDbName,
27 | String encryptedDbName, String password) {
28 | File unencryptedFile = application.getDatabasePath(unencryptedDbName);
29 | if (!unencryptedFile.exists()) {
30 | Log.i(TAG, "unencrypted database not exist");
31 | return true;
32 | }
33 |
34 | File encryptedFile = application.getDatabasePath(encryptedDbName);
35 | if (encryptedFile.exists()) {
36 | Log.i(TAG, "encrypted database is exist");
37 | return true;
38 | }
39 |
40 | Log.i(TAG, "encrypted database");
41 | SQLiteDatabase database = null;
42 | try {
43 | database = SQLiteDatabase.openOrCreateDatabase(unencryptedFile, "", null);
44 |
45 | database.rawExecSQL(String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s'",
46 | encryptedFile.getAbsolutePath(), password));
47 | database.rawExecSQL("select sqlcipher_export('encrypted')");
48 | database.rawExecSQL("DETACH DATABASE encrypted");
49 |
50 | return true;
51 | } catch (Exception e) {
52 | e.printStackTrace();
53 | return false;
54 | } finally {
55 | if (database != null) {
56 | database.close();
57 | }
58 | application.deleteDatabase(unencryptedDbName);
59 | SQLiteDatabase.releaseMemory();
60 | }
61 | }
62 |
63 | /**
64 | * 将加密数据库转换为常规数据库
65 | *
66 | * @param application application
67 | * @param encryptedDbName 加密数据库名
68 | * @param unencryptedDbName 未加密数据库名
69 | * @param password 加密数据库密码
70 | */
71 | public static boolean exportToUnencryptedDatabase(Application application, String encryptedDbName, String unencryptedDbName, String password) {
72 | File encryptedFile = application.getDatabasePath(encryptedDbName);
73 | if (!encryptedFile.exists()) {
74 | Log.i(TAG, "encrypted database not exist");
75 | return true;
76 | }
77 |
78 | File unencryptedFile = application.getDatabasePath(unencryptedDbName);
79 | if (unencryptedFile.exists()) {
80 | Log.i(TAG, "unencrypted database is exist");
81 | return true;
82 | }
83 |
84 | Log.i(TAG, "unencrypted database");
85 | SQLiteDatabase database = null;
86 | try {
87 | database = SQLiteDatabase.openOrCreateDatabase(encryptedFile, password, null);
88 |
89 | application.deleteDatabase(unencryptedDbName);
90 | database.rawExecSQL(String.format("ATTACH DATABASE '%s' as plaintext KEY '';",
91 | unencryptedFile.getAbsolutePath()));
92 | database.rawExecSQL("SELECT sqlcipher_export('plaintext');");
93 | database.rawExecSQL("DETACH DATABASE plaintext;");
94 |
95 | return true;
96 | } catch (Exception e) {
97 | e.printStackTrace();
98 | return false;
99 | } finally {
100 | if (database != null) {
101 | database.close();
102 | }
103 | application.deleteDatabase(encryptedDbName);
104 | SQLiteDatabase.releaseMemory();
105 | }
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/AndroidCompiledStatement.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android;
2 |
3 |
4 | import com.j256.ormlite.dao.ObjectCache;
5 | import com.j256.ormlite.field.SqlType;
6 | import com.j256.ormlite.logger.Logger;
7 | import com.j256.ormlite.logger.LoggerFactory;
8 | import com.j256.ormlite.misc.SqlExceptionUtil;
9 | import com.j256.ormlite.sqlcipher.android.compat.ApiCompatibility;
10 | import com.j256.ormlite.sqlcipher.android.compat.ApiCompatibilityUtils;
11 | import com.j256.ormlite.stmt.StatementBuilder.StatementType;
12 | import com.j256.ormlite.support.CompiledStatement;
13 | import com.j256.ormlite.support.DatabaseResults;
14 |
15 | import net.sqlcipher.Cursor;
16 | import net.sqlcipher.database.SQLiteDatabase;
17 | import net.sqlcipher.database.SQLiteStatement;
18 |
19 | import java.sql.SQLException;
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | /**
24 | * Android implementation of the compiled statement.
25 | *
26 | * @author kevingalligan, graywatson
27 | */
28 | public class AndroidCompiledStatement implements CompiledStatement {
29 |
30 | private static Logger logger = LoggerFactory.getLogger(AndroidCompiledStatement.class);
31 |
32 | private static final String[] NO_STRING_ARGS = new String[0];
33 | private static final ApiCompatibility apiCompatibility = ApiCompatibilityUtils.getCompatibility();
34 |
35 | private final String sql;
36 | private final SQLiteDatabase db;
37 | private final StatementType type;
38 | private final boolean cancelQueriesEnabled;
39 |
40 | private Cursor cursor;
41 | private List args;
42 | private Integer max;
43 | private ApiCompatibility.CancellationHook cancellationHook;
44 |
45 | public AndroidCompiledStatement(String sql, SQLiteDatabase db, StatementType type, boolean cancelQueriesEnabled) {
46 | this.sql = sql;
47 | this.db = db;
48 | this.type = type;
49 | this.cancelQueriesEnabled = cancelQueriesEnabled;
50 | }
51 |
52 | public int getColumnCount() throws SQLException {
53 | return getCursor().getColumnCount();
54 | }
55 |
56 | public String getColumnName(int column) throws SQLException {
57 | return getCursor().getColumnName(column);
58 | }
59 |
60 | public DatabaseResults runQuery(ObjectCache objectCache) throws SQLException {
61 | // this could come from DELETE or UPDATE, just not a SELECT
62 | if (!type.isOkForQuery()) {
63 | throw new IllegalArgumentException("Cannot call query on a " + type + " statement");
64 | }
65 | return new AndroidDatabaseResults(getCursor(), objectCache);
66 | }
67 |
68 | public int runUpdate() throws SQLException {
69 | if (!type.isOkForUpdate()) {
70 | throw new IllegalArgumentException("Cannot call update on a " + type + " statement");
71 | }
72 | String finalSql;
73 | if (max == null) {
74 | finalSql = sql;
75 | } else {
76 | finalSql = sql + " " + max;
77 | }
78 | return execSql(db, "runUpdate", finalSql, getArgArray());
79 | }
80 |
81 | public int runExecute() throws SQLException {
82 | if (!type.isOkForExecute()) {
83 | throw new IllegalArgumentException("Cannot call execute on a " + type + " statement");
84 | }
85 | return execSql(db, "runExecute", sql, getArgArray());
86 | }
87 |
88 | public void close() throws SQLException {
89 | if (cursor != null) {
90 | try {
91 | cursor.close();
92 | } catch (android.database.SQLException e) {
93 | throw SqlExceptionUtil.create("Problems closing Android cursor", e);
94 | }
95 | }
96 | cancellationHook = null;
97 | }
98 |
99 | public void closeQuietly() {
100 | try {
101 | close();
102 | } catch (SQLException e) {
103 | // ignored
104 | }
105 | }
106 |
107 | public void cancel() {
108 | if (cancellationHook != null) {
109 | cancellationHook.cancel();
110 | }
111 | }
112 |
113 | public void setObject(int parameterIndex, Object obj, SqlType sqlType) throws SQLException {
114 | isInPrep();
115 | if (args == null) {
116 | args = new ArrayList();
117 | }
118 | if (obj == null) {
119 | args.add(parameterIndex, null);
120 | return;
121 | }
122 |
123 | switch (sqlType) {
124 | case STRING :
125 | case LONG_STRING :
126 | case DATE :
127 | case BOOLEAN :
128 | case CHAR :
129 | case BYTE :
130 | case SHORT :
131 | case INTEGER :
132 | case LONG :
133 | case FLOAT :
134 | case DOUBLE :
135 | args.add(parameterIndex, obj.toString());
136 | break;
137 | case BYTE_ARRAY :
138 | case SERIALIZABLE :
139 | args.add(parameterIndex, obj);
140 | break;
141 | case BLOB :
142 | // this is only for derby serializable
143 | case BIG_DECIMAL :
144 | // this should be handled as a STRING
145 | throw new SQLException("Invalid Android type: " + sqlType);
146 | case UNKNOWN :
147 | default :
148 | throw new SQLException("Unknown sql argument type: " + sqlType);
149 | }
150 | }
151 |
152 | public void setMaxRows(int max) throws SQLException {
153 | isInPrep();
154 | this.max = max;
155 | }
156 |
157 | public void setQueryTimeout(long millis) {
158 | // as far as I could tell this is not supported by Android API
159 | }
160 |
161 | /***
162 | * This is mostly an internal class but is exposed for those people who need access to the Cursor itself.
163 | *
164 | *
165 | * NOTE: This is not thread safe. Not sure if we need it, but keep that in mind.
166 | *
167 | */
168 | public Cursor getCursor() throws SQLException {
169 | if (cursor == null) {
170 | String finalSql = null;
171 | try {
172 | if (max == null) {
173 | finalSql = sql;
174 | } else {
175 | finalSql = sql + " " + max;
176 | }
177 | if (cancelQueriesEnabled) {
178 | cancellationHook = apiCompatibility.createCancellationHook();
179 | }
180 | cursor = apiCompatibility.rawQuery(db, finalSql, getStringArray(), cancellationHook);
181 | cursor.moveToFirst();
182 | logger.trace("{}: started rawQuery cursor for: {}", this, finalSql);
183 | } catch (android.database.SQLException e) {
184 | throw SqlExceptionUtil.create("Problems executing Android query: " + finalSql, e);
185 | }
186 | }
187 |
188 | return cursor;
189 | }
190 |
191 | @Override
192 | public String toString() {
193 | return getClass().getSimpleName() + "@" + Integer.toHexString(super.hashCode());
194 | }
195 |
196 | /**
197 | * Execute some SQL on the database and return the number of rows changed.
198 | */
199 | static int execSql(SQLiteDatabase db, String label, String finalSql, Object[] argArray) throws SQLException {
200 | try {
201 | db.execSQL(finalSql, argArray);
202 | } catch (android.database.SQLException e) {
203 | throw SqlExceptionUtil.create("Problems executing " + label + " Android statement: " + finalSql, e);
204 | }
205 | int result;
206 | SQLiteStatement stmt = null;
207 | try {
208 | // ask sqlite how many rows were just changed
209 | stmt = db.compileStatement("SELECT CHANGES()");
210 | result = (int) stmt.simpleQueryForLong();
211 | } catch (android.database.SQLException e) {
212 | // ignore the exception and just return 1 if it failed
213 | result = 1;
214 | } finally {
215 | if (stmt != null) {
216 | stmt.close();
217 | }
218 | }
219 | logger.trace("executing statement {} changed {} rows: {}", label, result, finalSql);
220 | return result;
221 | }
222 |
223 | private void isInPrep() throws SQLException {
224 | if (cursor != null) {
225 | throw new SQLException("Query already run. Cannot add argument values.");
226 | }
227 | }
228 |
229 | private Object[] getArgArray() {
230 | if (args == null) {
231 | // this will work for Object[] as well as String[]
232 | return NO_STRING_ARGS;
233 | } else {
234 | return args.toArray(new Object[args.size()]);
235 | }
236 | }
237 |
238 | private String[] getStringArray() {
239 | if (args == null) {
240 | return NO_STRING_ARGS;
241 | } else {
242 | // we assume we have Strings in args
243 | return args.toArray(new String[args.size()]);
244 | }
245 | }
246 | }
247 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/AndroidConnectionSource.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android;
2 |
3 |
4 | import com.j256.ormlite.db.DatabaseType;
5 | import com.j256.ormlite.logger.Logger;
6 | import com.j256.ormlite.logger.LoggerFactory;
7 | import com.j256.ormlite.misc.SqlExceptionUtil;
8 | import com.j256.ormlite.sqlcipher.android.apptools.OrmLiteSqliteOpenHelper;
9 | import com.j256.ormlite.sqlcipher.db.SqliteAndroidDatabaseType;
10 | import com.j256.ormlite.support.BaseConnectionSource;
11 | import com.j256.ormlite.support.ConnectionSource;
12 | import com.j256.ormlite.support.DatabaseConnection;
13 | import com.j256.ormlite.support.DatabaseConnectionProxyFactory;
14 |
15 | import net.sqlcipher.database.SQLiteDatabase;
16 | import net.sqlcipher.database.SQLiteOpenHelper;
17 |
18 | import java.sql.SQLException;
19 |
20 | /**
21 | * Android version of the connection source. Takes a standard Android {@link SQLiteOpenHelper}. For best results, use
22 | * {@link OrmLiteSqliteOpenHelper}. You can also construct with a {@link SQLiteDatabase}.
23 | *
24 | * @author kevingalligan, graywatson
25 | */
26 | public class AndroidConnectionSource extends BaseConnectionSource implements ConnectionSource {
27 |
28 | private static final Logger logger = LoggerFactory.getLogger(AndroidConnectionSource.class);
29 |
30 | private final SQLiteOpenHelper helper;
31 | private final SQLiteDatabase sqliteDatabase;
32 | private DatabaseConnection connection = null;
33 | private volatile boolean isOpen = true;
34 | private final DatabaseType databaseType = new SqliteAndroidDatabaseType();
35 | private static DatabaseConnectionProxyFactory connectionProxyFactory;
36 | private boolean cancelQueriesEnabled = false;
37 |
38 | public AndroidConnectionSource(SQLiteOpenHelper helper) {
39 | this.helper = helper;
40 | this.sqliteDatabase = null;
41 | }
42 |
43 | public AndroidConnectionSource(SQLiteDatabase sqliteDatabase) {
44 | this.helper = null;
45 | this.sqliteDatabase = sqliteDatabase;
46 | }
47 |
48 | public DatabaseConnection getReadOnlyConnection() throws SQLException {
49 | /*
50 | * We have to use the read-write connection because getWritableDatabase() can call close on
51 | * getReadableDatabase() in the future. This has something to do with Android's SQLite connection management.
52 | *
53 | * See android docs: http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html
54 | */
55 | return getReadWriteConnection();
56 | }
57 |
58 | public DatabaseConnection getReadWriteConnection() throws SQLException {
59 | DatabaseConnection conn = getSavedConnection();
60 | if (conn != null) {
61 | return conn;
62 | }
63 | if (connection == null) {
64 | SQLiteDatabase db;
65 | if (sqliteDatabase == null) {
66 | String password ;
67 | if (helper instanceof OrmLiteSqliteOpenHelper){
68 | password = ((OrmLiteSqliteOpenHelper)helper).getCipherPassword();
69 | }else {
70 | throw new IllegalArgumentException("you should set sqlcipher password to open database");
71 | }
72 | try {
73 | db = helper.getWritableDatabase(password);
74 | } catch (android.database.SQLException e) {
75 | throw SqlExceptionUtil.create("Getting a writable database from helper " + helper + " failed", e);
76 | }
77 | } else {
78 | db = sqliteDatabase;
79 | }
80 | connection = new AndroidDatabaseConnection(db, true, cancelQueriesEnabled);
81 | if (connectionProxyFactory != null) {
82 | connection = connectionProxyFactory.createProxy(connection);
83 | }
84 | logger.trace("created connection {} for db {}, helper {}", connection, db, helper);
85 | } else {
86 | logger.trace("{}: returning read-write connection {}, helper {}", this, connection, helper);
87 | }
88 | return connection;
89 | }
90 |
91 | public void releaseConnection(DatabaseConnection connection) {
92 | // noop since connection management is handled by AndroidOS
93 | }
94 |
95 | public boolean saveSpecialConnection(DatabaseConnection connection) throws SQLException {
96 | return saveSpecial(connection);
97 | }
98 |
99 | public void clearSpecialConnection(DatabaseConnection connection) {
100 | clearSpecial(connection, logger);
101 | }
102 |
103 | public void close() {
104 | // the helper is closed so it calls close here, so this CANNOT be a call back to helper.close()
105 | isOpen = false;
106 | }
107 |
108 | public void closeQuietly() {
109 | close();
110 | }
111 |
112 | public DatabaseType getDatabaseType() {
113 | return databaseType;
114 | }
115 |
116 | public boolean isOpen() {
117 | return isOpen;
118 | }
119 |
120 | /**
121 | * Set to enable connection proxying. Set to null to disable.
122 | */
123 | public static void setDatabaseConnectionProxyFactory(DatabaseConnectionProxyFactory connectionProxyFactory) {
124 | AndroidConnectionSource.connectionProxyFactory = connectionProxyFactory;
125 | }
126 |
127 | public boolean isCancelQueriesEnabled() {
128 | return cancelQueriesEnabled;
129 | }
130 |
131 | /**
132 | * Set to true to enable the canceling of queries.
133 | *
134 | *
135 | * NOTE: This will incur a slight memory increase for all Cursor based queries -- even if cancel is not
136 | * called for them.
137 | *
138 | */
139 | public void setCancelQueriesEnabled(boolean cancelQueriesEnabled) {
140 | this.cancelQueriesEnabled = cancelQueriesEnabled;
141 | }
142 |
143 | @Override
144 | public String toString() {
145 | return getClass().getSimpleName() + "@" + Integer.toHexString(super.hashCode());
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/AndroidDatabaseResults.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android;
2 |
3 |
4 | import com.j256.ormlite.dao.ObjectCache;
5 | import com.j256.ormlite.db.DatabaseType;
6 | import com.j256.ormlite.sqlcipher.db.SqliteAndroidDatabaseType;
7 | import com.j256.ormlite.support.DatabaseResults;
8 |
9 | import net.sqlcipher.Cursor;
10 |
11 | import java.io.ByteArrayInputStream;
12 | import java.io.InputStream;
13 | import java.math.BigDecimal;
14 | import java.sql.SQLException;
15 | import java.sql.Timestamp;
16 | import java.util.Arrays;
17 | import java.util.HashMap;
18 | import java.util.Map;
19 |
20 | /**
21 | * Android implementation of our results object.
22 | *
23 | * @author kevingalligan, graywatson
24 | */
25 | public class AndroidDatabaseResults implements DatabaseResults {
26 |
27 | private static final int MIN_NUM_COLUMN_NAMES_MAP = 8;
28 |
29 | private final Cursor cursor;
30 | private final String[] columnNames;
31 | private final Map columnNameMap;
32 | private final ObjectCache objectCache;
33 | private static final DatabaseType databaseType = new SqliteAndroidDatabaseType();
34 |
35 | public AndroidDatabaseResults(Cursor cursor, ObjectCache objectCache) {
36 | this.cursor = cursor;
37 | this.columnNames = cursor.getColumnNames();
38 | if (this.columnNames.length >= MIN_NUM_COLUMN_NAMES_MAP) {
39 | this.columnNameMap = new HashMap();
40 | for (int i = 0; i < this.columnNames.length; i++) {
41 | // NOTE: this is case sensitive
42 | this.columnNameMap.put(this.columnNames[i], i);
43 | }
44 | } else {
45 | columnNameMap = null;
46 | }
47 | this.objectCache = objectCache;
48 | }
49 |
50 | /**
51 | * Constructor that allows you to inject a cursor that has already been configured with first-call set to false.
52 | *
53 | * @deprecated The firstCall is no longer needed since the library now calls first() and next on its own.
54 | */
55 | @Deprecated
56 | public AndroidDatabaseResults(Cursor cursor, boolean firstCall, ObjectCache objectCache) {
57 | this(cursor, objectCache);
58 | }
59 |
60 | public int getColumnCount() {
61 | return cursor.getColumnCount();
62 | }
63 |
64 | public String[] getColumnNames() {
65 | int colN = getColumnCount();
66 | String[] columnNames = new String[colN];
67 | for (int colC = 0; colC < colN; colC++) {
68 | columnNames[colC] = cursor.getColumnName(colC);
69 | }
70 | return columnNames;
71 | }
72 |
73 | public boolean first() {
74 | return cursor.moveToFirst();
75 | }
76 |
77 | public boolean next() {
78 | return cursor.moveToNext();
79 | }
80 |
81 | public boolean last() {
82 | return cursor.moveToLast();
83 | }
84 |
85 | public boolean previous() {
86 | return cursor.moveToPrevious();
87 | }
88 |
89 | public boolean moveRelative(int offset) {
90 | return cursor.move(offset);
91 | }
92 |
93 | public boolean moveAbsolute(int position) {
94 | return cursor.moveToPosition(position);
95 | }
96 |
97 | /**
98 | * Returns the count of results from the cursor.
99 | */
100 | public int getCount() {
101 | return cursor.getCount();
102 | }
103 |
104 | /**
105 | * Returns the position of the cursor in the list of results.
106 | */
107 | public int getPosition() {
108 | return cursor.getPosition();
109 | }
110 |
111 | public int findColumn(String columnName) throws SQLException {
112 | int index = lookupColumn(columnName);
113 | if (index >= 0) {
114 | return index;
115 | }
116 |
117 | /*
118 | * Hack here. It turns out that if we've asked for '*' then the field foo is in the cursor as foo. But if we ask
119 | * for a particular field list with DISTINCT, which escapes the field names, they are in the cursor _with_ the
120 | * escaping. Ugly!!
121 | */
122 | StringBuilder sb = new StringBuilder(columnName.length() + 4);
123 | databaseType.appendEscapedEntityName(sb, columnName);
124 | index = lookupColumn(sb.toString());
125 | if (index >= 0) {
126 | return index;
127 | } else {
128 | String[] columnNames = cursor.getColumnNames();
129 | throw new SQLException("Unknown field '" + columnName + "' from the Android sqlite cursor, not in:"
130 | + Arrays.toString(columnNames));
131 | }
132 | }
133 |
134 | public String getString(int columnIndex) {
135 | return cursor.getString(columnIndex);
136 | }
137 |
138 | public boolean getBoolean(int columnIndex) {
139 | if (cursor.isNull(columnIndex) || cursor.getShort(columnIndex) == 0) {
140 | return false;
141 | } else {
142 | return true;
143 | }
144 | }
145 |
146 | public char getChar(int columnIndex) throws SQLException {
147 | String string = cursor.getString(columnIndex);
148 | if (string == null || string.length() == 0) {
149 | return 0;
150 | } else if (string.length() == 1) {
151 | return string.charAt(0);
152 | } else {
153 | throw new SQLException("More than 1 character stored in database column: " + columnIndex);
154 | }
155 | }
156 |
157 | public byte getByte(int columnIndex) {
158 | return (byte) getShort(columnIndex);
159 | }
160 |
161 | public byte[] getBytes(int columnIndex) {
162 | return cursor.getBlob(columnIndex);
163 | }
164 |
165 | public short getShort(int columnIndex) {
166 | return cursor.getShort(columnIndex);
167 | }
168 |
169 | public int getInt(int columnIndex) {
170 | return cursor.getInt(columnIndex);
171 | }
172 |
173 | public long getLong(int columnIndex) {
174 | return cursor.getLong(columnIndex);
175 | }
176 |
177 | public float getFloat(int columnIndex) {
178 | return cursor.getFloat(columnIndex);
179 | }
180 |
181 | public double getDouble(int columnIndex) {
182 | return cursor.getDouble(columnIndex);
183 | }
184 |
185 | public Timestamp getTimestamp(int columnIndex) throws SQLException {
186 | throw new SQLException("Android does not support timestamp. Use JAVA_DATE_LONG or JAVA_DATE_STRING types");
187 | }
188 |
189 | public InputStream getBlobStream(int columnIndex) {
190 | return new ByteArrayInputStream(cursor.getBlob(columnIndex));
191 | }
192 |
193 | public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
194 | throw new SQLException("Android does not support BigDecimal type. Use BIG_DECIMAL or BIG_DECIMAL_STRING types");
195 | }
196 |
197 | public boolean wasNull(int columnIndex) {
198 | return cursor.isNull(columnIndex);
199 | }
200 |
201 | public ObjectCache getObjectCache() {
202 | return objectCache;
203 | }
204 |
205 | public void close() {
206 | cursor.close();
207 | }
208 |
209 | public void closeQuietly() {
210 | close();
211 | }
212 |
213 | /***
214 | * Returns the underlying Android cursor object. This should not be used unless you know what you are doing.
215 | */
216 | public Cursor getRawCursor() {
217 | return cursor;
218 | }
219 |
220 | @Override
221 | public String toString() {
222 | return getClass().getSimpleName() + "@" + Integer.toHexString(super.hashCode());
223 | }
224 |
225 | private int lookupColumn(String columnName) {
226 | // we either use linear search or our name map
227 | if (columnNameMap == null) {
228 | for (int i = 0; i < columnNames.length; i++) {
229 | // NOTE: this is case sensitive
230 | if (columnNames[i].equals(columnName)) {
231 | return i;
232 | }
233 | }
234 | return -1;
235 | } else {
236 | // NOTE: this is case sensitive
237 | Integer index = columnNameMap.get(columnName);
238 | if (index == null) {
239 | return -1;
240 | } else {
241 | return index;
242 | }
243 | }
244 | }
245 | }
246 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/AndroidLog.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android;
2 |
3 | import android.util.Log;
4 |
5 | import com.j256.ormlite.logger.LoggerFactory;
6 |
7 | /**
8 | * Implementation of our logger which delegates to the internal Android logger.
9 | *
10 | *
11 | * To see log messages you will do something like:
12 | *
13 | *
20 | * NOTE: Unfortunately, Android variables are limited in size so this class takes that last 23 (sic) characters
21 | * of the class name if it is larger than 23 characters. For example, if the class is AndroidDatabaseConnection you
22 | * would do:
23 | *
24 | *
36 | *
37 | * @author graywatson
38 | */
39 | public class AndroidLog implements com.j256.ormlite.logger.Log {
40 |
41 | private final static String ALL_LOGS_NAME = "ORMLite";
42 | private final static int REFRESH_LEVEL_CACHE_EVERY = 200;
43 |
44 | private final static int MAX_TAG_LENGTH = 23;
45 | private String className;
46 |
47 | // we do this because supposedly Log.isLoggable() always does IO
48 | private volatile int levelCacheC = 0;
49 | private final boolean levelCache[];
50 |
51 | public AndroidLog(String className) {
52 | // get the last part of the class name
53 | this.className = LoggerFactory.getSimpleClassName(className);
54 | // make sure that our tag length is not too long
55 | int length = this.className.length();
56 | if (length > MAX_TAG_LENGTH) {
57 | this.className = this.className.substring(length - MAX_TAG_LENGTH, length);
58 | }
59 | // find the maximum level value
60 | int maxLevel = 0;
61 | for (com.j256.ormlite.logger.Log.Level level : com.j256.ormlite.logger.Log.Level.values()) {
62 | int androidLevel = levelToAndroidLevel(level);
63 | if (androidLevel > maxLevel) {
64 | maxLevel = androidLevel;
65 | }
66 | }
67 | levelCache = new boolean[maxLevel + 1];
68 | refreshLevelCache();
69 | }
70 |
71 | public boolean isLevelEnabled(Level level) {
72 | // we don't care if this is not synchronized, it will be updated sooner or later and multiple updates are fine.
73 | if (++levelCacheC >= REFRESH_LEVEL_CACHE_EVERY) {
74 | refreshLevelCache();
75 | levelCacheC = 0;
76 | }
77 | int androidLevel = levelToAndroidLevel(level);
78 | if (androidLevel < levelCache.length) {
79 | return levelCache[androidLevel];
80 | } else {
81 | return isLevelEnabledInternal(androidLevel);
82 | }
83 | }
84 |
85 | public void log(Level level, String msg) {
86 | switch (level) {
87 | case TRACE :
88 | Log.v(className, msg);
89 | break;
90 | case DEBUG :
91 | Log.d(className, msg);
92 | break;
93 | case INFO :
94 | Log.i(className, msg);
95 | break;
96 | case WARNING :
97 | Log.w(className, msg);
98 | break;
99 | case ERROR :
100 | Log.e(className, msg);
101 | break;
102 | case FATAL :
103 | Log.e(className, msg);
104 | break;
105 | default :
106 | Log.i(className, msg);
107 | break;
108 | }
109 | }
110 |
111 | public void log(Level level, String msg, Throwable t) {
112 | switch (level) {
113 | case TRACE :
114 | Log.v(className, msg, t);
115 | break;
116 | case DEBUG :
117 | Log.d(className, msg, t);
118 | break;
119 | case INFO :
120 | Log.i(className, msg, t);
121 | break;
122 | case WARNING :
123 | Log.w(className, msg, t);
124 | break;
125 | case ERROR :
126 | Log.e(className, msg, t);
127 | break;
128 | case FATAL :
129 | Log.e(className, msg, t);
130 | break;
131 | default :
132 | Log.i(className, msg, t);
133 | break;
134 | }
135 | }
136 |
137 | private void refreshLevelCache() {
138 | for (com.j256.ormlite.logger.Log.Level level : com.j256.ormlite.logger.Log.Level.values()) {
139 | int androidLevel = levelToAndroidLevel(level);
140 | if (androidLevel < levelCache.length) {
141 | levelCache[androidLevel] = isLevelEnabledInternal(androidLevel);
142 | }
143 | }
144 | }
145 |
146 | private boolean isLevelEnabledInternal(int androidLevel) {
147 | // this is supposedly expensive with an IO operation for each call so we cache them into levelCache[]
148 | return Log.isLoggable(className, androidLevel) || Log.isLoggable(ALL_LOGS_NAME, androidLevel);
149 | }
150 |
151 | private int levelToAndroidLevel(com.j256.ormlite.logger.Log.Level level) {
152 | switch (level) {
153 | case TRACE :
154 | return Log.VERBOSE;
155 | case DEBUG :
156 | return Log.DEBUG;
157 | case INFO :
158 | return Log.INFO;
159 | case WARNING :
160 | return Log.WARN;
161 | case ERROR :
162 | return Log.ERROR;
163 | case FATAL :
164 | return Log.ERROR;
165 | default :
166 | return Log.INFO;
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/apptools/OrmLiteBaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.apptools;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 |
7 | import com.j256.ormlite.logger.Logger;
8 | import com.j256.ormlite.logger.LoggerFactory;
9 | import com.j256.ormlite.support.ConnectionSource;
10 |
11 | /**
12 | * Base class to use for activities in Android.
13 | *
14 | * You can simply call {@link #getHelper()} to get your helper class, or {@link #getConnectionSource()} to get a
15 | * {@link ConnectionSource}.
16 | *
17 | * The method {@link #getHelper()} assumes you are using the default helper factory -- see {@link OpenHelperManager}. If
18 | * not, you'll need to provide your own helper instances which will need to implement a reference counting scheme. This
19 | * method will only be called if you use the database, and only called once for this activity's life-cycle. 'close' will
20 | * also be called once for each call to createInstance.
21 | *
22 | * @author graywatson, kevingalligan
23 | */
24 | public abstract class OrmLiteBaseActivity extends Activity {
25 |
26 | private volatile H helper;
27 | private volatile boolean created = false;
28 | private volatile boolean destroyed = false;
29 | private static Logger logger = LoggerFactory.getLogger(OrmLiteBaseActivity.class);
30 |
31 | /**
32 | * Get a helper for this action.
33 | */
34 | public H getHelper() {
35 | if (helper == null) {
36 | if (!created) {
37 | throw new IllegalStateException("A call has not been made to onCreate() yet so the helper is null");
38 | } else if (destroyed) {
39 | throw new IllegalStateException(
40 | "A call to onDestroy has already been made and the helper cannot be used after that point");
41 | } else {
42 | throw new IllegalStateException("Helper is null for some unknown reason");
43 | }
44 | } else {
45 | return helper;
46 | }
47 | }
48 |
49 | /**
50 | * Get a connection source for this action.
51 | */
52 | public ConnectionSource getConnectionSource() {
53 | return getHelper().getConnectionSource();
54 | }
55 |
56 | @Override
57 | protected void onCreate(Bundle savedInstanceState) {
58 | if (helper == null) {
59 | helper = getHelperInternal(this);
60 | created = true;
61 | }
62 | super.onCreate(savedInstanceState);
63 | }
64 |
65 | @Override
66 | protected void onDestroy() {
67 | super.onDestroy();
68 | releaseHelper(helper);
69 | destroyed = true;
70 | }
71 |
72 | /**
73 | * This is called internally by the class to populate the helper object instance. This should not be called directly
74 | * by client code unless you know what you are doing. Use {@link #getHelper()} to get a helper instance. If you are
75 | * managing your own helper creation, override this method to supply this activity with a helper instance.
76 | *
77 | *
78 | * NOTE: If you override this method, you most likely will need to override the
79 | * {@link #releaseHelper(OrmLiteSqliteOpenHelper)} method as well.
80 | *
81 | */
82 | protected H getHelperInternal(Context context) {
83 | @SuppressWarnings({ "unchecked", "deprecation" })
84 | H newHelper = (H) OpenHelperManager.getHelper(context);
85 | logger.trace("{}: got new helper {} from OpenHelperManager", this, newHelper);
86 | return newHelper;
87 | }
88 |
89 | /**
90 | * Release the helper instance created in {@link #getHelperInternal(Context)}. You most likely will not need to call
91 | * this directly since {@link #onDestroy()} does it for you.
92 | *
93 | *
94 | * NOTE: If you override this method, you most likely will need to override the
95 | * {@link #getHelperInternal(Context)} method as well.
96 | *
97 | */
98 | protected void releaseHelper(H helper) {
99 | OpenHelperManager.releaseHelper();
100 | logger.trace("{}: helper {} was released, set to null", this, helper);
101 | this.helper = null;
102 | }
103 |
104 | @Override
105 | public String toString() {
106 | return getClass().getSimpleName() + "@" + Integer.toHexString(super.hashCode());
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/apptools/OrmLiteBaseActivityGroup.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.apptools;
2 |
3 | import android.app.ActivityGroup;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 |
7 | import com.j256.ormlite.support.ConnectionSource;
8 |
9 | /**
10 | * Base class to use for activity groups in Android.
11 | *
12 | * You can simply call {@link #getHelper()} to get your helper class, or {@link #getConnectionSource()} to get a
13 | * {@link ConnectionSource}.
14 | *
15 | * The method {@link #getHelper()} assumes you are using the default helper factory -- see {@link OpenHelperManager}. If
16 | * not, you'll need to provide your own helper instances which will need to implement a reference counting scheme. This
17 | * method will only be called if you use the database, and only called once for this activity's life-cycle. 'close' will
18 | * also be called once for each call to createInstance.
19 | *
20 | * @author graywatson, kevingalligan
21 | */
22 | public abstract class OrmLiteBaseActivityGroup extends ActivityGroup {
23 |
24 | private volatile H helper;
25 | private volatile boolean created = false;
26 | private volatile boolean destroyed = false;
27 |
28 | /**
29 | * Get a helper for this action.
30 | */
31 | public H getHelper() {
32 | if (helper == null) {
33 | if (!created) {
34 | throw new IllegalStateException("A call has not been made to onCreate() yet so the helper is null");
35 | } else if (destroyed) {
36 | throw new IllegalStateException(
37 | "A call to onDestroy has already been made and the helper cannot be used after that point");
38 | } else {
39 | throw new IllegalStateException("Helper is null for some unknown reason");
40 | }
41 | } else {
42 | return helper;
43 | }
44 | }
45 |
46 | /**
47 | * Get a connection source for this action.
48 | */
49 | public ConnectionSource getConnectionSource() {
50 | return getHelper().getConnectionSource();
51 | }
52 |
53 | @Override
54 | protected void onCreate(Bundle savedInstanceState) {
55 | if (helper == null) {
56 | helper = getHelperInternal(this);
57 | created = true;
58 | }
59 | super.onCreate(savedInstanceState);
60 | }
61 |
62 | @Override
63 | protected void onDestroy() {
64 | super.onDestroy();
65 | releaseHelper(helper);
66 | destroyed = true;
67 | }
68 |
69 | /**
70 | * This is called internally by the class to populate the helper object instance. This should not be called directly
71 | * by client code unless you know what you are doing. Use {@link #getHelper()} to get a helper instance. If you are
72 | * managing your own helper creation, override this method to supply this activity with a helper instance.
73 | *
74 | *
75 | * NOTE: If you override this method, you most likely will need to override the
76 | * {@link #releaseHelper(OrmLiteSqliteOpenHelper)} method as well.
77 | *
78 | */
79 | protected H getHelperInternal(Context context) {
80 | @SuppressWarnings({ "unchecked", "deprecation" })
81 | H newHelper = (H) OpenHelperManager.getHelper(context);
82 | return newHelper;
83 | }
84 |
85 | /**
86 | * Release the helper instance created in {@link #getHelperInternal(Context)}. You most likely will not need to call
87 | * this directly since {@link #onDestroy()} does it for you.
88 | *
89 | *
90 | * NOTE: If you override this method, you most likely will need to override the
91 | * {@link #getHelperInternal(Context)} method as well.
92 | *
93 | */
94 | protected void releaseHelper(H helper) {
95 | OpenHelperManager.releaseHelper();
96 | this.helper = null;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/apptools/OrmLiteBaseListActivity.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.apptools;
2 |
3 | import android.app.ListActivity;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 |
7 | import com.j256.ormlite.support.ConnectionSource;
8 |
9 | /**
10 | * Base class to use for Tab activities in Android.
11 | *
12 | * For more information, see {@link OrmLiteBaseActivity}.
13 | *
14 | * @author graywatson, kevingalligan
15 | */
16 | public abstract class OrmLiteBaseListActivity extends ListActivity {
17 |
18 | private volatile H helper;
19 | private volatile boolean created = false;
20 | private volatile boolean destroyed = false;
21 |
22 | /**
23 | * Get a helper for this action.
24 | */
25 | public H getHelper() {
26 | if (helper == null) {
27 | if (!created) {
28 | throw new IllegalStateException("A call has not been made to onCreate() yet so the helper is null");
29 | } else if (destroyed) {
30 | throw new IllegalStateException(
31 | "A call to onDestroy has already been made and the helper cannot be used after that point");
32 | } else {
33 | throw new IllegalStateException("Helper is null for some unknown reason");
34 | }
35 | } else {
36 | return helper;
37 | }
38 | }
39 |
40 | /**
41 | * Get a connection source for this action.
42 | */
43 | public ConnectionSource getConnectionSource() {
44 | return getHelper().getConnectionSource();
45 | }
46 |
47 | @Override
48 | protected void onCreate(Bundle savedInstanceState) {
49 | if (helper == null) {
50 | helper = getHelperInternal(this);
51 | created = true;
52 | }
53 | super.onCreate(savedInstanceState);
54 | }
55 |
56 | @Override
57 | protected void onDestroy() {
58 | super.onDestroy();
59 | releaseHelper(helper);
60 | destroyed = true;
61 | }
62 |
63 | /**
64 | * This is called internally by the class to populate the helper object instance. This should not be called directly
65 | * by client code unless you know what you are doing. Use {@link #getHelper()} to get a helper instance. If you are
66 | * managing your own helper creation, override this method to supply this activity with a helper instance.
67 | *
68 | *
69 | * NOTE: If you override this method, you most likely will need to override the
70 | * {@link #releaseHelper(OrmLiteSqliteOpenHelper)} method as well.
71 | *
72 | */
73 | protected H getHelperInternal(Context context) {
74 | @SuppressWarnings({ "unchecked", "deprecation" })
75 | H newHelper = (H) OpenHelperManager.getHelper(context);
76 | return newHelper;
77 | }
78 |
79 | /**
80 | * Release the helper instance created in {@link #getHelperInternal(Context)}. You most likely will not need to call
81 | * this directly since {@link #onDestroy()} does it for you.
82 | *
83 | *
84 | * NOTE: If you override this method, you most likely will need to override the
85 | * {@link #getHelperInternal(Context)} method as well.
86 | *
87 | */
88 | protected void releaseHelper(H helper) {
89 | OpenHelperManager.releaseHelper();
90 | this.helper = null;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/apptools/OrmLiteBaseService.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.apptools;
2 |
3 | import android.app.Service;
4 | import android.content.Context;
5 |
6 | import com.j256.ormlite.support.ConnectionSource;
7 |
8 | /**
9 | * Base class to use for services in Android.
10 | *
11 | * For more information, see {@link OrmLiteBaseActivity}.
12 | *
13 | * @author graywatson, kevingalligan
14 | */
15 | public abstract class OrmLiteBaseService extends Service {
16 |
17 | private volatile H helper;
18 | private volatile boolean created = false;
19 | private volatile boolean destroyed = false;
20 |
21 | /**
22 | * Get a helper for this action.
23 | */
24 | public H getHelper() {
25 | if (helper == null) {
26 | if (!created) {
27 | throw new IllegalStateException("A call has not been made to onCreate() yet so the helper is null");
28 | } else if (destroyed) {
29 | throw new IllegalStateException(
30 | "A call to onDestroy has already been made and the helper cannot be used after that point");
31 | } else {
32 | throw new IllegalStateException("Helper is null for some unknown reason");
33 | }
34 | } else {
35 | return helper;
36 | }
37 | }
38 |
39 | /**
40 | * Get a connection source for this action.
41 | */
42 | public ConnectionSource getConnectionSource() {
43 | return getHelper().getConnectionSource();
44 | }
45 |
46 | @Override
47 | public void onCreate() {
48 | if (helper == null) {
49 | helper = getHelperInternal(this);
50 | created = true;
51 | }
52 | super.onCreate();
53 | }
54 |
55 | @Override
56 | public void onDestroy() {
57 | super.onDestroy();
58 | releaseHelper(helper);
59 | destroyed = true;
60 | }
61 |
62 | /**
63 | * This is called internally by the class to populate the helper object instance. This should not be called directly
64 | * by client code unless you know what you are doing. Use {@link #getHelper()} to get a helper instance. If you are
65 | * managing your own helper creation, override this method to supply this activity with a helper instance.
66 | *
67 | *
68 | * NOTE: If you override this method, you most likely will need to override the
69 | * {@link #releaseHelper(OrmLiteSqliteOpenHelper)} method as well.
70 | *
71 | */
72 | protected H getHelperInternal(Context context) {
73 | @SuppressWarnings({ "unchecked", "deprecation" })
74 | H newHelper = (H) OpenHelperManager.getHelper(context);
75 | return newHelper;
76 | }
77 |
78 | /**
79 | * Release the helper instance created in {@link #getHelperInternal(Context)}. You most likely will not need to call
80 | * this directly since {@link #onDestroy()} does it for you.
81 | *
82 | *
83 | * NOTE: If you override this method, you most likely will need to override the
84 | * {@link #getHelperInternal(Context)} method as well.
85 | *
86 | */
87 | protected void releaseHelper(H helper) {
88 | OpenHelperManager.releaseHelper();
89 | this.helper = null;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/apptools/OrmLiteBaseTabActivity.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.apptools;
2 |
3 | import android.app.TabActivity;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 |
7 | import com.j256.ormlite.support.ConnectionSource;
8 |
9 | /**
10 | * Base class to use for Tab activities in Android.
11 | *
12 | * For more information, see {@link OrmLiteBaseActivity}.
13 | *
14 | * @author graywatson, kevingalligan
15 | */
16 | public abstract class OrmLiteBaseTabActivity extends TabActivity {
17 |
18 | private volatile H helper;
19 | private volatile boolean created = false;
20 | private volatile boolean destroyed = false;
21 |
22 | /**
23 | * Get a helper for this action.
24 | */
25 | public H getHelper() {
26 | if (helper == null) {
27 | if (!created) {
28 | throw new IllegalStateException("A call has not been made to onCreate() yet so the helper is null");
29 | } else if (destroyed) {
30 | throw new IllegalStateException(
31 | "A call to onDestroy has already been made and the helper cannot be used after that point");
32 | } else {
33 | throw new IllegalStateException("Helper is null for some unknown reason");
34 | }
35 | } else {
36 | return helper;
37 | }
38 | }
39 |
40 | /**
41 | * Get a connection source for this action.
42 | */
43 | public ConnectionSource getConnectionSource() {
44 | return getHelper().getConnectionSource();
45 | }
46 |
47 | @Override
48 | protected void onCreate(Bundle savedInstanceState) {
49 | if (helper == null) {
50 | helper = getHelperInternal(this);
51 | created = true;
52 | }
53 | super.onCreate(savedInstanceState);
54 | }
55 |
56 | @Override
57 | protected void onDestroy() {
58 | super.onDestroy();
59 | releaseHelper(helper);
60 | destroyed = true;
61 | }
62 |
63 | /**
64 | * This is called internally by the class to populate the helper object instance. This should not be called directly
65 | * by client code unless you know what you are doing. Use {@link #getHelper()} to get a helper instance. If you are
66 | * managing your own helper creation, override this method to supply this activity with a helper instance.
67 | *
68 | *
69 | * NOTE: If you override this method, you most likely will need to override the
70 | * {@link #releaseHelper(OrmLiteSqliteOpenHelper)} method as well.
71 | *
72 | *
73 | * @see OpenHelperManager#getHelper(Context)
74 | */
75 | protected H getHelperInternal(Context context) {
76 | @SuppressWarnings({ "unchecked", "deprecation" })
77 | H newHelper = (H) OpenHelperManager.getHelper(context);
78 | return newHelper;
79 | }
80 |
81 | /**
82 | * Release the helper instance created in {@link #getHelperInternal(Context)}. You most likely will not need to call
83 | * this directly since {@link #onDestroy()} does it for you.
84 | *
85 | *
86 | * NOTE: If you override this method, you most likely will need to override the
87 | * {@link #getHelperInternal(Context)} method as well.
88 | *
36 | * With help from the user list and especially Ian Dees, we discovered that calls to annotation methods in Android are
37 | * _very_ expensive because Method.equals() was doing a huge toString(). This was causing folks to see 2-3 seconds
38 | * startup time when configuring 10-15 DAOs because of 1000s of calls to @DatabaseField methods. See this Android bug report.
40 | *
41 | *
42 | *
43 | * I added this utility class which writes a configuration file into the raw resource "res/raw" directory inside of your
44 | * project containing the table and field names and associated details. This file can then be loaded into the
45 | * {@link DaoManager} with the help of the
46 | * {@link OrmLiteSqliteOpenHelper#OrmLiteSqliteOpenHelper(android.content.Context, String, SQLiteDatabase.CursorFactory, int, int)}
47 | * constructor. This means that you can configure your classes _without_ any runtime calls to annotations. It seems
48 | * significantly faster.
49 | *
50 | *
51 | *
52 | * WARNING: Although this is fast, the big problem is that you have to remember to regenerate the config file
53 | * whenever you edit one of your database classes. There is no way that I know of to do this automagically.
54 | *
55 | *
56 | * @author graywatson
57 | */
58 | public class OrmLiteConfigUtil {
59 |
60 | /**
61 | * Resource directory name that we are looking for.
62 | */
63 | protected static final String RESOURCE_DIR_NAME = "res";
64 | /**
65 | * Raw directory name that we are looking for.
66 | */
67 | protected static final String RAW_DIR_NAME = "raw";
68 |
69 | /**
70 | * Maximum recursion level while we are looking for source files.
71 | */
72 | protected static int maxFindSourceLevel = 20;
73 |
74 | private static final DatabaseType databaseType = new SqliteAndroidDatabaseType();
75 |
76 | /**
77 | * A call through to {@link #writeConfigFile(String)} taking the file name from the single command line argument.
78 | */
79 | public static void main(String[] args) throws Exception {
80 | if (args.length != 1) {
81 | throw new IllegalArgumentException("Main can take a single file-name argument.");
82 | }
83 | writeConfigFile(args[0]);
84 | }
85 |
86 | /**
87 | * Finds the annotated classes in the current directory or below and writes a configuration file to the file-name in
88 | * the raw folder.
89 | */
90 | public static void writeConfigFile(String fileName) throws SQLException, IOException {
91 | List> classList = new ArrayList>();
92 | findAnnotatedClasses(classList, new File("."), 0);
93 | writeConfigFile(fileName, classList.toArray(new Class[classList.size()]));
94 | }
95 |
96 | /**
97 | * Writes a configuration fileName in the raw directory with the configuration for classes.
98 | */
99 | public static void writeConfigFile(String fileName, Class>[] classes) throws SQLException, IOException {
100 | File rawDir = findRawDir(new File("."));
101 | if (rawDir == null) {
102 | System.err.println("Could not find " + RAW_DIR_NAME + " directory which is typically in the "
103 | + RESOURCE_DIR_NAME + " directory");
104 | } else {
105 | File configFile = new File(rawDir, fileName);
106 | writeConfigFile(configFile, classes);
107 | }
108 | }
109 |
110 | /**
111 | * Finds the annotated classes in the current directory or below and writes a configuration file.
112 | */
113 | public static void writeConfigFile(File configFile) throws SQLException, IOException {
114 | writeConfigFile(configFile, new File("."));
115 | }
116 |
117 | /**
118 | * Finds the annotated classes in the specified search directory or below and writes a configuration file.
119 | */
120 | public static void writeConfigFile(File configFile, File searchDir) throws SQLException, IOException {
121 | List> classList = new ArrayList>();
122 | findAnnotatedClasses(classList, searchDir, 0);
123 | writeConfigFile(configFile, classList.toArray(new Class[classList.size()]));
124 | }
125 |
126 | /**
127 | * Write a configuration file with the configuration for classes.
128 | */
129 | public static void writeConfigFile(File configFile, Class>[] classes) throws SQLException, IOException {
130 | System.out.println("Writing configurations to " + configFile.getAbsolutePath());
131 | writeConfigFile(new FileOutputStream(configFile), classes);
132 | }
133 |
134 | /**
135 | * Write a configuration file to an output stream with the configuration for classes.
136 | */
137 | public static void writeConfigFile(OutputStream outputStream, File searchDir) throws SQLException, IOException {
138 | List> classList = new ArrayList>();
139 | findAnnotatedClasses(classList, searchDir, 0);
140 | writeConfigFile(outputStream, classList.toArray(new Class[classList.size()]));
141 | }
142 |
143 | /**
144 | * Write a configuration file to an output stream with the configuration for classes.
145 | */
146 | public static void writeConfigFile(OutputStream outputStream, Class>[] classes) throws SQLException, IOException {
147 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream), 4096);
148 | try {
149 | writeHeader(writer);
150 | for (Class> clazz : classes) {
151 | writeConfigForTable(writer, clazz);
152 | }
153 | // NOTE: done is here because this is public
154 | System.out.println("Done.");
155 | } finally {
156 | writer.close();
157 | }
158 | }
159 |
160 | /**
161 | * Look for the resource-directory in the current directory or the directories above. Then look for the
162 | * raw-directory underneath the resource-directory.
163 | */
164 | protected static File findRawDir(File dir) {
165 | for (int i = 0; dir != null && i < 20; i++) {
166 | File rawDir = findResRawDir(dir);
167 | if (rawDir != null) {
168 | return rawDir;
169 | }
170 | dir = dir.getParentFile();
171 | }
172 | return null;
173 | }
174 |
175 | private static void writeHeader(BufferedWriter writer) throws IOException {
176 | writer.append('#');
177 | writer.newLine();
178 | writer.append("# generated on ").append(new SimpleDateFormat("yyyy/MM/dd hh:mm:ss").format(new Date()));
179 | writer.newLine();
180 | writer.append('#');
181 | writer.newLine();
182 | }
183 |
184 | private static void findAnnotatedClasses(List> classList, File dir, int level) throws SQLException,
185 | IOException {
186 | for (File file : dir.listFiles()) {
187 | if (file.isDirectory()) {
188 | // recurse if we aren't deep enough
189 | if (level < maxFindSourceLevel) {
190 | findAnnotatedClasses(classList, file, level + 1);
191 | }
192 | continue;
193 | }
194 | // skip non .java files
195 | if (!file.getName().endsWith(".java")) {
196 | continue;
197 | }
198 | String packageName = getPackageOfClass(file);
199 | if (packageName == null) {
200 | System.err.println("Could not find package name for: " + file);
201 | continue;
202 | }
203 | // get the filename and cut off the .java
204 | String name = file.getName();
205 | name = name.substring(0, name.length() - ".java".length());
206 | String className = packageName + "." + name;
207 | Class> clazz;
208 | try {
209 | clazz = Class.forName(className);
210 | } catch (Throwable t) {
211 | // amazingly, this sometimes throws an Error
212 | System.err.println("Could not load class file for: " + file);
213 | System.err.println(" " + t);
214 | continue;
215 | }
216 | if (classHasAnnotations(clazz)) {
217 | classList.add(clazz);
218 | }
219 | // handle inner classes
220 | try {
221 | for (Class> innerClazz : clazz.getDeclaredClasses()) {
222 | if (classHasAnnotations(innerClazz)) {
223 | classList.add(innerClazz);
224 | }
225 | }
226 | } catch (Throwable t) {
227 | // amazingly, this sometimes throws an Error
228 | System.err.println("Could not load inner classes for: " + clazz);
229 | System.err.println(" " + t);
230 | continue;
231 | }
232 | }
233 | }
234 |
235 | private static void writeConfigForTable(BufferedWriter writer, Class> clazz) throws SQLException, IOException {
236 | String tableName = DatabaseTableConfig.extractTableName(clazz);
237 | List fieldConfigs = new ArrayList();
238 | // walk up the classes finding the fields
239 | try {
240 | for (Class> working = clazz; working != null; working = working.getSuperclass()) {
241 | for (Field field : working.getDeclaredFields()) {
242 | DatabaseFieldConfig fieldConfig = DatabaseFieldConfig.fromField(databaseType, tableName, field);
243 | if (fieldConfig != null) {
244 | fieldConfigs.add(fieldConfig);
245 | }
246 | }
247 | }
248 | } catch (Error e) {
249 | System.err.println("Skipping " + clazz + " because we got an error finding its definition: "
250 | + e.getMessage());
251 | return;
252 | }
253 | if (fieldConfigs.isEmpty()) {
254 | System.out.println("Skipping " + clazz + " because no annotated fields found");
255 | return;
256 | }
257 | @SuppressWarnings({ "rawtypes", "unchecked" })
258 | DatabaseTableConfig> tableConfig = new DatabaseTableConfig(clazz, tableName, fieldConfigs);
259 | DatabaseTableConfigLoader.write(writer, tableConfig);
260 | writer.append("#################################");
261 | writer.newLine();
262 | System.out.println("Wrote config for " + clazz);
263 | }
264 |
265 | private static boolean classHasAnnotations(Class> clazz) {
266 | while (clazz != null) {
267 | if (clazz.getAnnotation(DatabaseTable.class) != null) {
268 | return true;
269 | }
270 | Field[] fields;
271 | try {
272 | fields = clazz.getDeclaredFields();
273 | } catch (Throwable t) {
274 | // amazingly, this sometimes throws an Error
275 | System.err.println("Could not load get delcared fields from: " + clazz);
276 | System.err.println(" " + t);
277 | return false;
278 | }
279 | for (Field field : fields) {
280 | if (field.getAnnotation(DatabaseField.class) != null
281 | || field.getAnnotation(ForeignCollectionField.class) != null) {
282 | return true;
283 | }
284 | }
285 | try {
286 | clazz = clazz.getSuperclass();
287 | } catch (Throwable t) {
288 | // amazingly, this sometimes throws an Error
289 | System.err.println("Could not get super class for: " + clazz);
290 | System.err.println(" " + t);
291 | return false;
292 | }
293 | }
294 |
295 | return false;
296 | }
297 |
298 | /**
299 | * Returns the package name of a file that has one of the annotations we are looking for.
300 | *
301 | * @return Package prefix string or null or no annotations.
302 | */
303 | private static String getPackageOfClass(File file) throws IOException {
304 | BufferedReader reader = new BufferedReader(new FileReader(file));
305 | try {
306 | while (true) {
307 | String line = reader.readLine();
308 | if (line == null) {
309 | return null;
310 | }
311 | if (line.contains("package")) {
312 | String[] parts = line.split("[ \t;]");
313 | if (parts.length > 1 && parts[0].equals("package")) {
314 | return parts[1];
315 | }
316 | }
317 | }
318 | } finally {
319 | reader.close();
320 | }
321 | }
322 |
323 | /**
324 | * Look for the resource directory with raw beneath it.
325 | */
326 | private static File findResRawDir(File dir) {
327 | for (File file : dir.listFiles()) {
328 | if (file.getName().equals(RESOURCE_DIR_NAME) && file.isDirectory()) {
329 | File[] rawFiles = file.listFiles(new FileFilter() {
330 | public boolean accept(File file) {
331 | return file.getName().equals(RAW_DIR_NAME) && file.isDirectory();
332 | }
333 | });
334 | if (rawFiles.length == 1) {
335 | return rawFiles[0];
336 | }
337 | }
338 | }
339 | return null;
340 | }
341 | }
342 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/compat/ApiCompatibility.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.compat;
2 |
3 |
4 | import net.sqlcipher.Cursor;
5 | import net.sqlcipher.database.SQLiteDatabase;
6 |
7 | /**
8 | * Compatibility interface to support various different versions of the Android API.
9 | *
10 | * @author graywatson
11 | */
12 | public interface ApiCompatibility {
13 |
14 | /**
15 | * Perform a raw query on a database with an optional cancellation-hook.
16 | */
17 | public Cursor rawQuery(SQLiteDatabase db, String sql, String[] selectionArgs, CancellationHook cancellationHook);
18 |
19 | /**
20 | * Return a cancellation hook object that will be passed to the
21 | * {@link #rawQuery(SQLiteDatabase, String, String[], CancellationHook)}. If not supported then this will return
22 | * null.
23 | */
24 | public CancellationHook createCancellationHook();
25 |
26 | /**
27 | * Cancellation hook class returned by {@link ApiCompatibility#createCancellationHook()}.
28 | */
29 | public interface CancellationHook {
30 | /**
31 | * Cancel the associated query.
32 | */
33 | public void cancel();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/compat/ApiCompatibilityUtils.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.compat;
2 |
3 | import android.os.Build;
4 |
5 |
6 | /**
7 | * Utility class which loads the various classes based on which API version is being supported.
8 | *
9 | * @author graywatson
10 | */
11 | @SuppressWarnings("unused")
12 | public class ApiCompatibilityUtils {
13 |
14 | private static ApiCompatibility compatibility;
15 |
16 | /**
17 | * Copied from {@link Build.VERSION_CODES}. We don't use those codes because they won't be in certain versions of
18 | * Build.
19 | */
20 | private static final int BASE = 1;
21 | private static final int BASE_1_1 = 2;
22 | private static final int CUPCAKE = 3;
23 | private static final int DONUT = 4;
24 | private static final int ECLAIR = 5;
25 | private static final int ECLAIR_0_1 = 6;
26 | private static final int ECLAIR_MR1 = 7;
27 | private static final int FROYO = 8;
28 | private static final int GINGERBREAD = 9;
29 | private static final int GINGERBREAD_MR1 = 10;
30 | private static final int HONEYCOMB = 11;
31 | private static final int HONEYCOMB_MR1 = 12;
32 | private static final int HONEYCOMB_MR2 = 13;
33 | private static final int ICE_CREAM_SANDWICH = 14;
34 | private static final int ICE_CREAM_SANDWICH_MR1 = 15;
35 | private static final int JELLY_BEAN = 16;
36 | private static final int JELLY_BEAN_MR1 = 17;
37 | private static final int JELLY_BEAN_MR2 = 18;
38 |
39 | static {
40 | if (Build.VERSION.SDK_INT >= JELLY_BEAN) {
41 | compatibility = new com.j256.ormlite.sqlcipher.android.compat.JellyBeanApiCompatibility();
42 | } else {
43 | compatibility = new com.j256.ormlite.sqlcipher.android.compat.BasicApiCompatibility();
44 | }
45 | }
46 |
47 | /**
48 | * Return the compatibility class that matches our build number.
49 | */
50 | public static ApiCompatibility getCompatibility() {
51 | return compatibility;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/compat/BasicApiCompatibility.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.compat;
2 |
3 |
4 | import net.sqlcipher.Cursor;
5 | import net.sqlcipher.database.SQLiteDatabase;
6 |
7 | /**
8 | * Basic class which provides no-op methods for all Android version.
9 | *
10 | * @author graywatson
11 | */
12 | public class BasicApiCompatibility implements ApiCompatibility {
13 |
14 | public Cursor rawQuery(SQLiteDatabase db, String sql, String[] selectionArgs, CancellationHook cancellationHook) {
15 | // NOTE: cancellationHook will always be null
16 | return db.rawQuery(sql, selectionArgs);
17 | }
18 |
19 | public CancellationHook createCancellationHook() {
20 | return null;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/android/compat/JellyBeanApiCompatibility.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.android.compat;
2 |
3 | import android.annotation.TargetApi;
4 | import android.os.Build;
5 | import android.os.CancellationSignal;
6 |
7 | import net.sqlcipher.Cursor;
8 | import net.sqlcipher.database.SQLiteDatabase;
9 |
10 | /**
11 | * Basic class which provides no-op methods for all Android version.
12 | *
13 | *
14 | * NOTE: Will show as in error if compiled with previous Android versions.
15 | *
16 | *
17 | * @author graywatson
18 | */
19 | public class JellyBeanApiCompatibility extends BasicApiCompatibility {
20 |
21 | @Override
22 | public Cursor rawQuery(SQLiteDatabase db, String sql, String[] selectionArgs, CancellationHook cancellationHook) {
23 | // NOTE: in patched version this is the same as BasicApiCompatibility
24 | // because SqlCipher supports Android version lower than API level 16 (Jelly Bean)
25 | // if (cancellationHook == null) {
26 | return db.rawQuery(sql, selectionArgs);
27 | // } else {
28 | // return db.rawQuery(sql, selectionArgs, ((JellyBeanCancellationHook) cancellationHook).cancellationSignal);
29 | // }
30 | }
31 |
32 | @Override
33 | public CancellationHook createCancellationHook() {
34 | return new JellyBeanCancellationHook();
35 | }
36 |
37 | protected static class JellyBeanCancellationHook implements CancellationHook {
38 |
39 | private final CancellationSignal cancellationSignal;
40 |
41 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
42 | public JellyBeanCancellationHook() {
43 | this.cancellationSignal = new CancellationSignal();
44 | }
45 |
46 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
47 | public void cancel() {
48 | cancellationSignal.cancel();
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/java/com/j256/ormlite/sqlcipher/db/SqliteAndroidDatabaseType.java:
--------------------------------------------------------------------------------
1 | package com.j256.ormlite.sqlcipher.db;
2 |
3 | import com.j256.ormlite.db.BaseSqliteDatabaseType;
4 | import com.j256.ormlite.field.DataPersister;
5 | import com.j256.ormlite.field.FieldConverter;
6 | import com.j256.ormlite.field.FieldType;
7 | import com.j256.ormlite.field.types.DateStringType;
8 | import com.j256.ormlite.sqlcipher.android.DatabaseTableConfigUtil;
9 | import com.j256.ormlite.support.ConnectionSource;
10 | import com.j256.ormlite.table.DatabaseTableConfig;
11 |
12 | import java.sql.SQLException;
13 |
14 | /**
15 | * Sqlite database type information for the Android OS that makes native calls to the Android OS database APIs.
16 | *
17 | * @author graywatson
18 | */
19 | public class SqliteAndroidDatabaseType extends BaseSqliteDatabaseType {
20 |
21 | @Override
22 | public void loadDriver() {
23 | // noop
24 | }
25 |
26 | public boolean isDatabaseUrlThisType(String url, String dbTypePart) {
27 | // not used by the android code
28 | return true;
29 | }
30 |
31 | @Override
32 | protected String getDriverClassName() {
33 | // no driver to load in android-land
34 | return null;
35 | }
36 |
37 | public String getDatabaseName() {
38 | return "Android SQLite";
39 | }
40 |
41 | @Override
42 | protected void appendDateType(StringBuilder sb, FieldType fieldType, int fieldWidth) {
43 | // default is to store the date as a string
44 | appendStringType(sb, fieldType, fieldWidth);
45 | }
46 |
47 | @Override
48 | protected void appendBooleanType(StringBuilder sb, FieldType fieldType, int fieldWidth) {
49 | // we have to convert booleans to numbers
50 | appendShortType(sb, fieldType, fieldWidth);
51 | }
52 |
53 | @Override
54 | public FieldConverter getFieldConverter(DataPersister dataPersister) {
55 | // we are only overriding certain types
56 | switch (dataPersister.getSqlType()) {
57 | case DATE :
58 | return DateStringType.getSingleton();
59 | default :
60 | return super.getFieldConverter(dataPersister);
61 | }
62 | }
63 |
64 | @Override
65 | public boolean isNestedSavePointsSupported() {
66 | return false;
67 | }
68 |
69 | @Override
70 | public boolean isBatchUseTransaction() {
71 | return true;
72 | }
73 |
74 | @Override
75 | public DatabaseTableConfig extractDatabaseTableConfig(ConnectionSource connectionSource, Class clazz)
76 | throws SQLException {
77 | return DatabaseTableConfigUtil.fromClass(connectionSource, clazz);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/sqlcipher/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | database
3 |
4 |
--------------------------------------------------------------------------------