org.mariotaku.twidere.provider.TweetStoreProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.mariotaku.twidere.provider.TweetStoreProvider.java

Source

/*
 *            Twidere - Twitter client for Android
 * 
 * Copyright (C) 2012 Mariotaku Lee <mariotaku.lee@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.mariotaku.twidere.provider;

import static org.mariotaku.twidere.util.Utils.clearAccountColor;
import static org.mariotaku.twidere.util.Utils.clearAccountName;
import static org.mariotaku.twidere.util.Utils.getAllStatusesCount;
import static org.mariotaku.twidere.util.Utils.getBiggerTwitterProfileImage;
import static org.mariotaku.twidere.util.Utils.getTableId;
import static org.mariotaku.twidere.util.Utils.getTableNameForContentUri;
import static org.mariotaku.twidere.util.Utils.isFiltered;
import static org.mariotaku.twidere.util.Utils.notifyForUpdatedUri;
import static org.mariotaku.twidere.util.Utils.parseInt;

import java.io.File;
import java.util.Calendar;
import java.util.List;

import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.HomeActivity;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.provider.TweetStore.DirectMessages;
import org.mariotaku.twidere.provider.TweetStore.DirectMessages.Conversation;
import org.mariotaku.twidere.provider.TweetStore.DirectMessages.ConversationsEntry;
import org.mariotaku.twidere.provider.TweetStore.Mentions;
import org.mariotaku.twidere.provider.TweetStore.Statuses;
import org.mariotaku.twidere.util.DatabaseHelper;
import org.mariotaku.twidere.util.LazyImageLoader;
import org.mariotaku.twidere.util.NoDuplicatesArrayList;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.NotificationCompat;

public final class TweetStoreProvider extends ContentProvider implements Constants {

    private SQLiteDatabase mDatabase;

    private int mNewMessagesCount, mNewMentionsCount, mNewStatusesCount;

    private boolean mNotificationIsAudible;

    private final BroadcastReceiver mHomeActivityStateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            final String action = intent.getAction();
            if (BROADCAST_HOME_ACTIVITY_ONSTART.equals(action)) {
                mNotificationIsAudible = false;
            } else if (BROADCAST_HOME_ACTIVITY_ONSTOP.equals(action)) {
                mNotificationIsAudible = true;
            }
        }

    };

    private NotificationManager mNotificationManager;

    private SharedPreferences mPreferences;
    private LazyImageLoader mProfileImageLoader;

    @Override
    public int bulkInsert(final Uri uri, final ContentValues[] values) {
        final String table = getTableNameForContentUri(uri);
        final int table_id = getTableId(uri);
        int result = 0;
        final int notification_count;
        if (table != null && values != null) {
            final Context context = getContext();
            final int old_count;
            switch (table_id) {
            case URI_STATUSES: {
                old_count = getAllStatusesCount(context, Statuses.CONTENT_URI);
                break;
            }
            case URI_MENTIONS: {
                old_count = getAllStatusesCount(context, Mentions.CONTENT_URI);
                break;
            }
            default:
                old_count = 0;
            }
            mDatabase.beginTransaction();
            for (final ContentValues contentValues : values) {
                mDatabase.insert(table, null, contentValues);
                result++;
            }
            mDatabase.setTransactionSuccessful();
            mDatabase.endTransaction();
            if (!"false".equals(uri.getQueryParameter(QUERY_PARAM_NOTIFY))) {
                switch (table_id) {
                case URI_STATUSES: {
                    mNewStatusesCount += notification_count = getAllStatusesCount(context, Statuses.CONTENT_URI)
                            - old_count;
                    break;
                }
                case URI_MENTIONS: {
                    mNewMentionsCount += notification_count = getAllStatusesCount(context, Mentions.CONTENT_URI)
                            - old_count;
                    break;
                }
                case URI_DIRECT_MESSAGES_INBOX: {
                    mNewMessagesCount += notification_count = result;
                    break;
                }
                default:
                    notification_count = 0;
                }
            } else {
                notification_count = 0;
            }
        } else {
            notification_count = 0;
        }
        if (result > 0) {
            onDatabaseUpdated(uri);
        }
        onNewItemsInserted(uri, notification_count, values);
        return result;
    };

    @Override
    public int delete(final Uri uri, final String selection, final String[] selectionArgs) {
        final String table = getTableNameForContentUri(uri);
        if (getTableId(uri) == URI_NOTIFICATIONS) {
            final List<String> segments = uri.getPathSegments();
            if (segments.size() != 2)
                return 0;
            clearNotification(parseInt(segments.get(1)));
        }
        if (table == null)
            return 0;
        final int result = mDatabase.delete(table, selection, selectionArgs);
        if (result > 0) {
            onDatabaseUpdated(uri);
        }
        return result;
    }

    @Override
    public String getType(final Uri uri) {
        return null;
    }

    @Override
    public Uri insert(final Uri uri, final ContentValues values) {
        final String table = getTableNameForContentUri(uri);
        if (table == null)
            return null;
        if (TABLE_DIRECT_MESSAGES_CONVERSATION.equals(table))
            return null;
        else if (TABLE_DIRECT_MESSAGES.equals(table))
            return null;
        else if (TABLE_DIRECT_MESSAGES_CONVERSATIONS_ENTRY.equals(table))
            return null;
        final long row_id = mDatabase.insert(table, null, values);
        if (!"false".equals(uri.getQueryParameter(QUERY_PARAM_NOTIFY))) {
            switch (getTableId(uri)) {
            case URI_STATUSES: {
                mNewStatusesCount++;
                break;
            }
            case URI_MENTIONS: {
                mNewMentionsCount++;
                break;
            }
            case URI_DIRECT_MESSAGES_INBOX: {
                mNewMessagesCount++;
                break;
            }
            default:
            }
        }
        onDatabaseUpdated(uri);
        onNewItemsInserted(uri, 1, values);
        return Uri.withAppendedPath(uri, String.valueOf(row_id));
    }

    @Override
    public boolean onCreate() {
        final Context context = getContext();
        mDatabase = new DatabaseHelper(context, DATABASES_NAME, DATABASES_VERSION).getWritableDatabase();
        mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        mPreferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
        mProfileImageLoader = TwidereApplication.getInstance(context).getProfileImageLoader();
        final IntentFilter filter = new IntentFilter();
        filter.addAction(BROADCAST_HOME_ACTIVITY_ONSTART);
        filter.addAction(BROADCAST_HOME_ACTIVITY_ONSTOP);
        context.registerReceiver(mHomeActivityStateReceiver, filter);
        return mDatabase != null;
    }

    @Override
    public Cursor query(final Uri uri, final String[] projection, final String selection,
            final String[] selectionArgs, final String sortOrder) {
        final String table = getTableNameForContentUri(uri);
        if (table == null)
            return null;
        if (TABLE_DIRECT_MESSAGES_CONVERSATION.equals(table)) {
            final List<String> segments = uri.getPathSegments();
            if (segments.size() != 3)
                return null;
            final String query = Conversation.QueryBuilder.buildByConversationId(projection,
                    Long.parseLong(segments.get(1)), Long.parseLong(segments.get(2)), selection, sortOrder);
            return mDatabase.rawQuery(query, selectionArgs);
        } else if (TABLE_DIRECT_MESSAGES_CONVERSATION_SCREEN_NAME.equals(table)) {
            final List<String> segments = uri.getPathSegments();
            if (segments.size() != 3)
                return null;
            final String query = Conversation.QueryBuilder.buildByScreenName(projection,
                    Long.parseLong(segments.get(1)), segments.get(2), selection, sortOrder);
            return mDatabase.rawQuery(query, selectionArgs);
        } else if (TABLE_DIRECT_MESSAGES.equals(table)) {
            final String query = DirectMessages.QueryBuilder.build(projection, selection, sortOrder);
            return mDatabase.rawQuery(query, selectionArgs);
        } else if (TABLE_DIRECT_MESSAGES_CONVERSATIONS_ENTRY.equals(table))
            return mDatabase.rawQuery(ConversationsEntry.QueryBuilder.build(selection), null);
        return mDatabase.query(table, projection, selection, selectionArgs, null, null, sortOrder);
    }

    @Override
    public int update(final Uri uri, final ContentValues values, final String selection,
            final String[] selectionArgs) {
        final String table = getTableNameForContentUri(uri);
        int result = 0;
        if (table != null) {
            if (TABLE_DIRECT_MESSAGES_CONVERSATION.equals(table))
                return 0;
            else if (TABLE_DIRECT_MESSAGES.equals(table))
                return 0;
            else if (TABLE_DIRECT_MESSAGES_CONVERSATIONS_ENTRY.equals(table))
                return 0;
            result = mDatabase.update(table, values, selection, selectionArgs);
        }
        if (result > 0) {
            onDatabaseUpdated(uri);
        }
        return result;
    }

    private Notification buildNotification(final NotificationCompat.Builder builder, final String ticker,
            final String title, final String message, final int icon, final Bitmap large_icon,
            final Intent content_intent, final Intent delete_intent) {
        final Context context = getContext();
        builder.setTicker(ticker);
        builder.setContentTitle(title);
        builder.setContentText(message);
        builder.setAutoCancel(true);
        builder.setWhen(System.currentTimeMillis());
        builder.setSmallIcon(icon);
        if (large_icon != null) {
            builder.setLargeIcon(large_icon);
        }
        if (delete_intent != null) {
            builder.setDeleteIntent(
                    PendingIntent.getBroadcast(context, 0, delete_intent, PendingIntent.FLAG_UPDATE_CURRENT));
        }
        if (content_intent != null) {
            builder.setContentIntent(
                    PendingIntent.getActivity(context, 0, content_intent, PendingIntent.FLAG_UPDATE_CURRENT));
        }
        int defaults = 0;
        final Calendar now = Calendar.getInstance();
        if (mNotificationIsAudible
                && !mPreferences.getBoolean("slient_notifications_at_" + now.get(Calendar.HOUR_OF_DAY), false)) {
            if (mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_HAVE_SOUND, false)) {
                builder.setSound(Uri.parse(mPreferences.getString(PREFERENCE_KEY_NOTIFICATION_RINGTONE,
                        Settings.System.DEFAULT_RINGTONE_URI.getPath())), Notification.STREAM_DEFAULT);
            }
            if (mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_HAVE_VIBRATION, false)) {
                defaults |= Notification.DEFAULT_VIBRATE;
            }
        }
        if (mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_HAVE_LIGHTS, false)) {
            final int color_def = context.getResources().getColor(R.color.holo_blue_dark);
            final int color = mPreferences.getInt(PREFERENCE_KEY_NOTIFICATION_LIGHT_COLOR, color_def);
            builder.setLights(color, 1000, 2000);
        }
        builder.setDefaults(defaults);
        return builder.build();
    }

    private void clearNotification(final int id) {
        switch (id) {
        case NOTIFICATION_ID_HOME_TIMELINE: {
            mNewStatusesCount = 0;
            break;
        }
        case NOTIFICATION_ID_MENTIONS: {
            mNewMentionsCount = 0;
            break;
        }
        case NOTIFICATION_ID_DIRECT_MESSAGES: {
            mNewMessagesCount = 0;
            break;
        }
        }
        mNotificationManager.cancel(id);
    }

    private void onDatabaseUpdated(final Uri uri) {
        if (uri == null)
            return;
        if ("false".equals(uri.getQueryParameter(QUERY_PARAM_NOTIFY)))
            return;
        final Context context = getContext();
        switch (getTableId(uri)) {
        case URI_ACCOUNTS: {
            clearAccountColor();
            clearAccountName();
            context.sendBroadcast(new Intent(BROADCAST_ACCOUNT_LIST_DATABASE_UPDATED));
            break;
        }
        case URI_DRAFTS: {
            context.sendBroadcast(new Intent(BROADCAST_DRAFTS_DATABASE_UPDATED));
            break;
        }
        case URI_STATUSES:
        case URI_MENTIONS:
        case URI_DIRECT_MESSAGES_INBOX:
        case URI_DIRECT_MESSAGES_OUTBOX: {
            notifyForUpdatedUri(context, uri);
            break;
        }
        case URI_TRENDS_LOCAL: {
            context.sendBroadcast(new Intent(BROADCAST_TRENDS_UPDATED));
            break;
        }
        case URI_TABS: {
            context.sendBroadcast(new Intent(BROADCAST_TABS_UPDATED));
            break;
        }
        case URI_FILTERED_USERS:
        case URI_FILTERED_KEYWORDS:
        case URI_FILTERED_SOURCES: {
            context.sendBroadcast(new Intent(BROADCAST_FILTERS_UPDATED));
            break;
        }
        default:
            return;
        }
        context.sendBroadcast(new Intent(BROADCAST_DATABASE_UPDATED));
    }

    private void onNewItemsInserted(final Uri uri, final int count, final ContentValues... values) {
        if (uri == null || values == null || values.length == 0 || count == 0)
            return;
        if ("false".equals(uri.getQueryParameter(QUERY_PARAM_NOTIFY)))
            return;
        final Context context = getContext();
        final Resources res = context.getResources();
        final NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        final boolean display_screen_name = NAME_DISPLAY_OPTION_SCREEN_NAME
                .equals(mPreferences.getString(PREFERENCE_KEY_NAME_DISPLAY_OPTION, NAME_DISPLAY_OPTION_BOTH));
        final boolean display_hires_profile_image = res.getBoolean(R.bool.hires_profile_image);
        switch (getTableId(uri)) {
        case URI_STATUSES: {
            if (!mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_HOME_TIMELINE, false))
                return;
            final String message = res.getQuantityString(R.plurals.Ntweets, mNewStatusesCount, mNewStatusesCount);
            final Intent delete_intent = new Intent(BROADCAST_NOTIFICATION_CLEARED);
            final Bundle delete_extras = new Bundle();
            delete_extras.putInt(INTENT_KEY_NOTIFICATION_ID, NOTIFICATION_ID_HOME_TIMELINE);
            delete_intent.putExtras(delete_extras);
            final Intent content_intent = new Intent(context, HomeActivity.class);
            content_intent.setAction(Intent.ACTION_MAIN);
            content_intent.addCategory(Intent.CATEGORY_LAUNCHER);
            final Bundle content_extras = new Bundle();
            content_extras.putInt(INTENT_KEY_INITIAL_TAB, HomeActivity.TAB_POSITION_HOME);
            content_intent.putExtras(content_extras);
            builder.setOnlyAlertOnce(true);
            final Notification notification = buildNotification(builder, res.getString(R.string.new_notifications),
                    message, message, R.drawable.ic_stat_tweet, null, content_intent, delete_intent);
            mNotificationManager.notify(NOTIFICATION_ID_HOME_TIMELINE, notification);
            break;
        }
        case URI_MENTIONS: {
            if (!mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_MENTIONS, false))
                return;
            if (mNewMentionsCount > 1) {
                builder.setNumber(mNewMentionsCount);
            }
            final Intent delete_intent = new Intent(BROADCAST_NOTIFICATION_CLEARED);
            final Bundle delete_extras = new Bundle();
            delete_extras.putInt(INTENT_KEY_NOTIFICATION_ID, NOTIFICATION_ID_MENTIONS);
            delete_intent.putExtras(delete_extras);
            final Intent content_intent;
            final List<String> screen_names = new NoDuplicatesArrayList<String>();
            ContentValues notification_value = null;
            int notified_count = 0;
            for (final ContentValues value : values) {
                final String screen_name = value.getAsString(Statuses.SCREEN_NAME);
                if (!isFiltered(mDatabase, screen_name, value.getAsString(Statuses.SOURCE),
                        value.getAsString(Statuses.TEXT_PLAIN))) {
                    if (notification_value == null) {
                        notification_value = value;
                    }
                    screen_names.add(screen_name);
                    notified_count++;
                }
            }
            if (notified_count == 1) {
                final Uri.Builder uri_builder = new Uri.Builder();
                uri_builder.scheme(SCHEME_TWIDERE);
                uri_builder.authority(AUTHORITY_STATUS);
                uri_builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID,
                        notification_value.getAsString(Statuses.ACCOUNT_ID));
                uri_builder.appendQueryParameter(QUERY_PARAM_STATUS_ID,
                        notification_value.getAsString(Statuses.STATUS_ID));
                content_intent = new Intent(Intent.ACTION_VIEW, uri_builder.build());

            } else {
                content_intent = new Intent(context, HomeActivity.class);
                content_intent.setAction(Intent.ACTION_MAIN);
                content_intent.addCategory(Intent.CATEGORY_LAUNCHER);
                final Bundle content_extras = new Bundle();
                content_extras.putInt(INTENT_KEY_INITIAL_TAB, HomeActivity.TAB_POSITION_MENTIONS);
                content_intent.putExtras(content_extras);
            }
            if (notification_value == null)
                return;
            final String title;
            if (screen_names.size() > 1) {
                title = res.getString(R.string.notification_mention_multiple,
                        display_screen_name ? notification_value.getAsString(Statuses.SCREEN_NAME)
                                : notification_value.getAsString(Statuses.NAME),
                        screen_names.size() - 1);
            } else {
                title = res.getString(R.string.notification_mention,
                        display_screen_name ? notification_value.getAsString(Statuses.SCREEN_NAME)
                                : notification_value.getAsString(Statuses.NAME));
            }
            final String message = notification_value.getAsString(Statuses.TEXT_PLAIN);
            final String profile_image_url_string = notification_value.getAsString(Statuses.PROFILE_IMAGE_URL);
            final File profile_image_file = mProfileImageLoader.getCachedImageFile(
                    display_hires_profile_image ? getBiggerTwitterProfileImage(profile_image_url_string)
                            : profile_image_url_string);
            final int w = res.getDimensionPixelSize(R.dimen.notification_large_icon_width);
            final int h = res.getDimensionPixelSize(R.dimen.notification_large_icon_height);
            builder.setLargeIcon(Bitmap.createScaledBitmap(profile_image_file != null && profile_image_file.isFile()
                    ? BitmapFactory.decodeFile(profile_image_file.getPath())
                    : BitmapFactory.decodeResource(res, R.drawable.ic_profile_image_default), w, h, true));
            final Notification notification = buildNotification(builder, title, title, message,
                    R.drawable.ic_stat_mention, null, content_intent, delete_intent);
            mNotificationManager.notify(NOTIFICATION_ID_MENTIONS, notification);
            break;
        }
        case URI_DIRECT_MESSAGES_INBOX: {
            if (!mPreferences.getBoolean(PREFERENCE_KEY_NOTIFICATION_ENABLE_DIRECT_MESSAGES, false))
                return;
            if (mNewMessagesCount > 1) {
                builder.setNumber(mNewMessagesCount);
            }
            final List<String> screen_names = new NoDuplicatesArrayList<String>();
            final ContentValues notification_value = values[0];
            for (final ContentValues value : values) {
                screen_names.add(value.getAsString(DirectMessages.SENDER_SCREEN_NAME));
            }
            if (notification_value == null)
                return;
            final String title;
            if (screen_names.size() > 1) {
                title = res.getString(R.string.notification_direct_message_multiple,
                        display_screen_name ? notification_value.getAsString(DirectMessages.SENDER_SCREEN_NAME)
                                : notification_value.getAsString(DirectMessages.SENDER_NAME),
                        screen_names.size() - 1);
            } else {
                title = res.getString(R.string.notification_direct_message,
                        display_screen_name ? notification_value.getAsString(DirectMessages.SENDER_SCREEN_NAME)
                                : notification_value.getAsString(DirectMessages.SENDER_NAME));
            }
            final String message = notification_value.getAsString(DirectMessages.TEXT_PLAIN);
            final String profile_image_url_string = notification_value
                    .getAsString(DirectMessages.SENDER_PROFILE_IMAGE_URL);
            final File profile_image_file = mProfileImageLoader.getCachedImageFile(
                    display_hires_profile_image ? getBiggerTwitterProfileImage(profile_image_url_string)
                            : profile_image_url_string);
            final int w = res.getDimensionPixelSize(R.dimen.notification_large_icon_width);
            final int h = res.getDimensionPixelSize(R.dimen.notification_large_icon_height);
            builder.setLargeIcon(Bitmap.createScaledBitmap(profile_image_file != null && profile_image_file.isFile()
                    ? BitmapFactory.decodeFile(profile_image_file.getPath())
                    : BitmapFactory.decodeResource(res, R.drawable.ic_profile_image_default), w, h, true));
            final Intent delete_intent = new Intent(BROADCAST_NOTIFICATION_CLEARED);
            final Bundle delete_extras = new Bundle();
            delete_extras.putInt(INTENT_KEY_NOTIFICATION_ID, NOTIFICATION_ID_DIRECT_MESSAGES);
            delete_intent.putExtras(delete_extras);
            final Intent content_intent;
            if (values.length == 1) {
                final Uri.Builder uri_builder = new Uri.Builder();
                final long account_id = notification_value.getAsLong(DirectMessages.ACCOUNT_ID);
                final long conversation_id = notification_value.getAsLong(DirectMessages.SENDER_ID);
                uri_builder.scheme(SCHEME_TWIDERE);
                uri_builder.authority(AUTHORITY_DIRECT_MESSAGES_CONVERSATION);
                uri_builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
                uri_builder.appendQueryParameter(QUERY_PARAM_CONVERSATION_ID, String.valueOf(conversation_id));
                content_intent = new Intent(Intent.ACTION_VIEW, uri_builder.build());
            } else {
                content_intent = new Intent(context, HomeActivity.class);
                content_intent.setAction(Intent.ACTION_MAIN);
                content_intent.addCategory(Intent.CATEGORY_LAUNCHER);
                final Bundle content_extras = new Bundle();
                content_extras.putInt(INTENT_KEY_INITIAL_TAB, HomeActivity.TAB_POSITION_MESSAGES);
                content_intent.putExtras(content_extras);
            }
            final Notification notification = buildNotification(builder, title, title, message,
                    R.drawable.ic_stat_direct_message, null, content_intent, delete_intent);
            mNotificationManager.notify(NOTIFICATION_ID_DIRECT_MESSAGES, notification);
            break;
        }
        }
    }
}