/* * Copyright 2015. Appsi Mobile * * 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 com.appsimobile.appsii.module.apps; import android.content.ContentProvider; 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.support.annotation.NonNull; import android.support.v4.util.ArrayMap; import android.text.TextUtils; import com.appsimobile.appsii.BuildConfig; import com.appsimobile.appsii.R; import static com.appsimobile.appsii.module.apps.AppsContract.LaunchHistoryColumns; import static com.appsimobile.appsii.module.apps.AppsContract.TagColumns; import static com.appsimobile.appsii.module.apps.AppsContract.TaggedAppColumns; /** * Created by Nick on 19/02/14. */ public class AppsProvider extends ContentProvider { public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".apps"; public static final int DATABASE_VERSION = 1; public static final String DATABASE_NAME = "apps.db"; private static final int TABLE_APPS = 1; private static final int TABLE_APPS_ITEM = 2; private static final int TABLE_TAGS = 3; private static final int TABLE_TAGS_ITEM = 4; private static final int TABLE_HISTORY = 5; private static final int TABLE_HISTORY_ITEM = 6; private static final UriMatcher sURLMatcher = new UriMatcher(UriMatcher.NO_MATCH); private static final ArrayMap<String, String> sAppsProjectionMap; private static final ArrayMap<String, String> sTagsProjectionMap; private static final ArrayMap<String, String> sHistoryProjectionMap; static { sURLMatcher.addURI(AUTHORITY, "taggedApps", TABLE_APPS); sURLMatcher.addURI(AUTHORITY, "taggedApps/#", TABLE_APPS_ITEM); sURLMatcher.addURI(AUTHORITY, "tags", TABLE_TAGS); sURLMatcher.addURI(AUTHORITY, "tags/#", TABLE_TAGS_ITEM); sURLMatcher.addURI(AUTHORITY, "launchHistory", TABLE_HISTORY); sURLMatcher.addURI(AUTHORITY, "launchHistory/#", TABLE_HISTORY_ITEM); sAppsProjectionMap = new ArrayMap<>(8); // Events columns sAppsProjectionMap.put(TaggedAppColumns._ID, TaggedAppColumns.TABLE_NAME + "." + TaggedAppColumns._ID); sAppsProjectionMap.put(TaggedAppColumns.POSITION, TaggedAppColumns.TABLE_NAME + "." + TaggedAppColumns.POSITION); sAppsProjectionMap.put(TaggedAppColumns.DELETED, TaggedAppColumns.TABLE_NAME + "." + TaggedAppColumns.DELETED); sAppsProjectionMap.put(TaggedAppColumns.COMPONENT_NAME, TaggedAppColumns.TABLE_NAME + "." + TaggedAppColumns.COMPONENT_NAME); sAppsProjectionMap.put(AppsContract.JOINED_APP_TAGS.TAG_NAME, TagColumns.TABLE_NAME + "." + TagColumns.NAME); sAppsProjectionMap.put(AppsContract.JOINED_APP_TAGS.TAG_ID, TagColumns.TABLE_NAME + "." + TagColumns._ID); sTagsProjectionMap = new ArrayMap<>(8); // Events columns sTagsProjectionMap.put(TagColumns._ID, TagColumns._ID); sTagsProjectionMap.put(TagColumns.POSITION, TagColumns.POSITION); sTagsProjectionMap.put(TagColumns.DEFAULT_EXPANDED, TagColumns.DEFAULT_EXPANDED); sTagsProjectionMap.put(TagColumns.VISIBLE, TagColumns.VISIBLE); sTagsProjectionMap.put(TagColumns.NAME, TagColumns.NAME); sTagsProjectionMap.put(TagColumns.COLUMN_COUNT, TagColumns.COLUMN_COUNT); sTagsProjectionMap.put(TagColumns.TAG_TYPE, TagColumns.TAG_TYPE); sHistoryProjectionMap = new ArrayMap<>(5); // Events columns sHistoryProjectionMap.put(LaunchHistoryColumns._ID, LaunchHistoryColumns._ID); sHistoryProjectionMap.put(LaunchHistoryColumns.COMPONENT_NAME, LaunchHistoryColumns.COMPONENT_NAME); sHistoryProjectionMap.put(LaunchHistoryColumns.LAST_LAUNCHED, LaunchHistoryColumns.LAST_LAUNCHED); sHistoryProjectionMap.put(LaunchHistoryColumns.LAUNCH_COUNT, LaunchHistoryColumns.LAUNCH_COUNT); } private SQLiteOpenHelper mOpenHelper; @Override public boolean onCreate() { mOpenHelper = new DatabaseHelper(getContext()); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); // Generate the body of the query int match = sURLMatcher.match(uri); switch (match) { // loads all tagged-apps in a given tag. case TABLE_APPS_ITEM: long id = ContentUris.parseId(uri); qb.setTables(TaggedAppColumns.TABLE_NAME + "," + TagColumns.TABLE_NAME); qb.setProjectionMap(sAppsProjectionMap); qb.appendWhere(TaggedAppColumns.TAG_ID + "=" + id + " AND "); qb.appendWhere("taggedApps.tag_id=tags._id"); break; // loads all tagged apps case TABLE_APPS: qb.setTables(TaggedAppColumns.TABLE_NAME + "," + TagColumns.TABLE_NAME); qb.setProjectionMap(sAppsProjectionMap); qb.appendWhere("taggedApps.tag_id=tags._id"); break; // loads items in the launch history table case TABLE_HISTORY: qb.setTables(LaunchHistoryColumns.TABLE_NAME); qb.setProjectionMap(sHistoryProjectionMap); break; // loads all tags case TABLE_TAGS: qb.setTables(TagColumns.TABLE_NAME); qb.setProjectionMap(sTagsProjectionMap); break; default: throw new IllegalArgumentException("Invalid uri: " + uri); } return qb.query(db, projection, selection, selectionArgs, null, null, sortOrder); } @Override public String getType(Uri uri) { SqlArguments args = new SqlArguments(uri, null, null); if (TextUtils.isEmpty(args.where)) { return "vnd.android.cursor.dir/" + args.table; } else { return "vnd.android.cursor.item/" + args.table; } } @Override public Uri insert(Uri uri, ContentValues initialValues) { SqlArguments args = new SqlArguments(uri); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); final long rowId = db.insert(args.table, null, initialValues); if (rowId <= 0) return null; uri = ContentUris.withAppendedId(uri, rowId); sendNotify(uri); return uri; } @Override public int bulkInsert(Uri uri, @NonNull ContentValues[] values) { SqlArguments args = new SqlArguments(uri); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); db.beginTransaction(); try { int numValues = values.length; for (int i = 0; i < numValues; i++) { if (db.insert(args.table, null, values[i]) < 0) return 0; } db.setTransactionSuccessful(); } finally { db.endTransaction(); } sendNotify(uri); return values.length; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SqlArguments args = new SqlArguments(uri, selection, selectionArgs); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count; int match = sURLMatcher.match(uri); switch (match) { case TABLE_APPS_ITEM: { String id = uri.getLastPathSegment(); count = db.delete(args.table, "_id=" + id, args.args); break; } case TABLE_APPS: { count = db.delete(args.table, args.where, args.args); break; } case TABLE_TAGS_ITEM: { String id = uri.getLastPathSegment(); count = db.delete(args.table, "_id=" + id, args.args); break; } case TABLE_TAGS: { count = db.delete(args.table, args.where, args.args); break; } case TABLE_HISTORY_ITEM: { String id = uri.getLastPathSegment(); count = db.delete(args.table, "_id=" + id, args.args); break; } case TABLE_HISTORY: { count = db.delete(args.table, args.where, args.args); break; } default: { throw new IllegalArgumentException("Unknown URL " + uri); } } if (count > 0) { sendNotify(uri); } return count; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SqlArguments args = new SqlArguments(uri, selection, selectionArgs); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count = db.update(args.table, values, args.where, args.args); if (count > 0) sendNotify(uri); return count; } private void sendNotify(Uri uri) { getContext().getContentResolver().notifyChange(uri, null); } static class SqlArguments { public final String table; public final String where; public final String[] args; SqlArguments(Uri url, String where, String[] args) { if (url.getPathSegments().size() == 1) { this.table = url.getPathSegments().get(0); this.where = where; this.args = args; } else if (url.getPathSegments().size() != 2) { throw new IllegalArgumentException("Invalid URI: " + url); } else if (!TextUtils.isEmpty(where)) { throw new UnsupportedOperationException("WHERE clause not supported: " + url); } else { this.table = url.getPathSegments().get(0); this.where = "_id=" + ContentUris.parseId(url); this.args = null; } } SqlArguments(Uri url) { if (url.getPathSegments().size() == 1) { table = url.getPathSegments().get(0); where = null; args = null; } else { throw new IllegalArgumentException("Invalid URI: " + url); } } } public class DatabaseHelper extends SQLiteOpenHelper { // If you change the database schema, you must increment the database version. public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.beginTransaction(); Context context = getContext(); try { db.execSQL("CREATE TABLE " + TagColumns.TABLE_NAME + " (" + TagColumns._ID + " INTEGER PRIMARY KEY, " + TagColumns.DEFAULT_EXPANDED + " INTEGER NOT NULL DEFAULT 0, " + TagColumns.POSITION + " INTEGER NOT NULL DEFAULT 1, " + TagColumns.COLUMN_COUNT + " INTEGER NOT NULL DEFAULT 3, " + TagColumns.TAG_TYPE + " INTEGER NOT NULL DEFAULT " + TagColumns.TAG_TYPE_USER + ", " + TagColumns.VISIBLE + " INTEGER NOT NULL DEFAULT 1, " + TagColumns.NAME + " TEXT NOT NULL " + ");" ); // insert recent apps folder ContentValues values = new ContentValues(); values.put(TagColumns.DEFAULT_EXPANDED, 1); values.put(TagColumns.POSITION, 0); // get the default, this depends on the device's size values.put(TagColumns.COLUMN_COUNT, 6); values.put(TagColumns.TAG_TYPE, TagColumns.TAG_TYPE_RECENT); values.put(TagColumns.VISIBLE, 1); values.put(TagColumns.NAME, context.getString(R.string.folder_recent_apps)); db.insert(TagColumns.TABLE_NAME, null, values); // insert all apps folder values.clear(); values.put(TagColumns.DEFAULT_EXPANDED, 1); values.put(TagColumns.POSITION, 1); values.put(TagColumns.COLUMN_COUNT, 3); values.put(TagColumns.TAG_TYPE, TagColumns.TAG_TYPE_ALL); values.put(TagColumns.VISIBLE, 1); values.put(TagColumns.NAME, context.getString(R.string.all_apps)); db.insert(TagColumns.TABLE_NAME, null, values); // create the table for tagged apps db.execSQL("CREATE TABLE " + TaggedAppColumns.TABLE_NAME + " (" + TaggedAppColumns._ID + " INTEGER PRIMARY KEY, " + TaggedAppColumns.DELETED + " INTEGER NOT NULL DEFAULT 0, " + TaggedAppColumns.POSITION + " INTEGER NOT NULL DEFAULT 0, " + TaggedAppColumns.TAG_ID + " INTEGER NOT NULL, " + TaggedAppColumns.COMPONENT_NAME + " TEXT NOT NULL, " + " FOREIGN KEY (" + TaggedAppColumns.TAG_ID + ") " + " REFERENCES " + TagColumns.TABLE_NAME + " (" + TagColumns._ID + ")" + ");" ); // create table for app history db.execSQL("CREATE TABLE " + LaunchHistoryColumns.TABLE_NAME + " (" + LaunchHistoryColumns._ID + " INTEGER PRIMARY KEY, " + LaunchHistoryColumns.LAST_LAUNCHED + " INTEGER NOT NULL, " + LaunchHistoryColumns.LAUNCH_COUNT + " INTEGER NOT NULL, " + LaunchHistoryColumns.COMPONENT_NAME + " TEXT NOT NULL" + ");" ); db.setTransactionSuccessful(); } finally { db.endTransaction(); } } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // Once the db evolves, update here. } @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { onUpgrade(db, oldVersion, newVersion); } } }