Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import android.annotation.SuppressLint
import android.content.Context
import android.content.UriMatcher
import android.net.Uri
import android.os.Build
import android.text.TextUtils
import androidx.annotation.IntegerRes
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import androidx.core.content.ContentProviderCompat
import com.google.gson.GsonBuilder
Expand Down Expand Up @@ -55,15 +53,15 @@ class TwitterNewsProvider : NewsProvider() {
private const val FORCE_REFRESH = false
// private const val FORCE_REFRESH = true // DEBUG

private val VALIDITY_DEBUG_FACTOR = if (BuildConfig.DEBUG) 1L else 2L
private val VALIDITY_EXPANSIVE_API_FACTOR = VALIDITY_DEBUG_FACTOR * 1L
// private val VALIDITY_DEBUG_FACTOR = if (BuildConfig.DEBUG) 1L else 1L
private const val VALIDITY_EXPANSIVE_API_FACTOR = 1L

// https://docs.x.com/x-api/fundamentals/rate-limits (Basic)
// - [GET /2/users/by/username/:username] 500 requests / 24 hours PER APP
// - [GET /2/tweets] 15 requests / 15 mins PER APP
private val NEWS_MAX_VALIDITY_IN_MS = MAX_CACHE_VALIDITY_MS
private val NEWS_VALIDITY_IN_MS = TimeUnit.HOURS.toMillis(24L) * VALIDITY_EXPANSIVE_API_FACTOR
private val NEWS_VALIDITY_IN_FOCUS_IN_MS = TimeUnit.HOURS.toMillis(2L) * VALIDITY_EXPANSIVE_API_FACTOR
private val NEWS_VALIDITY_IN_FOCUS_IN_MS = TimeUnit.HOURS.toMillis(1L) * VALIDITY_EXPANSIVE_API_FACTOR
private val NEWS_MIN_DURATION_BETWEEN_REFRESH_IN_MS = TimeUnit.MINUTES.toMillis(30L) * VALIDITY_EXPANSIVE_API_FACTOR
private val NEWS_MIN_DURATION_BETWEEN_REFRESH_IN_FOCUS_IN_MS = TimeUnit.MINUTES.toMillis(15L) * VALIDITY_EXPANSIVE_API_FACTOR

Expand Down Expand Up @@ -215,6 +213,7 @@ class TwitterNewsProvider : NewsProvider() {
R.array.twitter_screen_names_severity
).toList()
}

@get:IntegerRes
private val _userNamesSeverityDefaultResId: Int get() = R.integer.news_provider_severity_info_agency

Expand All @@ -223,6 +222,7 @@ class TwitterNewsProvider : NewsProvider() {
R.array.twitter_screen_names_noteworthy
).toList().map { it.toLong() }
}

@get:StringRes
private val _userNamesNoteworthyDefaultResId: Int get() = R.string.news_provider_noteworthy_warning

Expand Down Expand Up @@ -327,16 +327,12 @@ class TwitterNewsProvider : NewsProvider() {
}

override fun getNewNews(newsFilter: NewsProviderContract.Filter): ArrayList<News>? {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return getCachedNews(newsFilter)
}
this.providedBearerToken = SecureStringUtils.dec(newsFilter.getProvidedEncryptKey(KeysIds.TWITTER_BEARER_TOKEN))
this.providedCachedApiUrl = SecureStringUtils.dec(newsFilter.getProvidedEncryptKey(KeysIds.TWITTER_CACHED_API_URL))
updateAgencyNewsDataIfRequired(requireContextCompat(), newsFilter.isInFocusOrDefault)
return getCachedNews(newsFilter)
}

@RequiresApi(Build.VERSION_CODES.O)
private fun updateAgencyNewsDataIfRequired(context: Context, inFocus: Boolean) {
if (FORCE_REFRESH) {
TwitterStorage.saveLastUpdateMs(context, 0L) // force refresh
Expand All @@ -352,7 +348,6 @@ class TwitterNewsProvider : NewsProvider() {
updateAgencyNewsDataIfRequiredSync(context, lastUpdateInMs, inFocus)
}

@RequiresApi(Build.VERSION_CODES.O)
@Synchronized
private fun updateAgencyNewsDataIfRequiredSync(
context: Context,
Expand All @@ -374,14 +369,12 @@ class TwitterNewsProvider : NewsProvider() {
deleteAllRequired = true // too old to display
}
val minUpdateMs = newsMaxValidityInMs.coerceAtMost(getNewsValidityInMs(inFocus))
if (deleteAllRequired
|| lastUpdateInMs + minUpdateMs < nowInMs
) {
updateAllAgencyNewsDataFromWWW(context, deleteAllRequired) // try to update
if (!deleteAllRequired && lastUpdateInMs + minUpdateMs >= nowInMs) {
return
}
updateAllAgencyNewsDataFromWWW(context, deleteAllRequired) // try to update
}

@RequiresApi(Build.VERSION_CODES.O)
private fun updateAllAgencyNewsDataFromWWW(context: Context, deleteAllRequired: Boolean) {
var deleteAllDone = false
@Suppress("SimplifyBooleanWithConstants")
Expand All @@ -407,7 +400,6 @@ class TwitterNewsProvider : NewsProvider() {
private fun getTwitterApi(context: Context, baseHostUrl: String) =
_twitterApi ?: createTwitterApi(context, baseHostUrl).also { _twitterApi = it }

@RequiresApi(Build.VERSION_CODES.O)
private fun loadAgencyNewsDataFromWWW(context: Context): ArrayList<News>? {
// @Suppress("ConstantConditionIf")
// if (true) {
Expand Down Expand Up @@ -460,7 +452,6 @@ class TwitterNewsProvider : NewsProvider() {

private fun getUserName(screenName: String) = "@$screenName"

@RequiresApi(Build.VERSION_CODES.O)
private fun loadUserTimeline(
context: Context,
twitterApi: TwitterV2Api,
Expand Down Expand Up @@ -583,7 +574,6 @@ class TwitterNewsProvider : NewsProvider() {
return response?.data?.id?.takeIf { it.isNotBlank() }
}

@RequiresApi(Build.VERSION_CODES.O)
private fun readNews(
context: Context,
tweet: Tweet,
Expand Down Expand Up @@ -797,4 +787,4 @@ class TwitterNewsProvider : NewsProvider() {
}

override fun getNewsLanguages() = _languages
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -152,20 +152,20 @@ public static Cursor queryS(@NonNull NewsProviderContract provider, @NonNull Uri

@Nullable
private static Cursor getNews(@NonNull NewsProviderContract provider, @Nullable String selection) {
NewsProviderContract.Filter newsFilter = NewsProviderContract.Filter.fromJSONString(selection);
final NewsProviderContract.Filter newsFilter = NewsProviderContract.Filter.fromJSONString(selection);
if (newsFilter == null) {
return getNewsCursor(null);
}
if (NewsProviderContract.Filter.isUUIDFilter(newsFilter)) {
return provider.getNewsFromDB(newsFilter);
}
long nowInMs = TimeUtils.currentTimeMillis();
ArrayList<News> cachedNews = provider.getCachedNews(newsFilter);
final long nowInMs = TimeUtils.currentTimeMillis();
final ArrayList<News> cachedNews = provider.getCachedNews(newsFilter);
boolean purgeNecessary = false;
if (cachedNews != null) {
Iterator<News> it = cachedNews.iterator();
final Iterator<News> it = cachedNews.iterator();
while (it.hasNext()) {
News news = it.next();
final News news = it.next();
if (news.getLastUpdateInMs() + provider.getNewsMaxValidityInMs() < nowInMs) {
it.remove();
purgeNecessary = true;
Expand All @@ -176,9 +176,9 @@ private static Cursor getNews(@NonNull NewsProviderContract provider, @Nullable
provider.purgeUselessCachedNews();
}
if (cachedNews != null) {
Iterator<News> it = cachedNews.iterator();
final Iterator<News> it = cachedNews.iterator();
while (it.hasNext()) {
News news = it.next();
final News news = it.next();
if (!news.isUseful()) {
provider.deleteCachedNews(news.getId());
it.remove();
Expand All @@ -189,23 +189,24 @@ private static Cursor getNews(@NonNull NewsProviderContract provider, @Nullable
return getNewsCursor(cachedNews);
}
long cacheValidityInMs = provider.getNewsValidityInMs(newsFilter.isInFocusOrDefault());
Long filterCacheValidityInMs = newsFilter.getCacheValidityInMsOrNull();
final Long filterCacheValidityInMs = newsFilter.getCacheValidityInMsOrNull();
if (filterCacheValidityInMs != null && filterCacheValidityInMs > provider.getMinDurationBetweenNewsRefreshInMs(newsFilter.isInFocusOrDefault())) {
cacheValidityInMs = filterCacheValidityInMs;
}
boolean loadNewNews = false;
if (CollectionUtils.getSize(cachedNews) == 0) {
loadNewNews = true;
} else if (cachedNews != null) {
final long tooOldNeedLoadingInMs = nowInMs - cacheValidityInMs;
for (News oneCachedNews : cachedNews) {
if (oneCachedNews.getLastUpdateInMs() + cacheValidityInMs < nowInMs) {
if (oneCachedNews.getLastUpdateInMs() < tooOldNeedLoadingInMs) {
loadNewNews = true;
break;
}
}
}
if (loadNewNews) {
ArrayList<News> newNews = provider.getNewNews(newsFilter);
final ArrayList<News> newNews = provider.getNewNews(newsFilter);
if (CollectionUtils.getSize(newNews) != 0) {
return getNewsCursor(newNews);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,19 +191,25 @@ private Filter setUUIDs(@Nullable List<String> uuids) {
return this;
}

@SuppressWarnings("unused")
@Nullable
public List<String> getUUIDs() {
return uuids;
}

@NonNull
public static Filter getNewTargetFilter(@NonNull POI poi) {
ArrayList<String> targets = new ArrayList<>();
return getNewTargetsFilter(makeTargets(poi));
}

@NonNull
public static ArrayList<String> makeTargets(@NonNull POI poi) {
final ArrayList<String> targets = new ArrayList<>();
targets.add(poi.getAuthority());
if (poi instanceof RouteDirectionStop) {
targets.add(POI.POIUtils.getUUID(poi.getAuthority(), ((RouteDirectionStop) poi).getRoute().getId()));
}
return getNewTargetsFilter(targets);
return targets;
}

@SuppressWarnings("unused")
Expand All @@ -226,6 +232,7 @@ private Filter setTargets(List<String> targets) {
return this;
}

@SuppressWarnings("unused")
@Nullable
public List<String> getTargets() {
return targets;
Expand Down Expand Up @@ -259,6 +266,19 @@ public String toString() {
return sb.toString();
}

@SuppressWarnings("unused")
@NonNull
public String toStringTargetsAndUuid() {
final StringBuilder sb = new StringBuilder(Filter.class.getSimpleName()).append('[');
if (isUUIDFilter(this)) {
sb.append("uuids:").append(this.uuids).append(',');
} else if (isTargetFilter(this)) {
sb.append("targets:").append(this.targets).append(',');
}
sb.append(']');
return sb.toString();
}

public static boolean isUUIDFilter(@Nullable Filter newsFilter) {
return newsFilter != null && CollectionUtils.getSize(newsFilter.uuids) > 0;
}
Expand Down Expand Up @@ -479,4 +499,4 @@ public static JSONObject toJSON(@NonNull Filter newsFilter) {
}
}
}
}
}