Browse Source

Added resume and pause buttons to the widget and fixed widget-related (UI) bugs.

pull/82/head
Eric Kok 11 years ago
parent
commit
957036e250
  1. 24
      core/res/layout-v11/widget_torrents_dark.xml
  2. 24
      core/res/layout-v11/widget_torrents_light.xml
  3. 4
      core/res/values/strings.xml
  4. 2
      core/res/xml/listwidget_info.xml
  5. 8
      core/src/org/transdroid/core/app/settings/ApplicationSettings.java
  6. 14
      core/src/org/transdroid/core/gui/TorrentsActivity.java
  7. 155
      core/src/org/transdroid/core/service/ControlService.java
  8. 4
      core/src/org/transdroid/core/widget/ListWidgetConfig.java
  9. 10
      core/src/org/transdroid/core/widget/ListWidgetConfigActivity.java
  10. 4
      core/src/org/transdroid/core/widget/ListWidgetPreviewAdapter.java
  11. 46
      core/src/org/transdroid/core/widget/ListWidgetProvider.java
  12. 13
      core/src/org/transdroid/core/widget/ListWidgetViewsService.java
  13. 30
      full/AndroidManifest.xml
  14. 8
      lib/src/org/transdroid/daemon/TorrentsComparator.java
  15. 29
      lite/AndroidManifest.xml

24
core/res/layout-v11/widget_torrents_dark.xml

@ -42,11 +42,33 @@
android:scaleType="fitXY" android:scaleType="fitXY"
android:src="@drawable/ic_action_refresh_dark" /> android:src="@drawable/ic_action_refresh_dark" />
<ImageButton
android:id="@+id/pauseall_button"
android:layout_width="@dimen/widget_header_height"
android:layout_height="@dimen/widget_header_height"
android:layout_toLeftOf="@id/refresh_button"
android:background="@drawable/selectable_background_transdroid2"
android:contentDescription="@string/action_pauseall"
android:padding="@dimen/widget_header_padding"
android:scaleType="fitXY"
android:src="@drawable/ic_action_pause_dark" />
<ImageButton
android:id="@+id/resumeall_button"
android:layout_width="@dimen/widget_header_height"
android:layout_height="@dimen/widget_header_height"
android:layout_toLeftOf="@id/pauseall_button"
android:background="@drawable/selectable_background_transdroid2"
android:contentDescription="@string/action_resumeall"
android:padding="@dimen/widget_header_padding"
android:scaleType="fitXY"
android:src="@drawable/ic_action_resume_dark" />
<LinearLayout <LinearLayout
android:id="@+id/navigation_view" android:id="@+id/navigation_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/widget_header_height" android:layout_height="@dimen/widget_header_height"
android:layout_toLeftOf="@id/refresh_button" android:layout_toLeftOf="@id/resumeall_button"
android:layout_toRightOf="@id/icon_image" android:layout_toRightOf="@id/icon_image"
android:background="@drawable/selectable_background_transdroid" android:background="@drawable/selectable_background_transdroid"
android:clickable="true" android:clickable="true"

24
core/res/layout-v11/widget_torrents_light.xml

@ -42,11 +42,33 @@
android:scaleType="fitXY" android:scaleType="fitXY"
android:src="@drawable/ic_action_refresh_light" /> android:src="@drawable/ic_action_refresh_light" />
<ImageButton
android:id="@+id/pauseall_button"
android:layout_width="@dimen/widget_header_height"
android:layout_height="@dimen/widget_header_height"
android:layout_toLeftOf="@id/refresh_button"
android:background="@drawable/selectable_background_transdroid2"
android:contentDescription="@string/action_pauseall"
android:padding="@dimen/widget_header_padding"
android:scaleType="fitXY"
android:src="@drawable/ic_action_pause_light" />
<ImageButton
android:id="@+id/resumeall_button"
android:layout_width="@dimen/widget_header_height"
android:layout_height="@dimen/widget_header_height"
android:layout_toLeftOf="@id/pauseall_button"
android:background="@drawable/selectable_background_transdroid2"
android:contentDescription="@string/action_resumeall"
android:padding="@dimen/widget_header_padding"
android:scaleType="fitXY"
android:src="@drawable/ic_action_resume_light" />
<LinearLayout <LinearLayout
android:id="@+id/navigation_view" android:id="@+id/navigation_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/widget_header_height" android:layout_height="@dimen/widget_header_height"
android:layout_toLeftOf="@id/refresh_button" android:layout_toLeftOf="@id/resumeall_button"
android:layout_toRightOf="@id/icon_image" android:layout_toRightOf="@id/icon_image"
android:background="@drawable/selectable_background_transdroid2" android:background="@drawable/selectable_background_transdroid2"
android:clickable="true" android:clickable="true"

4
core/res/values/strings.xml

@ -40,9 +40,13 @@
<string name="action_start">Start</string> <string name="action_start">Start</string>
<string name="action_start_default">Normal start</string> <string name="action_start_default">Normal start</string>
<string name="action_start_forced">Force start</string> <string name="action_start_forced">Force start</string>
<string name="action_startall">Start all</string>
<string name="action_stop">Stop</string> <string name="action_stop">Stop</string>
<string name="action_stopall">Stop all</string>
<string name="action_resume">Resume</string> <string name="action_resume">Resume</string>
<string name="action_resumeall">Resume all</string>
<string name="action_pause">Pause</string> <string name="action_pause">Pause</string>
<string name="action_pauseall">Pause all</string>
<string name="action_remove">Remove</string> <string name="action_remove">Remove</string>
<string name="action_remove_default">Remove torrent</string> <string name="action_remove_default">Remove torrent</string>
<string name="action_remove_withdata">Remove and delete data</string> <string name="action_remove_withdata">Remove and delete data</string>

2
core/res/xml/appwidget_info.xml → core/res/xml/listwidget_info.xml

@ -16,7 +16,7 @@
along with Transdroid. If not, see <http://www.gnu.org/licenses/>. along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
--> -->
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:configure="org.transdroid.core.widget.WidgetConfigActivity_" android:configure="org.transdroid.core.widget.ListWidgetConfigActivity_"
android:initialKeyguardLayout="@layout/widget_torrents_light" android:initialKeyguardLayout="@layout/widget_torrents_light"
android:initialLayout="@layout/widget_torrents_light" android:initialLayout="@layout/widget_torrents_light"
android:minHeight="110dip" android:minHeight="110dip"

8
core/src/org/transdroid/core/app/settings/ApplicationSettings.java

@ -32,7 +32,7 @@ import org.transdroid.core.app.search.SearchHelper;
import org.transdroid.core.app.search.SearchSite; import org.transdroid.core.app.search.SearchSite;
import org.transdroid.core.gui.navigation.StatusType; import org.transdroid.core.gui.navigation.StatusType;
import org.transdroid.core.gui.search.SearchSetting; import org.transdroid.core.gui.search.SearchSetting;
import org.transdroid.core.widget.WidgetConfig; import org.transdroid.core.widget.ListWidgetConfig;
import org.transdroid.daemon.Daemon; import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.OS; import org.transdroid.daemon.OS;
import org.transdroid.daemon.TorrentsSortBy; import org.transdroid.daemon.TorrentsSortBy;
@ -504,11 +504,11 @@ public class ApplicationSettings {
* @param appWidgetId The unique ID of the app widget to retrieve settings for, as supplied by the AppWidgetManager * @param appWidgetId The unique ID of the app widget to retrieve settings for, as supplied by the AppWidgetManager
* @return A widget configuration object, or null if no settings were stored for the widget ID * @return A widget configuration object, or null if no settings were stored for the widget ID
*/ */
public WidgetConfig getWidgetConfig(int appWidgetId) { public ListWidgetConfig getWidgetConfig(int appWidgetId) {
if (!prefs.contains("widget_server_" + appWidgetId)) if (!prefs.contains("widget_server_" + appWidgetId))
return null; return null;
// @formatter:off // @formatter:off
return new WidgetConfig(prefs.getInt("widget_server_" + appWidgetId, -1), StatusType.valueOf(prefs.getString( return new ListWidgetConfig(prefs.getInt("widget_server_" + appWidgetId, -1), StatusType.valueOf(prefs.getString(
"widget_status_" + appWidgetId, StatusType.ShowAll.name())), TorrentsSortBy.valueOf(prefs.getString( "widget_status_" + appWidgetId, StatusType.ShowAll.name())), TorrentsSortBy.valueOf(prefs.getString(
"widget_sortby_" + appWidgetId, TorrentsSortBy.Alphanumeric.name())), prefs.getBoolean( "widget_sortby_" + appWidgetId, TorrentsSortBy.Alphanumeric.name())), prefs.getBoolean(
"widget_reverse_" + appWidgetId, false), prefs.getBoolean("widget_darktheme_" + appWidgetId, false)); "widget_reverse_" + appWidgetId, false), prefs.getBoolean("widget_darktheme_" + appWidgetId, false));
@ -521,7 +521,7 @@ public class ApplicationSettings {
* @param appWidgetId The unique ID of the app widget to store settings for, as supplied by the AppWidgetManager * @param appWidgetId The unique ID of the app widget to store settings for, as supplied by the AppWidgetManager
* @param settings A widget configuration object, which may not be null * @param settings A widget configuration object, which may not be null
*/ */
public void setWidgetConfig(int appWidgetId, WidgetConfig settings) { public void setWidgetConfig(int appWidgetId, ListWidgetConfig settings) {
if (settings == null) if (settings == null)
throw new InvalidParameterException( throw new InvalidParameterException(
"The widget setting may not be null. Use removeWidgetConfig instead to remove existing settings for some app widget."); "The widget setting may not be null. Use removeWidgetConfig instead to remove existing settings for some app widget.");

14
core/src/org/transdroid/core/gui/TorrentsActivity.java

@ -69,7 +69,7 @@ import org.transdroid.core.gui.search.UrlEntryDialog;
import org.transdroid.core.gui.settings.MainSettingsActivity_; import org.transdroid.core.gui.settings.MainSettingsActivity_;
import org.transdroid.core.service.BootReceiver; import org.transdroid.core.service.BootReceiver;
import org.transdroid.core.service.ConnectivityHelper; import org.transdroid.core.service.ConnectivityHelper;
import org.transdroid.core.widget.WidgetProvider; import org.transdroid.core.widget.ListWidgetProvider;
import org.transdroid.daemon.Daemon; import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.IDaemonAdapter; import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.Priority; import org.transdroid.daemon.Priority;
@ -235,17 +235,17 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi
return; return;
} }
Torrent startTorrent = null; Torrent startTorrent = null;
if (getIntent().getAction() != null && getIntent().getAction().equals(WidgetProvider.INTENT_STARTSERVER) if (getIntent().getAction() != null && getIntent().getAction().equals(ListWidgetProvider.INTENT_STARTSERVER)
&& getIntent().getExtras() == null && getIntent().hasExtra(WidgetProvider.EXTRA_SERVER)) { && getIntent().getExtras() == null && getIntent().hasExtra(ListWidgetProvider.EXTRA_SERVER)) {
// A server settings order ID was provided in this org.transdroid.START_SERVER action intent // A server settings order ID was provided in this org.transdroid.START_SERVER action intent
int serverId = getIntent().getExtras().getInt(WidgetProvider.EXTRA_SERVER); int serverId = getIntent().getExtras().getInt(ListWidgetProvider.EXTRA_SERVER);
if (serverId < 0 || serverId > applicationSettings.getMaxServer()) { if (serverId < 0 || serverId > applicationSettings.getMaxServer()) {
Log.e(this, "Tried to start with " + WidgetProvider.EXTRA_SERVER + " intent but " + serverId Log.e(this, "Tried to start with " + ListWidgetProvider.EXTRA_SERVER + " intent but " + serverId
+ " is not an existing server order id"); + " is not an existing server order id");
} else { } else {
lastUsed = applicationSettings.getServerSetting(serverId); lastUsed = applicationSettings.getServerSetting(serverId);
if (getIntent().hasExtra(WidgetProvider.EXTRA_TORRENT)) if (getIntent().hasExtra(ListWidgetProvider.EXTRA_TORRENT))
startTorrent = getIntent().getParcelableExtra(WidgetProvider.EXTRA_TORRENT); startTorrent = getIntent().getParcelableExtra(ListWidgetProvider.EXTRA_TORRENT);
} }
} }

155
core/src/org/transdroid/core/service/ControlService.java

@ -0,0 +1,155 @@
package org.transdroid.core.service;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EService;
import org.transdroid.core.app.settings.ApplicationSettings;
import org.transdroid.core.app.settings.ServerSetting;
import org.transdroid.core.gui.log.Log;
import org.transdroid.core.widget.ListWidgetConfig;
import org.transdroid.core.widget.ListWidgetProvider;
import org.transdroid.core.widget.ListWidgetProvider_;
import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.task.DaemonTask;
import org.transdroid.daemon.task.DaemonTaskResult;
import org.transdroid.daemon.task.DaemonTaskSuccessResult;
import org.transdroid.daemon.task.PauseAllTask;
import org.transdroid.daemon.task.ResumeAllTask;
import org.transdroid.daemon.task.SetTransferRatesTask;
import org.transdroid.daemon.task.StartAllTask;
import org.transdroid.daemon.task.StopAllTask;
import android.app.IntentService;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
@EService
public class ControlService extends IntentService {
// NOTE: These are the same strings as Transdroid 1, for backwards compatibility
public static final String INTENT_SETTRANSFERRATES = "org.transdroid.control.SET_TRANSFER_RATES";
public static final String INTENT_PAUSEALL = "org.transdroid.control.PAUSE_ALL";
public static final String INTENT_RESUMEALL = "org.transdroid.control.RESUME_ALL";
public static final String INTENT_STARTALL = "org.transdroid.control.START_ALL";
public static final String INTENT_STOPALL = "org.transdroid.control.STOP_ALL";
public static final String EXTRA_DAEMON = "DAEMON";
public static final String EXTRA_UPLOAD_RATE = "UPLOAD_RATE";
public static final String EXTRA_DOWNLOAD_RATE = "DOWNLOAD_RATE";
@Bean
protected ConnectivityHelper connectivityHelper;
@Bean
protected ApplicationSettings applicationSettings;
public ControlService() {
super("ControlService");
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent == null)
return;
// We should have been supplied either am EXTRA_DAEMON or an AppWidgetManager.EXTRA_APPWIDGET_ID
ServerSetting server = null;
int appWidgetId = -1;
if (intent.hasExtra(EXTRA_DAEMON)) {
// See if the supplied server id is pointing to a valid server
int serverId = intent.getIntExtra(EXTRA_DAEMON, -1);
if (serverId < 0 || serverId > applicationSettings.getMaxServer()) {
// This server does not exist (any more) or no valid EXTRA_DAEMON value was supplied
Log.e(this, "The control service can be started with a DAEMON extra zero-based server id, but the"
+ "supplied id was invalid or no longer points to an existing server.");
return;
}
server = applicationSettings.getServerSetting(serverId);
} else if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
// This was called directly form a home screen widget
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
ListWidgetConfig config = applicationSettings.getWidgetConfig(appWidgetId);
if (config == null) {
Log.e(this,
"The control service can be started by a widget using the AppWidgetManager.EXTRA_APPWIDGET_ID, "
+ "but the id that was supplied does not point to an existing home screen widget.");
return;
}
int serverId = config.getServerId();
if (serverId < 0 || serverId > applicationSettings.getMaxServer()) {
Log.e(this, "The home screen widget points to a server that no longer exists.");
return;
}
server = applicationSettings.getServerSetting(serverId);
} else {
// Simply use the last-used server
server = applicationSettings.getLastUsedServer();
}
// Still no server? Then we don't have one specified yet
if (server == null) {
Log.e(this, "The control service was called, but there are nog servers configured at all.");
return;
}
// See which action should be performed on the server
IDaemonAdapter adapter = server.createServerAdapter(connectivityHelper.getConnectedNetworkName(), this);
DaemonTask task = null;
if (intent.getAction().equals(INTENT_RESUMEALL)) {
task = ResumeAllTask.create(adapter);
} else if (intent.getAction().equals(INTENT_PAUSEALL)) {
task = PauseAllTask.create(adapter);
} else if (intent.getAction().equals(INTENT_STARTALL)) {
task = StartAllTask.create(adapter, false);
} else if (intent.getAction().equals(INTENT_STOPALL)) {
task = StopAllTask.create(adapter);
} else if (intent.getAction().equals(INTENT_SETTRANSFERRATES)) {
// NOTE: If the upload or download rate was not specified, it will be reset on the server instead
int uploadRate = intent.getIntExtra(EXTRA_UPLOAD_RATE, -1);
int downloadRate = intent.getIntExtra(EXTRA_DOWNLOAD_RATE, -1);
task = SetTransferRatesTask.create(adapter, uploadRate == -1 ? null : uploadRate, downloadRate == -1 ? null
: downloadRate);
}
// Execute the task, if we have one now
if (task == null) {
Log.e(this, "The control service was started, but no (valid) action was specified, such as "
+ "org.transdroid.control.START_ALL or org.transdroid.control.SET_TRANSFER_RATES");
return;
}
DaemonTaskResult result = task.execute();
if (result instanceof DaemonTaskSuccessResult) {
Log.i(this,
task.getMethod().name() + " was successfully executed on " + server.getHumanReadableIdentifier());
} else {
Log.i(this,
task.getMethod().name() + " was NOT succcessfully executed on "
+ server.getHumanReadableIdentifier() + " (and we are NOT trying again)");
// No need to continue now
return;
}
// The task was successful, so maybe we need to update the original calling widget now too
if (appWidgetId >= 0) {
// Just wait for (max) two seconds, to give the server time to finish its last action
try {
Thread.sleep(2000);
} catch (Exception e) {
}
// Ask the app widget provider to update this specific widget
Intent update = new Intent(this, ListWidgetProvider_.class);
update.setAction("android.appwidget.action.APPWIDGET_UPDATE");
update.putExtra(ListWidgetProvider.EXTRA_REFRESH, appWidgetId);
update.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
sendBroadcast(update);
}
}
}

4
core/src/org/transdroid/core/widget/WidgetConfig.java → core/src/org/transdroid/core/widget/ListWidgetConfig.java

@ -23,7 +23,7 @@ import org.transdroid.daemon.TorrentsSortBy;
* Represents a set of settings that define how the user configured a specific app widget. * Represents a set of settings that define how the user configured a specific app widget.
* @author Eric Kok * @author Eric Kok
*/ */
public class WidgetConfig { public class ListWidgetConfig {
private final int serverId; private final int serverId;
private final StatusType statusType; private final StatusType statusType;
@ -31,7 +31,7 @@ public class WidgetConfig {
private final boolean reserveSort; private final boolean reserveSort;
private final boolean useDarkTheme; private final boolean useDarkTheme;
public WidgetConfig(int serverId, StatusType statusType, TorrentsSortBy sortBy, boolean reverseSort, public ListWidgetConfig(int serverId, StatusType statusType, TorrentsSortBy sortBy, boolean reverseSort,
boolean useDarkTheme) { boolean useDarkTheme) {
this.serverId = serverId; this.serverId = serverId;
this.statusType = statusType; this.statusType = statusType;

10
core/src/org/transdroid/core/widget/WidgetConfigActivity.java → core/src/org/transdroid/core/widget/ListWidgetConfigActivity.java

@ -64,7 +64,7 @@ import com.actionbarsherlock.app.SherlockActivity;
@TargetApi(Build.VERSION_CODES.HONEYCOMB) @TargetApi(Build.VERSION_CODES.HONEYCOMB)
@EActivity(resName = "activity_widgetconfig") @EActivity(resName = "activity_widgetconfig")
public class WidgetConfigActivity extends SherlockActivity { public class ListWidgetConfigActivity extends SherlockActivity {
// Views and adapters // Views and adapters
@ViewById @ViewById
@ -211,7 +211,7 @@ public class WidgetConfigActivity extends SherlockActivity {
.sort(filteredTorrents, new TorrentsComparator(serverType, sortBy, reverseorderCheckBox.isChecked())); .sort(filteredTorrents, new TorrentsComparator(serverType, sortBy, reverseorderCheckBox.isChecked()));
// Finally update the widget preview with the live, filtered and sorted torrents list // Finally update the widget preview with the live, filtered and sorted torrents list
torrentsList.setAdapter(new WidgetPreviewAdapter(this, 0, filteredTorrents)); torrentsList.setAdapter(new ListWidgetPreviewAdapter(this, 0, filteredTorrents));
torrentsList.setVisibility(View.VISIBLE); torrentsList.setVisibility(View.VISIBLE);
errorText.setVisibility(View.GONE); errorText.setVisibility(View.GONE);
} }
@ -241,13 +241,13 @@ public class WidgetConfigActivity extends SherlockActivity {
TorrentsSortBy sortBy = ((SortByListItem) sortSpinner.getSelectedItem()).getSortBy(); TorrentsSortBy sortBy = ((SortByListItem) sortSpinner.getSelectedItem()).getSortBy();
boolean reverseSort = reverseorderCheckBox.isChecked(); boolean reverseSort = reverseorderCheckBox.isChecked();
boolean useDarkTheme = darkthemeCheckBox.isChecked(); boolean useDarkTheme = darkthemeCheckBox.isChecked();
WidgetConfig config = new WidgetConfig(server, statusType, sortBy, reverseSort, useDarkTheme); ListWidgetConfig config = new ListWidgetConfig(server, statusType, sortBy, reverseSort, useDarkTheme);
applicationSettings.setWidgetConfig(appWidgetId, config); applicationSettings.setWidgetConfig(appWidgetId, config);
// Return the widget configuration result // Return the widget configuration result
AppWidgetManager manager = AppWidgetManager.getInstance(WidgetConfigActivity.this); AppWidgetManager manager = AppWidgetManager.getInstance(ListWidgetConfigActivity.this);
manager.updateAppWidget(appWidgetId, manager.updateAppWidget(appWidgetId,
WidgetProvider.buildRemoteViews(getApplicationContext(), appWidgetId, config)); ListWidgetProvider.buildRemoteViews(getApplicationContext(), appWidgetId, config));
manager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.torrents_list); manager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.torrents_list);
setResult(RESULT_OK, new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)); setResult(RESULT_OK, new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId));
finish(); finish();

4
core/src/org/transdroid/core/widget/WidgetPreviewAdapter.java → core/src/org/transdroid/core/widget/ListWidgetPreviewAdapter.java

@ -33,7 +33,7 @@ import android.widget.TextView;
* A list list item adapter that shows torrents as simplified, widget-style list items; the light theme is always used. * A list list item adapter that shows torrents as simplified, widget-style list items; the light theme is always used.
* @author Eric Kok * @author Eric Kok
*/ */
public class WidgetPreviewAdapter extends ArrayAdapter<Torrent> { public class ListWidgetPreviewAdapter extends ArrayAdapter<Torrent> {
/** /**
* Constructs the custom array adapter that shows torrents in a widget list style for preview. * Constructs the custom array adapter that shows torrents in a widget list style for preview.
@ -41,7 +41,7 @@ public class WidgetPreviewAdapter extends ArrayAdapter<Torrent> {
* @param foo Ignored parameter; the light theme widget appearance is always used * @param foo Ignored parameter; the light theme widget appearance is always used
* @param torrents The already-retrieved, non-null list of torrents to show * @param torrents The already-retrieved, non-null list of torrents to show
*/ */
public WidgetPreviewAdapter(Context context, int foo, List<Torrent> torrents) { public ListWidgetPreviewAdapter(Context context, int foo, List<Torrent> torrents) {
super(context, R.layout.list_item_widget_light, torrents); super(context, R.layout.list_item_widget_light, torrents);
} }

46
core/src/org/transdroid/core/widget/WidgetProvider.java → core/src/org/transdroid/core/widget/ListWidgetProvider.java

@ -22,6 +22,7 @@ import org.transdroid.core.R;
import org.transdroid.core.app.settings.*; import org.transdroid.core.app.settings.*;
import org.transdroid.core.gui.*; import org.transdroid.core.gui.*;
import org.transdroid.core.gui.log.Log; import org.transdroid.core.gui.log.Log;
import org.transdroid.core.service.ControlService;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.PendingIntent; import android.app.PendingIntent;
@ -33,9 +34,14 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.widget.RemoteViews; import android.widget.RemoteViews;
/**
* The provider of a list-style Transdroid widget, which controls the general loading and (touch) event handling. The
* list rows' remote views are loaded in the accompanying {@link ListWidgetViewsService}.
* @author Eric Kok
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB) @TargetApi(Build.VERSION_CODES.HONEYCOMB)
@EReceiver @EReceiver
public class WidgetProvider extends AppWidgetProvider { public class ListWidgetProvider extends AppWidgetProvider {
public static final String INTENT_STARTSERVER = "org.transdroid.START_SERVER"; public static final String INTENT_STARTSERVER = "org.transdroid.START_SERVER";
public static final String EXTRA_TORRENT = "extra_torrent"; public static final String EXTRA_TORRENT = "extra_torrent";
@ -47,15 +53,27 @@ public class WidgetProvider extends AppWidgetProvider {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (intent != null && intent.hasExtra(EXTRA_REFRESH)) { super.onReceive(context, intent);
if (intent == null)
return;
int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
// Refresh a specific app widget
if (intent.hasExtra(EXTRA_REFRESH)) {
// Manually requested a refresh for the app widget of which the ID was supplied // Manually requested a refresh for the app widget of which the ID was supplied
int appWidgetId = intent.getIntExtra(EXTRA_REFRESH, -1);
AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId,
buildRemoteViews(context, appWidgetId, applicationSettings.getWidgetConfig(appWidgetId))); buildRemoteViews(context, appWidgetId, applicationSettings.getWidgetConfig(appWidgetId)));
AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(appWidgetId, R.id.torrents_list); AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(appWidgetId, R.id.torrents_list);
return; return;
} }
super.onReceive(context, intent);
// No refresh: this is a control intent: copy the action and EXTRA_APPWIDGET_ID to start the control service
if (intent.getAction().startsWith("org.transdroid.control.")) {
Intent action = new Intent(intent.getAction());
action.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
context.startService(action);
}
} }
@Override @Override
@ -83,7 +101,7 @@ public class WidgetProvider extends AppWidgetProvider {
* @return A fully initialised set of remote views to update the widget with the AppWidgetManager * @return A fully initialised set of remote views to update the widget with the AppWidgetManager
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static RemoteViews buildRemoteViews(Context context, int appWidgetId, WidgetConfig config) { public static RemoteViews buildRemoteViews(Context context, int appWidgetId, ListWidgetConfig config) {
// Does the server to show and its widget settings actually still exist? // Does the server to show and its widget settings actually still exist?
if (context == null || config == null) if (context == null || config == null)
@ -100,7 +118,7 @@ public class WidgetProvider extends AppWidgetProvider {
config.shouldUseDarkTheme() ? R.layout.widget_torrents_dark : R.layout.widget_torrents_light); config.shouldUseDarkTheme() ? R.layout.widget_torrents_dark : R.layout.widget_torrents_light);
// Set up the widget's list view loading service which refers to the WidgetViewsFactory // Set up the widget's list view loading service which refers to the WidgetViewsFactory
Intent data = new Intent(context, WidgetService_.class); Intent data = new Intent(context, ListWidgetViewsService_.class);
data.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); data.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
data.setData(Uri.parse(data.toUri(Intent.URI_INTENT_SCHEME))); data.setData(Uri.parse(data.toUri(Intent.URI_INTENT_SCHEME)));
rv.setRemoteAdapter(appWidgetId, R.id.torrents_list, data); rv.setRemoteAdapter(appWidgetId, R.id.torrents_list, data);
@ -129,13 +147,27 @@ public class WidgetProvider extends AppWidgetProvider {
// Set up the widgets refresh button pending intent (calling this WidgetProvider itself) // Set up the widgets refresh button pending intent (calling this WidgetProvider itself)
// Make sure that the intent is unique using a custom data path (rather than just the extras) // Make sure that the intent is unique using a custom data path (rather than just the extras)
Intent refresh = new Intent(context, WidgetProvider_.class); Intent refresh = new Intent(context, ListWidgetProvider_.class);
refresh.setData(Uri.parse("intent://widget/" + appWidgetId + "/refresh")); refresh.setData(Uri.parse("intent://widget/" + appWidgetId + "/refresh"));
refresh.putExtra(EXTRA_REFRESH, appWidgetId); refresh.putExtra(EXTRA_REFRESH, appWidgetId);
refresh.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); refresh.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
rv.setOnClickPendingIntent(R.id.refresh_button, rv.setOnClickPendingIntent(R.id.refresh_button,
PendingIntent.getBroadcast(context, appWidgetId, refresh, PendingIntent.FLAG_UPDATE_CURRENT)); PendingIntent.getBroadcast(context, appWidgetId, refresh, PendingIntent.FLAG_UPDATE_CURRENT));
// Set up the control (pause and resume) buttons (calling the WidgetProvider itself)
Intent pauseall = new Intent(context, ListWidgetProvider_.class);
pauseall.setData(Uri.parse("intent://widget/" + appWidgetId + "/pauseall"));
pauseall.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
pauseall.setAction(ControlService.INTENT_PAUSEALL);
rv.setOnClickPendingIntent(R.id.pauseall_button,
PendingIntent.getBroadcast(context, appWidgetId, pauseall, PendingIntent.FLAG_UPDATE_CURRENT));
Intent resumeall = new Intent(context, ListWidgetProvider_.class);
resumeall.setData(Uri.parse("intent://widget/" + appWidgetId + "/resumeall"));
resumeall.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
resumeall.setAction(ControlService.INTENT_RESUMEALL);
rv.setOnClickPendingIntent(R.id.resumeall_button,
PendingIntent.getBroadcast(context, appWidgetId, resumeall, PendingIntent.FLAG_UPDATE_CURRENT));
return rv; return rv;
} }

13
core/src/org/transdroid/core/widget/WidgetService.java → core/src/org/transdroid/core/widget/ListWidgetViewsService.java

@ -43,9 +43,14 @@ import android.os.Build;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import android.widget.RemoteViewsService; import android.widget.RemoteViewsService;
/**
* A service for the list widget to update the remote views that a list widget shows, by getting the torrents from the
* server (synchronously) and building {@link RemoteViews} objects for each torrent.
* @author Eric Kok
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB) @TargetApi(Build.VERSION_CODES.HONEYCOMB)
@EService @EService
public class WidgetService extends RemoteViewsService { public class ListWidgetViewsService extends RemoteViewsService {
@Override @Override
public RemoteViewsFactory onGetViewFactory(Intent intent) { public RemoteViewsFactory onGetViewFactory(Intent intent) {
@ -60,7 +65,7 @@ class WidgetViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private final Context context; private final Context context;
private final int appWidgetId; private final int appWidgetId;
private List<Torrent> torrents = null; private List<Torrent> torrents = null;
private WidgetConfig config = null; private ListWidgetConfig config = null;
public WidgetViewsFactory(Context applicationContext, Intent intent) { public WidgetViewsFactory(Context applicationContext, Intent intent) {
this.context = applicationContext; this.context = applicationContext;
@ -153,8 +158,8 @@ class WidgetViewsFactory implements RemoteViewsService.RemoteViewsFactory {
} }
rv.setInt(R.id.status_view, "setBackgroundColor", context.getResources().getColor(statusColour)); rv.setInt(R.id.status_view, "setBackgroundColor", context.getResources().getColor(statusColour));
Intent startIntent = new Intent(); Intent startIntent = new Intent();
startIntent.putExtra(WidgetProvider.EXTRA_SERVER, config.getServerId()); startIntent.putExtra(ListWidgetProvider.EXTRA_SERVER, config.getServerId());
startIntent.putExtra(WidgetProvider.EXTRA_TORRENT, torrent); startIntent.putExtra(ListWidgetProvider.EXTRA_TORRENT, torrent);
rv.setOnClickFillInIntent(R.id.widget_line_layout, startIntent); rv.setOnClickFillInIntent(R.id.widget_line_layout, startIntent);
return rv; return rv;

30
full/AndroidManifest.xml

@ -16,6 +16,7 @@
along with Transdroid. If not, see <http://www.gnu.org/licenses/>. along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
--> -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.transdroid.full" package="org.transdroid.full"
android:versionCode="208" android:versionCode="208"
android:versionName="2.0.2" > android:versionName="2.0.2" >
@ -53,8 +54,8 @@
<activity <activity
android:name="org.transdroid.core.gui.TorrentsActivity_" android:name="org.transdroid.core.gui.TorrentsActivity_"
android:allowTaskReparenting="true" android:allowTaskReparenting="true"
android:launchMode="singleTop"
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/TransdroidTheme" android:theme="@style/TransdroidTheme"
android:uiOptions="splitActionBarWhenNarrow" > android:uiOptions="splitActionBarWhenNarrow" >
<intent-filter> <intent-filter>
@ -235,7 +236,7 @@
android:label="@string/rss_feeds" android:label="@string/rss_feeds"
android:theme="@style/TransdroidTheme" /> android:theme="@style/TransdroidTheme" />
<!-- Background service --> <!-- Background services -->
<service android:name="org.transdroid.core.service.ServerCheckerService_" /> <service android:name="org.transdroid.core.service.ServerCheckerService_" />
<service android:name="org.transdroid.core.service.RssCheckerService_" /> <service android:name="org.transdroid.core.service.RssCheckerService_" />
<service android:name="org.transdroid.core.service.AppUpdateService_" /> <service android:name="org.transdroid.core.service.AppUpdateService_" />
@ -249,24 +250,37 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<service
android:name="org.transdroid.core.service.ControlService_"
android:exported="true"
tools:ignore="ExportedService" >
<intent-filter>
<action android:name="org.transdroid.control.SET_TRANSFER_RATES" />
<action android:name="org.transdroid.control.PAUSE_ALL" />
<action android:name="org.transdroid.control.RESUME_ALL" />
<action android:name="org.transdroid.control.START_ALL" />
<action android:name="org.transdroid.control.STOP_ALL" />
</intent-filter>
</service>
<!-- Home screen widget --> <!-- Home screen widget -->
<activity <activity
android:name="org.transdroid.core.widget.WidgetConfigActivity_" android:name="org.transdroid.core.widget.ListWidgetConfigActivity_"
android:theme="@style/TransdroidTheme.WidgetConfig" android:enabled="@bool/widget_available"
android:enabled="@bool/widget_available" > android:theme="@style/TransdroidTheme.WidgetConfig" >
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /> <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter> </intent-filter>
</activity> </activity>
<service <service
android:name="org.transdroid.core.widget.WidgetService_" android:name="org.transdroid.core.widget.ListWidgetViewsService_"
android:enabled="@bool/widget_available" android:enabled="@bool/widget_available"
android:exported="false" android:exported="false"
android:permission="android.permission.BIND_REMOTEVIEWS" /> android:permission="android.permission.BIND_REMOTEVIEWS" />
<receiver <receiver
android:name="org.transdroid.core.widget.WidgetProvider_" android:name="org.transdroid.core.widget.ListWidgetProvider_"
android:enabled="@bool/widget_available" > android:enabled="@bool/widget_available" >
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -274,7 +288,7 @@
<meta-data <meta-data
android:name="android.appwidget.provider" android:name="android.appwidget.provider"
android:resource="@xml/appwidget_info" /> android:resource="@xml/listwidget_info" />
</receiver> </receiver>
</application> </application>

8
lib/src/org/transdroid/daemon/TorrentsComparator.java

@ -59,6 +59,10 @@ public class TorrentsComparator implements Comparator<Torrent> {
case Status: case Status:
return tor1.getStatusCode().compareStatusCodeTo(tor2.getStatusCode()); return tor1.getStatusCode().compareStatusCodeTo(tor2.getStatusCode());
case DateAdded: case DateAdded:
if (tor1.getDateAdded() == null)
return -1;
if (tor2.getDateAdded() == null)
return 1;
return tor1.getDateAdded().compareTo(tor2.getDateAdded()); return tor1.getDateAdded().compareTo(tor2.getDateAdded());
case DateDone: case DateDone:
return tor1.getDateDone().compareTo(tor2.getDateDone()); return tor1.getDateDone().compareTo(tor2.getDateDone());
@ -74,6 +78,10 @@ public class TorrentsComparator implements Comparator<Torrent> {
case Status: case Status:
return 0 - tor1.getStatusCode().compareStatusCodeTo(tor2.getStatusCode()); return 0 - tor1.getStatusCode().compareStatusCodeTo(tor2.getStatusCode());
case DateAdded: case DateAdded:
if (tor1.getDateAdded() == null)
return 1;
if (tor2.getDateAdded() == null)
return -1;
return 0 - tor1.getDateAdded().compareTo(tor2.getDateAdded()); return 0 - tor1.getDateAdded().compareTo(tor2.getDateAdded());
case DateDone: case DateDone:
return 0 - tor1.getDateDone().compareTo(tor2.getDateDone()); return 0 - tor1.getDateDone().compareTo(tor2.getDateDone());

29
lite/AndroidManifest.xml

@ -16,6 +16,7 @@
along with Transdroid. If not, see <http://www.gnu.org/licenses/>. along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
--> -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.transdroid.lite" package="org.transdroid.lite"
android:versionCode="208" android:versionCode="208"
android:versionName="2.0.2" > android:versionName="2.0.2" >
@ -53,8 +54,8 @@
<activity <activity
android:name="org.transdroid.core.gui.TorrentsActivity_" android:name="org.transdroid.core.gui.TorrentsActivity_"
android:allowTaskReparenting="true" android:allowTaskReparenting="true"
android:launchMode="singleTop"
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/TransdroidTheme" android:theme="@style/TransdroidTheme"
android:uiOptions="splitActionBarWhenNarrow" > android:uiOptions="splitActionBarWhenNarrow" >
<intent-filter> <intent-filter>
@ -195,25 +196,37 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<service
android:name="org.transdroid.core.service.ControlService_"
android:exported="true"
tools:ignore="ExportedService" >
<intent-filter>
<action android:name="org.transdroid.control.SET_TRANSFER_RATES" />
<action android:name="org.transdroid.control.PAUSE_ALL" />
<action android:name="org.transdroid.control.RESUME_ALL" />
<action android:name="org.transdroid.control.START_ALL" />
<action android:name="org.transdroid.control.STOP_ALL" />
</intent-filter>
</service>
<!-- Home screen widget --> <!-- Home screen widget -->
<activity <activity
android:name="org.transdroid.core.widget.WidgetConfigActivity_" android:name="org.transdroid.core.widget.ListWidgetConfigActivity_"
android:theme="@style/TransdroidTheme.WidgetConfig" android:enabled="@bool/widget_available"
android:enabled="@bool/widget_available" > android:theme="@style/TransdroidTheme.WidgetConfig" >
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /> <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter> </intent-filter>
</activity> </activity>
<service <service
android:name="org.transdroid.core.widget.WidgetService_" android:name="org.transdroid.core.widget.ListWidgetViewsService_"
android:enabled="@bool/widget_available" android:enabled="@bool/widget_available"
android:exported="false" android:exported="false"
android:permission="android.permission.BIND_REMOTEVIEWS" /> android:permission="android.permission.BIND_REMOTEVIEWS" />
<receiver <receiver
android:name="org.transdroid.core.widget.WidgetProvider_" android:name="org.transdroid.core.widget.ListWidgetProvider_"
android:theme="@style/TransdroidTheme.WidgetConfig"
android:enabled="@bool/widget_available" > android:enabled="@bool/widget_available" >
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -221,7 +234,7 @@
<meta-data <meta-data
android:name="android.appwidget.provider" android:name="android.appwidget.provider"
android:resource="@xml/appwidget_info" /> android:resource="@xml/listwidget_info" />
</receiver> </receiver>
</application> </application>

Loading…
Cancel
Save