Răsfoiți Sursa

Database locked issues fixed. Small UI improvements.

Iñigo Valentin 9 ani în urmă
părinte
comite
4c81a98a57

+ 2 - 2
app/src/main/AndroidManifest.xml

@@ -2,8 +2,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="com.ivalentin.margolariak"
-    android:versionCode="23"
-    android:versionName="3.0.2" >
+    android:versionCode="24"
+    android:versionName="3.0.3" >
 
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

+ 48 - 86
app/src/main/java/com/ivalentin/margolariak/AlarmReceiver.java

@@ -11,6 +11,7 @@ import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabaseLockedException;
 import android.graphics.BitmapFactory;
 import android.media.RingtoneManager;
 import android.support.v4.app.NotificationCompat;
@@ -59,11 +60,21 @@ public class AlarmReceiver extends BroadcastReceiver {
 				String o = fu.getOutput().toString();
 
 				//Open database
-				SQLiteDatabase db = context.openOrCreateDatabase(GM.DB.NAME, Activity.MODE_PRIVATE, null);
-				if (db.isReadOnly()){
-					Log.e("NOTIFICATIONS", "Database is locked and in read only mode.");
+				SQLiteDatabase db;
+				try {
+					db = context.openOrCreateDatabase(GM.DB.NAME, Activity.MODE_PRIVATE, null);
+					if (db.isReadOnly()) {
+						Log.e("NOTIFICATIONS", "Database is locked and in read only mode. Not reading new notifications now, but I'll try to sync.");
+						new Sync(context).execute(); // Sync before exiting.
+						return;
+					}
+				}
+				catch(SQLiteDatabaseLockedException ex){
+					Log.e("NOTIFICATIONS", "Database is locked and in read only mode. Not reading new notifications now, but I'll try to sync.");
+					new Sync(context).execute(); // Sync before exiting.
 					return;
 				}
+
 				Cursor cursor;
 
 				//Variables for parsing
@@ -82,12 +93,12 @@ public class AlarmReceiver extends BroadcastReceiver {
 
 					//Extract data
 					id = Integer.valueOf(not.substring(not.indexOf("\"id\":") + 6, not.indexOf("\",")));
-					title_es = not.substring(not.indexOf("\"title_es\":") + 12, not.indexOf("\"", not.indexOf("\"title_es\":") + 13));
-					title_en = not.substring(not.indexOf("\"title_en\":") + 12, not.indexOf("\"", not.indexOf("\"title_en\":") + 13));
-					title_eu = not.substring(not.indexOf("\"title_eu\":") + 12, not.indexOf("\"", not.indexOf("\"title_eu\":") + 13));
-					text_es = not.substring(not.indexOf("\"text_es\":") + 11, not.indexOf("\"", not.indexOf("\"text_es\":") + 12));
-					text_en = not.substring(not.indexOf("\"text_en\":") + 11, not.indexOf("\"", not.indexOf("\"text_en\":") + 12));
-					text_eu = not.substring(not.indexOf("\"text_eu\":") + 11, not.indexOf("\"", not.indexOf("\"text_eu\":") + 12));
+					title_es = decode(not.substring(not.indexOf("\"title_es\":") + 12, not.indexOf("\"", not.indexOf("\"title_es\":") + 13)));
+					title_en = decode(not.substring(not.indexOf("\"title_en\":") + 12, not.indexOf("\"", not.indexOf("\"title_en\":") + 13)));
+					title_eu = decode(not.substring(not.indexOf("\"title_eu\":") + 12, not.indexOf("\"", not.indexOf("\"title_eu\":") + 13)));
+					text_es = decode(not.substring(not.indexOf("\"text_es\":") + 11, not.indexOf("\"", not.indexOf("\"text_es\":") + 12)));
+					text_en = decode(not.substring(not.indexOf("\"text_en\":") + 11, not.indexOf("\"", not.indexOf("\"text_en\":") + 12)));
+					text_eu = decode(not.substring(not.indexOf("\"text_eu\":") + 11, not.indexOf("\"", not.indexOf("\"text_eu\":") + 12)));
 					dtime = not.substring(not.indexOf("\"dtime\":") + 9, not.indexOf("\"", not.indexOf("\"dtime\":") + 10));
 					action = not.substring(not.indexOf("\"action\":") + 10, not.indexOf("\"", not.indexOf("\"action\":") + 11));
 					gm = Integer.valueOf(not.substring(not.indexOf("\"gm\":") + 6, not.indexOf("\"", not.indexOf("\"gm\":") + 7)));
@@ -116,6 +127,9 @@ public class AlarmReceiver extends BroadcastReceiver {
 								break;
 						}
 
+						title = decode(title);
+						text = decode(text);
+
 						//Get the notification manager ready
 						NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
 
@@ -165,83 +179,6 @@ public class AlarmReceiver extends BroadcastReceiver {
 				}
 				db.close();
 
-
-
-
-				//Parse info
-				/*String o = fu.getOutput().toString();
-				while (o.contains("<notification>")){
-					//Get non-language-dependant fields
-					String notification = o.substring(o.indexOf("<notification>") + 14, o.indexOf("</notification>"));
-					String id = notification.substring(notification.indexOf("<id>") + 4, notification.indexOf("</id>"));
-					String action = notification.substring(notification.indexOf("<action>") + 8, notification.indexOf("</action>"));
-
-					//Is the notification seen already?
-					//TODO: Create a db table for this
-
-					//Get data from database
-					SQLiteDatabase db = SQLiteDatabase.openDatabase(context.getDatabasePath(GM.DB.NAME).getAbsolutePath(), null, SQLiteDatabase.NO_LOCALIZED_COLLATORS | SQLiteDatabase.OPEN_READONLY);
-					final Cursor cursor;
-					cursor = db.rawQuery("SELECT id, seen FROM notification WHERE id = " + id + ";", null);
-					if (cursor.getCount() == 0){
-
-					}
-					else {
-
-						if (cursor.getInt(1) == 0) {
-
-
-							String lang = GM.getLang();
-							String title = notification.substring(notification.indexOf("<title_" + lang + ">") + 10, notification.indexOf("</title_" + lang + ">"));
-							String text = notification.substring(notification.indexOf("<text_" + lang + ">") + 9, notification.indexOf("</text_" + lang + ">"));
-
-
-							//Get the notification manager ready
-							NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-
-							//Variables to create intents for each notification
-							Intent resultIntent;
-							TaskStackBuilder stackBuilder;
-
-							//Send the notification.
-							NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
-									.setSmallIcon(R.drawable.ic_notification)
-									.setContentTitle(title)
-									.setAutoCancel(true)
-									.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher))
-									.setVibrate((new long[]{400, 400, 400}))
-									.setColor(context.getResources().getColor(R.color.background_notification))
-									.setSubText(context.getString(R.string.app_name))
-									.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
-									.setContentText(text);
-
-							// Creates an intent for an Activity to be launched from the notification.
-							resultIntent = new Intent(context, MainActivity.class);
-							resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
-
-							//Set extras depending on type.
-							resultIntent.putExtra(GM.EXTRA.TEXT, text);
-							resultIntent.putExtra(GM.EXTRA.TITLE, title);
-							resultIntent.putExtra(GM.EXTRA.ACTION, action);
-
-							//Add the intent to the notification.
-							stackBuilder = TaskStackBuilder.create(context);
-							stackBuilder.addParentStack(MainActivity.class);
-
-							// Adds the Intent that starts the Activity to the top of the stack.
-							stackBuilder.addNextIntent(resultIntent);
-							PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
-							mBuilder.setContentIntent(resultPendingIntent);
-
-							//Actually send the notification.
-							mNotificationManager.notify(Integer.parseInt(id), mBuilder.build());
-
-							//Mark as notified
-							db.execSQL("UPDATE notification SET seen = 1 WHERE id = " + id);
-						}
-					}
-				o = o.substring(o.indexOf("</notification>") + 15);
-				}*/
 			}
 			catch(NumberFormatException ex) {
 				Log.e("NOTIFICATION", "Error parsing remote file: " + ex.toString());
@@ -255,6 +192,31 @@ public class AlarmReceiver extends BroadcastReceiver {
 		new Sync(context).execute();
     }
 
+		/**
+		 * Decodes unicode characters from a string.
+		 * Useful for JSON encoded strings.
+		 * @param in String to be decoded.
+		 * @return Decoded string.
+		 */
+		static final String decode(final String in){
+			String working = in;
+			int index = working.indexOf("\\u");
+			while(index > -1){
+				int length = working.length();
+					if(index > (length-6))
+						break;
+				int numStart = index + 2;
+				int numFinish = numStart + 4;
+				String substring = working.substring(numStart, numFinish);
+				int number = Integer.parseInt(substring,16);
+				String stringStart = working.substring(0, index);
+				String stringEnd   = working.substring(numFinish);
+				working = stringStart + ((char)number) + stringEnd;
+				index = working.indexOf("\\u");
+			}
+			return working;
+		}
+
     /**
      * Sets a repeating alarm. 
      * When the alarm fires, the app broadcasts an Intent to this WakefulBroadcastReceiver.

+ 1 - 2
app/src/main/java/com/ivalentin/margolariak/HomeLayout.java

@@ -214,8 +214,7 @@ public class HomeLayout extends Fragment implements LocationListener {
 
 			//Set time
 			tvRowTime = (TextView) entry.findViewById(R.id.tv_row_home_schedule_time);
-			String tm = cursorNow.getString(4).substring(cursorNow.getString(4).length() - 8, cursorNow.getString(4).length() - 3);
-			tvRowTime.setText(tm);
+			tvRowTime.setVisibility(View.GONE);
 
 			//Add the view
 			listNow.addView(entry);

+ 6 - 5
app/src/main/java/com/ivalentin/margolariak/ScheduleLayout.java

@@ -55,7 +55,7 @@ public class ScheduleLayout extends Fragment implements OnMapReadyCallback{
 
 	private Bundle bund;
 
-	private final String dates[] = new String[20];
+	private final String dates[] = new String[40];
 	private int dateCount = 0;
 	private int selected = 0;
 
@@ -135,10 +135,11 @@ public class ScheduleLayout extends Fragment implements OnMapReadyCallback{
 
 		//Log.e("Cur Date", curDate);
 		while (cursor.moveToNext()){
-			dates[dateCount] = cursor.getString(0);
-			//TODO: Check if some date is of today, and set selected
-			if (curDate.equals(cursor.getString(0))){
-				selected = dateCount;
+			if (dateCount < 40) {
+				dates[dateCount] = cursor.getString(0);
+				if (curDate.equals(cursor.getString(0))) {
+					selected = dateCount;
+				}
 			}
 			dateCount ++;
 		}

+ 13 - 5
app/src/main/java/com/ivalentin/margolariak/Sync.java

@@ -19,6 +19,7 @@ import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabaseLockedException;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.os.AsyncTask;
@@ -292,7 +293,7 @@ class Sync extends AsyncTask<Void, Void, Void> {
 	private boolean recreateDb(SQLiteDatabase db) {
 		boolean result = true;
 		try {
-			db.beginTransaction();
+			db.beginTransactionNonExclusive();
 			db.execSQL(GM.DB.QUERY.DROP.ACTIVITY);
 			db.execSQL(GM.DB.QUERY.DROP.ACTIVITY_COMMENT);
 			db.execSQL(GM.DB.QUERY.DROP.ACTIVITY_IMAGE);
@@ -319,7 +320,7 @@ class Sync extends AsyncTask<Void, Void, Void> {
 			db.setTransactionSuccessful();
 			db.endTransaction();
 			publishProgress();
-			db.beginTransaction();
+			db.beginTransactionNonExclusive();
 			db.execSQL(GM.DB.QUERY.CREATE.ACTIVITY);
 			db.execSQL(GM.DB.QUERY.CREATE.ACTIVITY_COMMENT);
 			db.execSQL(GM.DB.QUERY.CREATE.ACTIVITY_IMAGE);
@@ -687,8 +688,15 @@ class Sync extends AsyncTask<Void, Void, Void> {
 		String userCode = preferences.getString(GM.DATA.KEY.USER, GM.DATA.DEFAULT.USER);
 
 		//Get database. Stop if it's locked
-		SQLiteDatabase db = myContextRef.openOrCreateDatabase(GM.DB.NAME, Activity.MODE_PRIVATE, null);
-		if (db.isReadOnly()){
+		SQLiteDatabase db;
+		try {
+			db = myContextRef.openOrCreateDatabase(GM.DB.NAME, Activity.MODE_PRIVATE, null);
+			if (db.isReadOnly()) {
+				Log.e("SYNC", "Database is locked and in read only mode. Skipping sync.");
+				return null;
+			}
+		}
+		catch(SQLiteDatabaseLockedException ex){
 			Log.e("SYNC", "Database is locked and in read only mode. Skipping sync.");
 			return null;
 		}
@@ -756,7 +764,7 @@ class Sync extends AsyncTask<Void, Void, Void> {
 					publishProgress();
 
 					//If the data is correctly parsed and stored, commit changes to the database.
-					db.beginTransaction();
+					db.beginTransactionNonExclusive();
 
 
 					if (saveVersions(db, strVersion) && saveData(db, strData)){

+ 33 - 29
app/src/main/res/layout/fragment_layout_home.xml

@@ -125,41 +125,45 @@
 					android:adjustViewBounds="true"
 					android:contentDescription="@string/app_cdesc"
 					android:maxWidth="130dp"
-					android:minHeight="95dp"/>
+					android:minHeight="105dp"/>
 
-				<TextView
-					android:id="@+id/tv_home_section_lablanca_text"
+				<LinearLayout
 					android:layout_width="match_parent"
-					android:layout_height="wrap_content"
+					android:layout_height="match_parent"
 					android:layout_weight=".3"
-					android:maxLines="4"
-					android:padding="7dp"
-					android:textAppearance="@android:style/TextAppearance.Medium"/>
+					android:orientation="vertical"
+					>
 
-				<ImageView
-					android:layout_width="match_parent"
-					android:layout_height="40dp"
-					android:layout_marginTop="-40dp"
-					android:layout_weight="1"
-					android:background="@drawable/gradient_v_white"/>
+					<TextView
+						android:id="@+id/tv_home_section_lablanca_text"
+						android:layout_width="match_parent"
+						android:layout_height="80dp"
+						android:maxLines="4"
+						android:padding="7dp"
+						android:textAppearance="@android:style/TextAppearance.Medium"/>
 
-			</LinearLayout>
+					<ImageView
+						android:id="@+id/imageView6"
+						android:layout_width="match_parent"
+						android:layout_height="40dp"
+						android:layout_marginTop="-40dp"
+						android:background="@drawable/gradient_v_white"/>
+
+					<Button
+						android:id="@+id/bt_home_gm"
+						android:layout_width="match_parent"
+						android:layout_height="50dp"
+						android:layout_marginBottom="40dp"
+						android:layout_marginLeft="7dp"
+						android:layout_marginStart="7dp"
+						android:layout_marginTop="10dp"
+						android:background="@drawable/button_selector"
+						android:text="@string/lablanca_schedule_gm"
+						android:textColor="@color/input_button_color"
+						android:textStyle="bold"/>
+				</LinearLayout>
 
-			<Button
-				android:id="@+id/bt_home_gm"
-				android:layout_width="match_parent"
-				android:layout_height="wrap_content"
-				android:layout_marginBottom="20dp"
-				android:layout_marginEnd="50dp"
-				android:layout_marginLeft="50dp"
-				android:layout_marginRight="50dp"
-				android:layout_marginStart="50dp"
-				android:layout_marginTop="20dp"
-				android:layout_weight=".7"
-				android:background="@drawable/button_selector"
-				android:text="@string/lablanca_schedule_gm"
-				android:textColor="@color/input_button_color"
-				android:textStyle="bold"/>
+			</LinearLayout>
 
 		</LinearLayout>
 

+ 40 - 22
app/src/main/res/layout/row_home_schedule.xml

@@ -1,11 +1,18 @@
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
-    android:orientation="vertical"
     android:layout_margin="8dp"
-    android:padding="7dp">
+    android:orientation="vertical"
+    android:padding="7dp"
+    android:paddingBottom="7dp"
+    android:paddingEnd="7dp"
+    android:paddingLeft="25dp"
+    android:paddingRight="7dp"
+    android:paddingStart="25dp"
+    android:paddingTop="7dp">
 
     <TextView
         android:id="@+id/tv_row_home_schedule_id"
@@ -14,49 +21,60 @@
         android:visibility="gone"/>
 
     <LinearLayout
-        android:orientation="horizontal"
         android:layout_width="fill_parent"
-        android:layout_height="wrap_content">
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
 
         <TextView
-            android:id="@+id/tv_row_home_schedule_title"
-            android:layout_width="fill_parent"
+            android:id="@+id/tv_row_home_schedule_time"
+            android:layout_width="75dp"
             android:layout_height="wrap_content"
-            android:textAppearance="@android:style/TextAppearance.Large"
-            android:layout_weight=".3"
-            android:maxLines="2"/>
+            android:minWidth="75dp"
+            android:text="0000"
+            android:textAlignment="textEnd"
+            android:textAppearance="@android:style/TextAppearance.Medium"
+            android:textStyle="bold"/>
+
+        <ImageView
+            android:id="@+id/imageView5"
+            android:layout_width="15dp"
+            android:layout_height="match_parent"
+            android:layout_marginEnd="8dp"
+            android:layout_marginLeft="8dp"
+            android:layout_marginRight="8dp"
+            android:layout_marginStart="8dp"
+            android:adjustViewBounds="true"
+            android:src="@drawable/schedule_point"/>
 
         <TextView
-            android:id="@+id/tv_row_home_schedule_time"
-            android:layout_width="fill_parent"
+            android:id="@+id/tv_row_home_schedule_title"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginStart="20dp"
-            android:textAppearance="@android:style/TextAppearance.Medium"
-            android:minWidth="75dp"
-            android:layout_weight=".7"
-            android:textAlignment="textEnd"/>
+            android:maxLines="2"
+            android:textAppearance="@android:style/TextAppearance.Medium"/>
+
     </LinearLayout>
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="25dp"
-        android:layout_marginLeft="15dp"
-        android:layout_marginStart="15dp"
+        android:layout_marginBottom="10dp"
+        android:layout_marginLeft="55dp"
+        android:layout_marginStart="55dp"
         android:layout_marginTop="5dp"
         android:gravity="center_vertical"
         tools:ignore="UseCompoundDrawables">
 
         <ImageView
             android:id="@+id/iv_row_home_schedule_pinpoint"
-            android:layout_width="30dp"
-            android:layout_height="30dp"
+            android:layout_width="20dp"
+            android:layout_height="20dp"
             android:layout_gravity="center_vertical"
             android:adjustViewBounds="true"
             android:contentDescription="@string/app_cdesc"
             android:maxHeight="30dp"
             android:maxWidth="30dp"
-            android:src="@drawable/pinpoint" />
+            android:src="@drawable/pinpoint"/>
 
         <TextView
             android:id="@+id/tv_row_home_schedule_place"