From eb7434545ebede80669bea6a21c98c2e5a1be081 Mon Sep 17 00:00:00 2001 From: Mariotaku Lee Date: Thu, 2 Feb 2017 18:18:34 +0800 Subject: [PATCH] fixed media preload fixed #692 --- .../constant/SharedPreferenceConstants.java | 3 +- .../java/org/mariotaku/twidere/Twidere.java | 24 +- .../twidere/provider/TwidereDataProvider.java | 261 ++++++++---------- .../twidere/util/ImagePreloader.java | 73 ----- .../twidere/util/MediaLoaderWrapper.java | 261 ------------------ .../ktextension/TextViewExtensions.kt | 2 +- .../twidere/activity/ComposeActivity.kt | 2 +- .../StaggeredGridParcelableStatusesAdapter.kt | 2 +- .../twidere/app/TwidereApplication.kt | 7 +- .../twidere/constant/PreferenceKeys.kt | 5 +- .../receiver/ConnectivityStateReceiver.kt | 3 + .../twidere/task/twitter/GetActivitiesTask.kt | 37 ++- .../twidere/task/twitter/GetStatusesTask.kt | 29 +- .../twidere/util/DataStoreFunctions.kt | 1 + .../twidere/util/MediaLoaderWrapper.kt | 238 ++++++++++++++++ .../twidere/util/ReadStateManager.kt | 8 +- .../twidere/util/dagger/ApplicationModule.kt | 10 +- .../twidere/view/holder/StatusViewHolder.kt | 17 +- twidere/src/main/res/values/strings.xml | 6 +- .../src/main/res/xml/preferences_network.xml | 3 +- 20 files changed, 435 insertions(+), 557 deletions(-) delete mode 100644 twidere/src/main/java/org/mariotaku/twidere/util/ImagePreloader.java delete mode 100644 twidere/src/main/java/org/mariotaku/twidere/util/MediaLoaderWrapper.java create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/util/MediaLoaderWrapper.kt diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/SharedPreferenceConstants.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/SharedPreferenceConstants.java index 248f62c0bb..4e054362bd 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/SharedPreferenceConstants.java +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/SharedPreferenceConstants.java @@ -210,8 +210,7 @@ public interface SharedPreferenceConstants { String KEY_PHISHING_LINK_WARNING = "phishing_link_warning"; @Preference(type = STRING, hasDefault = true, defaultString = VALUE_LINK_HIGHLIGHT_OPTION_NONE) String KEY_LINK_HIGHLIGHT_OPTION = "link_highlight_option"; - String KEY_PRELOAD_PROFILE_IMAGES = "preload_profile_images"; - String KEY_PRELOAD_PREVIEW_IMAGES = "preload_preview_images"; + String KEY_MEDIA_PRELOAD = "media_preload"; @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true) String KEY_PRELOAD_WIFI_ONLY = "preload_wifi_only"; @Preference(type = BOOLEAN) diff --git a/twidere.library.extension/src/main/java/org/mariotaku/twidere/Twidere.java b/twidere.library.extension/src/main/java/org/mariotaku/twidere/Twidere.java index 752ede7604..96e4fd67a9 100644 --- a/twidere.library.extension/src/main/java/org/mariotaku/twidere/Twidere.java +++ b/twidere.library.extension/src/main/java/org/mariotaku/twidere/Twidere.java @@ -46,7 +46,8 @@ import org.mariotaku.twidere.model.ParcelableUser; import org.mariotaku.twidere.model.ParcelableUserList; import org.mariotaku.twidere.model.UserKey; -import org.mariotaku.twidere.provider.TwidereDataStore; +import org.mariotaku.twidere.provider.TwidereDataStore.CacheFiles; +import org.mariotaku.twidere.provider.TwidereDataStore.CachedImages; import org.mariotaku.twidere.provider.TwidereDataStore.DNS; import org.mariotaku.twidere.provider.TwidereDataStore.Permissions; import org.mariotaku.twidere.util.model.AccountDetailsUtils; @@ -78,7 +79,7 @@ public static void appendComposeActivityText(final Activity activity, final Stri public static ParcelFileDescriptor getCachedImageFd(final Context context, final String url) { if (context == null || url == null) return null; final ContentResolver resolver = context.getContentResolver(); - final Uri.Builder builder = TwidereDataStore.CachedImages.CONTENT_URI.buildUpon(); + final Uri.Builder builder = CachedImages.CONTENT_URI.buildUpon(); builder.appendQueryParameter(QUERY_PARAM_URL, url); try { return resolver.openFileDescriptor(builder.build(), "r"); @@ -87,27 +88,10 @@ public static ParcelFileDescriptor getCachedImageFd(final Context context, final } } - public static String getCachedImagePath(final Context context, final String url) { - if (context == null || url == null) return null; - final ContentResolver resolver = context.getContentResolver(); - final Uri.Builder builder = TwidereDataStore.CachedImages.CONTENT_URI.buildUpon(); - builder.appendQueryParameter(QUERY_PARAM_URL, url); - final Cursor cur = resolver.query(builder.build(), TwidereDataStore.CachedImages.MATRIX_COLUMNS, null, null, null); - if (cur == null) return null; - try { - if (cur.getCount() == 0) return null; - final int path_idx = cur.getColumnIndex(TwidereDataStore.CachedImages.PATH); - cur.moveToFirst(); - return cur.getString(path_idx); - } finally { - cur.close(); - } - } - public static ParcelFileDescriptor getCacheFileFd(final Context context, final String name) { if (context == null || name == null) return null; final ContentResolver resolver = context.getContentResolver(); - final Uri.Builder builder = TwidereDataStore.CacheFiles.CONTENT_URI.buildUpon(); + final Uri.Builder builder = CacheFiles.CONTENT_URI.buildUpon(); builder.appendQueryParameter(QUERY_PARAM_NAME, name); try { return resolver.openFileDescriptor(builder.build(), "r"); diff --git a/twidere/src/main/java/org/mariotaku/twidere/provider/TwidereDataProvider.java b/twidere/src/main/java/org/mariotaku/twidere/provider/TwidereDataProvider.java index 9556525cfe..ba92d5f029 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/provider/TwidereDataProvider.java +++ b/twidere/src/main/java/org/mariotaku/twidere/provider/TwidereDataProvider.java @@ -90,7 +90,6 @@ import org.mariotaku.twidere.model.ParcelableDirectMessageCursorIndices; import org.mariotaku.twidere.model.ParcelableStatusCursorIndices; import org.mariotaku.twidere.model.ParcelableUser; -import org.mariotaku.twidere.model.SpanItem; import org.mariotaku.twidere.model.StringLongPair; import org.mariotaku.twidere.model.UnreadItem; import org.mariotaku.twidere.model.UserKey; @@ -98,7 +97,6 @@ import org.mariotaku.twidere.model.util.ParcelableActivityUtils; import org.mariotaku.twidere.provider.TwidereDataStore.Activities; import org.mariotaku.twidere.provider.TwidereDataStore.CachedHashtags; -import org.mariotaku.twidere.provider.TwidereDataStore.CachedImages; import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships; import org.mariotaku.twidere.provider.TwidereDataStore.CachedStatuses; import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers; @@ -120,9 +118,7 @@ import org.mariotaku.twidere.util.DataStoreFunctionsKt; import org.mariotaku.twidere.util.DataStoreUtils; import org.mariotaku.twidere.util.DebugLog; -import org.mariotaku.twidere.util.ImagePreloader; import org.mariotaku.twidere.util.InternalTwitterContentUtils; -import org.mariotaku.twidere.util.JsonSerializer; import org.mariotaku.twidere.util.NotificationManagerWrapper; import org.mariotaku.twidere.util.ParseUtils; import org.mariotaku.twidere.util.PermissionsManager; @@ -137,7 +133,6 @@ import org.mariotaku.twidere.util.Utils; import org.mariotaku.twidere.util.collection.CompactHashSet; import org.mariotaku.twidere.util.dagger.GeneralComponentHelper; -import org.mariotaku.twidere.util.media.preview.PreviewMediaExtractor; import org.mariotaku.twidere.util.net.TwidereDns; import org.oshkimaadziig.george.androidutils.SpanFormatter; @@ -163,35 +158,45 @@ public final class TwidereDataProvider extends ContentProvider implements Consta public static final String TAG_OLDEST_MESSAGES = "oldest_messages"; private static final Pattern PATTERN_SCREEN_NAME = Pattern.compile("(?i)[@\uFF20]?([a-z0-9_]{1,20})"); @Inject - ReadStateManager mReadStateManager; + @NonNull + ReadStateManager readStateManager; @Inject - AsyncTwitterWrapper mTwitterWrapper; + @NonNull + AsyncTwitterWrapper twitterWrapper; @Inject - ImageLoader mMediaLoader; + @NonNull + ImageLoader mediaLoader; @Inject - NotificationManagerWrapper mNotificationManager; + @NonNull + NotificationManagerWrapper notificationManager; @Inject - SharedPreferencesWrapper mPreferences; + @NonNull + SharedPreferencesWrapper preferences; @Inject - TwidereDns mDns; + @NonNull + TwidereDns dns; @Inject - Bus mBus; + @NonNull + Bus bus; @Inject - UserColorNameManager mUserColorNameManager; + @NonNull + UserColorNameManager userColorNameManager; @Inject - BidiFormatter mBidiFormatter; + @NonNull + BidiFormatter bidiFormatter; @Inject - ActivityTracker mActivityTracker; + @NonNull + ActivityTracker activityTracker; @Inject - PermissionsManager mPermissionsManager; + @NonNull + PermissionsManager permissionsManager; private Handler mHandler; private ContentResolver mContentResolver; - private SQLiteDatabaseWrapper mDatabaseWrapper; - private ImagePreloader mImagePreloader; + private SQLiteDatabaseWrapper databaseWrapper; private Executor mBackgroundExecutor; - private boolean mNameFirst; - private boolean mUseStarForLikes; + private boolean nameFirst; + private boolean useStarForLikes; private static PendingIntent getMarkReadDeleteIntent(Context context, @NotificationType String type, @Nullable UserKey accountKey, long position, @@ -322,10 +327,10 @@ private boolean handleSQLException(SQLException e) { try { if (e instanceof SQLiteFullException) { // Drop cached databases - mDatabaseWrapper.delete(CachedUsers.TABLE_NAME, null, null); - mDatabaseWrapper.delete(CachedStatuses.TABLE_NAME, null, null); - mDatabaseWrapper.delete(CachedHashtags.TABLE_NAME, null, null); - mDatabaseWrapper.execSQL("VACUUM"); + databaseWrapper.delete(CachedUsers.TABLE_NAME, null, null); + databaseWrapper.delete(CachedStatuses.TABLE_NAME, null, null); + databaseWrapper.delete(CachedHashtags.TABLE_NAME, null, null); + databaseWrapper.execSQL("VACUUM"); return true; } } catch (SQLException ee) { @@ -347,13 +352,13 @@ private int bulkInsertInternal(@NonNull Uri uri, @NonNull ContentValues[] values int result = 0; final long[] newIds = new long[valuesArray.length]; if (table != null && valuesArray.length > 0) { - mDatabaseWrapper.beginTransaction(); + databaseWrapper.beginTransaction(); if (tableId == TABLE_ID_CACHED_USERS) { for (final ContentValues values : valuesArray) { final Expression where = Expression.equalsArgs(CachedUsers.USER_KEY); - mDatabaseWrapper.update(table, values, where.getSQL(), new String[]{ + databaseWrapper.update(table, values, where.getSQL(), new String[]{ values.getAsString(CachedUsers.USER_KEY)}); - newIds[result++] = mDatabaseWrapper.insertWithOnConflict(table, null, + newIds[result++] = databaseWrapper.insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_REPLACE); } } else if (tableId == TABLE_ID_SEARCH_HISTORY) { @@ -361,25 +366,25 @@ private int bulkInsertInternal(@NonNull Uri uri, @NonNull ContentValues[] values values.put(SearchHistory.RECENT_QUERY, System.currentTimeMillis()); final Expression where = Expression.equalsArgs(SearchHistory.QUERY); final String[] args = {values.getAsString(SearchHistory.QUERY)}; - mDatabaseWrapper.update(table, values, where.getSQL(), args); - newIds[result++] = mDatabaseWrapper.insertWithOnConflict(table, null, + databaseWrapper.update(table, values, where.getSQL(), args); + newIds[result++] = databaseWrapper.insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_IGNORE); } } else { final int conflictAlgorithm = getConflictAlgorithm(tableId); if (conflictAlgorithm != SQLiteDatabase.CONFLICT_NONE) { for (final ContentValues values : valuesArray) { - newIds[result++] = mDatabaseWrapper.insertWithOnConflict(table, null, + newIds[result++] = databaseWrapper.insertWithOnConflict(table, null, values, conflictAlgorithm); } } else { for (final ContentValues values : valuesArray) { - newIds[result++] = mDatabaseWrapper.insert(table, null, values); + newIds[result++] = databaseWrapper.insert(table, null, values); } } } - mDatabaseWrapper.setTransactionSuccessful(); - mDatabaseWrapper.endTransaction(); + databaseWrapper.setTransactionSuccessful(); + databaseWrapper.endTransaction(); } if (result > 0) { onDatabaseUpdated(tableId, uri); @@ -432,7 +437,7 @@ private int deleteInternal(@NonNull Uri uri, String selection, String[] selectio } } if (table == null) return 0; - final int result = mDatabaseWrapper.delete(table, selection, selectionArgs); + final int result = databaseWrapper.delete(table, selection, selectionArgs); if (result > 0) { onDatabaseUpdated(tableId, uri); } @@ -475,8 +480,8 @@ private Uri insertInternal(@NonNull Uri uri, ContentValues values) { case TABLE_ID_CACHED_USERS: { final Expression where = Expression.equalsArgs(CachedUsers.USER_KEY); final String[] whereArgs = {values.getAsString(CachedUsers.USER_KEY)}; - mDatabaseWrapper.update(table, values, where.getSQL(), whereArgs); - rowId = mDatabaseWrapper.insertWithOnConflict(table, null, values, + databaseWrapper.update(table, values, where.getSQL(), whereArgs); + rowId = databaseWrapper.insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_IGNORE); break; } @@ -484,8 +489,8 @@ private Uri insertInternal(@NonNull Uri uri, ContentValues values) { values.put(SearchHistory.RECENT_QUERY, System.currentTimeMillis()); final Expression where = Expression.equalsArgs(SearchHistory.QUERY); final String[] args = {values.getAsString(SearchHistory.QUERY)}; - mDatabaseWrapper.update(table, values, where.getSQL(), args); - rowId = mDatabaseWrapper.insertWithOnConflict(table, null, values, + databaseWrapper.update(table, values, where.getSQL(), args); + rowId = databaseWrapper.insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_IGNORE); break; } @@ -497,9 +502,9 @@ private Uri insertInternal(@NonNull Uri uri, ContentValues values) { Expression.equalsArgs(CachedRelationships.USER_KEY) ); final String[] whereArgs = {accountKey, userId}; - if (mDatabaseWrapper.update(table, values, where.getSQL(), whereArgs) > 0) { + if (databaseWrapper.update(table, values, where.getSQL(), whereArgs) > 0) { final String[] projection = {CachedRelationships._ID}; - final Cursor c = mDatabaseWrapper.query(table, projection, where.getSQL(), null, + final Cursor c = databaseWrapper.query(table, projection, where.getSQL(), null, null, null, null); if (c.moveToFirst()) { rowId = c.getLong(0); @@ -508,7 +513,7 @@ private Uri insertInternal(@NonNull Uri uri, ContentValues values) { } c.close(); } else { - rowId = mDatabaseWrapper.insertWithOnConflict(table, null, values, + rowId = databaseWrapper.insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_IGNORE); } break; @@ -520,10 +525,10 @@ private Uri insertInternal(@NonNull Uri uri, ContentValues values) { default: { final int conflictAlgorithm = getConflictAlgorithm(tableId); if (conflictAlgorithm != SQLiteDatabase.CONFLICT_NONE) { - rowId = mDatabaseWrapper.insertWithOnConflict(table, null, values, + rowId = databaseWrapper.insertWithOnConflict(table, null, values, conflictAlgorithm); } else if (table != null) { - rowId = mDatabaseWrapper.insert(table, null, values); + rowId = databaseWrapper.insert(table, null, values); } else { return null; } @@ -582,7 +587,7 @@ private long showDraftNotification(ContentValues values) { PendingIntent.getService(context, 0, sendIntent, PendingIntent.FLAG_ONE_SHOT)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); nb.setContentIntent(PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)); - mNotificationManager.notify(draftUri.toString(), NOTIFICATION_ID_DRAFTS, + notificationManager.notify(draftUri.toString(), NOTIFICATION_ID_DRAFTS, nb.build()); return draftId; } @@ -593,11 +598,10 @@ public boolean onCreate() { assert context != null; GeneralComponentHelper.build(context).inject(this); mHandler = new Handler(Looper.getMainLooper()); - mDatabaseWrapper = new SQLiteDatabaseWrapper(this); - mPreferences.registerOnSharedPreferenceChangeListener(this); + databaseWrapper = new SQLiteDatabaseWrapper(this); + preferences.registerOnSharedPreferenceChangeListener(this); mBackgroundExecutor = Executors.newSingleThreadExecutor(); updatePreferences(); - mImagePreloader = new ImagePreloader(context, mMediaLoader); // final GetWritableDatabaseTask task = new // GetWritableDatabaseTask(context, helper, mDatabaseWrapper); // task.executeTask(); @@ -660,7 +664,7 @@ public Cursor query(@NonNull final Uri uri, final String[] projection, final Str checkReadPermission(tableId, table, projection); switch (tableId) { case VIRTUAL_TABLE_ID_DATABASE_PREPARE: { - mDatabaseWrapper.prepare(); + databaseWrapper.prepare(); return new MatrixCursor(projection != null ? projection : new String[0]); } case VIRTUAL_TABLE_ID_PERMISSIONS: { @@ -669,12 +673,12 @@ public Cursor query(@NonNull final Uri uri, final String[] projection, final Str final MatrixCursor c = new MatrixCursor(Permissions.MATRIX_COLUMNS); final PackageManager pm = context.getPackageManager(); if (Binder.getCallingUid() == Process.myUid()) { - final Map map = mPermissionsManager.getAll(); + final Map map = permissionsManager.getAll(); for (final Map.Entry item : map.entrySet()) { c.addRow(new Object[]{item.getKey(), item.getValue()}); } } else { - final Map map = mPermissionsManager.getAll(); + final Map map = permissionsManager.getAll(); final String[] callingPackages = pm.getPackagesForUid(Binder.getCallingUid()); for (final Map.Entry item : map.entrySet()) { final String key = item.getKey(); @@ -686,17 +690,14 @@ public Cursor query(@NonNull final Uri uri, final String[] projection, final Str return c; } case VIRTUAL_TABLE_ID_ALL_PREFERENCES: { - return getPreferencesCursor(mPreferences, null); + return getPreferencesCursor(preferences, null); } case VIRTUAL_TABLE_ID_PREFERENCES: { - return getPreferencesCursor(mPreferences, uri.getLastPathSegment()); + return getPreferencesCursor(preferences, uri.getLastPathSegment()); } case VIRTUAL_TABLE_ID_DNS: { return getDNSCursor(uri.getLastPathSegment()); } - case VIRTUAL_TABLE_ID_CACHED_IMAGES: { - return getCachedImageCursor(uri.getQueryParameter(QUERY_PARAM_URL)); - } case VIRTUAL_TABLE_ID_NOTIFICATIONS: { final List segments = uri.getPathSegments(); if (segments.size() == 2) { @@ -726,7 +727,7 @@ public Cursor query(@NonNull final Uri uri, final String[] projection, final Str final Pair query = ConversationQueryBuilder .buildByConversationId(projection, accountId, conversationId, selection, sortOrder); - final Cursor c = mDatabaseWrapper.rawQuery(query.first.getSQL(), query.second); + final Cursor c = databaseWrapper.rawQuery(query.first.getSQL(), query.second); setNotificationUri(c, DirectMessages.CONTENT_URI); return c; } @@ -737,7 +738,7 @@ public Cursor query(@NonNull final Uri uri, final String[] projection, final Str final String screenName = segments.get(3); final Pair query = ConversationQueryBuilder.byScreenName( projection, accountKey, screenName, selection, sortOrder); - final Cursor c = mDatabaseWrapper.rawQuery(query.first.getSQL(), query.second); + final Cursor c = databaseWrapper.rawQuery(query.first.getSQL(), query.second); setNotificationUri(c, DirectMessages.CONTENT_URI); return c; } @@ -745,7 +746,7 @@ public Cursor query(@NonNull final Uri uri, final String[] projection, final Str final UserKey accountKey = UserKey.valueOf(uri.getLastPathSegment()); final Pair query = CachedUsersQueryBuilder.withRelationship(projection, selection, selectionArgs, sortOrder, accountKey); - final Cursor c = mDatabaseWrapper.rawQuery(query.first.getSQL(), query.second); + final Cursor c = databaseWrapper.rawQuery(query.first.getSQL(), query.second); setNotificationUri(c, CachedUsers.CONTENT_URI); return c; } @@ -753,12 +754,12 @@ public Cursor query(@NonNull final Uri uri, final String[] projection, final Str final UserKey accountKey = UserKey.valueOf(uri.getLastPathSegment()); final Pair query = CachedUsersQueryBuilder.withScore(projection, selection, selectionArgs, sortOrder, accountKey, 0); - final Cursor c = mDatabaseWrapper.rawQuery(query.first.getSQL(), query.second); + final Cursor c = databaseWrapper.rawQuery(query.first.getSQL(), query.second); setNotificationUri(c, CachedUsers.CONTENT_URI); return c; } case VIRTUAL_TABLE_ID_DRAFTS_UNSENT: { - final AsyncTwitterWrapper twitter = mTwitterWrapper; + final AsyncTwitterWrapper twitter = twitterWrapper; final RawItemArray sendingIds = new RawItemArray(twitter.getSendingDraftIds()); final Expression where; if (selection != null) { @@ -767,7 +768,7 @@ public Cursor query(@NonNull final Uri uri, final String[] projection, final Str } else { where = Expression.and(Expression.notIn(new Column(Drafts._ID), sendingIds)); } - final Cursor c = mDatabaseWrapper.query(Drafts.TABLE_NAME, projection, + final Cursor c = databaseWrapper.query(Drafts.TABLE_NAME, projection, where.getSQL(), selectionArgs, null, null, sortOrder); setNotificationUri(c, Utils.getNotificationUri(tableId, uri)); return c; @@ -788,11 +789,11 @@ public Cursor query(@NonNull final Uri uri, final String[] projection, final Str if (projection != null || selection != null || sortOrder != null) { throw new IllegalArgumentException(); } - return mDatabaseWrapper.rawQuery(uri.getLastPathSegment(), selectionArgs); + return databaseWrapper.rawQuery(uri.getLastPathSegment(), selectionArgs); } } if (table == null) return null; - final Cursor c = mDatabaseWrapper.query(table, projection, selection, selectionArgs, + final Cursor c = databaseWrapper.query(table, projection, selection, selectionArgs, null, null, sortOrder); setNotificationUri(c, Utils.getNotificationUri(tableId, uri)); return c; @@ -820,7 +821,7 @@ private Cursor getSearchSuggestionCursor(Uri uri) { new Column(SearchHistory.QUERY, Suggestions.Search.VALUE).getSQL(), }; final Expression historySelection = Expression.likeRaw(new Column(SearchHistory.QUERY), "?||'%'", "^"); - @SuppressLint("Recycle") final Cursor historyCursor = mDatabaseWrapper.query(true, + @SuppressLint("Recycle") final Cursor historyCursor = databaseWrapper.query(true, SearchHistory.TABLE_NAME, historyProjection, historySelection.getSQL(), new String[]{queryEscaped}, null, null, SearchHistory.DEFAULT_SORT_ORDER, TextUtils.isEmpty(query) ? "3" : "2"); @@ -837,7 +838,7 @@ private Cursor getSearchSuggestionCursor(Uri uri) { }; final Expression savedSearchesWhere = Expression.equalsArgs(SavedSearches.ACCOUNT_KEY); final String[] whereArgs = {accountKey.toString()}; - @SuppressLint("Recycle") final Cursor savedSearchesCursor = mDatabaseWrapper.query(true, + @SuppressLint("Recycle") final Cursor savedSearchesCursor = databaseWrapper.query(true, SavedSearches.TABLE_NAME, savedSearchesProjection, savedSearchesWhere.getSQL(), whereArgs, null, null, SavedSearches.DEFAULT_SORT_ORDER, null); cursors = new Cursor[2]; @@ -854,7 +855,7 @@ private Cursor getSearchSuggestionCursor(Uri uri) { new Column(CachedUsers.SCREEN_NAME, Suggestions.Search.VALUE).getSQL(), }; String queryTrimmed = queryEscaped.startsWith("@") ? queryEscaped.substring(1) : queryEscaped; - final String[] nicknameKeys = Utils.getMatchedNicknameKeys(query, mUserColorNameManager); + final String[] nicknameKeys = Utils.getMatchedNicknameKeys(query, userColorNameManager); final Expression usersSelection = Expression.or( Expression.likeRaw(new Column(CachedUsers.SCREEN_NAME), "?||'%'", "^"), Expression.likeRaw(new Column(CachedUsers.NAME), "?||'%'", "^"), @@ -869,9 +870,9 @@ private Cursor getSearchSuggestionCursor(Uri uri) { final Pair usersQuery = CachedUsersQueryBuilder.withScore(usersProjection, usersSelection.getSQL(), selectionArgs, orderBy.getSQL(), accountKey, 0); - @SuppressLint("Recycle") final Cursor usersCursor = mDatabaseWrapper.rawQuery(usersQuery.first.getSQL(), usersQuery.second); + @SuppressLint("Recycle") final Cursor usersCursor = databaseWrapper.rawQuery(usersQuery.first.getSQL(), usersQuery.second); final Expression exactUserSelection = Expression.or(Expression.likeRaw(new Column(CachedUsers.SCREEN_NAME), "?", "^")); - final Cursor exactUserCursor = mDatabaseWrapper.query(CachedUsers.TABLE_NAME, + final Cursor exactUserCursor = databaseWrapper.query(CachedUsers.TABLE_NAME, new String[]{SQLFunctions.COUNT()}, exactUserSelection.getSQL(), new String[]{queryTrimmed}, null, null, null, "1"); final boolean hasName = exactUserCursor.moveToPosition(0) && exactUserCursor.getInt(0) > 0; @@ -900,7 +901,7 @@ private Cursor getAutoCompleteSuggestionsCursor(@NonNull Uri uri) { if (query == null || type == null) return null; final String queryEscaped = query.replace("_", "^_"); if (Suggestions.AutoComplete.TYPE_USERS.equals(type)) { - final String[] nicknameKeys = Utils.getMatchedNicknameKeys(query, mUserColorNameManager); + final String[] nicknameKeys = Utils.getMatchedNicknameKeys(query, userColorNameManager); final Expression where = Expression.or(Expression.likeRaw(new Column(CachedUsers.SCREEN_NAME), "?||'%'", "^"), Expression.likeRaw(new Column(CachedUsers.NAME), "?||'%'", "^"), Expression.inArgs(new Column(CachedUsers.USER_KEY), nicknameKeys.length)); @@ -967,7 +968,7 @@ private int updateInternal(@NonNull Uri uri, ContentValues values, String select case TABLE_ID_DIRECT_MESSAGES_CONVERSATIONS_ENTRIES: return 0; } - result = mDatabaseWrapper.update(table, values, selection, selectionArgs); + result = databaseWrapper.update(table, values, selection, selectionArgs); } if (result > 0) { onDatabaseUpdated(tableId, uri); @@ -976,7 +977,7 @@ private int updateInternal(@NonNull Uri uri, ContentValues values, String select } private boolean checkPermission(final String... permissions) { - return mPermissionsManager.checkCallingPermission(permissions); + return permissionsManager.checkCallingPermission(permissions); } private void checkReadPermission(final int id, final String table, final String[] projection) { @@ -1019,7 +1020,7 @@ private void checkReadPermission(final int id, final String table, final String[ break; } default: { - if (!mPermissionsManager.checkSignature(Binder.getCallingUid())) { + if (!permissionsManager.checkSignature(Binder.getCallingUid())) { throw new SecurityException("Internal database " + id + " is not allowed for third-party applications"); } } @@ -1057,7 +1058,7 @@ private void checkWritePermission(final int id, final String table) { break; } default: { - if (!mPermissionsManager.checkSignature(Binder.getCallingUid())) { + if (!permissionsManager.checkSignature(Binder.getCallingUid())) { throw new SecurityException("Internal database is not allowed for third-party applications"); } } @@ -1065,30 +1066,18 @@ private void checkWritePermission(final int id, final String table) { } private void clearNotification() { - mNotificationManager.cancelAll(); + notificationManager.cancelAll(); } private void clearNotification(final int notificationType, final UserKey accountId) { - mNotificationManager.cancelById(Utils.getNotificationId(notificationType, accountId)); - } - - private Cursor getCachedImageCursor(final String url) { - if (BuildConfig.DEBUG) { - Log.d(LOGTAG, String.format("getCachedImageCursor(%s)", url)); - } - final MatrixCursor c = new MatrixCursor(CachedImages.MATRIX_COLUMNS); - final File file = mImagePreloader.getCachedImageFile(url); - if (url != null && file != null) { - c.addRow(new String[]{url, file.getPath()}); - } - return c; + notificationManager.cancelById(Utils.getNotificationId(notificationType, accountId)); } private ParcelFileDescriptor getCachedImageFd(final String url) throws FileNotFoundException { if (BuildConfig.DEBUG) { Log.d(LOGTAG, String.format("getCachedImageFd(%s)", url)); } - final File file = mImagePreloader.getCachedImageFile(url); + final File file = mediaLoader.getDiskCache().get(url); if (file == null) return null; return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } @@ -1113,7 +1102,7 @@ private ContentResolver getContentResolver() { private Cursor getDNSCursor(final String host) { final MatrixCursor c = new MatrixCursor(DNS.MATRIX_COLUMNS); try { - final List addresses = mDns.lookup(host); + final List addresses = dns.lookup(host); for (InetAddress address : addresses) { c.addRow(new String[]{host, address.getHostAddress()}); } @@ -1150,7 +1139,7 @@ private Cursor getUnreadCountsCursorByType(final String type) { } private boolean isNotificationAudible() { - return !mActivityTracker.isHomeActivityStarted(); + return !activityTracker.isHomeActivityStarted(); } private void notifyContentObserver(@NonNull final Uri uri) { @@ -1169,7 +1158,7 @@ private void notifyUnreadCountChanged(final int position) { mHandler.post(new Runnable() { @Override public void run() { - mBus.post(new UnreadCountUpdatedEvent(position)); + bus.post(new UnreadCountUpdatedEvent(position)); } }); notifyContentObserver(UnreadCounts.CONTENT_URI); @@ -1188,7 +1177,6 @@ private void onNewItemsInserted(final Uri uri, final int tableId, final ContentV final Context context = getContext(); if (uri == null || valuesArray == null || valuesArray.length == 0 || context == null) return; - preloadMedia(valuesArray); switch (tableId) { case TABLE_ID_STATUSES: { mBackgroundExecutor.execute(new Runnable() { @@ -1199,7 +1187,7 @@ public void run() { for (final AccountPreferences pref : prefs) { if (!pref.isHomeTimelineNotificationEnabled()) continue; final long positionTag = getPositionTag(CustomTabType.HOME_TIMELINE, pref.getAccountKey()); - showTimelineNotification(mPreferences, pref, positionTag); + showTimelineNotification(preferences, pref, positionTag); } notifyUnreadCountChanged(NOTIFICATION_ID_HOME_TIMELINE); } @@ -1212,7 +1200,7 @@ public void run() { public void run() { final AccountPreferences[] prefs = AccountPreferences.getNotificationEnabledPreferences(context, DataStoreUtils.getAccountKeys(context)); - final boolean combined = mPreferences.getBoolean(KEY_COMBINED_NOTIFICATIONS); + final boolean combined = preferences.getBoolean(KEY_COMBINED_NOTIFICATIONS); for (final AccountPreferences pref : prefs) { if (!pref.isInteractionsNotificationEnabled()) continue; showInteractionsNotification(pref, getPositionTag(ReadPositionTag.ACTIVITIES_ABOUT_ME, @@ -1228,7 +1216,7 @@ public void run() { DataStoreUtils.getAccountKeys(context)); for (final AccountPreferences pref : prefs) { if (!pref.isDirectMessagesNotificationEnabled()) continue; - final StringLongPair[] pairs = mReadStateManager.getPositionPairs(CustomTabType.DIRECT_MESSAGES); + final StringLongPair[] pairs = readStateManager.getPositionPairs(CustomTabType.DIRECT_MESSAGES); showMessagesNotification(pref, pairs, valuesArray); } notifyUnreadCountChanged(NOTIFICATION_ID_DIRECT_MESSAGES); @@ -1241,10 +1229,10 @@ public void run() { } private long getPositionTag(String tag, UserKey accountKey) { - final long position = mReadStateManager.getPosition(Utils.getReadPositionTagWithAccount(tag, + final long position = readStateManager.getPosition(Utils.getReadPositionTagWithAccount(tag, accountKey)); if (position != -1) return position; - return mReadStateManager.getPosition(tag); + return readStateManager.getPosition(tag); } private void showTimelineNotification(SharedPreferences preferences, AccountPreferences pref, long position) { @@ -1252,7 +1240,7 @@ private void showTimelineNotification(SharedPreferences preferences, AccountPref final Context context = getContext(); if (context == null) return; final Resources resources = context.getResources(); - final NotificationManagerWrapper nm = mNotificationManager; + final NotificationManagerWrapper nm = notificationManager; final Expression selection = Expression.and(Expression.equalsArgs(Statuses.ACCOUNT_KEY), Expression.greaterThan(Statuses.POSITION_KEY, position)); final String filteredSelection = DataStoreFunctionsKt.buildStatusFilterWhereClause(preferences, @@ -1260,9 +1248,9 @@ private void showTimelineNotification(SharedPreferences preferences, AccountPref final String[] selectionArgs = {accountKey.toString()}; final String[] userProjection = {Statuses.USER_KEY, Statuses.USER_NAME, Statuses.USER_SCREEN_NAME}; final String[] statusProjection = {Statuses.POSITION_KEY}; - final Cursor statusCursor = mDatabaseWrapper.query(Statuses.TABLE_NAME, statusProjection, + final Cursor statusCursor = databaseWrapper.query(Statuses.TABLE_NAME, statusProjection, filteredSelection, selectionArgs, null, null, Statuses.DEFAULT_SORT_ORDER); - final Cursor userCursor = mDatabaseWrapper.query(Statuses.TABLE_NAME, userProjection, + final Cursor userCursor = databaseWrapper.query(Statuses.TABLE_NAME, userProjection, filteredSelection, selectionArgs, Statuses.USER_KEY, null, Statuses.DEFAULT_SORT_ORDER); //noinspection TryFinallyCanBeTryWithResources try { @@ -1276,16 +1264,16 @@ private void showTimelineNotification(SharedPreferences preferences, AccountPref statusesCount, statusesCount); final String notificationContent; userCursor.moveToFirst(); - final String displayName = mUserColorNameManager.getDisplayName(userCursor.getString(userIndices.user_key), + final String displayName = userColorNameManager.getDisplayName(userCursor.getString(userIndices.user_key), userCursor.getString(userIndices.user_name), userCursor.getString(userIndices.user_screen_name), - mNameFirst); + nameFirst); if (usersCount == 1) { notificationContent = context.getString(R.string.from_name, displayName); } else if (usersCount == 2) { userCursor.moveToPosition(1); - final String othersName = mUserColorNameManager.getDisplayName(userCursor.getString(userIndices.user_key), + final String othersName = userColorNameManager.getDisplayName(userCursor.getString(userIndices.user_key), userCursor.getString(userIndices.user_name), userCursor.getString(userIndices.user_screen_name), - mNameFirst); + nameFirst); notificationContent = resources.getString(R.string.from_name_and_name, displayName, othersName); } else { notificationContent = resources.getString(R.string.from_name_and_N_others, displayName, usersCount - 1); @@ -1321,7 +1309,7 @@ private void showTimelineNotification(SharedPreferences preferences, AccountPref private void showInteractionsNotification(AccountPreferences pref, long position, boolean combined) { final Context context = getContext(); if (context == null) return; - final SQLiteDatabase db = mDatabaseWrapper.getSQLiteDatabase(); + final SQLiteDatabase db = databaseWrapper.getSQLiteDatabase(); final UserKey accountKey = pref.getAccountKey(); final String where = Expression.and( Expression.equalsArgs(Activities.ACCOUNT_KEY), @@ -1341,7 +1329,7 @@ private void showInteractionsNotification(AccountPreferences pref, long position applyNotificationPreferences(builder, pref, pref.getMentionsNotificationType()); final Resources resources = context.getResources(); - final String accountName = DataStoreUtils.getAccountDisplayName(context, accountKey, mNameFirst); + final String accountName = DataStoreUtils.getAccountDisplayName(context, accountKey, nameFirst); builder.setContentText(accountName); final InboxStyle style = new InboxStyle(); builder.setStyle(style); @@ -1380,8 +1368,8 @@ private void showInteractionsNotification(AccountPreferences pref, long position final ParcelableUser[] sources = ParcelableActivityUtils.INSTANCE.getAfterFilteredSources(activity); if (ArrayUtils.isEmpty(sources)) continue; final ActivityTitleSummaryMessage message = ActivityTitleSummaryMessage.get(context, - mUserColorNameManager, activity, sources, - 0, mUseStarForLikes, mNameFirst); + userColorNameManager, activity, sources, + 0, useStarForLikes, nameFirst); if (message != null) { final CharSequence summary = message.getSummary(); if (TextUtils.isEmpty(summary)) { @@ -1419,7 +1407,7 @@ private void showInteractionsNotification(AccountPreferences pref, long position } final int notificationId = Utils.getNotificationId(NOTIFICATION_ID_INTERACTIONS_TIMELINE, accountKey); - mNotificationManager.notify("interactions", notificationId, builder.build()); + notificationManager.notify("interactions", notificationId, builder.build()); Utils.sendPebbleNotification(context, context.getResources().getString(R.string.interactions), pebbleNotificationStringBuilder.toString()); @@ -1472,7 +1460,7 @@ private void showMessagesNotification(AccountPreferences pref, StringLongPair[] final Context context = getContext(); assert context != null; final UserKey accountKey = pref.getAccountKey(); - final long prevOldestId = mReadStateManager.getPosition(TAG_OLDEST_MESSAGES, + final long prevOldestId = readStateManager.getPosition(TAG_OLDEST_MESSAGES, String.valueOf(accountKey)); long oldestId = -1; for (final ContentValues contentValues : valuesArray) { @@ -1480,10 +1468,10 @@ private void showMessagesNotification(AccountPreferences pref, StringLongPair[] oldestId = oldestId < 0 ? messageId : Math.min(oldestId, messageId); if (messageId <= prevOldestId) return; } - mReadStateManager.setPosition(TAG_OLDEST_MESSAGES, String.valueOf(accountKey), oldestId, + readStateManager.setPosition(TAG_OLDEST_MESSAGES, String.valueOf(accountKey), oldestId, false); final Resources resources = context.getResources(); - final NotificationManagerWrapper nm = mNotificationManager; + final NotificationManagerWrapper nm = notificationManager; final ArrayList orExpressions = new ArrayList<>(); final String prefix = accountKey + "-"; final int prefixLength = prefix.length(); @@ -1519,10 +1507,10 @@ private void showMessagesNotification(AccountPreferences pref, StringLongPair[] final String[] messageProjection = {DirectMessages.MESSAGE_ID, DirectMessages.SENDER_ID, DirectMessages.SENDER_NAME, DirectMessages.SENDER_SCREEN_NAME, DirectMessages.TEXT_UNESCAPED, DirectMessages.MESSAGE_TIMESTAMP}; - final Cursor messageCursor = mDatabaseWrapper.query(DirectMessages.Inbox.TABLE_NAME, + final Cursor messageCursor = databaseWrapper.query(DirectMessages.Inbox.TABLE_NAME, messageProjection, filteredSelection, selectionArgs, null, null, DirectMessages.DEFAULT_SORT_ORDER); - final Cursor userCursor = mDatabaseWrapper.query(DirectMessages.Inbox.TABLE_NAME, + final Cursor userCursor = databaseWrapper.query(DirectMessages.Inbox.TABLE_NAME, userProjection, filteredSelection, selectionArgs, DirectMessages.SENDER_ID, null, DirectMessages.DEFAULT_SORT_ORDER); @@ -1544,8 +1532,8 @@ private void showMessagesNotification(AccountPreferences pref, StringLongPair[] messagesCount, messagesCount); final String notificationContent; userCursor.moveToFirst(); - final String displayName = mUserColorNameManager.getUserNickname(userCursor.getString(idxUserId), - mNameFirst ? userCursor.getString(idxUserName) : userCursor.getString(idxUserScreenName)); + final String displayName = userColorNameManager.getUserNickname(userCursor.getString(idxUserId), + nameFirst ? userCursor.getString(idxUserName) : userCursor.getString(idxUserScreenName)); if (usersCount == 1) { if (messagesCount == 1) { notificationContent = context.getString(R.string.notification_direct_message, displayName); @@ -1568,15 +1556,15 @@ private void showMessagesNotification(AccountPreferences pref, StringLongPair[] } if (i < 5) { final SpannableStringBuilder sb = new SpannableStringBuilder(); - sb.append(mUserColorNameManager.getUserNickname(messageCursor.getString(idxUserId), - mNameFirst ? messageCursor.getString(messageIndices.sender_name) : + sb.append(userColorNameManager.getUserNickname(messageCursor.getString(idxUserId), + nameFirst ? messageCursor.getString(messageIndices.sender_name) : messageCursor.getString(messageIndices.sender_screen_name))); sb.setSpan(new StyleSpan(Typeface.BOLD), 0, sb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); sb.append(' '); sb.append(messageCursor.getString(messageIndices.text_unescaped)); style.addLine(sb); - pebbleNotificationBuilder.append(mUserColorNameManager.getUserNickname(messageCursor.getString(idxUserId), - mNameFirst ? messageCursor.getString(messageIndices.sender_name) : + pebbleNotificationBuilder.append(userColorNameManager.getUserNickname(messageCursor.getString(idxUserId), + nameFirst ? messageCursor.getString(messageIndices.sender_name) : messageCursor.getString(messageIndices.sender_screen_name))); pebbleNotificationBuilder.append(": "); pebbleNotificationBuilder.append(messageCursor.getString(messageIndices.text_unescaped)); @@ -1586,7 +1574,7 @@ private void showMessagesNotification(AccountPreferences pref, StringLongPair[] final long messageId = messageCursor.getLong(messageIndices.id); idsMap.put(userId, Math.max(idsMap.get(userId, -1L), messageId)); } - if (mNameFirst) { + if (nameFirst) { style.setSummaryText(accountName); } else { style.setSummaryText("@" + accountScreenName); @@ -1627,33 +1615,6 @@ private void showMessagesNotification(AccountPreferences pref, StringLongPair[] } } - private void preloadMedia(final ContentValues... values) { - if (values == null) return; - final boolean preloadProfileImages = mPreferences.getBoolean(KEY_PRELOAD_PROFILE_IMAGES, false); - final boolean preloadPreviewMedia = mPreferences.getBoolean(KEY_PRELOAD_PREVIEW_IMAGES, false); - for (final ContentValues v : values) { - if (preloadProfileImages) { - mImagePreloader.preloadImage(v.getAsString(Statuses.USER_PROFILE_IMAGE_URL)); - mImagePreloader.preloadImage(v.getAsString(DirectMessages.SENDER_PROFILE_IMAGE_URL)); - mImagePreloader.preloadImage(v.getAsString(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL)); - } - if (preloadPreviewMedia) { - preloadSpans(JsonSerializer.parseList(v.getAsString(Statuses.SPANS), SpanItem.class)); - preloadSpans(JsonSerializer.parseList(v.getAsString(Statuses.QUOTED_SPANS), SpanItem.class)); - } - } - } - - private void preloadSpans(List spans) { - if (spans == null) return; - for (SpanItem span : spans) { - if (span.link == null) continue; - if (PreviewMediaExtractor.isSupported(span.link)) { - mImagePreloader.preloadImage(span.link); - } - } - } - private void setNotificationUri(final Cursor c, final Uri uri) { final ContentResolver cr = getContentResolver(); if (cr == null || c == null || uri == null) return; @@ -1661,8 +1622,8 @@ private void setNotificationUri(final Cursor c, final Uri uri) { } private void updatePreferences() { - mNameFirst = mPreferences.getBoolean(KEY_NAME_FIRST); - mUseStarForLikes = mPreferences.getBoolean(KEY_I_WANT_MY_STARS_BACK); + nameFirst = preferences.getBoolean(KEY_NAME_FIRST); + useStarForLikes = preferences.getBoolean(KEY_I_WANT_MY_STARS_BACK); } } diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/ImagePreloader.java b/twidere/src/main/java/org/mariotaku/twidere/util/ImagePreloader.java deleted file mode 100644 index 10748a567b..0000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/ImagePreloader.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Twidere - Twitter client for Android - * - * Copyright (C) 2012-2014 Mariotaku Lee - * - * 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 . - */ - -package org.mariotaku.twidere.util; - -import android.content.Context; -import android.content.SharedPreferences; -import android.net.ConnectivityManager; -import android.support.v4.net.ConnectivityManagerCompat; -import android.text.TextUtils; - -import com.nostra13.universalimageloader.cache.disc.DiskCache; -import com.nostra13.universalimageloader.core.ImageLoader; - -import java.io.File; - -import static org.mariotaku.twidere.TwidereConstants.SHARED_PREFERENCES_NAME; -import static org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_PRELOAD_WIFI_ONLY; - -/** - * @author mariotaku - */ -public class ImagePreloader { - - public static final String LOGTAG = "ImagePreloader"; - - private final SharedPreferences mPreferences; - private final DiskCache mDiskCache; - private final ImageLoader mImageLoader; - private final ConnectivityManager mConnectivityManager; - - public ImagePreloader(final Context context, final ImageLoader loader) { - mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - mPreferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); - mImageLoader = loader; - mDiskCache = loader.getDiskCache(); - } - - public File getCachedImageFile(final String url) { - if (url == null) return null; - final File cache = mDiskCache.get(url); - if (ImageValidator.isValid(ImageValidator.checkImageValidity(cache))) - return cache; - else { - preloadImage(url); - } - return null; - } - - public void preloadImage(final String url) { - if (TextUtils.isEmpty(url)) return; - if (ConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager) - && mPreferences.getBoolean(KEY_PRELOAD_WIFI_ONLY, true)) return; - mImageLoader.loadImage(url, null); - } - -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/MediaLoaderWrapper.java b/twidere/src/main/java/org/mariotaku/twidere/util/MediaLoaderWrapper.java deleted file mode 100644 index 1f51d60bc9..0000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/MediaLoaderWrapper.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Twidere - Twitter client for Android - * - * Copyright (C) 2012-2014 Mariotaku Lee - * - * 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 . - */ - -package org.mariotaku.twidere.util; - -import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; -import android.widget.ImageView; - -import com.nostra13.universalimageloader.core.DisplayImageOptions; -import com.nostra13.universalimageloader.core.DisplayImageOptions.Builder; -import com.nostra13.universalimageloader.core.ImageLoader; -import com.nostra13.universalimageloader.core.assist.ImageSize; -import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; - -import org.mariotaku.twidere.model.AccountDetails; -import org.mariotaku.twidere.model.ParcelableStatus; -import org.mariotaku.twidere.model.ParcelableUser; -import org.mariotaku.twidere.model.ParcelableUserList; -import org.mariotaku.twidere.model.UserKey; -import org.mariotaku.twidere.model.util.ParcelableUserUtils; -import org.mariotaku.twidere.util.imageloader.OvalBitmapDisplayer; -import org.mariotaku.twidere.util.media.MediaExtra; - -import javax.inject.Singleton; - -import static org.mariotaku.twidere.util.InternalTwitterContentUtils.getBestBannerUrl; - -@Singleton -public class MediaLoaderWrapper { - - private final ImageLoader mImageLoader; - private final DisplayImageOptions mProfileImageDisplayOptions; - private final DisplayImageOptions mDashboardProfileImageDisplayOptions; - private final DisplayImageOptions mOvalProfileImageDisplayOptions; - private final DisplayImageOptions mImageDisplayOptions, mBannerDisplayOptions; - - public MediaLoaderWrapper(final ImageLoader loader) { - mImageLoader = loader; - final DisplayImageOptions.Builder profileOptsBuilder = new DisplayImageOptions.Builder(); - profileOptsBuilder.cacheInMemory(true); - profileOptsBuilder.cacheOnDisk(true); - profileOptsBuilder.bitmapConfig(Bitmap.Config.ARGB_8888); - profileOptsBuilder.resetViewBeforeLoading(true); - final DisplayImageOptions.Builder ovalProfileOptsBuilder = new DisplayImageOptions.Builder(); - ovalProfileOptsBuilder.cacheInMemory(true); - ovalProfileOptsBuilder.cacheOnDisk(true); - ovalProfileOptsBuilder.bitmapConfig(Bitmap.Config.ARGB_8888); - ovalProfileOptsBuilder.displayer(new OvalBitmapDisplayer()); - ovalProfileOptsBuilder.resetViewBeforeLoading(true); - final DisplayImageOptions.Builder imageOptsBuilder = new DisplayImageOptions.Builder(); - imageOptsBuilder.cacheInMemory(true); - imageOptsBuilder.cacheOnDisk(true); - imageOptsBuilder.bitmapConfig(Bitmap.Config.RGB_565); - imageOptsBuilder.resetViewBeforeLoading(true); - final DisplayImageOptions.Builder bannerOptsBuilder = new DisplayImageOptions.Builder(); - bannerOptsBuilder.resetViewBeforeLoading(true); - bannerOptsBuilder.showImageOnLoading(android.R.color.transparent); - bannerOptsBuilder.cacheInMemory(true); - bannerOptsBuilder.cacheOnDisk(true); - bannerOptsBuilder.bitmapConfig(Bitmap.Config.RGB_565); - final DisplayImageOptions.Builder dashboardProfileOptsBuilder = new DisplayImageOptions.Builder(); - dashboardProfileOptsBuilder.cacheInMemory(true); - dashboardProfileOptsBuilder.cacheOnDisk(true); - dashboardProfileOptsBuilder.bitmapConfig(Bitmap.Config.RGB_565); - - mProfileImageDisplayOptions = profileOptsBuilder.build(); - mOvalProfileImageDisplayOptions = ovalProfileOptsBuilder.build(); - mImageDisplayOptions = imageOptsBuilder.build(); - mBannerDisplayOptions = bannerOptsBuilder.build(); - mDashboardProfileImageDisplayOptions = dashboardProfileOptsBuilder.build(); - } - - public ImageLoader getImageLoader() { - return mImageLoader; - } - - public void clearFileCache() { - mImageLoader.clearDiskCache(); - } - - public void clearMemoryCache() { - mImageLoader.clearMemoryCache(); - } - - public void displayPreviewImage(final String uri, final ImageView view) { - mImageLoader.displayImage(uri, view, mImageDisplayOptions); - } - - public void displayPreviewImage(final ImageView view, final String url, final MediaLoadingHandler loadingHandler) { - mImageLoader.displayImage(url, view, mImageDisplayOptions, loadingHandler, loadingHandler); - } - - public void displayPreviewImageWithCredentials(final ImageView view, final String url, - final UserKey accountKey, - final MediaLoadingHandler loadingHandler) { - if (accountKey == null) { - displayPreviewImage(view, url, loadingHandler); - return; - } - final DisplayImageOptions.Builder b = new DisplayImageOptions.Builder(); - b.cloneFrom(mImageDisplayOptions); - MediaExtra extra = new MediaExtra(); - extra.setAccountKey(accountKey); - b.extraForDownloader(extra); - mImageLoader.displayImage(url, view, b.build(), loadingHandler, loadingHandler); - } - - public void displayProfileBanner(final ImageView view, final String url, - final ImageLoadingListener listener) { - mImageLoader.displayImage(url, view, mBannerDisplayOptions, listener); - } - - public void displayProfileBanner(final ImageView view, final String url, final int width, - final ImageLoadingListener listener) { - mImageLoader.displayImage(getBestBannerUrl(url, width), view, mBannerDisplayOptions, - listener); - } - - public void displayProfileBanner(final ImageView view, final String url) { - displayProfileBanner(view, url, null); - } - - public void displayProfileBanner(final ImageView view, final String baseUrl, final int width) { - displayProfileBanner(view, getBestBannerUrl(baseUrl, width)); - } - - - public void displayProfileBanner(final ImageView view, final AccountDetails account, final int width) { - displayProfileBanner(view, getBestBannerUrl(ParcelableUserUtils.getProfileBannerUrl(account.user), width)); - } - - public void displayOriginalProfileImage(final ImageView view, final ParcelableUser user) { - if (user.extras != null && !TextUtils.isEmpty(user.extras.profile_image_url_original)) { - displayProfileImage(view, user.extras.profile_image_url_original); - } else if (user.extras != null && !TextUtils.isEmpty(user.extras.profile_image_url_profile_size)) { - displayProfileImage(view, user.extras.profile_image_url_profile_size); - } else { - displayProfileImage(view, Utils.getOriginalTwitterProfileImage(user.profile_image_url)); - } - } - - public void displayProfileImage(final ImageView view, final ParcelableUser user) { - if (user.extras != null && !TextUtils.isEmpty(user.extras.profile_image_url_profile_size)) { - displayProfileImage(view, user.extras.profile_image_url_profile_size); - } else { - displayProfileImage(view, user.profile_image_url); - } - } - - public void displayProfileImage(final ImageView view, final ParcelableUserList userList) { - displayProfileImage(view, userList.user_profile_image_url); - } - - public void displayProfileImage(final ImageView view, final AccountDetails account) { - if (account.user.extras != null && !TextUtils.isEmpty(account.user.extras.profile_image_url_profile_size)) { - displayProfileImage(view, account.user.extras.profile_image_url_profile_size); - } else { - displayProfileImage(view, account.user.profile_image_url); - } - } - - public void displayProfileImage(final ImageView view, final ParcelableStatus status) { - if (status.extras != null && !TextUtils.isEmpty(status.extras.user_profile_image_url_profile_size)) { - displayProfileImage(view, status.extras.user_profile_image_url_profile_size); - } else { - displayProfileImage(view, status.user_profile_image_url); - } - } - - public void displayProfileImage(final ImageView view, final String url) { - mImageLoader.displayImage(url, view, mProfileImageDisplayOptions); - } - - public Bitmap loadImageSync(String uri) { - return mImageLoader.loadImageSync(uri); - } - - public Bitmap loadImageSync(String uri, DisplayImageOptions options) { - return mImageLoader.loadImageSync(uri, options); - } - - public Bitmap loadImageSync(String uri, ImageSize targetImageSize) { - return mImageLoader.loadImageSync(uri, targetImageSize); - } - - public Bitmap loadImageSync(String uri, ImageSize targetImageSize, DisplayImageOptions options) { - return mImageLoader.loadImageSync(uri, targetImageSize, options); - } - - public void displayDashboardProfileImage(@NonNull final ImageView view, - @NonNull final AccountDetails account, - @Nullable final Drawable drawableOnLoading) { - if (account.user.extras != null && !TextUtils.isEmpty(account.user.extras.profile_image_url_profile_size)) { - displayDashboardProfileImage(view, account.user.extras.profile_image_url_profile_size, - drawableOnLoading); - } else { - displayDashboardProfileImage(view, account.user.profile_image_url, drawableOnLoading); - } - } - - void displayDashboardProfileImage(final ImageView view, final String url, Drawable drawableOnLoading) { - if (drawableOnLoading != null) { - final Builder builder = new Builder(); - builder.cloneFrom(mDashboardProfileImageDisplayOptions); - builder.showImageOnLoading(drawableOnLoading); - builder.showImageOnFail(drawableOnLoading); - mImageLoader.displayImage(url, view, builder.build()); - return; - } - mImageLoader.displayImage(url, view, mDashboardProfileImageDisplayOptions); - } - - - public void displayImage(final ImageView view, final String url) { - mImageLoader.displayImage(url, view); - } - - public void displayProfileImage(final ImageView view, final String url, final ImageLoadingListener listener) { - mImageLoader.displayImage(url, view, mProfileImageDisplayOptions, listener); - } - - public void loadProfileImage(final AccountDetails account, final ImageLoadingListener listener) { - if (account.user.extras != null && !TextUtils.isEmpty(account.user.extras.profile_image_url_profile_size)) { - loadProfileImage(account.user.extras.profile_image_url_profile_size, listener); - } else { - loadProfileImage(account.user.profile_image_url, listener); - } - } - - public void loadProfileImage(final String url, final ImageLoadingListener listener) { - mImageLoader.loadImage(url, mProfileImageDisplayOptions, listener); - } - - public void displayOvalProfileImage(final String url, final ImageView view) { - mImageLoader.displayImage(url, view, mOvalProfileImageDisplayOptions); - } - - public void cancelDisplayTask(ImageView imageView) { - mImageLoader.cancelDisplayTask(imageView); - } -} diff --git a/twidere/src/main/kotlin/org/mariotaku/ktextension/TextViewExtensions.kt b/twidere/src/main/kotlin/org/mariotaku/ktextension/TextViewExtensions.kt index fc1709c58d..18390157e2 100644 --- a/twidere/src/main/kotlin/org/mariotaku/ktextension/TextViewExtensions.kt +++ b/twidere/src/main/kotlin/org/mariotaku/ktextension/TextViewExtensions.kt @@ -8,6 +8,6 @@ val TextView.empty: Boolean fun TextView.applyFontFamily(lightFont: Boolean) { if (lightFont) { - typeface = Typeface.create("sans-serif-light", typeface?.style ?: 0) + typeface = Typeface.create("sans-serif-light", typeface?.style ?: Typeface.NORMAL) } } \ No newline at end of file diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt index dcdf7f1a14..5c9abd8af4 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt @@ -1783,7 +1783,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener } fun displayMedia(adapter: MediaPreviewAdapter, media: ParcelableMediaUpdate) { - adapter.mediaLoader.displayPreviewImage(media.uri, imageView) + adapter.mediaLoader.displayPreviewImage(imageView, media.uri) videoIndicatorView.visibility = if (media.type == ParcelableMedia.Type.VIDEO) { View.VISIBLE } else { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/StaggeredGridParcelableStatusesAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/StaggeredGridParcelableStatusesAdapter.kt index 566e052bb2..638eb42677 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/StaggeredGridParcelableStatusesAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/StaggeredGridParcelableStatusesAdapter.kt @@ -59,7 +59,7 @@ class StaggeredGridParcelableStatusesAdapter(context: Context) : ParcelableStatu private val mediaImageContainer: AspectLockedFrameLayout private val mediaImageView: MediaPreviewImageView - override val profileImageView: ImageView? + override val profileImageView: ImageView private val mediaTextView: TextView private var listener: IStatusViewHolder.StatusClickListener? = null diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt index 047527e3da..8a5fe9965e 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt @@ -81,6 +81,8 @@ class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeLis lateinit internal var syncController: SyncController @Inject lateinit internal var extraFeaturesService: ExtraFeaturesService + @Inject + lateinit internal var mediaLoader: MediaLoaderWrapper override fun attachBaseContext(base: Context) { super.attachBaseContext(base) @@ -216,6 +218,7 @@ class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeLis } override fun onLowMemory() { + mediaLoader.clearMemoryCache() super.onLowMemory() } @@ -241,6 +244,9 @@ class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeLis KEY_THUMBOR_ADDRESS, KEY_THUMBOR_ENABLED, KEY_THUMBOR_SECURITY_KEY -> { (mediaDownloader as TwidereMediaDownloader).reloadConnectivitySettings() } + KEY_MEDIA_PRELOAD, KEY_PRELOAD_WIFI_ONLY -> { + mediaLoader.reloadOptions(preferences) + } } } @@ -253,7 +259,6 @@ class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeLis dns.reloadDnsSettings() } - private fun initializeAsyncTask() { // AsyncTask class needs to be loaded in UI thread. // So we load it here to comply the rule. diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/constant/PreferenceKeys.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/constant/PreferenceKeys.kt index 9f6b09a7ac..4ac5ce7405 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/constant/PreferenceKeys.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/constant/PreferenceKeys.kt @@ -7,9 +7,8 @@ import org.mariotaku.kpreferences.* import org.mariotaku.ktextension.toLong import org.mariotaku.twidere.BuildConfig import org.mariotaku.twidere.Constants.* +import org.mariotaku.twidere.TwidereConstants.KEY_MEDIA_PRELOAD import org.mariotaku.twidere.annotation.AccountType -import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_COMPOSE_ACCOUNTS -import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_DISPLAY_SENSITIVE_CONTENTS import org.mariotaku.twidere.extension.getNonEmptyString import org.mariotaku.twidere.model.CustomAPIConfig import org.mariotaku.twidere.model.UserKey @@ -60,6 +59,8 @@ val chromeCustomTabKey = KBooleanKey("chrome_custom_tab", true) val usageStatisticsKey = KBooleanKey(KEY_USAGE_STATISTICS, false) val lightFontKey = KBooleanKey("light_font", false) val extraFeaturesNoticeVersionKey = KIntKey("extra_features_notice_version", 0) +val mediaPreloadKey = KBooleanKey(KEY_MEDIA_PRELOAD, false) +val mediaPreloadOnWifiOnlyKey = KBooleanKey(KEY_PRELOAD_WIFI_ONLY, true) object themeBackgroundAlphaKey : KSimpleKey(KEY_THEME_BACKGROUND_ALPHA, 0xFF) { override fun read(preferences: SharedPreferences): Int { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/receiver/ConnectivityStateReceiver.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/receiver/ConnectivityStateReceiver.kt index df49342403..dbb1842efc 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/receiver/ConnectivityStateReceiver.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/receiver/ConnectivityStateReceiver.kt @@ -34,6 +34,7 @@ import org.mariotaku.twidere.app.TwidereApplication import org.mariotaku.twidere.constant.usageStatisticsKey import org.mariotaku.twidere.util.DebugLog import org.mariotaku.twidere.util.Utils +import org.mariotaku.twidere.util.dagger.DependencyHolder class ConnectivityStateReceiver : BroadcastReceiver() { @@ -42,6 +43,7 @@ class ConnectivityStateReceiver : BroadcastReceiver() { if (ConnectivityManager.CONNECTIVITY_ACTION != intent.action) return val application = TwidereApplication.getInstance(context) // application.reloadConnectivitySettings(); + val prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE) if (prefs[usageStatisticsKey]) { @@ -54,6 +56,7 @@ class ConnectivityStateReceiver : BroadcastReceiver() { val appContext = context.applicationContext val cm = appContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val isNetworkMetered = ConnectivityManagerCompat.isActiveNetworkMetered(cm) + DependencyHolder.get(context).mediaLoader.isNetworkMetered = isNetworkMetered val isCharging = Utils.isCharging(appContext) if (!isNetworkMetered && isCharging) { val currentTime = System.currentTimeMillis() diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesTask.kt index af907c3267..8bf66ae2a6 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesTask.kt @@ -38,6 +38,7 @@ import javax.inject.Inject abstract class GetActivitiesTask( protected val context: Context ) : AbstractTask Unit>() { + private var initialized: Boolean = false @Inject lateinit var preferences: KPreferences @Inject @@ -48,13 +49,20 @@ abstract class GetActivitiesTask( lateinit var readStateManager: ReadStateManager @Inject lateinit var userColorNameManager: UserColorNameManager + @Inject + lateinit var mediaLoader: MediaLoaderWrapper + + protected abstract val errorInfoKey: String + + protected abstract val contentUri: Uri init { GeneralComponentHelper.build(context).inject(this) + initialized = true } override fun doLongOperation(param: RefreshTaskParam) { - if (param.shouldAbort) return + if (!initialized || param.shouldAbort) return val accountIds = param.accountKeys val maxIds = param.maxIds val maxSortIds = param.maxSortIds @@ -112,7 +120,12 @@ abstract class GetActivitiesTask( } } - protected abstract val errorInfoKey: String + override fun afterExecute(handler: ((Boolean) -> Unit)?, result: Unit) { + if (!initialized) return + context.contentResolver.notifyChange(contentUri, null) + bus.post(GetActivitiesTaskEvent(contentUri, false, null)) + handler?.invoke(true) + } private fun storeActivities(cr: ContentResolver, loadItemLimit: Int, details: AccountDetails, noItemsBefore: Boolean, activities: ResponseList, @@ -129,6 +142,7 @@ abstract class GetActivitiesTask( for (i in activities.indices) { val item = activities[i] val activity = ParcelableActivityUtils.fromActivity(item, details.key, false) + mediaLoader.preloadActivity(activity) activity.position_key = GetStatusesTask.getPositionKey(activity.timestamp, activity.timestamp, lastSortId, sortDiff, i, activities.size) if (deleteBound[0] < 0) { @@ -184,21 +198,14 @@ abstract class GetActivitiesTask( } } - protected abstract fun saveReadPosition(accountKey: UserKey, details: AccountDetails, twitter: MicroBlog) - - @Throws(MicroBlogException::class) - protected abstract fun getActivities(twitter: MicroBlog, details: AccountDetails, paging: Paging): ResponseList - - override fun afterExecute(handler: ((Boolean) -> Unit)?, result: Unit) { - context.contentResolver.notifyChange(contentUri, null) - bus.post(GetActivitiesTaskEvent(contentUri, false, null)) - handler?.invoke(true) - } - - protected abstract val contentUri: Uri - @UiThread override fun beforeExecute() { + if (!initialized) return bus.post(GetActivitiesTaskEvent(contentUri, true, null)) } + + protected abstract fun saveReadPosition(accountKey: UserKey, details: AccountDetails, twitter: MicroBlog) + + @Throws(MicroBlogException::class) + protected abstract fun getActivities(twitter: MicroBlog, details: AccountDetails, paging: Paging): ResponseList } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetStatusesTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetStatusesTask.kt index 7d4b7a2957..21cde221dd 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetStatusesTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetStatusesTask.kt @@ -45,6 +45,7 @@ import javax.inject.Inject abstract class GetStatusesTask( protected val context: Context ) : AbstractTask, (Boolean) -> Unit>() { + private var initialized: Boolean = false @Inject lateinit var preferences: SharedPreferencesWrapper @Inject @@ -55,9 +56,12 @@ abstract class GetStatusesTask( lateinit var manager: UserColorNameManager @Inject lateinit var wrapper: AsyncTwitterWrapper + @Inject + lateinit var mediaLoader: MediaLoaderWrapper init { GeneralComponentHelper.build(context).inject(this) + initialized = true } @Throws(MicroBlogException::class) @@ -67,20 +71,10 @@ abstract class GetStatusesTask( protected abstract val timelineType: String - override fun afterExecute(handler: ((Boolean) -> Unit)?, result: List) { - context.contentResolver.notifyChange(contentUri, null) - bus.post(GetStatusesTaskEvent(contentUri, false, AsyncTwitterWrapper.getException(result))) - handler?.invoke(true) - } - - override fun beforeExecute() { - bus.post(GetStatusesTaskEvent(contentUri, true, null)) - } - protected abstract val errorInfoKey: String override fun doLongOperation(param: RefreshTaskParam): List { - if (param.shouldAbort) return emptyList() + if (!initialized || param.shouldAbort) return emptyList() val accountKeys = param.accountKeys val maxIds = param.maxIds val sinceIds = param.sinceIds @@ -149,6 +143,18 @@ abstract class GetStatusesTask( return result } + override fun afterExecute(handler: ((Boolean) -> Unit)?, result: List) { + if (!initialized) return + context.contentResolver.notifyChange(contentUri, null) + bus.post(GetStatusesTaskEvent(contentUri, false, AsyncTwitterWrapper.getException(result))) + handler?.invoke(true) + } + + override fun beforeExecute() { + if (!initialized) return + bus.post(GetStatusesTaskEvent(contentUri, true, null)) + } + private fun storeStatus(accountKey: UserKey, details: AccountDetails, statuses: List, sinceId: String?, maxId: String?, @@ -177,6 +183,7 @@ abstract class GetStatusesTask( status.position_key = getPositionKey(status.timestamp, status.sort_id, lastSortId, sortDiff, i, statuses.size) status.inserted_date = System.currentTimeMillis() + mediaLoader.preloadStatus(status) values[i] = ParcelableStatusValuesCreator.create(status) if (minIdx == -1 || item < statuses[minIdx]) { minIdx = i diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/DataStoreFunctions.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/DataStoreFunctions.kt index 51ccd09ad5..c2fcae2bea 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/DataStoreFunctions.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/DataStoreFunctions.kt @@ -110,6 +110,7 @@ fun deleteAccountData(resolver: ContentResolver, accountKey: UserKey) { // deleted. resolver.delete(Statuses.CONTENT_URI, where, whereArgs) resolver.delete(Mentions.CONTENT_URI, where, whereArgs) + resolver.delete(Activities.AboutMe.CONTENT_URI, where, whereArgs) resolver.delete(DirectMessages.Inbox.CONTENT_URI, where, whereArgs) resolver.delete(DirectMessages.Outbox.CONTENT_URI, where, whereArgs) } \ No newline at end of file diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/MediaLoaderWrapper.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/MediaLoaderWrapper.kt new file mode 100644 index 0000000000..160d8800d3 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/MediaLoaderWrapper.kt @@ -0,0 +1,238 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * 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 . + */ + +package org.mariotaku.twidere.util + +import android.content.SharedPreferences +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import android.text.TextUtils +import android.widget.ImageView +import com.nostra13.universalimageloader.core.DisplayImageOptions +import com.nostra13.universalimageloader.core.DisplayImageOptions.Builder +import com.nostra13.universalimageloader.core.ImageLoader +import com.nostra13.universalimageloader.core.assist.ImageSize +import com.nostra13.universalimageloader.core.listener.ImageLoadingListener +import org.mariotaku.kpreferences.get +import org.mariotaku.twidere.constant.mediaPreloadKey +import org.mariotaku.twidere.constant.mediaPreloadOnWifiOnlyKey +import org.mariotaku.twidere.model.* +import org.mariotaku.twidere.model.util.ParcelableUserUtils +import org.mariotaku.twidere.model.util.getActivityStatus +import org.mariotaku.twidere.util.InternalTwitterContentUtils.getBestBannerUrl +import org.mariotaku.twidere.util.media.MediaExtra +import javax.inject.Singleton + +@Singleton +class MediaLoaderWrapper(val imageLoader: ImageLoader) { + + var isNetworkMetered: Boolean = true + private var preloadEnabled: Boolean = false + private var preloadOnWifiOnly: Boolean = true + + private val shouldPreload: Boolean get() = preloadEnabled && (!preloadOnWifiOnly || !isNetworkMetered) + + private val profileImageDisplayOptions = DisplayImageOptions.Builder() + .resetViewBeforeLoading(true) + .cacheInMemory(true) + .cacheOnDisk(true) + .bitmapConfig(Bitmap.Config.ARGB_8888) + .build() + + private val dashboardProfileImageDisplayOptions = DisplayImageOptions.Builder() + .cacheInMemory(true) + .cacheOnDisk(true) + .bitmapConfig(Bitmap.Config.RGB_565) + .build() + + private val previewDisplayOptions = DisplayImageOptions.Builder() + .resetViewBeforeLoading(true) + .cacheInMemory(true) + .cacheOnDisk(true) + .bitmapConfig(Bitmap.Config.RGB_565) + .build() + + private val bannerDisplayOptions = DisplayImageOptions.Builder() + .resetViewBeforeLoading(true) + .showImageOnLoading(android.R.color.transparent) + .cacheInMemory(true) + .cacheOnDisk(true) + .bitmapConfig(Bitmap.Config.RGB_565) + .build() + + + fun displayPreviewImage(view: ImageView, uri: String?) { + imageLoader.displayImage(uri, view, previewDisplayOptions) + } + + fun displayPreviewImage(view: ImageView, url: String?, loadingHandler: MediaLoadingHandler?) { + imageLoader.displayImage(url, view, previewDisplayOptions, loadingHandler, loadingHandler) + } + + fun displayPreviewImageWithCredentials(view: ImageView, url: String?, accountKey: UserKey?, loadingHandler: MediaLoadingHandler?) { + if (accountKey == null) { + displayPreviewImage(view, url, loadingHandler) + return + } + val b = DisplayImageOptions.Builder() + b.cloneFrom(previewDisplayOptions) + val extra = MediaExtra() + extra.accountKey = accountKey + b.extraForDownloader(extra) + imageLoader.displayImage(url, view, b.build(), loadingHandler, loadingHandler) + } + + + fun displayProfileBanner(view: ImageView, url: String?, listener: ImageLoadingListener? = null) { + imageLoader.displayImage(url, view, bannerDisplayOptions, listener) + } + + + fun displayProfileBanner(view: ImageView, baseUrl: String?, width: Int) { + displayProfileBanner(view, getBestBannerUrl(baseUrl, width)) + } + + fun displayProfileBanner(view: ImageView, account: AccountDetails, width: Int) { + displayProfileBanner(view, getBestBannerUrl(ParcelableUserUtils.getProfileBannerUrl(account.user), width)) + } + + fun displayOriginalProfileImage(view: ImageView, user: ParcelableUser) { + if (user.extras != null && !TextUtils.isEmpty(user.extras.profile_image_url_original)) { + displayProfileImage(view, user.extras.profile_image_url_original) + } else if (user.extras != null && !TextUtils.isEmpty(user.extras.profile_image_url_profile_size)) { + displayProfileImage(view, user.extras.profile_image_url_profile_size) + } else { + displayProfileImage(view, Utils.getOriginalTwitterProfileImage(user.profile_image_url)) + } + } + + fun displayProfileImage(view: ImageView, user: ParcelableUser) { + if (user.extras != null && !TextUtils.isEmpty(user.extras.profile_image_url_profile_size)) { + displayProfileImage(view, user.extras.profile_image_url_profile_size) + } else { + displayProfileImage(view, user.profile_image_url) + } + } + + fun displayProfileImage(view: ImageView, userList: ParcelableUserList) { + displayProfileImage(view, userList.user_profile_image_url) + } + + fun displayProfileImage(view: ImageView, account: AccountDetails) { + if (account.user.extras != null && !TextUtils.isEmpty(account.user.extras.profile_image_url_profile_size)) { + displayProfileImage(view, account.user.extras.profile_image_url_profile_size) + } else { + displayProfileImage(view, account.user.profile_image_url) + } + } + + fun displayProfileImage(view: ImageView, status: ParcelableStatus) { + if (status.extras != null && !TextUtils.isEmpty(status.extras.user_profile_image_url_profile_size)) { + displayProfileImage(view, status.extras.user_profile_image_url_profile_size) + } else { + displayProfileImage(view, status.user_profile_image_url) + } + } + + fun displayProfileImage(view: ImageView, url: String) { + imageLoader.displayImage(url, view, profileImageDisplayOptions) + } + + fun loadImageSync(uri: String, targetImageSize: ImageSize, options: DisplayImageOptions): Bitmap { + return imageLoader.loadImageSync(uri, targetImageSize, options) + } + + fun displayDashboardProfileImage(view: ImageView, account: AccountDetails, drawableOnLoading: Drawable?) { + if (account.user.extras != null && !TextUtils.isEmpty(account.user.extras.profile_image_url_profile_size)) { + displayDashboardProfileImage(view, account.user.extras.profile_image_url_profile_size, + drawableOnLoading) + } else { + displayDashboardProfileImage(view, account.user.profile_image_url, drawableOnLoading) + } + } + + + fun displayImage(view: ImageView, url: String) { + imageLoader.displayImage(url, view) + } + + fun displayProfileImage(view: ImageView, url: String, listener: ImageLoadingListener) { + imageLoader.displayImage(url, view, profileImageDisplayOptions, listener) + } + + fun cancelDisplayTask(imageView: ImageView) { + imageLoader.cancelDisplayTask(imageView) + } + + fun preloadStatus(status: ParcelableStatus) { + if (!shouldPreload) return + preloadProfileImage(status.user_profile_image_url) + preloadProfileImage(status.quoted_user_profile_image) + preloadMedia(status.media) + preloadMedia(status.quoted_media) + } + + fun preloadActivity(activity: ParcelableActivity) { + if (!shouldPreload) return + activity.getActivityStatus()?.let { preloadStatus(it) } + } + + fun clearFileCache() { + imageLoader.clearDiskCache() + } + + fun clearMemoryCache() { + imageLoader.clearMemoryCache() + } + + fun reloadOptions(preferences: SharedPreferences) { + preloadEnabled = preferences[mediaPreloadKey] + preloadOnWifiOnly = preferences[mediaPreloadOnWifiOnlyKey] + } + + private fun displayDashboardProfileImage(view: ImageView, url: String, drawableOnLoading: Drawable?) { + if (drawableOnLoading != null) { + val builder = Builder() + builder.cloneFrom(dashboardProfileImageDisplayOptions) + builder.showImageOnLoading(drawableOnLoading) + builder.showImageOnFail(drawableOnLoading) + imageLoader.displayImage(url, view, builder.build()) + return + } + imageLoader.displayImage(url, view, dashboardProfileImageDisplayOptions) + } + + private fun preloadMedia(media: Array?) { + media?.forEach { item -> + val url = item.preview_url ?: item.media_url ?: return@forEach + preloadPreviewImage(url) + } + } + + private fun preloadProfileImage(url: String?) { + if (url == null) return + imageLoader.loadImage(url, profileImageDisplayOptions, null) + } + + private fun preloadPreviewImage(url: String?) { + if (url == null) return + imageLoader.loadImage(url, previewDisplayOptions, null) + } + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/ReadStateManager.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/ReadStateManager.kt index f40b7670d2..8b40cc6903 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/ReadStateManager.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/ReadStateManager.kt @@ -31,12 +31,8 @@ import org.mariotaku.twidere.util.collection.CompactHashSet class ReadStateManager(context: Context) { - private val preferences: SharedPreferencesWrapper - - init { - preferences = SharedPreferencesWrapper.getInstance(context, - TIMELINE_POSITIONS_PREFERENCES_NAME, Context.MODE_PRIVATE) - } + private val preferences: SharedPreferencesWrapper = SharedPreferencesWrapper.getInstance(context, + TIMELINE_POSITIONS_PREFERENCES_NAME, Context.MODE_PRIVATE) fun getPosition(key: String): Long { if (TextUtils.isEmpty(key)) return -1 diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/ApplicationModule.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/ApplicationModule.kt index 92c1166bf9..6c1b7b45a8 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/ApplicationModule.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/ApplicationModule.kt @@ -22,8 +22,10 @@ package org.mariotaku.twidere.util.dagger import android.app.Application import android.content.Context import android.location.LocationManager +import android.net.ConnectivityManager import android.os.Build import android.os.Looper +import android.support.v4.net.ConnectivityManagerCompat import android.support.v4.text.BidiFormatter import com.nostra13.universalimageloader.cache.disc.DiskCache import com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache @@ -188,8 +190,12 @@ class ApplicationModule(private val application: Application) { @Provides @Singleton - fun mediaLoaderWrapper(loader: ImageLoader): MediaLoaderWrapper { - return MediaLoaderWrapper(loader) + fun mediaLoaderWrapper(loader: ImageLoader, preferences: SharedPreferencesWrapper): MediaLoaderWrapper { + val wrapper = MediaLoaderWrapper(loader) + wrapper.reloadOptions(preferences) + val cm = application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + wrapper.isNetworkMetered = ConnectivityManagerCompat.isActiveNetworkMetered(cm) + return wrapper } @Provides diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/StatusViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/StatusViewHolder.kt index 80dd884c68..fc06843f1d 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/StatusViewHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/StatusViewHolder.kt @@ -85,14 +85,6 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View) itemView.quotedMediaPreview) } - nameView.applyFontFamily(adapter.lightFont) - timeView.applyFontFamily(adapter.lightFont) - textView.applyFontFamily(adapter.lightFont) - mediaLabelTextView.applyFontFamily(adapter.lightFont) - - quotedNameView.applyFontFamily(adapter.lightFont) - quotedTextView.applyFontFamily(adapter.lightFont) - quotedMediaLabelTextView.applyFontFamily(adapter.lightFont) } @@ -524,6 +516,15 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View) timeView.showAbsoluteTime = adapter.showAbsoluteTime favoriteIcon.activatedColor = favColor + + nameView.applyFontFamily(adapter.lightFont) + timeView.applyFontFamily(adapter.lightFont) + textView.applyFontFamily(adapter.lightFont) + mediaLabelTextView.applyFontFamily(adapter.lightFont) + + quotedNameView.applyFontFamily(adapter.lightFont) + quotedTextView.applyFontFamily(adapter.lightFont) + quotedMediaLabelTextView.applyFontFamily(adapter.lightFont) } override fun playLikeAnimation(listener: LikeAnimationDrawable.OnLikedListener) { diff --git a/twidere/src/main/res/values/strings.xml b/twidere/src/main/res/values/strings.xml index 66add32563..9cfc162155 100644 --- a/twidere/src/main/res/values/strings.xml +++ b/twidere/src/main/res/values/strings.xml @@ -94,6 +94,8 @@ Skip Start + Block users… + Mute users… Subscribe subscribing to list @@ -236,8 +238,6 @@ Add or remove from list Add tab Add to filter - Block users… - Mute users… Add to list Added Rename existing accounts? Open links in in-app browser (Powered by Chrome) Upper limit of items stored in databases for each account, set to a smaller value to save space and increase loading speed. + Preload media only on free networks like Wi-Fi Accounts Advanced In-app browser @@ -872,6 +873,7 @@ Manage Filter subscriptions Light font + Preload on free network Storage Translate diff --git a/twidere/src/main/res/xml/preferences_network.xml b/twidere/src/main/res/xml/preferences_network.xml index c1ec39326a..18ee21a512 100644 --- a/twidere/src/main/res/xml/preferences_network.xml +++ b/twidere/src/main/res/xml/preferences_network.xml @@ -12,7 +12,8 @@ + android:summary="@string/preference_summary_media_preload_non_metered_network" + android:title="@string/preference_title_media_preload_non_metered_network"/>