Skip to content

Commit

Permalink
Adding Up Analytical widget provider class for Deck Picker Widget .
Browse files Browse the repository at this point in the history
  • Loading branch information
xenonnn4w committed Jul 18, 2024
1 parent 4f47106 commit eb434a2
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 19 deletions.
27 changes: 8 additions & 19 deletions AnkiDroid/src/main/java/com/ichi2/widget/AddNoteWidget.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,24 @@
package com.ichi2.widget

import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.widget.RemoteViews
import androidx.core.app.PendingIntentCompat
import com.ichi2.anki.IntentHandler
import com.ichi2.anki.NoteEditor
import com.ichi2.anki.R
import com.ichi2.anki.analytics.UsageAnalytics
import timber.log.Timber

class AddNoteWidget : AppWidgetProvider() {
override fun onEnabled(context: Context) {
super.onEnabled(context)
UsageAnalytics.sendAnalyticsEvent(this.javaClass.simpleName, "enabled")
}

override fun onDisabled(context: Context) {
super.onDisabled(context)
UsageAnalytics.sendAnalyticsEvent(this.javaClass.simpleName, "disabled")
}
class AddNoteWidget : AnalyticsWidgetProvider() {

override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
super.onUpdate(context, appWidgetManager, appWidgetIds)
if (!IntentHandler.grantedStoragePermissions(context, showToast = false)) {
Timber.w("Opening AddNote widget without storage access")
return
}
Timber.d("onUpdate")
override fun performUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
usageAnalytics: UsageAnalytics
) {
Timber.d("AddNoteWidget: performUpdate")
updateWidgets(context, appWidgetManager, appWidgetIds)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (c) 2024 Anoop <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.ichi2.widget

import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import androidx.annotation.CallSuper
import com.ichi2.anki.IntentHandler
import com.ichi2.anki.analytics.UsageAnalytics
import timber.log.Timber

/**
* AnalyticsWidgetProvider is an abstract base class for App Widgets that integrates
* with UsageAnalytics to send analytics events when the widget is enabled, disabled,
* or updated.
*
* This class should always be used as the base class for App Widgets in this application.
* Direct usage of AppWidgetProvider should be avoided.
* TODO: Add a lint rule to forbid the direct use of AppWidgetProvider.
*
* Subclasses must override [performUpdate] to define the widget update logic.
*
* - To use this class, extend it and implement the [performUpdate] method.
* - Override [onUpdate] if additional logic is required beyond [performUpdate].
*/
abstract class AnalyticsWidgetProvider : AppWidgetProvider() {

/**
* Called when the widget is enabled. Sends an analytics event.
*
* @param context The context in which the receiver is running.
*/
@CallSuper
override fun onEnabled(context: Context) {
super.onEnabled(context)
UsageAnalytics.sendAnalyticsEvent(this.javaClass.simpleName, "enabled")
}

/**
* Called when the widget is disabled. Sends an analytics event.
*
* @param context The context in which the receiver is running.
*/
@CallSuper
override fun onDisabled(context: Context) {
super.onDisabled(context)
UsageAnalytics.sendAnalyticsEvent(this.javaClass.simpleName, "disabled")
}

/**
* Called to update the widget. Checks storage permissions and delegates to [performUpdate].
*
* @param context The context in which the receiver is running.
* @param appWidgetManager The AppWidgetManager instance to use for updating widgets.
* @param appWidgetIds The app widget IDs to update.
*/
@CallSuper
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
super.onUpdate(context, appWidgetManager, appWidgetIds)
if (!IntentHandler.grantedStoragePermissions(context, showToast = false)) {
Timber.w("Opening widget ${this.javaClass.name} without storage access")
return
}
// Pass usageAnalytics to performUpdate
performUpdate(context, appWidgetManager, appWidgetIds, UsageAnalytics)
Timber.d("${this.javaClass.name}: performUpdate")
}

/**
* Abstract method to be implemented by subclasses to perform widget updates.
* <p>
* Note: When this method is executed, it is assumed that the storage access is granted.
*
* @param context The context in which the receiver is running.
* @param appWidgetManager The AppWidgetManager instance to use for updating widgets.
* @param appWidgetIds The app widget IDs to update.
* @param usageAnalytics The UsageAnalytics instance for logging analytics events.
*/

abstract fun performUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, usageAnalytics: UsageAnalytics)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2024 David Allison <[email protected]>
* Copyright (c) 2024 Anoop <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

import android.appwidget.AppWidgetManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.ichi2.anki.RobolectricTest
import com.ichi2.anki.analytics.UsageAnalytics
import com.ichi2.widget.AnalyticsWidgetProvider
import io.mockk.every
import io.mockk.mockkObject
import io.mockk.unmockkObject
import io.mockk.verify
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class DeckPickerWidgetTest : RobolectricTest() {

@Before
override fun setUp() {
super.setUp()
mockkObject(UsageAnalytics)
every { UsageAnalytics.sendAnalyticsEvent(any(), any()) } answers { }
}

@After
override fun tearDown() {
super.tearDown()
unmockkObject(UsageAnalytics)
}

@Test
fun testAnalyticsEventLogging() {
val widgetProvider = TestWidgetProvider()

widgetProvider.onEnabled(targetContext)

verify { UsageAnalytics.sendAnalyticsEvent("TestWidgetProvider", "enabled") }
}

private class TestWidgetProvider : AnalyticsWidgetProvider() {
override fun performUpdate(
context: android.content.Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
usageAnalytics: UsageAnalytics
) {
// Do nothing
}
}
}

0 comments on commit eb434a2

Please sign in to comment.