Skip to content

Commit 4d4ed8d

Browse files
committed
Merge branch 'hotfix/5.251.1'
2 parents 21b93a8 + 21b4361 commit 4d4ed8d

28 files changed

+443
-409
lines changed

app/build.gradle

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,9 +417,6 @@ dependencies {
417417
implementation project(':serp-logos-api')
418418
implementation project(':serp-logos-impl')
419419

420-
// Widgets
421-
implementation "androidx.core:core-remoteviews:1.1.0"
422-
423420
// Deprecated. TODO: Stop using this artifact.
424421
implementation "androidx.legacy:legacy-support-v4:_"
425422
debugImplementation Square.leakCanary.android

app/src/main/AndroidManifest.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,16 @@
488488
android:parentActivityName="com.duckduckgo.app.settings.SettingsActivity"
489489
/>
490490

491+
<service
492+
android:name="com.duckduckgo.widget.FavoritesWidgetService"
493+
android:exported="false"
494+
android:permission="android.permission.BIND_REMOTEVIEWS" />
495+
496+
<service
497+
android:name="com.duckduckgo.widget.EmptyFavoritesWidgetService"
498+
android:exported="false"
499+
android:permission="android.permission.BIND_REMOTEVIEWS" />
500+
491501
<service
492502
android:name="com.duckduckgo.customtabs.impl.service.DuckDuckGoCustomTabService"
493503
android:exported="true"

app/src/main/java/com/duckduckgo/app/di/AppComponent.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ import com.duckduckgo.app.onboarding.di.OnboardingModule
2727
import com.duckduckgo.app.surrogates.di.ResourceSurrogateModule
2828
import com.duckduckgo.app.usage.di.AppUsageModule
2929
import com.duckduckgo.di.scopes.AppScope
30-
import com.duckduckgo.widget.EmptyFavoritesWidgetItemFactory
31-
import com.duckduckgo.widget.FavoritesWidgetItemFactory
30+
import com.duckduckgo.widget.EmptyFavoritesWidgetService
31+
import com.duckduckgo.widget.FavoritesWidgetService
3232
import com.duckduckgo.widget.SearchAndFavoritesWidget
3333
import com.duckduckgo.widget.SearchOnlyWidget
3434
import com.duckduckgo.widget.SearchWidget
@@ -88,11 +88,11 @@ interface AppComponent : AndroidInjector<DuckDuckGoApplication> {
8888

8989
fun inject(searchOnlyWidget: SearchOnlyWidget)
9090

91-
fun inject(searchAndFavoritesWidget: SearchAndFavoritesWidget)
91+
fun inject(searchAndFavsWidget: SearchAndFavoritesWidget)
9292

93-
fun inject(favoritesWidgetItemFactory: FavoritesWidgetItemFactory)
93+
fun inject(favoritesWidgetItemFactory: FavoritesWidgetService.FavoritesWidgetItemFactory)
9494

95-
fun inject(emptyFavoritesWidgetItemFactory: EmptyFavoritesWidgetItemFactory)
95+
fun inject(emptyFavoritesWidgetItemFactory: EmptyFavoritesWidgetService.EmptyFavoritesWidgetItemFactory)
9696

9797
// accessor to Retrofit instance for test only only for test
9898
@Named("api")

app/src/main/java/com/duckduckgo/app/widget/FavoritesObserver.kt

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ package com.duckduckgo.app.widget
1919
import android.appwidget.AppWidgetManager
2020
import android.content.ComponentName
2121
import android.content.Context
22-
import android.content.Intent
2322
import androidx.lifecycle.LifecycleOwner
2423
import androidx.lifecycle.coroutineScope
24+
import com.duckduckgo.app.browser.R
2525
import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver
2626
import com.duckduckgo.common.utils.DispatcherProvider
2727
import com.duckduckgo.di.scopes.AppScope
@@ -33,7 +33,7 @@ import javax.inject.Inject
3333

3434
@SingleInstanceIn(AppScope::class)
3535
class FavoritesObserver @Inject constructor(
36-
private val context: Context,
36+
context: Context,
3737
private val savedSitesRepository: SavedSitesRepository,
3838
private val dispatcherProvider: DispatcherProvider,
3939
) : MainProcessLifecycleObserver {
@@ -47,13 +47,8 @@ class FavoritesObserver @Inject constructor(
4747
owner.lifecycle.coroutineScope.launch(dispatcherProvider.io()) {
4848
appWidgetManager?.let { instance ->
4949
savedSitesRepository.getFavorites().collect {
50-
val appWidgetIds = instance.getAppWidgetIds(componentName)
51-
if (appWidgetIds.isNotEmpty()) {
52-
val updateIntent = Intent(context, SearchAndFavoritesWidget::class.java)
53-
updateIntent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
54-
updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
55-
context.sendBroadcast(updateIntent)
56-
}
50+
instance.notifyAppWidgetViewDataChanged(instance.getAppWidgetIds(componentName), R.id.favoritesGrid)
51+
instance.notifyAppWidgetViewDataChanged(instance.getAppWidgetIds(componentName), R.id.emptyfavoritesGrid)
5752
}
5853
}
5954
}
Lines changed: 0 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +0,0 @@
1-
/*
2-
* Copyright (c) 2021 DuckDuckGo
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
16-
17-
package com.duckduckgo.widget
18-
19-
import android.content.Context
20-
import android.widget.RemoteViews
21-
import android.widget.RemoteViewsService
22-
import com.duckduckgo.app.browser.R
23-
import com.duckduckgo.app.global.DuckDuckGoApplication
24-
import com.duckduckgo.common.utils.DispatcherProvider
25-
import com.duckduckgo.savedsites.api.SavedSitesRepository
26-
import kotlinx.coroutines.withContext
27-
import logcat.logcat
28-
import javax.inject.Inject
29-
30-
/**
31-
* This RemoteViewsFactory will not render any item. It's used for convenience to simplify executing background operations to show/hide empty widget CTA.
32-
* If this RemoteViewsFactory count is 0, SearchAndFavoritesWidget R.id.emptyFavoritesGrid will show the configured EmptyView.
33-
*/
34-
class EmptyFavoritesWidgetItemFactory(
35-
val context: Context,
36-
) : RemoteViewsService.RemoteViewsFactory {
37-
38-
@Inject
39-
lateinit var savedSitesRepository: SavedSitesRepository
40-
41-
@Inject
42-
lateinit var dispatchers: DispatcherProvider
43-
44-
private var count = 0
45-
46-
override fun onCreate() {
47-
inject(context)
48-
}
49-
50-
override fun onDataSetChanged() {
51-
// no-op, we use our own update mechanism
52-
}
53-
54-
suspend fun updateEmptyWidgetFavoritesAsync() {
55-
runCatching {
56-
count = getItemsCountFromFavorites()
57-
}.onFailure { error ->
58-
logcat { "Failed to update Search and Favorites widget when empty: ${error.message}" }
59-
}
60-
}
61-
62-
override fun onDestroy() {
63-
// no-op
64-
}
65-
66-
override fun getCount(): Int {
67-
return count
68-
}
69-
70-
override fun getViewAt(position: Int): RemoteViews {
71-
return RemoteViews(context.packageName, R.layout.empty_view)
72-
}
73-
74-
override fun getLoadingView(): RemoteViews {
75-
return RemoteViews(context.packageName, R.layout.empty_view)
76-
}
77-
78-
override fun getViewTypeCount(): Int {
79-
return 1
80-
}
81-
82-
override fun getItemId(position: Int): Long {
83-
return position.toLong()
84-
}
85-
86-
override fun hasStableIds(): Boolean {
87-
return true
88-
}
89-
90-
private suspend fun getItemsCountFromFavorites(): Int {
91-
return withContext(dispatchers.io()) {
92-
if (savedSitesRepository.hasFavorites()) 1 else 0
93-
}
94-
}
95-
96-
private fun inject(context: Context) {
97-
val application = context.applicationContext as DuckDuckGoApplication
98-
application.daggerAppComponent.inject(this)
99-
}
100-
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright (c) 2021 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.widget
18+
19+
import android.content.Context
20+
import android.content.Intent
21+
import android.widget.RemoteViews
22+
import android.widget.RemoteViewsService
23+
import com.duckduckgo.app.browser.R
24+
import com.duckduckgo.app.global.DuckDuckGoApplication
25+
import com.duckduckgo.savedsites.api.SavedSitesRepository
26+
import javax.inject.Inject
27+
28+
class EmptyFavoritesWidgetService : RemoteViewsService() {
29+
30+
companion object {
31+
const val MAX_ITEMS_EXTRAS = "MAX_ITEMS_EXTRAS"
32+
}
33+
34+
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
35+
return EmptyFavoritesWidgetItemFactory(this.applicationContext, intent)
36+
}
37+
38+
/**
39+
* This RemoteViewsFactory will not render any item. It's used by is used for convenience to simplify executing background operations to show/hide empty widget CTA.
40+
* If this RemoteViewsFactory count is 0, SearchAndFavoritesWidget R.id.emptyfavoritesGrid will show the configured EmptyView.
41+
*/
42+
class EmptyFavoritesWidgetItemFactory(
43+
val context: Context,
44+
intent: Intent,
45+
) : RemoteViewsFactory {
46+
47+
@Inject
48+
lateinit var savedSitesRepository: SavedSitesRepository
49+
50+
private var count = 0
51+
52+
override fun onCreate() {
53+
inject(context)
54+
}
55+
56+
override fun onDataSetChanged() {
57+
count = if (savedSitesRepository.hasFavorites()) 1 else 0
58+
}
59+
60+
override fun onDestroy() {
61+
}
62+
63+
override fun getCount(): Int {
64+
return count
65+
}
66+
67+
override fun getViewAt(position: Int): RemoteViews {
68+
return RemoteViews(context.packageName, R.layout.empty_view)
69+
}
70+
71+
override fun getLoadingView(): RemoteViews {
72+
return RemoteViews(context.packageName, R.layout.empty_view)
73+
}
74+
75+
override fun getViewTypeCount(): Int {
76+
return 1
77+
}
78+
79+
override fun getItemId(position: Int): Long {
80+
return position.toLong()
81+
}
82+
83+
override fun hasStableIds(): Boolean {
84+
return true
85+
}
86+
87+
private fun inject(context: Context) {
88+
val application = context.applicationContext as DuckDuckGoApplication
89+
application.daggerAppComponent.inject(this)
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)