Eric Kok
12 years ago
29 changed files with 573 additions and 39 deletions
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 3.2 KiB |
@ -0,0 +1,8 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<!-- This layout is a simple wrapper to display dialogs (which might be show full screen, without border) --> |
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||||
|
android:id="@+id/dialogholder" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
tools:context=".DialogHolderActivity" /> |
@ -0,0 +1,48 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:orientation="vertical" |
||||||
|
android:layout_margin="@dimen/margin_default" > |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_gravity="center_horizontal" |
||||||
|
android:text="@string/app_name" |
||||||
|
android:textSize="36sp" |
||||||
|
android:textColor="@android:color/white" |
||||||
|
android:fontFamily="sans-serif-condensed" |
||||||
|
android:drawableLeft="@drawable/ic_launcher" |
||||||
|
android:drawablePadding="@dimen/margin_half" |
||||||
|
android:layout_marginTop="@dimen/margin_half" |
||||||
|
android:layout_marginBottom="@dimen/margin_half" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_gravity="center_horizontal" |
||||||
|
android:text="@string/system_description" |
||||||
|
android:gravity="center" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_gravity="center_horizontal" |
||||||
|
android:layout_marginTop="@dimen/margin_default" |
||||||
|
android:text="@string/app_developer" |
||||||
|
android:textColor="@android:color/white" |
||||||
|
android:textSize="18sp" |
||||||
|
android:fontFamily="sans-serif-condensed" |
||||||
|
android:gravity="center" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_gravity="center_horizontal" |
||||||
|
android:layout_marginTop="4dip" |
||||||
|
android:layout_marginBottom="@dimen/margin_default" |
||||||
|
android:text="@string/app_license" |
||||||
|
android:gravity="center" /> |
||||||
|
|
||||||
|
</LinearLayout> |
@ -0,0 +1,9 @@ |
|||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android" > |
||||||
|
|
||||||
|
<item |
||||||
|
android:id="@+id/action_visitwebsite" |
||||||
|
android:icon="@drawable/ic_action_website" |
||||||
|
android:showAsAction="always" |
||||||
|
android:title="@string/action_visitwebsite" /> |
||||||
|
|
||||||
|
</menu> |
@ -0,0 +1,5 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
<!-- Used to determine if a device is 'small', i.e. a phone; for reference: a Nexus 7's smallest width is 533dip --> |
||||||
|
<bool name="small_screen">false</bool> |
||||||
|
</resources> |
@ -0,0 +1,5 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
<!-- Used to determine if a device is 'small', i.e. a phone; for reference: a Nexus 7's smallest width is 533dip --> |
||||||
|
<bool name="small_screen">true</bool> |
||||||
|
</resources> |
@ -0,0 +1,42 @@ |
|||||||
|
package org.transdroid.core.gui; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.AfterViews; |
||||||
|
import org.androidannotations.annotations.EFragment; |
||||||
|
import org.androidannotations.annotations.OptionsItem; |
||||||
|
import org.androidannotations.annotations.OptionsMenu; |
||||||
|
|
||||||
|
import android.app.Dialog; |
||||||
|
import android.content.Intent; |
||||||
|
import android.net.Uri; |
||||||
|
import android.os.Bundle; |
||||||
|
import android.view.Window; |
||||||
|
|
||||||
|
import com.actionbarsherlock.app.SherlockDialogFragment; |
||||||
|
|
||||||
|
/** |
||||||
|
* Fragment that shows info about the application developer and used open source libraries. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@EFragment(resName="fragment_about") |
||||||
|
@OptionsMenu(resName="fragment_about") |
||||||
|
public class AboutFragment extends SherlockDialogFragment { |
||||||
|
|
||||||
|
@AfterViews |
||||||
|
protected void init() { |
||||||
|
// TODO: Add list of used open source libraries
|
||||||
|
} |
||||||
|
|
||||||
|
@OptionsItem(resName="action_visitwebsite") |
||||||
|
protected void visitWebsite() { |
||||||
|
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://transdroid.org"))); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) { |
||||||
|
// Allow presenting of this fragment as a dialog
|
||||||
|
Dialog dialog = super.onCreateDialog(savedInstanceState); |
||||||
|
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); |
||||||
|
return dialog; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,51 @@ |
|||||||
|
package org.transdroid.core.gui.log; |
||||||
|
|
||||||
|
import java.sql.SQLException; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.database.sqlite.SQLiteDatabase; |
||||||
|
import android.util.Log; |
||||||
|
|
||||||
|
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; |
||||||
|
import com.j256.ormlite.support.ConnectionSource; |
||||||
|
import com.j256.ormlite.table.TableUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* Helper to access the database to access persisting objects. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public class DatabaseHelper extends OrmLiteSqliteOpenHelper { |
||||||
|
|
||||||
|
private static final String DATABASE_NAME = "transdroid.db"; |
||||||
|
private static final int DATABASE_VERSION = 1; |
||||||
|
|
||||||
|
public DatabaseHelper(Context context) { |
||||||
|
super(context, DATABASE_NAME, null, DATABASE_VERSION); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onCreate(SQLiteDatabase sqLiteDatabase, ConnectionSource connectionSource) { |
||||||
|
try { |
||||||
|
TableUtils.createTable(connectionSource, ErrorLogEntry.class); |
||||||
|
} catch (SQLException e) { |
||||||
|
Log.e(org.transdroid.core.gui.log.Log.LOG_NAME, "Could not create new table for ErrorLogEntry", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onUpgrade(SQLiteDatabase sqLiteDatabase, ConnectionSource connectionSource, int oldVersion, |
||||||
|
int newVersion) { |
||||||
|
try { |
||||||
|
switch (oldVersion) { |
||||||
|
case 1: |
||||||
|
TableUtils.createTable(connectionSource, ErrorLogEntry.class); |
||||||
|
/*case 1: |
||||||
|
etc...*/ |
||||||
|
} |
||||||
|
|
||||||
|
} catch (SQLException e) { |
||||||
|
Log.e(org.transdroid.core.gui.log.Log.LOG_NAME, "Could not upgrade the table for ErrorLogEntry", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,92 @@ |
|||||||
|
package org.transdroid.core.gui.log; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
import android.os.Parcel; |
||||||
|
import android.os.Parcelable; |
||||||
|
|
||||||
|
import com.j256.ormlite.field.DatabaseField; |
||||||
|
import com.j256.ormlite.table.DatabaseTable; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents an error log entry to be registered in the database. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@DatabaseTable(tableName = "ErrorLogEntry") |
||||||
|
public class ErrorLogEntry implements Parcelable { |
||||||
|
|
||||||
|
public static final String ID = "logId"; |
||||||
|
public static final String DATEANDTIME = "dateAndTime"; |
||||||
|
|
||||||
|
@DatabaseField(id = true, columnName = ID) |
||||||
|
private Integer logId; |
||||||
|
@DatabaseField(columnName = DATEANDTIME) |
||||||
|
private Date dateAndTime; |
||||||
|
@DatabaseField |
||||||
|
private Integer priority; |
||||||
|
@DatabaseField |
||||||
|
private String tag; |
||||||
|
@DatabaseField |
||||||
|
private String message; |
||||||
|
|
||||||
|
public ErrorLogEntry() { |
||||||
|
} |
||||||
|
|
||||||
|
public ErrorLogEntry(Integer priority, String tag, String message) { |
||||||
|
this.dateAndTime = new Date(); |
||||||
|
this.priority = priority; |
||||||
|
this.tag = tag; |
||||||
|
this.message = message; |
||||||
|
} |
||||||
|
|
||||||
|
public Integer getLogId() { |
||||||
|
return logId; |
||||||
|
} |
||||||
|
|
||||||
|
public Date getDateAndTime() { |
||||||
|
return dateAndTime; |
||||||
|
} |
||||||
|
|
||||||
|
public Integer getPriority() { |
||||||
|
return priority; |
||||||
|
} |
||||||
|
|
||||||
|
public String getTag() { |
||||||
|
return tag; |
||||||
|
} |
||||||
|
|
||||||
|
public String getMessage() { |
||||||
|
return message; |
||||||
|
} |
||||||
|
|
||||||
|
public int describeContents() { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
public void writeToParcel(Parcel out, int flags) { |
||||||
|
out.writeInt(logId); |
||||||
|
out.writeLong(dateAndTime.getTime()); |
||||||
|
out.writeInt(priority); |
||||||
|
out.writeString(tag); |
||||||
|
out.writeString(message); |
||||||
|
} |
||||||
|
|
||||||
|
public static final Parcelable.Creator<ErrorLogEntry> CREATOR = new Parcelable.Creator<ErrorLogEntry>() { |
||||||
|
public ErrorLogEntry createFromParcel(Parcel in) { |
||||||
|
return new ErrorLogEntry(in); |
||||||
|
} |
||||||
|
|
||||||
|
public ErrorLogEntry[] newArray(int size) { |
||||||
|
return new ErrorLogEntry[size]; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
private ErrorLogEntry(Parcel in) { |
||||||
|
logId = in.readInt(); |
||||||
|
dateAndTime = new Date(in.readLong()); |
||||||
|
priority = in.readInt(); |
||||||
|
tag = in.readString(); |
||||||
|
message = in.readString(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,73 @@ |
|||||||
|
package org.transdroid.core.gui.log; |
||||||
|
|
||||||
|
import java.sql.SQLException; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.Bean; |
||||||
|
import org.androidannotations.annotations.EBean; |
||||||
|
import org.androidannotations.annotations.OrmLiteDao; |
||||||
|
import org.transdroid.core.R; |
||||||
|
import org.transdroid.core.app.settings.ServerSetting; |
||||||
|
import org.transdroid.core.gui.navigation.NavigationHelper; |
||||||
|
|
||||||
|
import android.app.Activity; |
||||||
|
import android.content.ActivityNotFoundException; |
||||||
|
import android.content.Intent; |
||||||
|
|
||||||
|
import com.j256.ormlite.dao.Dao; |
||||||
|
|
||||||
|
@EBean |
||||||
|
public class ErrorLogSender { |
||||||
|
|
||||||
|
@Bean |
||||||
|
protected NavigationHelper navigationHelper; |
||||||
|
@OrmLiteDao(helper = DatabaseHelper.class, model = ErrorLogEntry.class) |
||||||
|
protected Dao<ErrorLogEntry, Integer> errorLogDao; |
||||||
|
|
||||||
|
public void collectAndSendLog(final Activity callingActivity, final ServerSetting serverSetting) { |
||||||
|
|
||||||
|
try { |
||||||
|
|
||||||
|
// Prepare an email with error logging information
|
||||||
|
StringBuilder body = new StringBuilder(); |
||||||
|
body.append("Please describe your problem:\n\n\n"); |
||||||
|
body.append("\n"); |
||||||
|
body.append(navigationHelper.getAppNameAndVersion()); |
||||||
|
body.append("\n"); |
||||||
|
body.append(serverSetting.getType().toString()); |
||||||
|
body.append(" settings: "); |
||||||
|
body.append(serverSetting.getHumanReadableIdentifier()); |
||||||
|
body.append("\n\nConnection and error log:"); |
||||||
|
|
||||||
|
// Print the individual error log messages as stored in the database
|
||||||
|
List<ErrorLogEntry> all = errorLogDao.queryBuilder().orderBy(ErrorLogEntry.ID, true).query(); |
||||||
|
for (ErrorLogEntry errorLogEntry : all) { |
||||||
|
body.append("\n"); |
||||||
|
body.append(errorLogEntry.getLogId()); |
||||||
|
body.append(" -- "); |
||||||
|
body.append(errorLogEntry.getDateAndTime()); |
||||||
|
body.append(" -- "); |
||||||
|
body.append(errorLogEntry.getPriority()); |
||||||
|
body.append(" -- "); |
||||||
|
body.append(errorLogEntry.getMessage()); |
||||||
|
} |
||||||
|
|
||||||
|
Intent target = new Intent(Intent.ACTION_SEND); |
||||||
|
target.setType("message/rfc822"); |
||||||
|
target.putExtra(Intent.EXTRA_EMAIL, new String[] { "transdroid.org@gmail.com" }); |
||||||
|
target.putExtra(Intent.EXTRA_SUBJECT, "Transdroid error report"); |
||||||
|
target.putExtra(Intent.EXTRA_TEXT, body.toString()); |
||||||
|
try { |
||||||
|
callingActivity.startActivity(Intent.createChooser(target, |
||||||
|
callingActivity.getString(R.string.pref_sendlog)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); |
||||||
|
} catch (ActivityNotFoundException e) { |
||||||
|
Log.i(callingActivity, "Tried to send error log, but there is no email app installed."); |
||||||
|
} |
||||||
|
|
||||||
|
} catch (SQLException e) { |
||||||
|
Log.e(callingActivity, "Cannot read the error log to build an error report to send: " + e.toString()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
package org.transdroid.core.gui.log; |
||||||
|
|
||||||
|
import java.sql.SQLException; |
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.EBean; |
||||||
|
import org.androidannotations.annotations.EBean.Scope; |
||||||
|
import org.androidannotations.annotations.OrmLiteDao; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
|
||||||
|
import com.j256.ormlite.dao.Dao; |
||||||
|
import com.j256.ormlite.stmt.DeleteBuilder; |
||||||
|
|
||||||
|
/** |
||||||
|
* Application-wide logging class that registers entries in the database (for a certain time). |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@EBean(scope = Scope.Singleton) |
||||||
|
public class Log { |
||||||
|
|
||||||
|
public static final String LOG_NAME = "Transdroid"; |
||||||
|
private static final long MAX_LOG_AGE = 15 * 60 * 1000; // 15 minutes
|
||||||
|
|
||||||
|
@OrmLiteDao(helper = DatabaseHelper.class, model = ErrorLogEntry.class) |
||||||
|
Dao<ErrorLogEntry, Integer> errorLogDao; |
||||||
|
|
||||||
|
protected void log(String logName, int priority, String message) { |
||||||
|
android.util.Log.println(priority, LOG_NAME, message); |
||||||
|
try { |
||||||
|
// Store this log message to the database
|
||||||
|
errorLogDao.create(new ErrorLogEntry(priority, logName, message)); |
||||||
|
// Truncate the error log
|
||||||
|
DeleteBuilder<ErrorLogEntry, Integer> db = errorLogDao.deleteBuilder(); |
||||||
|
db.setWhere(db.where().le(ErrorLogEntry.DATEANDTIME, new Date(new Date().getTime() - MAX_LOG_AGE))); |
||||||
|
errorLogDao.delete(db.prepare()); |
||||||
|
} catch (SQLException e) { |
||||||
|
android.util.Log.e(LOG_NAME, "Cannot write log message to database: " + e.toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void e(Context caller, String message) { |
||||||
|
Log_.getInstance_(caller).log(caller.getClass().toString(), android.util.Log.ERROR, message); |
||||||
|
} |
||||||
|
|
||||||
|
public static void i(Context caller, String message) { |
||||||
|
Log_.getInstance_(caller).log(caller.getClass().toString(), android.util.Log.INFO, message); |
||||||
|
} |
||||||
|
|
||||||
|
public static void d(Context caller, String message) { |
||||||
|
Log_.getInstance_(caller).log(caller.getClass().toString(), android.util.Log.DEBUG, message); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
package org.transdroid.core.gui.navigation; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.AfterViews; |
||||||
|
import org.androidannotations.annotations.EActivity; |
||||||
|
import org.androidannotations.annotations.Extra; |
||||||
|
import org.transdroid.core.gui.log.Log; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.support.v4.app.DialogFragment; |
||||||
|
import android.support.v4.app.FragmentTransaction; |
||||||
|
|
||||||
|
import com.actionbarsherlock.app.SherlockFragmentActivity; |
||||||
|
|
||||||
|
@EActivity(resName = "activity_dialogholder") |
||||||
|
public class DialogHolderActivity extends SherlockFragmentActivity { |
||||||
|
|
||||||
|
@Extra |
||||||
|
protected String dialogType; |
||||||
|
|
||||||
|
/** |
||||||
|
* Use this method to show some dialog; it will show the dialog as full screen fragment on smaller devices. Use the |
||||||
|
* DialogFragment's class here only; a new instance will be created by this holder activity. |
||||||
|
*/ |
||||||
|
public static void showDialog(Context context, Class<? extends DialogFragment> dialogType) { |
||||||
|
DialogHolderActivity_.intent(context).start(); |
||||||
|
} |
||||||
|
|
||||||
|
@AfterViews |
||||||
|
public void init() { |
||||||
|
try { |
||||||
|
// Instantiate an instance of the requested dialog
|
||||||
|
DialogFragment dialog = (DialogFragment) Class.forName(dialogType).newInstance(); |
||||||
|
// Determine if the dialog should be shown as full size screen
|
||||||
|
boolean isSmall = NavigationHelper_.getInstance_(this).isSmallScreen(); |
||||||
|
if (!isSmall) { |
||||||
|
// Show as normal dialog
|
||||||
|
dialog.show(this.getSupportFragmentManager(), "about_dialog"); |
||||||
|
} else { |
||||||
|
// Small device, so show the fragment full screen
|
||||||
|
FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction(); |
||||||
|
// Note: the fragment is not added to the back stack, as this activity already is
|
||||||
|
ft.add(android.R.id.content, dialog).commit(); |
||||||
|
} |
||||||
|
} catch (InstantiationException e) { |
||||||
|
Log.e(this, "Tried to show a dialog of type " + dialogType + ", but that cannot be instantiated."); |
||||||
|
} catch (IllegalAccessException e) { |
||||||
|
Log.e(this, "Tried to show a dialog of type " + dialogType + ", but it is not accessible."); |
||||||
|
} catch (ClassNotFoundException e) { |
||||||
|
Log.e(this, "Tried to show a dialog of type " + dialogType + ", but that class doesn't exist."); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue