Convert Astrid2TaskProvider to Kotlin

pull/1025/head
Alex Baker 4 years ago
parent 94787c7d1d
commit e94d230d1b

@ -1,246 +0,0 @@
/*
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.provider;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import androidx.annotation.ColorRes;
import androidx.annotation.NonNull;
import com.google.common.base.Joiner;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import dagger.hilt.EntryPoint;
import dagger.hilt.InstallIn;
import dagger.hilt.android.EntryPointAccessors;
import dagger.hilt.android.components.ApplicationComponent;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import org.tasks.BuildConfig;
import org.tasks.R;
import org.tasks.analytics.Firebase;
import org.tasks.data.TagDao;
import org.tasks.data.TagData;
import org.tasks.data.TagDataDao;
import timber.log.Timber;
/**
* This is the legacy Astrid task provider. While it will continue to be supported, note that it
* does not expose all of the information in Astrid, nor does it support many editing operations.
*
* <p>See the individual methods for a description of what is returned.
*
* @author Tim Su <tim@todoroo.com>
*/
public class Astrid2TaskProvider extends ContentProvider {
@EntryPoint
@InstallIn(ApplicationComponent.class)
public interface Astrid2TaskProviderEntryPoint {
TagDataDao getTagDataDao();
TaskDao getTaskDao();
TagDao getTagDao();
Firebase getFirebase();
}
private static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".tasksprovider";
private static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
private static final String NAME = "name";
private static final String IMPORTANCE_COLOR = "importance_color";
private static final String IDENTIFIER = "identifier";
private static final String PREFERRED_DUE_DATE = "preferredDueDate";
private static final String DEFINITE_DUE_DATE = "definiteDueDate";
private static final String IMPORTANCE = "importance";
private static final String ID = "id";
private static final String TAGS_ID = "tags_id";
private static final String[] TASK_FIELD_LIST =
new String[] {
NAME,
IMPORTANCE_COLOR,
PREFERRED_DUE_DATE,
DEFINITE_DUE_DATE,
IMPORTANCE,
IDENTIFIER,
TAGS_ID
};
private static final String[] TAGS_FIELD_LIST = new String[] {ID, NAME};
private static final int URI_TASKS = 0;
private static final int URI_TAGS = 1;
private static final String TAG_SEPARATOR = "|";
static {
URI_MATCHER.addURI(AUTHORITY, "tasks", URI_TASKS);
URI_MATCHER.addURI(AUTHORITY, "tags", URI_TAGS);
}
public static void notifyDatabaseModification(Context context) {
try {
context.getContentResolver().notifyChange(CONTENT_URI, null);
} catch (Exception e) {
Timber.e(e);
}
}
@Override
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Override
public Uri insert(@NonNull Uri uri, ContentValues values) {
return null;
}
@Override
public boolean onCreate() {
return true;
}
private Astrid2TaskProviderEntryPoint hilt() {
return EntryPointAccessors.fromApplication(
getContext().getApplicationContext(), Astrid2TaskProviderEntryPoint.class);
}
/**
* Note: tag id is no longer a real column, so we pass in a UID generated from the tag string.
*
* @return two-column cursor: tag id (string) and tag name
*/
private Cursor getTags() {
List<TagData> tags = hilt().getTagDataDao().tagDataOrderedByName();
MatrixCursor ret = new MatrixCursor(TAGS_FIELD_LIST);
for (TagData tag : tags) {
Object[] values = new Object[2];
values[0] = tagNameToLong(tag.getName());
values[1] = tag.getName();
ret.addRow(values);
}
return ret;
}
private long tagNameToLong(String tag) {
MessageDigest m;
try {
m = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
Timber.e(e);
return -1;
}
m.update(tag.getBytes(), 0, tag.length());
return new BigInteger(1, m.digest()).longValue();
}
/**
* Cursor with the following columns
*
* <ol>
* <li>task title, string
* <li>task importance color, int android RGB color
* <li>task due date (was: preferred due date), long millis since epoch
* <li>task due date (was: absolute due date), long millis since epoch
* <li>task importance, integer from 0 to 3 (0 => most important)
* <li>task id, long
* <li>task tags, string tags separated by |
* </ol>
*
* @return cursor as described above
*/
private Cursor getTasks() {
Astrid2TaskProviderEntryPoint hilt = hilt();
hilt.getFirebase().logEvent(R.string.event_query_legacy_content_provider);
List<Task> tasks = hilt.getTaskDao().getAstrid2TaskProviderTasks();
MatrixCursor ret = new MatrixCursor(TASK_FIELD_LIST);
for (Task task : tasks) {
String taskTags = getTagsAsString(task.getId(), TAG_SEPARATOR);
Object[] values = new Object[7];
values[0] = task.getTitle();
values[1] = getPriorityColor(getContext(), task.getPriority());
values[2] = task.getDueDate();
values[3] = task.getDueDate();
values[4] = task.getPriority();
values[5] = task.getId();
values[6] = taskTags;
ret.addRow(values);
}
return ret;
}
private static int getPriorityColor(Context context, int priority) {
return context.getColor(getPriorityResId(priority));
}
@ColorRes private static int getPriorityResId(int priority) {
if (priority <= 0) {
return R.color.red_500;
} else if (priority == 1) {
return R.color.amber_500;
} else if (priority == 2) {
return R.color.blue_500;
} else {
return R.color.grey_500;
}
}
@Override
public Cursor query(
@NonNull Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder) {
switch (URI_MATCHER.match(uri)) {
case URI_TASKS:
return getTasks();
case URI_TAGS:
return getTags();
default:
throw new IllegalStateException("Unrecognized URI:" + uri);
}
}
@Override
public int update(
@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("not supported");
}
/**
* Return tags as a list of strings separated by given separator
*
* @return empty string if no tags, otherwise string
*/
private String getTagsAsString(long taskId, String separator) {
return Joiner.on(separator).join(hilt().getTagDao().getTagNames(taskId));
}
}

@ -0,0 +1,208 @@
/*
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.provider
import android.content.ContentProvider
import android.content.ContentValues
import android.content.Context
import android.content.UriMatcher
import android.database.Cursor
import android.database.MatrixCursor
import android.net.Uri
import androidx.annotation.ColorRes
import com.todoroo.astrid.dao.TaskDao
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.android.components.ApplicationComponent
import org.tasks.BuildConfig
import org.tasks.R
import org.tasks.analytics.Firebase
import org.tasks.data.TagDao
import org.tasks.data.TagDataDao
import timber.log.Timber
import java.math.BigInteger
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
/**
* This is the legacy Astrid task provider. While it will continue to be supported, note that it
* does not expose all of the information in Astrid, nor does it support many editing operations.
*
*
* See the individual methods for a description of what is returned.
*
* @author Tim Su <tim></tim>@todoroo.com>
*/
class Astrid2TaskProvider : ContentProvider() {
@EntryPoint
@InstallIn(ApplicationComponent::class)
interface Astrid2TaskProviderEntryPoint {
val tagDataDao: TagDataDao
val taskDao: TaskDao
val tagDao: TagDao
val firebase: Firebase
}
companion object {
private const val AUTHORITY = BuildConfig.APPLICATION_ID + ".tasksprovider"
private val CONTENT_URI = Uri.parse("content://$AUTHORITY")
private val URI_MATCHER = UriMatcher(UriMatcher.NO_MATCH)
private const val NAME = "name"
private const val IMPORTANCE_COLOR = "importance_color"
private const val IDENTIFIER = "identifier"
private const val PREFERRED_DUE_DATE = "preferredDueDate"
private const val DEFINITE_DUE_DATE = "definiteDueDate"
private const val IMPORTANCE = "importance"
private const val ID = "id"
private const val TAGS_ID = "tags_id"
private val TASK_FIELD_LIST = arrayOf(
NAME,
IMPORTANCE_COLOR,
PREFERRED_DUE_DATE,
DEFINITE_DUE_DATE,
IMPORTANCE,
IDENTIFIER,
TAGS_ID
)
private val TAGS_FIELD_LIST = arrayOf(ID, NAME)
private const val URI_TASKS = 0
private const val URI_TAGS = 1
private const val TAG_SEPARATOR = "|"
@JvmStatic
fun notifyDatabaseModification(context: Context) {
try {
context.contentResolver.notifyChange(CONTENT_URI, null)
} catch (e: Exception) {
Timber.e(e)
}
}
private fun getPriorityColor(context: Context?, priority: Int): Int {
return context!!.getColor(getPriorityResId(priority))
}
@ColorRes
private fun getPriorityResId(priority: Int): Int {
return when {
priority <= 0 -> R.color.red_500
priority == 1 -> R.color.amber_500
priority == 2 -> R.color.blue_500
else -> R.color.grey_500
}
}
init {
URI_MATCHER.addURI(AUTHORITY, "tasks", URI_TASKS)
URI_MATCHER.addURI(AUTHORITY, "tags", URI_TAGS)
}
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?) = 0
override fun getType(uri: Uri): String? = null
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
override fun onCreate() = true
private fun hilt(): Astrid2TaskProviderEntryPoint {
return EntryPointAccessors.fromApplication(
context!!.applicationContext, Astrid2TaskProviderEntryPoint::class.java)
}
/**
* Note: tag id is no longer a real column, so we pass in a UID generated from the tag string.
*
* @return two-column cursor: tag id (string) and tag name
*/
private val tags: Cursor
get() {
val tags = hilt().tagDataDao.tagDataOrderedByName()
val ret = MatrixCursor(TAGS_FIELD_LIST)
for (tag in tags) {
val values = arrayOfNulls<Any>(2)
values[0] = tagNameToLong(tag.name)
values[1] = tag.name
ret.addRow(values)
}
return ret
}
private fun tagNameToLong(tag: String?): Long {
val m: MessageDigest
m = try {
MessageDigest.getInstance("MD5")
} catch (e: NoSuchAlgorithmException) {
Timber.e(e)
return -1
}
m.update(tag!!.toByteArray(), 0, tag.length)
return BigInteger(1, m.digest()).toLong()
}
/**
* Cursor with the following columns
*
*
* 1. task title, string
* 1. task importance color, int android RGB color
* 1. task due date (was: preferred due date), long millis since epoch
* 1. task due date (was: absolute due date), long millis since epoch
* 1. task importance, integer from 0 to 3 (0 => most important)
* 1. task id, long
* 1. task tags, string tags separated by |
*
*
* @return cursor as described above
*/
private val tasks: Cursor
get() {
val hilt = hilt()
hilt.firebase.logEvent(R.string.event_query_legacy_content_provider)
val tasks = hilt.taskDao.getAstrid2TaskProviderTasks()
val ret = MatrixCursor(TASK_FIELD_LIST)
for (task in tasks) {
val taskTags = getTagsAsString(task.id, TAG_SEPARATOR)
val values = arrayOfNulls<Any>(7)
values[0] = task.title
values[1] = getPriorityColor(context, task.priority)
values[2] = task.dueDate
values[3] = task.dueDate
values[4] = task.priority
values[5] = task.id
values[6] = taskTags
ret.addRow(values)
}
return ret
}
override fun query(
uri: Uri,
projection: Array<String>?,
selection: String?,
selectionArgs: Array<String>?,
sortOrder: String?): Cursor? {
return when (URI_MATCHER.match(uri)) {
URI_TASKS -> tasks
URI_TAGS -> tags
else -> throw IllegalStateException("Unrecognized URI:$uri")
}
}
override fun update(
uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<String>?): Int {
throw UnsupportedOperationException("not supported")
}
/**
* Return tags as a list of strings separated by given separator
*
* @return empty string if no tags, otherwise string
*/
private fun getTagsAsString(taskId: Long, separator: String) =
hilt().tagDao.getTagNames(taskId).joinToString(separator)
}
Loading…
Cancel
Save