From d0959ffcb5d4ababb104858165e051d865eeb0fc Mon Sep 17 00:00:00 2001 From: tzugen Date: Tue, 5 Apr 2022 21:56:25 +0200 Subject: [PATCH] AppWidget to Kotlin --- .../provider/UltrasonicAppWidgetProvider.java | 221 ------------------ .../UltrasonicAppWidgetProvider4X1.java | 42 ---- .../UltrasonicAppWidgetProvider4X2.java | 42 ---- .../UltrasonicAppWidgetProvider4X3.java | 42 ---- .../UltrasonicAppWidgetProvider4X4.java | 42 ---- .../provider/UltrasonicAppWidgetProvider.kt | 207 ++++++++++++++++ .../UltrasonicAppWidgetProvider4X1.kt | 28 +++ .../UltrasonicAppWidgetProvider4X2.kt | 28 +++ .../UltrasonicAppWidgetProvider4X3.kt | 28 +++ .../UltrasonicAppWidgetProvider4X4.kt | 28 +++ 10 files changed, 319 insertions(+), 389 deletions(-) delete mode 100644 ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.java delete mode 100644 ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X1.java delete mode 100644 ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X2.java delete mode 100644 ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X3.java delete mode 100644 ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X4.java create mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.kt create mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X1.kt create mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X2.kt create mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X3.kt create mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X4.kt diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.java b/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.java deleted file mode 100644 index 29cd9bcc..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.java +++ /dev/null @@ -1,221 +0,0 @@ -package org.moire.ultrasonic.provider; - -import android.app.PendingIntent; -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProvider; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.os.Environment; -import android.view.KeyEvent; -import android.widget.RemoteViews; - -import org.moire.ultrasonic.R; -import org.moire.ultrasonic.activity.NavigationActivity; -import org.moire.ultrasonic.domain.Track; -import org.moire.ultrasonic.imageloader.BitmapUtils; -import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver; -import org.moire.ultrasonic.service.MediaPlayerController; -import org.moire.ultrasonic.util.Constants; - -import timber.log.Timber; - -/** - * Widget Provider for the Ultrasonic Widgets - */ -public class UltrasonicAppWidgetProvider extends AppWidgetProvider -{ - protected int layoutId; - - @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) - { - defaultAppWidget(context, appWidgetIds); - } - - /** - * Initialize given widgets to default state, where we launch Ultrasonic on default click - * and hide actions if service not running. - */ - private void defaultAppWidget(Context context, int[] appWidgetIds) - { - final Resources res = context.getResources(); - final RemoteViews views = new RemoteViews(context.getPackageName(), this.layoutId); - - views.setTextViewText(R.id.title, null); - views.setTextViewText(R.id.album, null); - views.setTextViewText(R.id.artist, res.getText(R.string.widget_initial_text)); - - linkButtons(context, views, false); - pushUpdate(context, appWidgetIds, views); - } - - private void pushUpdate(Context context, int[] appWidgetIds, RemoteViews views) - { - // Update specific list of appWidgetIds if given, otherwise default to all - final AppWidgetManager manager = AppWidgetManager.getInstance(context); - - if (manager != null) - { - if (appWidgetIds != null) - { - manager.updateAppWidget(appWidgetIds, views); - } - else - { - manager.updateAppWidget(new ComponentName(context, this.getClass()), views); - } - } - } - - /** - * Handle a change notification coming over from {@link MediaPlayerController} - */ - public void notifyChange(Context context, Track currentSong, boolean playing, boolean setAlbum) - { - if (hasInstances(context)) - { - performUpdate(context, currentSong, playing, setAlbum); - } - } - - /** - * Check against {@link AppWidgetManager} if there are any instances of this widget. - */ - private boolean hasInstances(Context context) - { - AppWidgetManager manager = AppWidgetManager.getInstance(context); - - if (manager != null) - { - int[] appWidgetIds = manager.getAppWidgetIds(new ComponentName(context, getClass())); - return (appWidgetIds.length > 0); - } - - return false; - } - - /** - * Update all active widget instances by pushing changes - */ - private void performUpdate(Context context, Track currentSong, boolean playing, boolean setAlbum) - { - final Resources res = context.getResources(); - final RemoteViews views = new RemoteViews(context.getPackageName(), this.layoutId); - - String title = currentSong == null ? null : currentSong.getTitle(); - String artist = currentSong == null ? null : currentSong.getArtist(); - String album = currentSong == null ? null : currentSong.getAlbum(); - CharSequence errorState = null; - - // Show error message? - String status = Environment.getExternalStorageState(); - if (status.equals(Environment.MEDIA_SHARED) || status.equals(Environment.MEDIA_UNMOUNTED)) - { - errorState = res.getText(R.string.widget_sdcard_busy); - } - else if (status.equals(Environment.MEDIA_REMOVED)) - { - errorState = res.getText(R.string.widget_sdcard_missing); - } - else if (currentSong == null) - { - errorState = res.getText(R.string.widget_initial_text); - } - - if (errorState != null) - { - // Show error state to user - views.setTextViewText(R.id.title, null); - views.setTextViewText(R.id.artist, errorState); - if (setAlbum) - { - views.setTextViewText(R.id.album, null); - } - views.setImageViewResource(R.id.appwidget_coverart, R.drawable.unknown_album); - } - else - { - // No error, so show normal titles - views.setTextViewText(R.id.title, title); - views.setTextViewText(R.id.artist, artist); - if (setAlbum) - { - views.setTextViewText(R.id.album, album); - } - } - - // Set correct drawable for pause state - if (playing) - { - views.setImageViewResource(R.id.control_play, R.drawable.media_pause_normal_dark); - } - else - { - views.setImageViewResource(R.id.control_play, R.drawable.media_start_normal_dark); - } - - // Set the cover art - try - { - Bitmap bitmap = currentSong == null ? null : BitmapUtils.Companion.getAlbumArtBitmapFromDisk(currentSong, 240); - - if (bitmap == null) - { - // Set default cover art - views.setImageViewResource(R.id.appwidget_coverart, R.drawable.unknown_album); - } - else - { - views.setImageViewBitmap(R.id.appwidget_coverart, bitmap); - } - } - catch (Exception x) - { - Timber.e(x, "Failed to load cover art"); - views.setImageViewResource(R.id.appwidget_coverart, R.drawable.unknown_album); - } - - // Link actions buttons to intents - linkButtons(context, views, currentSong != null); - - pushUpdate(context, null, views); - } - - /** - * Link up various button actions using {@link PendingIntent}. - */ - private static void linkButtons(Context context, RemoteViews views, boolean playerActive) - { - Intent intent = new Intent(context, NavigationActivity.class).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - if (playerActive) - intent.putExtra(Constants.INTENT_SHOW_PLAYER, true); - - intent.setAction("android.intent.action.MAIN"); - intent.addCategory("android.intent.category.LAUNCHER"); - PendingIntent pendingIntent = PendingIntent.getActivity(context, 10, intent, PendingIntent.FLAG_UPDATE_CURRENT); - views.setOnClickPendingIntent(R.id.appwidget_coverart, pendingIntent); - views.setOnClickPendingIntent(R.id.appwidget_top, pendingIntent); - - // Emulate media button clicks. - intent = new Intent(Constants.CMD_PROCESS_KEYCODE); - intent.setComponent(new ComponentName(context, MediaButtonIntentReceiver.class)); - intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)); - pendingIntent = PendingIntent.getBroadcast(context, 11, intent, 0); - views.setOnClickPendingIntent(R.id.control_play, pendingIntent); - - intent = new Intent(Constants.CMD_PROCESS_KEYCODE); - intent.setComponent(new ComponentName(context, MediaButtonIntentReceiver.class)); - intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT)); - pendingIntent = PendingIntent.getBroadcast(context, 12, intent, 0); - views.setOnClickPendingIntent(R.id.control_next, pendingIntent); - - intent = new Intent(Constants.CMD_PROCESS_KEYCODE); - intent.setComponent(new ComponentName(context, MediaButtonIntentReceiver.class)); - intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS)); - pendingIntent = PendingIntent.getBroadcast(context, 13, intent, 0); - views.setOnClickPendingIntent(R.id.control_previous, pendingIntent); - } -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X1.java b/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X1.java deleted file mode 100644 index 0c8a8ca8..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X1.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package org.moire.ultrasonic.provider; - -import org.moire.ultrasonic.R; - -public class UltrasonicAppWidgetProvider4X1 extends UltrasonicAppWidgetProvider -{ - - public UltrasonicAppWidgetProvider4X1() - { - super(); - this.layoutId = R.layout.appwidget4x1; - } - - private static UltrasonicAppWidgetProvider4X1 instance; - - public static synchronized UltrasonicAppWidgetProvider4X1 getInstance() - { - if (instance == null) - { - instance = new UltrasonicAppWidgetProvider4X1(); - } - return instance; - } -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X2.java b/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X2.java deleted file mode 100644 index 3ba12ae6..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X2.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package org.moire.ultrasonic.provider; - -import org.moire.ultrasonic.R; - -public class UltrasonicAppWidgetProvider4X2 extends UltrasonicAppWidgetProvider -{ - - public UltrasonicAppWidgetProvider4X2() - { - super(); - this.layoutId = R.layout.appwidget4x2; - } - - private static UltrasonicAppWidgetProvider4X2 instance; - - public static synchronized UltrasonicAppWidgetProvider4X2 getInstance() - { - if (instance == null) - { - instance = new UltrasonicAppWidgetProvider4X2(); - } - return instance; - } -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X3.java b/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X3.java deleted file mode 100644 index 15b2a561..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X3.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package org.moire.ultrasonic.provider; - -import org.moire.ultrasonic.R; - -public class UltrasonicAppWidgetProvider4X3 extends UltrasonicAppWidgetProvider -{ - - public UltrasonicAppWidgetProvider4X3() - { - super(); - this.layoutId = R.layout.appwidget4x3; - } - - private static UltrasonicAppWidgetProvider4X3 instance; - - public static synchronized UltrasonicAppWidgetProvider4X3 getInstance() - { - if (instance == null) - { - instance = new UltrasonicAppWidgetProvider4X3(); - } - return instance; - } -} diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X4.java b/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X4.java deleted file mode 100644 index c28c55ab..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X4.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package org.moire.ultrasonic.provider; - -import org.moire.ultrasonic.R; - -public class UltrasonicAppWidgetProvider4X4 extends UltrasonicAppWidgetProvider -{ - - public UltrasonicAppWidgetProvider4X4() - { - super(); - this.layoutId = R.layout.appwidget4x4; - } - - private static UltrasonicAppWidgetProvider4X4 instance; - - public static synchronized UltrasonicAppWidgetProvider4X4 getInstance() - { - if (instance == null) - { - instance = new UltrasonicAppWidgetProvider4X4(); - } - return instance; - } -} diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.kt new file mode 100644 index 00000000..46acf216 --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider.kt @@ -0,0 +1,207 @@ +/* + * UltrasonicAppWidgetProvider.kt + * Copyright (C) 2009-2022 Ultrasonic developers + * + * Distributed under terms of the GNU GPLv3 license. + */ + +package org.moire.ultrasonic.provider + +import android.annotation.SuppressLint +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.os.Environment +import android.view.KeyEvent +import android.widget.RemoteViews +import org.moire.ultrasonic.R +import org.moire.ultrasonic.activity.NavigationActivity +import org.moire.ultrasonic.domain.Track +import org.moire.ultrasonic.imageloader.BitmapUtils +import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver +import org.moire.ultrasonic.util.Constants +import timber.log.Timber +import java.lang.Exception + +/** + * Widget Provider for the Ultrasonic Widgets + */ +open class UltrasonicAppWidgetProvider : AppWidgetProvider() { + @JvmField + protected var layoutId = 0 + override fun onUpdate( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray + ) { + defaultAppWidget(context, appWidgetIds) + } + + /** + * Initialize given widgets to default state, where we launch Ultrasonic on default click + * and hide actions if service not running. + */ + private fun defaultAppWidget(context: Context, appWidgetIds: IntArray) { + val res = context.resources + val views = RemoteViews(context.packageName, layoutId) + views.setTextViewText(R.id.title, null) + views.setTextViewText(R.id.album, null) + views.setTextViewText(R.id.artist, res.getText(R.string.widget_initial_text)) + linkButtons(context, views, false) + pushUpdate(context, appWidgetIds, views) + } + + private fun pushUpdate(context: Context, appWidgetIds: IntArray?, views: RemoteViews) { + // Update specific list of appWidgetIds if given, otherwise default to all + val manager = AppWidgetManager.getInstance(context) + if (manager != null) { + if (appWidgetIds != null) { + manager.updateAppWidget(appWidgetIds, views) + } else { + manager.updateAppWidget(ComponentName(context, this.javaClass), views) + } + } + } + + /** + * Handle a change notification coming over from [MediaPlayerController] + */ + fun notifyChange(context: Context, currentSong: Track?, playing: Boolean, setAlbum: Boolean) { + if (hasInstances(context)) { + performUpdate(context, currentSong, playing, setAlbum) + } + } + + /** + * Check against [AppWidgetManager] if there are any instances of this widget. + */ + private fun hasInstances(context: Context): Boolean { + val manager = AppWidgetManager.getInstance(context) + if (manager != null) { + val appWidgetIds = manager.getAppWidgetIds(ComponentName(context, javaClass)) + return appWidgetIds.isNotEmpty() + } + return false + } + + /** + * Update all active widget instances by pushing changes + */ + private fun performUpdate( + context: Context, + currentSong: Track?, + playing: Boolean, + setAlbum: Boolean + ) { + val res = context.resources + val views = RemoteViews(context.packageName, layoutId) + val title = currentSong?.title + val artist = currentSong?.artist + val album = currentSong?.album + var errorState: CharSequence? = null + + // Show error message? + val status = Environment.getExternalStorageState() + if (status == Environment.MEDIA_SHARED || status == Environment.MEDIA_UNMOUNTED) { + errorState = res.getText(R.string.widget_sdcard_busy) + } else if (status == Environment.MEDIA_REMOVED) { + errorState = res.getText(R.string.widget_sdcard_missing) + } else if (currentSong == null) { + errorState = res.getText(R.string.widget_initial_text) + } + if (errorState != null) { + // Show error state to user + views.setTextViewText(R.id.title, null) + views.setTextViewText(R.id.artist, errorState) + if (setAlbum) { + views.setTextViewText(R.id.album, null) + } + views.setImageViewResource(R.id.appwidget_coverart, R.drawable.unknown_album) + } else { + // No error, so show normal titles + views.setTextViewText(R.id.title, title) + views.setTextViewText(R.id.artist, artist) + if (setAlbum) { + views.setTextViewText(R.id.album, album) + } + } + + // Set correct drawable for pause state + if (playing) { + views.setImageViewResource(R.id.control_play, R.drawable.media_pause_normal_dark) + } else { + views.setImageViewResource(R.id.control_play, R.drawable.media_start_normal_dark) + } + + // Set the cover art + try { + val bitmap = + if (currentSong == null) null else BitmapUtils.getAlbumArtBitmapFromDisk( + currentSong, + 240 + ) + if (bitmap == null) { + // Set default cover art + views.setImageViewResource(R.id.appwidget_coverart, R.drawable.unknown_album) + } else { + views.setImageViewBitmap(R.id.appwidget_coverart, bitmap) + } + } catch (x: Exception) { + Timber.e(x, "Failed to load cover art") + views.setImageViewResource(R.id.appwidget_coverart, R.drawable.unknown_album) + } + + // Link actions buttons to intents + linkButtons(context, views, currentSong != null) + pushUpdate(context, null, views) + } + + companion object { + /** + * Link up various button actions using [PendingIntent]. + */ + @SuppressLint("UnspecifiedImmutableFlag") + private fun linkButtons(context: Context, views: RemoteViews, playerActive: Boolean) { + var intent = Intent( + context, + NavigationActivity::class.java + ).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) + if (playerActive) intent.putExtra(Constants.INTENT_SHOW_PLAYER, true) + intent.action = "android.intent.action.MAIN" + intent.addCategory("android.intent.category.LAUNCHER") + var pendingIntent = + PendingIntent.getActivity(context, 10, intent, PendingIntent.FLAG_UPDATE_CURRENT) + views.setOnClickPendingIntent(R.id.appwidget_coverart, pendingIntent) + views.setOnClickPendingIntent(R.id.appwidget_top, pendingIntent) + + // Emulate media button clicks. + intent = Intent(Constants.CMD_PROCESS_KEYCODE) + intent.component = ComponentName(context, MediaButtonIntentReceiver::class.java) + intent.putExtra( + Intent.EXTRA_KEY_EVENT, + KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) + ) + pendingIntent = PendingIntent.getBroadcast(context, 11, intent, 0) + views.setOnClickPendingIntent(R.id.control_play, pendingIntent) + intent = Intent(Constants.CMD_PROCESS_KEYCODE) + intent.component = ComponentName(context, MediaButtonIntentReceiver::class.java) + intent.putExtra( + Intent.EXTRA_KEY_EVENT, + KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT) + ) + pendingIntent = PendingIntent.getBroadcast(context, 12, intent, 0) + views.setOnClickPendingIntent(R.id.control_next, pendingIntent) + intent = Intent(Constants.CMD_PROCESS_KEYCODE) + intent.component = ComponentName(context, MediaButtonIntentReceiver::class.java) + intent.putExtra( + Intent.EXTRA_KEY_EVENT, + KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS) + ) + pendingIntent = PendingIntent.getBroadcast(context, 13, intent, 0) + views.setOnClickPendingIntent(R.id.control_previous, pendingIntent) + } + } +} \ No newline at end of file diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X1.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X1.kt new file mode 100644 index 00000000..97c96027 --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X1.kt @@ -0,0 +1,28 @@ +/* + * UltrasonicAppWidgetProvider4X1.kt + * Copyright (C) 2009-2022 Ultrasonic developers + * + * Distributed under terms of the GNU GPLv3 license. + */ + +package org.moire.ultrasonic.provider + +import org.moire.ultrasonic.R + +class UltrasonicAppWidgetProvider4X1 : UltrasonicAppWidgetProvider() { + companion object { + @get:Synchronized + var instance: UltrasonicAppWidgetProvider4X1? = null + get() { + if (field == null) { + field = UltrasonicAppWidgetProvider4X1() + } + return field + } + private set + } + + init { + layoutId = R.layout.appwidget4x1 + } +} \ No newline at end of file diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X2.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X2.kt new file mode 100644 index 00000000..f30c6efe --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X2.kt @@ -0,0 +1,28 @@ +/* + * UltrasonicAppWidgetProvider4X2.kt + * Copyright (C) 2009-2022 Ultrasonic developers + * + * Distributed under terms of the GNU GPLv3 license. + */ + +package org.moire.ultrasonic.provider + +import org.moire.ultrasonic.R + +class UltrasonicAppWidgetProvider4X2 : UltrasonicAppWidgetProvider() { + companion object { + @get:Synchronized + var instance: UltrasonicAppWidgetProvider4X2? = null + get() { + if (field == null) { + field = UltrasonicAppWidgetProvider4X2() + } + return field + } + private set + } + + init { + layoutId = R.layout.appwidget4x2 + } +} \ No newline at end of file diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X3.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X3.kt new file mode 100644 index 00000000..324efcee --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X3.kt @@ -0,0 +1,28 @@ +/* + * UltrasonicAppWidgetProvider4X3.kt + * Copyright (C) 2009-2022 Ultrasonic developers + * + * Distributed under terms of the GNU GPLv3 license. + */ + +package org.moire.ultrasonic.provider + +import org.moire.ultrasonic.R + +class UltrasonicAppWidgetProvider4X3 : UltrasonicAppWidgetProvider() { + companion object { + @get:Synchronized + var instance: UltrasonicAppWidgetProvider4X3? = null + get() { + if (field == null) { + field = UltrasonicAppWidgetProvider4X3() + } + return field + } + private set + } + + init { + layoutId = R.layout.appwidget4x3 + } +} \ No newline at end of file diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X4.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X4.kt new file mode 100644 index 00000000..4d03970a --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/provider/UltrasonicAppWidgetProvider4X4.kt @@ -0,0 +1,28 @@ +/* + * UltrasonicAppWidgetProvider4X4.kt + * Copyright (C) 2009-2022 Ultrasonic developers + * + * Distributed under terms of the GNU GPLv3 license. + */ + +package org.moire.ultrasonic.provider + +import org.moire.ultrasonic.R + +class UltrasonicAppWidgetProvider4X4 : UltrasonicAppWidgetProvider() { + companion object { + @get:Synchronized + var instance: UltrasonicAppWidgetProvider4X4? = null + get() { + if (field == null) { + field = UltrasonicAppWidgetProvider4X4() + } + return field + } + private set + } + + init { + layoutId = R.layout.appwidget4x4 + } +} \ No newline at end of file