summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Olsson <johan@jmvo.se>2017-10-03 13:23:05 +0200
committerLuca Stefani <luca.stefani.ge1@gmail.com>2017-12-09 17:55:32 +0100
commitc42034e2751b4154c7f5ba642469687eab25b0ae (patch)
tree2f6aa59f872f2adefab920e9c8d1584d75b0d396
parent3c45694302fac8250dad69989aab0fb0df4ead77 (diff)
downloadandroid_packages_apps_Jelly-c42034e2751b4154c7f5ba642469687eab25b0ae.tar.gz
android_packages_apps_Jelly-c42034e2751b4154c7f5ba642469687eab25b0ae.tar.bz2
android_packages_apps_Jelly-c42034e2751b4154c7f5ba642469687eab25b0ae.zip
Jelly: Implementing favorite management through a ContentProvider.
Inspired by the history ContentProvider. Previously database queries were being invoked on the UI thread. This is no longer the case. Edit and delete favorite were also taken into account and even the delete animation is working like before. Edit, Add and Delete actions implemented as static inner classes to avoid implicit activity reference. May otherwise cause memory leakage. Snackbar parent view is referenced as weak to avoid potential illegal state exceptions. Change-Id: I214ec25a90e86048da0e97be62f899d0af99c1a0
-rw-r--r--app/src/main/AndroidManifest.xml5
-rw-r--r--app/src/main/java/org/lineageos/jelly/MainActivity.java43
-rw-r--r--app/src/main/java/org/lineageos/jelly/favorite/Favorite.java64
-rw-r--r--app/src/main/java/org/lineageos/jelly/favorite/FavoriteActivity.java110
-rw-r--r--app/src/main/java/org/lineageos/jelly/favorite/FavoriteAdapter.java69
-rw-r--r--app/src/main/java/org/lineageos/jelly/favorite/FavoriteDatabaseHandler.java106
-rw-r--r--app/src/main/java/org/lineageos/jelly/favorite/FavoriteHolder.java17
-rw-r--r--app/src/main/java/org/lineageos/jelly/favorite/FavoriteProvider.java243
8 files changed, 407 insertions, 250 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index abef89e..6a38c78 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -97,6 +97,11 @@
</provider>
<provider
+ android:name=".favorite.FavoriteProvider"
+ android:authorities="org.lineageos.jelly.favorite"
+ android:exported="false" />
+
+ <provider
android:name=".history.HistoryProvider"
android:authorities="org.lineageos.jelly.history"
android:exported="false" />
diff --git a/app/src/main/java/org/lineageos/jelly/MainActivity.java b/app/src/main/java/org/lineageos/jelly/MainActivity.java
index 606676a..b1d7eef 100644
--- a/app/src/main/java/org/lineageos/jelly/MainActivity.java
+++ b/app/src/main/java/org/lineageos/jelly/MainActivity.java
@@ -19,6 +19,7 @@ import android.Manifest;
import android.app.ActivityManager;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -32,6 +33,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.net.Uri;
import android.net.http.HttpResponseCache;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@@ -70,9 +72,8 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
-import org.lineageos.jelly.favorite.Favorite;
import org.lineageos.jelly.favorite.FavoriteActivity;
-import org.lineageos.jelly.favorite.FavoriteDatabaseHandler;
+import org.lineageos.jelly.favorite.FavoriteProvider;
import org.lineageos.jelly.history.HistoryActivity;
import org.lineageos.jelly.suggestions.SuggestionsAdapter;
import org.lineageos.jelly.ui.SearchBarController;
@@ -86,6 +87,7 @@ import org.lineageos.jelly.webview.WebViewExtActivity;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.lang.ref.WeakReference;
public class MainActivity extends WebViewExtActivity implements
SearchBarController.OnCancelListener {
@@ -453,15 +455,12 @@ public class MainActivity extends WebViewExtActivity implements
}
private void setAsFavorite(String title, String url) {
- FavoriteDatabaseHandler handler = new FavoriteDatabaseHandler(this);
boolean hasValidIcon = mUrlIcon != null && !mUrlIcon.isRecycled();
int color = hasValidIcon ? UiUtils.getColor(mUrlIcon, false) : Color.TRANSPARENT;
if (color == Color.TRANSPARENT) {
color = ContextCompat.getColor(this, R.color.colorAccent);
}
- handler.addItem(new Favorite(title, url, color));
- Snackbar.make(mCoordinator, getString(R.string.favorite_added),
- Snackbar.LENGTH_LONG).show();
+ new SetAsFavoriteTask(getContentResolver(), title, url, color, mCoordinator).execute();
}
public void downloadFileAsk(String url, String contentDisposition, String mimeType) {
@@ -699,4 +698,36 @@ public class MainActivity extends WebViewExtActivity implements
super.onWindowFocusChanged(hasFocus);
setImmersiveMode(hasFocus && mCustomView != null);
}
+
+ private static class SetAsFavoriteTask extends AsyncTask<Void, Void, Boolean> {
+ private ContentResolver contentResolver;
+ private final String title;
+ private final String url;
+ private final int color;
+ private final WeakReference<View> parentView;
+
+ SetAsFavoriteTask(ContentResolver contentResolver, String title, String url,
+ int color, View parentView) {
+ this.contentResolver = contentResolver;
+ this.title = title;
+ this.url = url;
+ this.color = color;
+ this.parentView = new WeakReference<>(parentView);
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ FavoriteProvider.addOrUpdateItem(contentResolver, title, url, color);
+ return true;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean aBoolean) {
+ View view = parentView.get();
+ if (view != null) {
+ Snackbar.make(view, view.getContext().getString(R.string.favorite_added),
+ Snackbar.LENGTH_LONG).show();
+ }
+ }
+ }
}
diff --git a/app/src/main/java/org/lineageos/jelly/favorite/Favorite.java b/app/src/main/java/org/lineageos/jelly/favorite/Favorite.java
deleted file mode 100644
index 56f8801..0000000
--- a/app/src/main/java/org/lineageos/jelly/favorite/Favorite.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2017 The LineageOS Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.lineageos.jelly.favorite;
-
-public class Favorite {
- private long id = -1;
- private String title;
- private String url;
- private final int color;
-
- public Favorite(String title, String url, int color) {
- this.title = title;
- this.url = url;
- this.color = color;
- }
-
- Favorite(long id, String title, String url, int color) {
- this.id = id;
- this.title = title;
- this.url = url;
- this.color = color;
- }
-
- public long getId() {
- return id;
- }
-
- public void setId(long id) {
- this.id = id;
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- String getUrl() {
- return url;
- }
-
- void setUrl(String url) {
- this.url = url;
- }
-
- public int getColor() {
- return color;
- }
-}
diff --git a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteActivity.java b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteActivity.java
index db6c051..4aaebe1 100644
--- a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteActivity.java
+++ b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteActivity.java
@@ -15,6 +15,14 @@
*/
package org.lineageos.jelly.favorite;
+import android.app.LoaderManager;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.CursorLoader;
+import android.content.Loader;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
@@ -32,14 +40,10 @@ import android.widget.LinearLayout;
import org.lineageos.jelly.R;
import org.lineageos.jelly.utils.UiUtils;
-import java.util.ArrayList;
-import java.util.List;
-
public class FavoriteActivity extends AppCompatActivity {
private RecyclerView mList;
private View mEmptyView;
- private FavoriteDatabaseHandler mDbHandler;
private FavoriteAdapter mAdapter;
@Override
@@ -56,8 +60,31 @@ public class FavoriteActivity extends AppCompatActivity {
mList = (RecyclerView) findViewById(R.id.favorite_list);
mEmptyView = findViewById(R.id.favorite_empty_layout);
- mDbHandler = new FavoriteDatabaseHandler(this);
- mAdapter = new FavoriteAdapter(this, new ArrayList<>());
+ mAdapter = new FavoriteAdapter(this);
+
+ getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() {
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ return new CursorLoader(FavoriteActivity.this, FavoriteProvider.Columns.CONTENT_URI,
+ null, null, null, FavoriteProvider.Columns._ID + " DESC");
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
+ mAdapter.swapCursor(cursor);
+
+ if (cursor.getCount() == 0) {
+ mList.setVisibility(View.GONE);
+ mEmptyView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ mAdapter.swapCursor(null);
+ }
+ });
+
mList.setLayoutManager(new GridLayoutManager(this, 2));
mList.setItemAnimator(new DefaultItemAnimator());
mList.setAdapter(mAdapter);
@@ -76,30 +103,14 @@ public class FavoriteActivity extends AppCompatActivity {
});
}
- @Override
- public void onResume() {
- super.onResume();
- refresh();
- }
-
- void refresh() {
- List<Favorite> items = mDbHandler.getAllItems();
- mAdapter.updateList(items);
-
- if (items.isEmpty()) {
- mList.setVisibility(View.GONE);
- mEmptyView.setVisibility(View.VISIBLE);
- }
- }
-
- void editItem(Favorite item) {
+ void editItem(long id, String title, String url) {
View view = LayoutInflater.from(this)
.inflate(R.layout.dialog_favorite_edit, new LinearLayout(this));
EditText titleEdit = (EditText) view.findViewById(R.id.favorite_edit_title);
EditText urlEdit = (EditText) view.findViewById(R.id.favorite_edit_url);
- titleEdit.setText(item.getTitle());
- urlEdit.setText(item.getUrl());
+ titleEdit.setText(title);
+ urlEdit.setText(url);
String error = getString(R.string.favorite_edit_error);
urlEdit.addTextChangedListener(new TextWatcher() {
@@ -127,22 +138,19 @@ public class FavoriteActivity extends AppCompatActivity {
.setView(view)
.setPositiveButton(R.string.favorite_edit_positive,
((dialog, which) -> {
- String url = urlEdit.getText().toString();
- String title = titleEdit.getText().toString();
+ String updatedUrl = urlEdit.getText().toString();
+ String updatedTitle = titleEdit.getText().toString();
if (url.isEmpty()) {
urlEdit.setError(error);
urlEdit.requestFocus();
}
- item.setTitle(title);
- item.setUrl(url);
- mDbHandler.updateItem(item);
- refresh();
+ new UpdateFavoriteTask(getContentResolver(), id, updatedTitle,
+ updatedUrl).execute();
dialog.dismiss();
}))
.setNeutralButton(R.string.favorite_edit_delete,
(dialog, which) -> {
- mDbHandler.deleteItem(item.getId());
- mAdapter.removeItem(item.getId());
+ new DeleteFavoriteTask(getContentResolver()).execute(id);
dialog.dismiss();
})
.setNegativeButton(android.R.string.cancel,
@@ -150,4 +158,40 @@ public class FavoriteActivity extends AppCompatActivity {
.show();
}
+ private static class UpdateFavoriteTask extends AsyncTask<Void, Void, Void> {
+ private final ContentResolver contentResolver;
+ private final long id;
+ private final String title;
+ private final String url;
+
+ UpdateFavoriteTask(ContentResolver contentResolver, long id, String title, String url) {
+ this.contentResolver = contentResolver;
+ this.id = id;
+ this.title = title;
+ this.url = url;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ FavoriteProvider.updateItem(contentResolver, id, title, url);
+ return null;
+ }
+ }
+
+ private static class DeleteFavoriteTask extends AsyncTask<Long, Void, Void> {
+ private final ContentResolver contentResolver;
+
+ DeleteFavoriteTask(ContentResolver contentResolver) {
+ this.contentResolver = contentResolver;
+ }
+
+ @Override
+ protected Void doInBackground(Long... ids) {
+ for (Long id : ids) {
+ Uri uri = ContentUris.withAppendedId(FavoriteProvider.Columns.CONTENT_URI, id);
+ contentResolver.delete(uri, null, null);
+ }
+ return null;
+ }
+ }
}
diff --git a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteAdapter.java b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteAdapter.java
index e315f75..bd9d120 100644
--- a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteAdapter.java
+++ b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteAdapter.java
@@ -16,21 +16,42 @@
package org.lineageos.jelly.favorite;
import android.content.Context;
+import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import org.lineageos.jelly.R;
-import java.util.List;
-
class FavoriteAdapter extends RecyclerView.Adapter<FavoriteHolder> {
private final Context mContext;
- private List<Favorite> mList;
+ private Cursor mCursor;
+
+ private int mIdColumnIndex;
+ private int mTitleColumnIndex;
+ private int mUrlColumnIndex;
+ private int mColorColumnIndex;
- FavoriteAdapter(Context context, List<Favorite> list) {
+ FavoriteAdapter(Context context) {
mContext = context;
- mList = list;
+ setHasStableIds(true);
+ }
+
+ void swapCursor(Cursor cursor) {
+ if (cursor == mCursor) {
+ return;
+ }
+ if (mCursor != null) {
+ mCursor.close();
+ }
+ mCursor = cursor;
+ if (mCursor != null) {
+ mIdColumnIndex = cursor.getColumnIndexOrThrow(FavoriteProvider.Columns._ID);
+ mTitleColumnIndex = cursor.getColumnIndexOrThrow(FavoriteProvider.Columns.TITLE);
+ mUrlColumnIndex = cursor.getColumnIndexOrThrow(FavoriteProvider.Columns.URL);
+ mColorColumnIndex = cursor.getColumnIndexOrThrow(FavoriteProvider.Columns.COLOR);
+ }
+ notifyDataSetChanged();
}
@Override
@@ -41,37 +62,23 @@ class FavoriteAdapter extends RecyclerView.Adapter<FavoriteHolder> {
@Override
public void onBindViewHolder(FavoriteHolder holder, int position) {
- holder.setData(mContext, mList.get(position));
+ if (!mCursor.moveToPosition(position)) {
+ return;
+ }
+ long id = mCursor.getLong(mIdColumnIndex);
+ String title = mCursor.getString(mTitleColumnIndex);
+ String url = mCursor.getString(mUrlColumnIndex);
+ int color = mCursor.getInt(mColorColumnIndex);
+ holder.bind(mContext, id, title, url, color);
}
@Override
public int getItemCount() {
- return mList.size();
+ return mCursor != null ? mCursor.getCount() : 0;
}
- void updateList(List<Favorite> list) {
- mList = list;
- notifyDataSetChanged();
- }
-
- void removeItem(long id) {
- int position = 0;
- for (; position < mList.size(); position++) {
- if (mList.get(position).getId() == id) {
- break;
- }
- }
-
- if (position == mList.size()) {
- return;
- }
-
- mList.remove(position);
- notifyItemRemoved(position);
-
- if (mList.isEmpty()) {
- // Show empty status
- ((FavoriteActivity) mContext).refresh();
- }
+ @Override
+ public long getItemId(int position) {
+ return mCursor.moveToPosition(position) ? mCursor.getLong(mIdColumnIndex) : -1;
}
}
diff --git a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteDatabaseHandler.java b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteDatabaseHandler.java
deleted file mode 100644
index ba1c6b6..0000000
--- a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteDatabaseHandler.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2017 The LineageOS Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.lineageos.jelly.favorite;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class FavoriteDatabaseHandler extends SQLiteOpenHelper {
- private static final int DB_VERSION = 1;
- private static final String DB_NAME = "FavoriteDatabase";
- private static final String DB_TABLE_FAVORITES = "favorites";
- private static final String KEY_ID = "id";
- private static final String KEY_TITLE = "title";
- private static final String KEY_URL = "url";
- private static final String KEY_COLOR = "color";
-
-
- public FavoriteDatabaseHandler(Context context) {
- super(context, DB_NAME, null, DB_VERSION);
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + DB_TABLE_FAVORITES + " (" +
- KEY_ID + " INTEGER PRIMARY KEY, " +
- KEY_TITLE + " TEXT, " +
- KEY_URL + " TEXT, " +
- KEY_COLOR + " INTEGER)");
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- // Update this when db table will be changed
- }
-
- public void addItem(Favorite item) {
- if (item.getId() == -1) {
- item.setId(System.currentTimeMillis());
- }
-
- ContentValues values = new ContentValues();
- values.put(KEY_ID, item.getId());
- values.put(KEY_TITLE, item.getTitle());
- values.put(KEY_URL, item.getUrl());
- values.put(KEY_COLOR, item.getColor());
-
- SQLiteDatabase db = getWritableDatabase();
- db.insert(DB_TABLE_FAVORITES, null, values);
- db.close();
- }
-
- void updateItem(Favorite item) {
- SQLiteDatabase db = getWritableDatabase();
-
- ContentValues values = new ContentValues();
- values.put(KEY_TITLE, item.getTitle());
- values.put(KEY_URL, item.getUrl());
- values.put(KEY_COLOR, item.getColor());
-
- db.update(DB_TABLE_FAVORITES, values, KEY_ID + "=?",
- new String[]{String.valueOf(item.getId())});
- }
-
- void deleteItem(long id) {
- SQLiteDatabase db = getWritableDatabase();
- db.delete(DB_TABLE_FAVORITES, KEY_ID + "=?", new String[]{String.valueOf(id)});
- db.close();
- }
-
- List<Favorite> getAllItems() {
- List<Favorite> list = new ArrayList<>();
- SQLiteDatabase db = getWritableDatabase();
- Cursor cursor = db.rawQuery("SELECT * FROM " + DB_TABLE_FAVORITES +
- " ORDER BY " + KEY_ID + " DESC", null);
-
- if (cursor.moveToFirst()) {
- do {
- list.add(new Favorite(Long.parseLong(cursor.getString(0)),
- cursor.getString(1), cursor.getString(2),
- Integer.parseInt(cursor.getString(3))));
- } while (cursor.moveToNext());
- }
- cursor.close();
- db.close();
- return list;
- }
-}
diff --git a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteHolder.java b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteHolder.java
index f2c047d..8ea1d3d 100644
--- a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteHolder.java
+++ b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteHolder.java
@@ -38,23 +38,20 @@ class FavoriteHolder extends RecyclerView.ViewHolder {
mTitle = (TextView) view.findViewById(R.id.row_favorite_title);
}
- void setData(Context context, Favorite item) {
- String title = item.getTitle();
- if (title == null || title.isEmpty()) {
- title = item.getUrl().split("/")[2];
- }
- mTitle.setText(title);
- mTitle.setTextColor(UiUtils.isColorLight(item.getColor()) ? Color.BLACK : Color.WHITE);
- mCard.setCardBackgroundColor(item.getColor());
+ void bind(Context context, long id, String title, String url, int color) {
+ String adjustedTitle = title == null || title.isEmpty() ? url.split("/")[2] : title;
+ mTitle.setText(adjustedTitle);
+ mTitle.setTextColor(UiUtils.isColorLight(color) ? Color.BLACK : Color.WHITE);
+ mCard.setCardBackgroundColor(color);
mCard.setOnClickListener(v -> {
Intent intent = new Intent(context, MainActivity.class);
- intent.setData(Uri.parse(item.getUrl()));
+ intent.setData(Uri.parse(url));
context.startActivity(intent);
});
mCard.setOnLongClickListener(v -> {
- ((FavoriteActivity) context).editItem(item);
+ ((FavoriteActivity) context).editItem(id, adjustedTitle, url);
return true;
});
}
diff --git a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteProvider.java b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteProvider.java
new file mode 100644
index 0000000..32aca33
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteProvider.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.favorite;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+public class FavoriteProvider extends ContentProvider {
+ public interface Columns extends BaseColumns {
+ String AUTHORITY = "org.lineageos.jelly.favorite";
+ Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/favorite");
+
+ String TITLE = "title";
+ String URL = "url";
+ String COLOR = "color";
+ }
+
+ private static final int MATCH_ALL = 0;
+ private static final int MATCH_ID = 1;
+
+ private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ static {
+ sURIMatcher.addURI(Columns.AUTHORITY, "favorite", MATCH_ALL);
+ sURIMatcher.addURI(Columns.AUTHORITY, "favorite/#", MATCH_ID);
+ }
+
+ private FavoriteDbHelper mDbHelper;
+
+ public static void addOrUpdateItem(ContentResolver resolver, String title, String url,
+ int color) {
+ long existingId = -1;
+ Cursor cursor = resolver.query(Columns.CONTENT_URI, new String[] { Columns._ID },
+ Columns.URL + "=?", new String[] { url }, null);
+ if (cursor != null) {
+ if (cursor.moveToFirst()) {
+ existingId = cursor.getLong(0);
+ }
+ cursor.close();
+ }
+
+ ContentValues values = new ContentValues();
+ values.put(Columns.TITLE, title);
+ values.put(Columns.COLOR, color);
+
+ if (existingId >= 0) {
+ resolver.update(ContentUris.withAppendedId(Columns.CONTENT_URI, existingId),
+ values, null, null);
+ } else {
+ values.put(Columns.URL, url);
+ resolver.insert(Columns.CONTENT_URI, values);
+ }
+ }
+
+ public static void updateItem(ContentResolver resolver, long id, String title, String url) {
+ ContentValues values = new ContentValues();
+ values.put(Columns.TITLE, title);
+ values.put(Columns.URL, url);
+
+ resolver.update(ContentUris.withAppendedId(Columns.CONTENT_URI, id), values, null, null);
+ }
+
+ @Override
+ public boolean onCreate() {
+ mDbHelper = new FavoriteDbHelper(getContext());
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+ @Nullable String selection, @Nullable String[] selectionArgs,
+ @Nullable String sortOrder) {
+ SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+ int match = sURIMatcher.match(uri);
+
+ qb.setTables(FavoriteDbHelper.DB_TABLE_FAVORITES);
+
+ switch (match) {
+ case MATCH_ALL:
+ break;
+ case MATCH_ID:
+ qb.appendWhere(Columns._ID + " = " + uri.getLastPathSegment());
+ break;
+ default:
+ return null;
+ }
+
+ SQLiteDatabase db = mDbHelper.getReadableDatabase();
+ Cursor ret = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);
+
+ ret.setNotificationUri(getContext().getContentResolver(), uri);
+
+ return ret;
+ }
+
+ @Nullable
+ @Override
+ public String getType(@NonNull Uri uri) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
+ if (sURIMatcher.match(uri) != MATCH_ALL) {
+ return null;
+ }
+
+ SQLiteDatabase db = mDbHelper.getWritableDatabase();
+ long rowID = db.insert(FavoriteDbHelper.DB_TABLE_FAVORITES, null, values);
+ if (rowID <= 0) {
+ return null;
+ }
+
+ getContext().getContentResolver().notifyChange(Columns.CONTENT_URI, null);
+
+ return ContentUris.withAppendedId(Columns.CONTENT_URI, rowID);
+ }
+
+ @Override
+ public int update(@NonNull Uri uri, @Nullable ContentValues values,
+ @Nullable String selection, @Nullable String[] selectionArgs) {
+ int count;
+ int match = sURIMatcher.match(uri);
+ SQLiteDatabase db = mDbHelper.getWritableDatabase();
+
+ switch (match) {
+ case MATCH_ALL:
+ count = db.update(FavoriteDbHelper.DB_TABLE_FAVORITES,
+ values, selection, selectionArgs);
+ break;
+ case MATCH_ID:
+ if (selection != null || selectionArgs != null) {
+ throw new UnsupportedOperationException(
+ "Cannot update URI " + uri + " with a where clause");
+ }
+ count = db.update(FavoriteDbHelper.DB_TABLE_FAVORITES, values, Columns._ID + " = ?",
+ new String[] { uri.getLastPathSegment() });
+ break;
+ default:
+ throw new UnsupportedOperationException("Cannot update that URI: " + uri);
+ }
+
+ if (count > 0) {
+ getContext().getContentResolver().notifyChange(Columns.CONTENT_URI, null);
+ }
+
+ return count;
+ }
+
+ @Override
+ public int delete(@NonNull Uri uri, @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ int match = sURIMatcher.match(uri);
+ SQLiteDatabase db = mDbHelper.getWritableDatabase();
+
+ switch (match) {
+ case MATCH_ALL:
+ break;
+ case MATCH_ID:
+ if (selection != null || selectionArgs != null) {
+ throw new UnsupportedOperationException(
+ "Cannot delete URI " + uri + " with a where clause");
+ }
+ selection = Columns._ID + " = ?";
+ selectionArgs = new String[] { uri.getLastPathSegment() };
+ break;
+ default:
+ throw new UnsupportedOperationException("Cannot delete the URI " + uri);
+ }
+
+ int count = db.delete(FavoriteDbHelper.DB_TABLE_FAVORITES, selection, selectionArgs);
+
+ if (count > 0) {
+ getContext().getContentResolver().notifyChange(Columns.CONTENT_URI, null);
+ }
+
+ return count;
+ }
+
+ private static class FavoriteDbHelper extends SQLiteOpenHelper {
+ private static final int DB_VERSION = 2;
+ private static final String DB_NAME = "FavoriteDatabase";
+ private static final String DB_TABLE_FAVORITES = "favorites";
+
+ FavoriteDbHelper(Context context) {
+ super(context, DB_NAME, null, DB_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + DB_TABLE_FAVORITES + " (" +
+ Columns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ Columns.TITLE + " TEXT, " +
+ Columns.URL + " TEXT, " +
+ Columns.COLOR + " INTEGER)");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ if (oldVersion < 2) {
+ // Recreate table with auto incrementing id column.
+ db.execSQL("CREATE TABLE " + DB_TABLE_FAVORITES + "_new (" +
+ Columns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ Columns.TITLE + " TEXT, " +
+ Columns.URL + " TEXT, " +
+ Columns.COLOR + " INTEGER)");
+ db.execSQL("INSERT INTO " + DB_TABLE_FAVORITES + "_new("
+ + Columns.TITLE + ", " + Columns.URL + ", " + Columns.COLOR
+ + ") SELECT " + Columns.TITLE + ", " + Columns.URL + ", " + Columns.COLOR
+ + " FROM " + DB_TABLE_FAVORITES);
+ db.execSQL("DROP TABLE " + DB_TABLE_FAVORITES);
+ db.execSQL("ALTER TABLE " + DB_TABLE_FAVORITES
+ + "_new RENAME TO " + DB_TABLE_FAVORITES);
+ }
+ }
+ }
+}