Refactor deprecated widget code

This replaces the deprecated widget method with the new one and ensures
it consistently updates on changes.
This commit is contained in:
Sylvia van Os committed 2025-07-30 21:23:14 +02:00
1 parent 9a0149def8
commit 7277ff26fc
6 files changed
+91 -126

No files matched your search

+1
View File
@@ -112,6 +112,7 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.7.1") implementation("androidx.appcompat:appcompat:1.7.1")
implementation("androidx.constraintlayout:constraintlayout:2.2.1") implementation("androidx.constraintlayout:constraintlayout:2.2.1")
implementation("androidx.core:core-ktx:1.16.0") implementation("androidx.core:core-ktx:1.16.0")
implementation("androidx.core:core-remoteviews:1.1.0")
implementation("androidx.core:core-splashscreen:1.0.1") implementation("androidx.core:core-splashscreen:1.0.1")
implementation("androidx.exifinterface:exifinterface:1.4.1") implementation("androidx.exifinterface:exifinterface:1.4.1")
implementation("androidx.palette:palette:1.0.0") implementation("androidx.palette:palette:1.0.0")
-4
View File
@@ -218,9 +218,5 @@
<action android:name="android.service.controls.ControlsProviderService" /> <action android:name="android.service.controls.ControlsProviderService" />
</intent-filter> </intent-filter>
</service> </service>
<service
android:name=".CatimaRemoteViewsService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
</application> </application>
</manifest> </manifest>
@@ -1,110 +0,0 @@
package protect.card_locker
import android.content.Context
import android.content.Intent
import android.database.sqlite.SQLiteDatabase
import android.graphics.Color
import android.graphics.drawable.Icon
import android.os.Build
import android.view.View
import android.widget.RemoteViews
import android.widget.RemoteViewsService
import protect.card_locker.DBHelper.LoyaltyCardArchiveFilter
import kotlin.math.max
class CatimaWidgetRemoteViewsFactory(private var context: Context) :
RemoteViewsService.RemoteViewsFactory {
private var mDatabase: SQLiteDatabase = DBHelper(context).readableDatabase
override fun onCreate() {
onDataSetChanged()
}
private var mCards: ArrayList<LoyaltyCard> = ArrayList()
override fun onDataSetChanged() {
val mOrder = Utils.getLoyaltyCardOrder(context);
val mOrderDirection = Utils.getLoyaltyCardOrderDirection(context);
val cur = DBHelper.getLoyaltyCardCursor(
mDatabase,
"",
null,
mOrder,
mOrderDirection,
LoyaltyCardArchiveFilter.Unarchived
)
mCards.clear()
if (cur.moveToFirst()) {
do {
val item = LoyaltyCard.fromCursor(context, cur)
mCards.add(item)
} while (cur.moveToNext())
}
}
override fun onDestroy() {}
override fun getCount(): Int {
return max(1, mCards.count())
}
private fun createRemoteView(item: LoyaltyCard): RemoteViews
{
val rv = RemoteViews(context.packageName, R.layout.catima_widget_item).apply {
val headerColor = Utils.getHeaderColor(context, item)
val foreground = if (Utils.needsDarkForeground(headerColor)) Color.BLACK else Color.WHITE
setInt(R.id.item_container, "setBackgroundColor", headerColor)
val icon = item.getImageThumbnail(context)
// setImageViewIcon is not supported on Android 5, so force Android 5 down the text path
if (icon != null && Build.VERSION.SDK_INT >= 23) {
setInt(R.id.item_container, "setBackgroundColor", foreground)
setImageViewIcon(R.id.item_image, Icon.createWithBitmap(icon))
setViewVisibility(R.id.item_text, View.INVISIBLE)
setViewVisibility(R.id.item_image, View.VISIBLE)
} else {
setImageViewBitmap(R.id.item_image, null)
setTextViewText(R.id.item_text, item.store)
setViewVisibility(R.id.item_text, View.VISIBLE)
setViewVisibility(R.id.item_image, View.INVISIBLE)
setTextColor(
R.id.item_text,
foreground
)
}
val fillInIntent = Intent().apply {
putExtra(LoyaltyCardViewActivity.BUNDLE_ID, item.id)
}
setOnClickFillInIntent(R.id.item_container, fillInIntent)
}
return rv
}
override fun getViewAt(position: Int): RemoteViews {
if (mCards.isEmpty()) {
return RemoteViews(context.packageName, R.layout.catima_widget_empty)
}
val item = mCards[position]
return createRemoteView(item)
}
override fun getLoadingView(): RemoteViews? = null
override fun getViewTypeCount(): Int = 1
override fun getItemId(position: Int): Long = position.toLong()
override fun hasStableIds(): Boolean = true
}
class CatimaRemoteViewsService : RemoteViewsService() {
override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory {
return CatimaWidgetRemoteViewsFactory(applicationContext)
}
}
@@ -3,22 +3,36 @@ package protect.card_locker
import android.app.PendingIntent import android.app.PendingIntent
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.Icon
import android.os.Build
import android.view.View
import android.widget.RemoteViews import android.widget.RemoteViews
import androidx.core.widget.RemoteViewsCompat
import protect.card_locker.DBHelper.LoyaltyCardArchiveFilter
class CatimaWidget : AppWidgetProvider() { class CatimaWidget : AppWidgetProvider() {
fun updateAll(context: Context) {
val appWidgetManager = AppWidgetManager.getInstance(context)
val componentName = ComponentName(context, CatimaWidget::class.java)
onUpdate(
context,
appWidgetManager,
appWidgetManager.getAppWidgetIds(componentName)
)
}
override fun onUpdate( override fun onUpdate(
context: Context, context: Context,
appWidgetManager: AppWidgetManager, appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray appWidgetIds: IntArray
) { ) {
for (appWidgetId in appWidgetIds) { for (appWidgetId in appWidgetIds) {
// Prepare generic widget
val views = RemoteViews(context.packageName, R.layout.catima_widget) val views = RemoteViews(context.packageName, R.layout.catima_widget)
val intent = Intent(context, CatimaRemoteViewsService::class.java)
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
views.setRemoteAdapter(R.id.grid_view, intent)
val templateIntent = Intent(context, LoyaltyCardViewActivity::class.java) val templateIntent = Intent(context, LoyaltyCardViewActivity::class.java)
val pendingIntent = PendingIntent.getActivity( val pendingIntent = PendingIntent.getActivity(
context, context,
@@ -26,9 +40,75 @@ class CatimaWidget : AppWidgetProvider() {
templateIntent, templateIntent,
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
) )
views.setPendingIntentTemplate(R.id.grid_view, pendingIntent) views.setPendingIntentTemplate(R.id.grid_view, pendingIntent)
// Get cards
val order = Utils.getLoyaltyCardOrder(context);
val orderDirection = Utils.getLoyaltyCardOrderDirection(context);
val database = DBHelper(context).readableDatabase
val loyaltyCardCursor = DBHelper.getLoyaltyCardCursor(
database,
"",
null,
order,
orderDirection,
LoyaltyCardArchiveFilter.Unarchived
)
// Bind every card to cell in the grid
val remoteCollectionItemsBuilder = RemoteViewsCompat.RemoteCollectionItems.Builder()
if (loyaltyCardCursor.moveToFirst()) {
do {
val loyaltyCard = LoyaltyCard.fromCursor(context, loyaltyCardCursor)
remoteCollectionItemsBuilder.addItem(
loyaltyCard.id.toLong(),
createRemoteViews(
context, loyaltyCard
)
)
} while (loyaltyCardCursor.moveToNext())
}
RemoteViewsCompat.setRemoteAdapter(context, views, appWidgetId, R.id.grid_view, remoteCollectionItemsBuilder.build())
// Let Android know the widget is ready for display
appWidgetManager.updateAppWidget(appWidgetId, views) appWidgetManager.updateAppWidget(appWidgetId, views)
} }
} }
private fun createRemoteViews(context: Context, loyaltyCard: LoyaltyCard): RemoteViews {
// Create a single cell for the grid view, bind it to open in the LoyaltyCardViewActivity
// Note: Android 5 will not use bitmaps
val remoteViews = RemoteViews(context.packageName, R.layout.catima_widget_item).apply {
val headerColor = Utils.getHeaderColor(context, loyaltyCard)
val foreground = if (Utils.needsDarkForeground(headerColor)) Color.BLACK else Color.WHITE
setInt(R.id.item_container, "setBackgroundColor", headerColor)
val icon = loyaltyCard.getImageThumbnail(context)
// setImageViewIcon is not supported on Android 5, so force Android 5 down the text path
if (icon != null && Build.VERSION.SDK_INT >= 23) {
setInt(R.id.item_container, "setBackgroundColor", foreground)
setImageViewIcon(R.id.item_image, Icon.createWithBitmap(icon))
setViewVisibility(R.id.item_text, View.INVISIBLE)
setViewVisibility(R.id.item_image, View.VISIBLE)
} else {
setImageViewBitmap(R.id.item_image, null)
setTextViewText(R.id.item_text, loyaltyCard.store)
setViewVisibility(R.id.item_text, View.VISIBLE)
setViewVisibility(R.id.item_image, View.INVISIBLE)
setTextColor(
R.id.item_text,
foreground
)
}
// Add the card ID to the intent template
val fillInIntent = Intent().apply {
putExtra(LoyaltyCardViewActivity.BUNDLE_ID, loyaltyCard.id)
}
setOnClickFillInIntent(R.id.item_container, fillInIntent)
}
return remoteViews
}
} }
@@ -880,6 +880,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
} else if (id == R.id.action_star_unstar) { } else if (id == R.id.action_star_unstar) {
DBHelper.updateLoyaltyCardStarStatus(database, loyaltyCardId, loyaltyCard.starStatus == 0 ? 1 : 0); DBHelper.updateLoyaltyCardStarStatus(database, loyaltyCardId, loyaltyCard.starStatus == 0 ? 1 : 0);
new CatimaWidget().updateAll(LoyaltyCardViewActivity.this);
// Re-init loyaltyCard with new data from DB // Re-init loyaltyCard with new data from DB
onResume(); onResume();
invalidateOptionsMenu(); invalidateOptionsMenu();
@@ -890,6 +892,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
Toast.makeText(LoyaltyCardViewActivity.this, R.string.archived, Toast.LENGTH_LONG).show(); Toast.makeText(LoyaltyCardViewActivity.this, R.string.archived, Toast.LENGTH_LONG).show();
ShortcutHelper.removeShortcut(LoyaltyCardViewActivity.this, loyaltyCardId); ShortcutHelper.removeShortcut(LoyaltyCardViewActivity.this, loyaltyCardId);
new CatimaWidget().updateAll(LoyaltyCardViewActivity.this);
// Re-init loyaltyCard with new data from DB // Re-init loyaltyCard with new data from DB
onResume(); onResume();
@@ -915,6 +918,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements
DBHelper.deleteLoyaltyCard(database, LoyaltyCardViewActivity.this, loyaltyCardId); DBHelper.deleteLoyaltyCard(database, LoyaltyCardViewActivity.this, loyaltyCardId);
ShortcutHelper.removeShortcut(LoyaltyCardViewActivity.this, loyaltyCardId); ShortcutHelper.removeShortcut(LoyaltyCardViewActivity.this, loyaltyCardId);
new CatimaWidget().updateAll(LoyaltyCardViewActivity.this);
finish(); finish();
dialog.dismiss(); dialog.dismiss();
@@ -431,13 +431,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
mCurrentActionMode.finish(); mCurrentActionMode.finish();
} }
updateWidget(mAdapter.mContext); new CatimaWidget().updateAll(mAdapter.mContext);
}
private void updateWidget(Context context) {
AppWidgetManager manager = AppWidgetManager.getInstance(context);
int[] ids = manager.getAppWidgetIds(new ComponentName(context, CatimaWidget.class));
manager.notifyAppWidgetViewDataChanged(ids, R.id.grid_view);
} }
private void processParseResultList(List<ParseResult> parseResultList, String group, boolean closeAppOnNoBarcode) { private void processParseResultList(List<ParseResult> parseResultList, String group, boolean closeAppOnNoBarcode) {