Browse Source

Fully developer (but untest) widget configuration, service and remote views factory.

pull/13/merge
Eric Kok 11 years ago
parent
commit
1f6d4c893d
  1. 0
      core/res/layout-v11/actionbar_donebutton.xml
  2. 0
      core/res/layout-v11/activity_widgetconfig.xml
  3. 66
      core/res/layout-v11/list_item_widget_dark.xml
  4. 66
      core/res/layout-v11/list_item_widget_light.xml
  5. 0
      core/res/layout-v11/widget_torrents_dark.xml
  6. 2
      core/res/layout-v11/widget_torrents_light.xml
  7. 40
      core/res/layout/actionbar_progressitem.xml
  8. 27
      core/res/values-v11/bools.xml
  9. 2
      core/res/values/bools.xml
  10. 14
      core/res/values/colors.xml
  11. 2
      core/res/xml/appwidget_info.xml
  12. 32
      core/src/org/transdroid/core/app/settings/ApplicationSettings.java
  13. 2
      core/src/org/transdroid/core/gui/FilterEntryDialog.java
  14. 24
      core/src/org/transdroid/core/gui/TorrentsActivity.java
  15. 9
      core/src/org/transdroid/core/gui/lists/TorrentFilePriorityLayout.java
  16. 29
      core/src/org/transdroid/core/gui/lists/TorrentStatusLayout.java
  17. 12
      core/src/org/transdroid/core/gui/navigation/StatusType.java
  18. 2
      core/src/org/transdroid/core/gui/search/BarcodeHelper.java
  19. 2
      core/src/org/transdroid/core/gui/search/FilePickerHelper.java
  20. 2
      core/src/org/transdroid/core/gui/search/UrlEntryDialog.java
  21. 4
      core/src/org/transdroid/core/widget/WidgetConfig.java
  22. 19
      core/src/org/transdroid/core/widget/WidgetConfigActivity.java
  23. 101
      core/src/org/transdroid/core/widget/WidgetProvider.java
  24. 198
      core/src/org/transdroid/core/widget/WidgetService.java
  25. 19
      full/AndroidManifest.xml
  26. 32
      lite/AndroidManifest.xml

0
core/res/layout/actionbar_donebutton.xml → core/res/layout-v11/actionbar_donebutton.xml

0
core/res/layout/activity_widgetconfig.xml → core/res/layout-v11/activity_widgetconfig.xml

66
core/res/layout-v11/list_item_widget_dark.xml

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2010-2013 Eric Kok et al.
Transdroid 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.
Transdroid 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 Transdroid. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_line_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/selectable_background_transdroid"
android:paddingRight="@dimen/margin_default" >
<View
android:id="@+id/status_view"
android:layout_height="match_parent"
android:layout_width="6dp" />
<TextView
android:id="@+id/name_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_torrentlistleft"
android:fontFamily="sans-serif-condensed"
android:paddingTop="@dimen/margin_half"
android:textColor="@color/text_bright_dark"
android:textIsSelectable="false"
android:maxLines="1"
android:ellipsize="end"
android:textSize="@dimen/text_enlarged" />
<TextView
android:id="@+id/ratio_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/name_text"
android:layout_marginLeft="@dimen/margin_half"
android:layout_marginTop="4.0dip"
android:paddingBottom="@dimen/margin_half"
android:textIsSelectable="false"
android:textSize="@dimen/text_small" />
<TextView
android:id="@+id/progress_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/ratio_text"
android:layout_alignParentLeft="true"
android:layout_marginLeft="@dimen/margin_torrentlistleft"
android:layout_toLeftOf="@id/priority_image"
android:textIsSelectable="false"
android:textSize="@dimen/text_small" />
</RelativeLayout>

66
core/res/layout-v11/list_item_widget_light.xml

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2010-2013 Eric Kok et al.
Transdroid 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.
Transdroid 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 Transdroid. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_line_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/selectable_background_transdroid2"
android:paddingRight="@dimen/margin_default" >
<View
android:id="@+id/status_view"
android:layout_height="match_parent"
android:layout_width="6dp" />
<TextView
android:id="@+id/name_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_torrentlistleft"
android:fontFamily="sans-serif-condensed"
android:paddingTop="@dimen/margin_half"
android:textColor="@color/text_bright_light"
android:textIsSelectable="false"
android:maxLines="1"
android:ellipsize="end"
android:textSize="@dimen/text_enlarged" />
<TextView
android:id="@+id/ratio_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/name_text"
android:layout_marginLeft="@dimen/margin_half"
android:layout_marginTop="4.0dip"
android:paddingBottom="@dimen/margin_half"
android:textIsSelectable="false"
android:textSize="@dimen/text_small" />
<TextView
android:id="@+id/progress_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/ratio_text"
android:layout_alignParentLeft="true"
android:layout_marginLeft="@dimen/margin_torrentlistleft"
android:layout_toLeftOf="@id/priority_image"
android:textIsSelectable="false"
android:textSize="@dimen/text_small" />
</RelativeLayout>

0
core/res/layout/widget_torrents_dark.xml → core/res/layout-v11/widget_torrents_dark.xml

2
core/res/layout/widget_torrents_light.xml → core/res/layout-v11/widget_torrents_light.xml

@ -45,7 +45,7 @@ @@ -45,7 +45,7 @@
android:layout_alignParentBottom="true"
android:background="@color/green" />
<com.actionbarsherlock.view.SherlockListView
<ListView
android:id="@+id/torrents_list"
android:layout_height="wrap_content"
android:layout_width="match_parent"

40
core/res/layout/actionbar_progressitem.xml

@ -1,40 +0,0 @@ @@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2010-2013 Eric Kok et al.
Transdroid 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.
Transdroid 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 Transdroid. If not, see <http://www.gnu.org/licenses/>.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="?attr/actionBarSize">
<!-- This is a wrapper to be able to set the size of the progress item (since the first FrameLayout will be merged) -->
<FrameLayout
android:layout_width="26dip"
android:layout_height="match_parent"
android:paddingLeft="3dip">
<ProgressBar
android:id="@+id/progress"
android:layout_width="20dip"
android:layout_height="20dip"
android:layout_gravity="center_vertical"
style="@android:style/Widget.ProgressBar.Small.Inverse"
android:indeterminate="true"
android:indeterminateOnly="true" />
</FrameLayout>
</FrameLayout>

27
core/res/layout-v14/actionbar_progressitem.xml → core/res/values-v11/bools.xml

@ -15,26 +15,7 @@ @@ -15,26 +15,7 @@
You should have received a copy of the GNU General Public License
along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="?attr/actionBarSize">
<!-- This is a wrapper to be able to set the size of the progress item (since the first FrameLayout will be merged) -->
<FrameLayout
android:layout_width="56dip"
android:layout_height="match_parent"
android:paddingLeft="3dip">
<ProgressBar
android:id="@+id/progress"
android:layout_width="20dip"
android:layout_height="20dip"
android:layout_gravity="center"
style="@android:style/Widget.ProgressBar.Small.Inverse"
android:indeterminate="true"
android:indeterminateOnly="true" />
</FrameLayout>
</FrameLayout>
<resources>
<!-- Used to enable the scrolling widget on Honeycomb (API 11) and higher only -->
<bool name="widget_available">true</bool>
</resources>

2
core/res/values/bools.xml

@ -18,4 +18,6 @@ @@ -18,4 +18,6 @@
<resources>
<!-- Used to determine if a device is 'small', i.e. a phone; for reference: a Nexus 7's smallest width is 533dip -->
<bool name="show_dialog_fullscreen">true</bool>
<!-- Used to enable the scrolling widget on Honeycomb (API 11) and higher only -->
<bool name="widget_available">false</bool>
</resources>

14
core/res/values/colors.xml

@ -16,8 +16,22 @@ @@ -16,8 +16,22 @@
along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
-->
<resources>
<!-- General layout colours -->
<color name="green">#8acc12</color>
<color name="ledgreen">#7dbb21</color>
<color name="crouton_error">#c81113</color>
<color name="crouton_info">#aada62</color>
<!-- Torrent and file status colours -->
<color name="torrent_downloading">#42a8fa</color> <!-- Blue -->
<color name="torrent_paused">#a759d4</color> <!-- Purple -->
<color name="torrent_seeding">#8acc12</color> <!-- Green -->
<color name="torrent_error">#de3939</color> <!-- Red -->
<color name="torrent_other">#9e9e9e</color> <!-- Grey -->
<color name="file_low">#c8e88e</color> <!-- Light green -->
<color name="file_normal">#8acc12</color> <!-- Normal green -->
<color name="file_high">#4b6617</color> <!-- Dark green -->
<color name="file_off">#9e9e9e</color> <!-- Grey -->
</resources>

2
core/res/xml/appwidget_info.xml

@ -25,5 +25,5 @@ @@ -25,5 +25,5 @@
android:minWidth="180dp"
android:previewImage="@drawable/ic_launcher"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="86400000"
android:updatePeriodMillis="3600000"
android:widgetCategory="home_screen|keyguard" />

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

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
*/
package org.transdroid.core.app.settings;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@ -31,7 +32,7 @@ import org.transdroid.core.app.search.SearchHelper; @@ -31,7 +32,7 @@ import org.transdroid.core.app.search.SearchHelper;
import org.transdroid.core.app.search.SearchSite;
import org.transdroid.core.gui.navigation.StatusType;
import org.transdroid.core.gui.search.SearchSetting;
import org.transdroid.core.widget.WidgetSettings;
import org.transdroid.core.widget.WidgetConfig;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.OS;
import org.transdroid.daemon.TorrentsSortBy;
@ -511,11 +512,11 @@ public class ApplicationSettings { @@ -511,11 +512,11 @@ public class ApplicationSettings {
* @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
*/
public WidgetSettings getWidgetConfig(int appWidgetId) {
public WidgetConfig getWidgetConfig(int appWidgetId) {
if (!prefs.contains("widget_server_" + appWidgetId))
return null;
// @formatter:off
return new WidgetSettings(
return new WidgetConfig(
prefs.getInt("widget_server_" + appWidgetId, -1),
StatusType.valueOf(prefs.getString("widget_status_" + appWidgetId, StatusType.ShowAll.name())),
TorrentsSortBy.valueOf(prefs.getString("widget_sortby_" + appWidgetId, TorrentsSortBy.Alphanumeric.name())),
@ -524,7 +525,16 @@ public class ApplicationSettings { @@ -524,7 +525,16 @@ public class ApplicationSettings {
// @formatter:on
}
public void setWidgetConfig(int appWidgetId, WidgetSettings settings) {
/**
* Stores the user settings for some specific app widget. Existing settings for the supplied app widget ID will be
* overridden.
* @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
*/
public void setWidgetConfig(int appWidgetId, WidgetConfig settings) {
if (settings == null)
throw new InvalidParameterException(
"The widget setting may not be null. Use removeWidgetConfig instead to remove existing settings for some app widget.");
Editor edit = prefs.edit();
edit.putInt("widget_server_" + appWidgetId, settings.getServerId());
edit.putString("widget_status_" + appWidgetId, settings.getStatusType().name());
@ -534,4 +544,18 @@ public class ApplicationSettings { @@ -534,4 +544,18 @@ public class ApplicationSettings {
edit.commit();
}
/**
* Remove the setting for some specific app widget.
* @param appWidgetId The unique ID of the app widget to store settings for, as supplied by the AppWidgetManager
*/
public void removeWidgetConfig(int appWidgetId) {
Editor edit = prefs.edit();
edit.remove("widget_server_" + appWidgetId);
edit.remove("widget_status_" + appWidgetId);
edit.remove("widget_sortby_" + appWidgetId);
edit.remove("widget_reverse_" + appWidgetId);
edit.remove("widget_darktheme_" + appWidgetId);
edit.commit();
}
}

2
core/src/org/transdroid/core/gui/FilterEntryDialog.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
*/
package org.transdroid.core.gui;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
@ -32,6 +33,7 @@ public class FilterEntryDialog { @@ -32,6 +33,7 @@ public class FilterEntryDialog {
* torrents.
* @param activity The activity that opens (and owns) this dialog
*/
@SuppressLint("ValidFragment")
public static void startFilterEntry(final TorrentsActivity activity) {
new DialogFragment() {
public android.app.Dialog onCreateDialog(android.os.Bundle savedInstanceState) {

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

@ -56,6 +56,7 @@ import org.transdroid.core.gui.search.UrlEntryDialog; @@ -56,6 +56,7 @@ import org.transdroid.core.gui.search.UrlEntryDialog;
import org.transdroid.core.gui.settings.*;
import org.transdroid.core.service.BootReceiver;
import org.transdroid.core.service.ConnectivityHelper;
import org.transdroid.core.widget.WidgetProvider;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.Priority;
@ -212,9 +213,19 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi @@ -212,9 +213,19 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi
// No server settings yet;
return;
}
if (getIntent().getExtras() == null && getIntent().hasExtra("org.transdroid.START_SERVER")) {
lastUsed = applicationSettings.getServerSetting(getIntent().getExtras().getInt(
"org.transdroid.START_SERVER"));
Torrent startTorrent = null;
if (getIntent().getAction() != null && getIntent().getAction().equals(WidgetProvider.INTENT_STARTSERVER)
&& getIntent().getExtras() == null && getIntent().hasExtra(WidgetProvider.EXTRA_SERVER)) {
// A server settings order ID was provided in this org.transdroid.START_SERVER action intent
int serverId = getIntent().getExtras().getInt(WidgetProvider.EXTRA_SERVER);
if (serverId < 0 || serverId > applicationSettings.getMaxServer()) {
Log.e(this, "Tried to start with " + WidgetProvider.EXTRA_SERVER + " intent but " + serverId
+ " is not an existing server order id");
} else {
lastUsed = applicationSettings.getServerSetting(serverId);
if (getIntent().hasExtra(WidgetProvider.EXTRA_TORRENT))
startTorrent = getIntent().getParcelableExtra(WidgetProvider.EXTRA_TORRENT);
}
}
// Set this as selection in the action bar spinner; we can use the server setting key since we have stable ids
@ -222,7 +233,10 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi @@ -222,7 +233,10 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi
skipNextOnNavigationItemSelectedCall = true;
// Handle any start up intents
if (firstStart && getIntent() != null) {
if (startTorrent != null) {
openDetails(startTorrent);
startTorrent = null;
} else if (firstStart && getIntent() != null) {
currentConnection = lastUsed.createServerAdapter(connectivityHelper.getConnectedNetworkName());
handleStartIntent();
}
@ -495,7 +509,7 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi @@ -495,7 +509,7 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi
}
return true;
}
@OptionsItem(resName = "action_add_fromurl")
protected void startUrlEntryDialog() {
UrlEntryDialog.startUrlEntry(this);

9
core/src/org/transdroid/core/gui/lists/TorrentFilePriorityLayout.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
*/
package org.transdroid.core.gui.lists;
import org.transdroid.core.R;
import org.transdroid.daemon.Priority;
import android.content.Context;
@ -56,10 +57,10 @@ public class TorrentFilePriorityLayout extends CheckableRelativeLayout { @@ -56,10 +57,10 @@ public class TorrentFilePriorityLayout extends CheckableRelativeLayout {
}
private void initPaints() {
offPaint.setColor(0xFF9E9E9E); // Grey
lowPaint.setColor(0xFFC8E88E); // Light green
normalPaint.setColor(0xFF8ACC12); // Normal green
highPaint.setColor(0xFF4B6617); // Dark green
offPaint.setColor(getResources().getColor(R.color.file_off));
lowPaint.setColor(getResources().getColor(R.color.file_low));
normalPaint.setColor(getResources().getColor(R.color.file_normal));
highPaint.setColor(getResources().getColor(R.color.file_high));
}
public void setPriority(Priority priority) {

29
core/src/org/transdroid/core/gui/lists/TorrentStatusLayout.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
*/
package org.transdroid.core.gui.lists;
import org.transdroid.core.R;
import org.transdroid.daemon.TorrentStatus;
import android.content.Context;
@ -37,10 +38,10 @@ public class TorrentStatusLayout extends CheckableRelativeLayout { @@ -37,10 +38,10 @@ public class TorrentStatusLayout extends CheckableRelativeLayout {
private final int WIDTH = (int) (6 * scale + 0.5f);
private TorrentStatus status = null;
private final Paint inactiveDonePaint = new Paint();
private final Paint inactivePaint = new Paint();
private final Paint progressPaint = new Paint();
private final Paint donePaint = new Paint();
private final Paint pausedPaint = new Paint();
private final Paint otherPaint = new Paint();
private final Paint downloadingPaint = new Paint();
private final Paint seedingPaint = new Paint();
private final Paint errorPaint = new Paint();
private final RectF fullRect = new RectF();
@ -57,11 +58,11 @@ public class TorrentStatusLayout extends CheckableRelativeLayout { @@ -57,11 +58,11 @@ public class TorrentStatusLayout extends CheckableRelativeLayout {
}
private void initPaints() {
inactiveDonePaint.setColor(0xFFA759D4); // Purple
inactivePaint.setColor(0xFF9E9E9E); // Grey
progressPaint.setColor(0xFF42A8FA); // Blue
donePaint.setColor(0xFF8ACC12); // Green
errorPaint.setColor(0xFFDE3939); // Red
pausedPaint.setColor(getResources().getColor(R.color.torrent_paused));
otherPaint.setColor(getResources().getColor(R.color.torrent_other));
downloadingPaint.setColor(getResources().getColor(R.color.torrent_downloading));
seedingPaint.setColor(getResources().getColor(R.color.torrent_seeding));
errorPaint.setColor(getResources().getColor(R.color.torrent_error));
}
/**
@ -85,22 +86,22 @@ public class TorrentStatusLayout extends CheckableRelativeLayout { @@ -85,22 +86,22 @@ public class TorrentStatusLayout extends CheckableRelativeLayout {
if (status == null) {
return;
}
switch (status) {
case Downloading:
canvas.drawRect(fullRect, progressPaint);
canvas.drawRect(fullRect, downloadingPaint);
break;
case Paused:
canvas.drawRect(fullRect, inactiveDonePaint);
canvas.drawRect(fullRect, pausedPaint);
break;
case Seeding:
canvas.drawRect(fullRect, donePaint);
canvas.drawRect(fullRect, seedingPaint);
break;
case Error:
canvas.drawRect(fullRect, errorPaint);
break;
default: // Checking, Waiting, Queued, Unknown
canvas.drawRect(fullRect, inactivePaint);
canvas.drawRect(fullRect, otherPaint);
break;
}

12
core/src/org/transdroid/core/gui/navigation/StatusType.java

@ -35,27 +35,27 @@ import android.os.Parcelable; @@ -35,27 +35,27 @@ import android.os.Parcelable;
public enum StatusType {
ShowAll {
StatusTypeFilter getFilterItem(Context context) {
public StatusTypeFilter getFilterItem(Context context) {
return new StatusTypeFilter(StatusType.ShowAll, context.getString(R.string.navigation_status_showall));
}
},
OnlyDownloading {
StatusTypeFilter getFilterItem(Context context) {
public StatusTypeFilter getFilterItem(Context context) {
return new StatusTypeFilter(StatusType.OnlyDownloading, context.getString(R.string.navigation_status_onlydown));
}
},
OnlyUploading {
StatusTypeFilter getFilterItem(Context context) {
public StatusTypeFilter getFilterItem(Context context) {
return new StatusTypeFilter(StatusType.OnlyUploading, context.getString(R.string.navigation_status_onlyup));
}
},
OnlyActive {
StatusTypeFilter getFilterItem(Context context) {
public StatusTypeFilter getFilterItem(Context context) {
return new StatusTypeFilter(StatusType.OnlyActive, context.getString(R.string.navigation_status_onlyactive));
}
},
OnlyInactive {
StatusTypeFilter getFilterItem(Context context) {
public StatusTypeFilter getFilterItem(Context context) {
return new StatusTypeFilter(StatusType.OnlyInactive, context.getString(R.string.navigation_status_onlyinactive));
}
};
@ -85,7 +85,7 @@ public enum StatusType { @@ -85,7 +85,7 @@ public enum StatusType {
* @param context The Android UI context, to access translations
* @return A filter item object to show in the GUI
*/
abstract StatusTypeFilter getFilterItem(Context context);
public abstract StatusTypeFilter getFilterItem(Context context);
public static class StatusTypeFilter implements SimpleListItem, NavigationFilter {

2
core/src/org/transdroid/core/gui/search/BarcodeHelper.java

@ -19,6 +19,7 @@ package org.transdroid.core.gui.search; @@ -19,6 +19,7 @@ package org.transdroid.core.gui.search;
import org.transdroid.core.R;
import org.transdroid.core.app.search.GoogleWebSearchBarcodeResolver;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@ -41,6 +42,7 @@ public class BarcodeHelper { @@ -41,6 +42,7 @@ public class BarcodeHelper {
* @param activity The calling activity, to which the result is returned or a dialog is bound that asks to install
* the bar code scanner
*/
@SuppressLint("ValidFragment")
public static void startBarcodeScanner(final SherlockFragmentActivity activity) {
try {
// Start a bar code scanner that can handle the SCAN intent (specifically ZXing)

2
core/src/org/transdroid/core/gui/search/FilePickerHelper.java

@ -18,6 +18,7 @@ package org.transdroid.core.gui.search; @@ -18,6 +18,7 @@ package org.transdroid.core.gui.search;
import org.transdroid.core.R;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@ -38,6 +39,7 @@ public class FilePickerHelper { @@ -38,6 +39,7 @@ public class FilePickerHelper {
* @param activity The calling activity, to which the result is returned or a dialog is bound that asks to install
* the file picker
*/
@SuppressLint("ValidFragment")
public static void startFilePicker(final SherlockFragmentActivity activity) {
try {
// Start a file manager that can handle the PICK_FILE intent (specifically IO File Manager)

2
core/src/org/transdroid/core/gui/search/UrlEntryDialog.java

@ -19,6 +19,7 @@ package org.transdroid.core.gui.search; @@ -19,6 +19,7 @@ package org.transdroid.core.gui.search;
import org.transdroid.core.gui.TorrentsActivity;
import org.transdroid.core.gui.navigation.NavigationHelper;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
@ -37,6 +38,7 @@ public class UrlEntryDialog { @@ -37,6 +38,7 @@ public class UrlEntryDialog {
* activity's {@link TorrentsActivity#addTorrentByUrl(String, String) method}.
* @param activity The activity that opens (and owns) this dialog
*/
@SuppressLint("ValidFragment")
public static void startUrlEntry(final TorrentsActivity activity) {
new DialogFragment() {
public android.app.Dialog onCreateDialog(android.os.Bundle savedInstanceState) {

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

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

19
core/src/org/transdroid/core/widget/WidgetConfigActivity.java

@ -25,7 +25,6 @@ import org.androidannotations.annotations.Background; @@ -25,7 +25,6 @@ import org.androidannotations.annotations.Background;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.ItemSelect;
import org.androidannotations.annotations.SystemService;
import org.androidannotations.annotations.UiThread;
import org.androidannotations.annotations.ViewById;
import org.transdroid.core.R;
@ -49,10 +48,11 @@ import org.transdroid.daemon.task.DaemonTaskResult; @@ -49,10 +48,11 @@ import org.transdroid.daemon.task.DaemonTaskResult;
import org.transdroid.daemon.task.RetrieveTask;
import org.transdroid.daemon.task.RetrieveTaskSuccessResult;
import android.annotation.TargetApi;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
@ -65,6 +65,7 @@ import com.actionbarsherlock.app.ActionBar; @@ -65,6 +65,7 @@ import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.SherlockListView;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@EActivity(resName = "activity_widgetconfig")
public class WidgetConfigActivity extends SherlockActivity {
@ -82,10 +83,6 @@ public class WidgetConfigActivity extends SherlockActivity { @@ -82,10 +83,6 @@ public class WidgetConfigActivity extends SherlockActivity {
private List<Torrent> previewTorrents = null;
// Settings and helpers
@SystemService
protected AppWidgetManager appWidgetManager;
@SystemService
protected LayoutInflater layoutInflater;
@Bean
protected ConnectivityHelper connectivityHelper;
@Bean
@ -136,7 +133,7 @@ public class WidgetConfigActivity extends SherlockActivity { @@ -136,7 +133,7 @@ public class WidgetConfigActivity extends SherlockActivity {
// Inspired by NoNonsenseNotes's ListWidgetConfig.java (Apache License, Version 2.0)
getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE);
View doneButtonFrame = layoutInflater.inflate(R.layout.actionbar_donebutton, null);
View doneButtonFrame = getLayoutInflater().inflate(R.layout.actionbar_donebutton, null);
doneButtonFrame.findViewById(R.id.actionbar_done).setOnClickListener(doneClicked);
getSupportActionBar().setCustomView(doneButtonFrame);
@ -252,11 +249,13 @@ public class WidgetConfigActivity extends SherlockActivity { @@ -252,11 +249,13 @@ public class WidgetConfigActivity extends SherlockActivity {
TorrentsSortBy sortBy = ((SortByListItem) sortSpinner.getSelectedItem()).getSortBy();
boolean reverseSort = reverseorderCheckBox.isChecked();
boolean useDarkTheme = darkthemeCheckBox.isChecked();
applicationSettings.setWidgetConfig(appWidgetId, new WidgetSettings(server, statusType, sortBy,
reverseSort, useDarkTheme));
WidgetConfig config = new WidgetConfig(server, statusType, sortBy, reverseSort, useDarkTheme);
applicationSettings.setWidgetConfig(appWidgetId, config);
// Return the widget configuration result
appWidgetManager.updateAppWidget(appWidgetId, null);
AppWidgetManager manager = AppWidgetManager.getInstance(WidgetConfigActivity.this);
manager.updateAppWidget(appWidgetId, WidgetProvider.buildRemoteViews(getApplicationContext(), appWidgetId, config));
manager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.torrents_list);
setResult(RESULT_OK, new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId));
finish();

101
core/src/org/transdroid/core/widget/WidgetProvider.java

@ -16,19 +16,116 @@ @@ -16,19 +16,116 @@
*/
package org.transdroid.core.widget;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EReceiver;
import org.transdroid.core.R;
import org.transdroid.core.app.settings.*;
import org.transdroid.core.app.settings.ServerSetting;
import org.transdroid.core.gui.log.Log;
import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.widget.RemoteViews;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@EReceiver
public class WidgetProvider extends AppWidgetProvider {
public static final String INTENT_STARTSERVER = "org.transdroid.START_SERVER";
public static final String EXTRA_TORRENT = "extra_torrent";
public static final String EXTRA_SERVER = "extra_server";
@Bean
protected ApplicationSettings applicationSettings;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
appWidgetManager.updateAppWidget(appWidgetId,
buildRemoteViews(context, appWidgetId, applicationSettings.getWidgetConfig(appWidgetId)));
}
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
for (int appWidgetId : appWidgetIds) {
applicationSettings.removeWidgetConfig(appWidgetId);
}
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null || intent.getAction() == null || intent.getExtras() == null
|| !intent.hasExtra(EXTRA_SERVER))
return;
// Launch an Intent to start Transdroid on some specific server; and possibly a specific torrent too
Intent start = new Intent(INTENT_STARTSERVER);
start.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
start.putExtra(EXTRA_SERVER, intent.getIntExtra(EXTRA_SERVER, -1));
if (intent.getAction().equals(EXTRA_TORRENT)) {
start.putExtra(EXTRA_TORRENT, intent.getParcelableExtra(EXTRA_TORRENT));
}
context.startActivity(start);
super.onReceive(context, intent);
}
/**
* Loads and sets up the layout for some specific app widget given the user's widget settings. Note that the views
* for the list view rows are loaded separately in the {@link WidgetViewsFactory}.
* @param context The app widget context, with access to resources
* @param appWidgetId The specific ID of the app widget to load
* @param config The user widget configuration, with filter and theme preferences
* @return A fully initialised set of remote views to update the widget with the AppWidgetManager
*/
@SuppressWarnings("deprecation")
public static RemoteViews buildRemoteViews(Context context, int appWidgetId, WidgetConfig config) {
// Does the server to show and its widget settings actually still exist?
if (context == null || config == null)
return null;
ApplicationSettings appSettings = ApplicationSettings_.getInstance_(context);
if (config.getServerId() < 0 || config.getServerId() > appSettings.getMaxServer()) {
Log.e(context, "Tried to set up widget " + appWidgetId + " but the bound server ID " + config.getServerId()
+ " no longer exists.");
return null;
}
// Load the dark or light widget layout xml
RemoteViews rv = new RemoteViews(context.getPackageName(),
config.shouldUseDarkTheme() ? R.layout.list_item_widget_dark : R.layout.list_item_widget_light);
// Set up the widget's list view loading service which refers to the WidgetViewsFactory
// Use a unique data URI next to the extra to make sure the intents are unique form each widget
Intent intent = new Intent(context, WidgetService.class);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME) + "//widget/" + appWidgetId + "/server/"
+ config.getServerId()));
intent.putExtra(EXTRA_SERVER, config.getServerId());
rv.setRemoteAdapter(appWidgetId, R.id.torrents_list, intent);
rv.setPendingIntentTemplate(R.id.torrents_list,
PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
rv.setEmptyView(R.id.torrents_list, R.id.error_text);
rv.setTextViewText(R.id.error_text, context.getString(R.string.navigation_emptytorrents));
// Show the server and status type filter from the widget configuration
ServerSetting server = appSettings.getServerSetting(config.getServerId());
rv.setTextViewText(R.id.server_text, server.getName());
rv.setTextViewText(R.id.filter_text, config.getStatusType().getFilterItem(context).getName());
rv.setOnClickPendingIntent(R.id.icon_image,
PendingIntent.getActivity(context, 0, intent.cloneFilter(), PendingIntent.FLAG_UPDATE_CURRENT));
return rv;
// TODO
}
}

198
core/src/org/transdroid/core/widget/WidgetService.java

@ -0,0 +1,198 @@ @@ -0,0 +1,198 @@
/*
* Copyright 2010-2013 Eric Kok et al.
*
* Transdroid 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.
*
* Transdroid 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 Transdroid. If not, see <http://www.gnu.org/licenses/>.
*/
package org.transdroid.core.widget;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.androidannotations.annotations.EService;
import org.transdroid.core.R;
import org.transdroid.core.app.settings.*;
import org.transdroid.core.app.settings.ServerSetting;
import org.transdroid.core.gui.lists.LocalTorrent;
import org.transdroid.core.gui.log.Log;
import org.transdroid.core.service.*;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentsComparator;
import org.transdroid.daemon.task.DaemonTaskResult;
import org.transdroid.daemon.task.RetrieveTask;
import org.transdroid.daemon.task.RetrieveTaskSuccessResult;
import android.annotation.TargetApi;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Build;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@EService
public class WidgetService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new WidgetViewsFactory(this.getApplicationContext(), intent);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
class WidgetViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private final Context context;
private final int appWidgetId;
private List<Torrent> torrents = null;
private WidgetConfig config = null;
public WidgetViewsFactory(Context applicationContext, Intent intent) {
this.context = applicationContext;
this.appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
@Override
public void onCreate() {
// Nothing to do here (wait for onDataSetChanged)
}
@Override
public void onDataSetChanged() {
// Load the widget settings
ApplicationSettings settings = ApplicationSettings_.getInstance_(context);
config = settings.getWidgetConfig(appWidgetId);
if (config == null || config.getServerId() < 0) {
Log.e(context, "Looking for widget data while the widget wasn't yet configured");
return;
}
ServerSetting server = settings.getServerSetting(config.getServerId());
if (server == null) {
// TODO: Show error text some how in the remote view, perhaps via the EmptyView's text?
Log.e(context, "The server for which this widget was created no longer exists");
if (torrents != null)
torrents.clear();
return;
}
// Load the torrents; synchronously
IDaemonAdapter connection = server.createServerAdapter(ConnectivityHelper_.getInstance_(context)
.getConnectedNetworkName());
DaemonTaskResult result = RetrieveTask.create(connection).execute();
if (!(result instanceof RetrieveTaskSuccessResult)) {
// TODO: Show error text somehow in the remote view, perhaps via the EmptyView's text?
Log.e(context, "The torrents could not be retrieved at this time; probably a connection issue");
if (torrents != null)
torrents.clear();
return;
}
// We have data; filter, sort and store it to use later when getViewAt gets called
ArrayList<Torrent> filteredTorrents = new ArrayList<Torrent>();
for (Torrent torrent : ((RetrieveTaskSuccessResult) result).getTorrents()) {
if (config.getStatusType().getFilterItem(context).matches(torrent))
filteredTorrents.add(torrent);
}
if (filteredTorrents.size() > 0) {
// Only sort when there are actually torrents left after filtering
Daemon serverType = filteredTorrents.get(0).getDaemon();
Collections.sort(filteredTorrents,
new TorrentsComparator(serverType, config.getSortBy(), config.shouldReserveSort()));
}
torrents = filteredTorrents;
}
@Override
public RemoteViews getViewAt(int position) {
// Load the dark or light widget list item layout xml
RemoteViews rv = new RemoteViews(context.getPackageName(),
config.shouldUseDarkTheme() ? R.layout.list_item_widget_dark : R.layout.list_item_widget_light);
// Bind the torrent details texts and status colour
Torrent torrent = torrents.get(position);
LocalTorrent local = LocalTorrent.fromTorrent(torrent);
Resources r = context.getResources();
rv.setTextViewText(R.id.name_text, torrent.getName());
rv.setTextViewText(R.id.progress_text, local.getProgressSizeText(r, false));
rv.setTextViewText(R.id.ratio_text, local.getProgressEtaRatioText(r));
int statusColour;
switch (torrent.getStatusCode()) {
case Downloading:
statusColour = r.getColor(r.getColor(R.color.torrent_downloading));
break;
case Paused:
statusColour = r.getColor(r.getColor(R.color.torrent_paused));
break;
case Seeding:
statusColour = r.getColor(r.getColor(R.color.torrent_seeding));
break;
case Error:
statusColour = r.getColor(r.getColor(R.color.torrent_error));
break;
default: // Checking, Waiting, Queued, Unknown
statusColour = r.getColor(r.getColor(R.color.torrent_other));
break;
}
rv.setInt(R.id.status_view, "setBackgroundColor", r.getColor(statusColour));
Intent startIntent = new Intent();
startIntent.putExtra(WidgetProvider.EXTRA_SERVER, config.getServerId());
startIntent.putExtra(WidgetProvider.EXTRA_TORRENT, torrent);
rv.setOnClickFillInIntent(R.id.widget_line_layout, startIntent);
return rv;
}
@Override
public RemoteViews getLoadingView() {
return null;
}
@Override
public void onDestroy() {
torrents.clear();
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
if (torrents == null)
return 0;
return torrents.size();
}
@Override
public long getItemId(int position) {
return position;
}
}

19
full/AndroidManifest.xml

@ -69,6 +69,11 @@ @@ -69,6 +69,11 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="org.transdroid.START_SERVER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@ -243,13 +248,23 @@ @@ -243,13 +248,23 @@
</receiver>
<!-- Home screen widget -->
<activity android:name="org.transdroid.core.widget.WidgetConfigActivity_" >
<activity
android:name="org.transdroid.core.widget.WidgetConfigActivity_"
android:enabled="@bool/widget_available" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<receiver android:name="org.transdroid.core.widget.WidgetProvider_" >
<service
android:name="org.transdroid.core.widget.WidgetService_"
android:enabled="@bool/widget_available"
android:exported="false"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<receiver
android:name="org.transdroid.core.widget.WidgetProvider_"
android:enabled="@bool/widget_available" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>

32
lite/AndroidManifest.xml

@ -69,6 +69,11 @@ @@ -69,6 +69,11 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="org.transdroid.START_SERVER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@ -194,6 +199,33 @@ @@ -194,6 +199,33 @@
android:value="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<!-- Home screen widget -->
<activity
android:name="org.transdroid.core.widget.WidgetConfigActivity_"
android:enabled="@bool/widget_available" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<service
android:name="org.transdroid.core.widget.WidgetService_"
android:enabled="@bool/widget_available"
android:exported="false"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<receiver
android:name="org.transdroid.core.widget.WidgetProvider_"
android:enabled="@bool/widget_available" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget_info" />
</receiver>
</application>
</manifest>
Loading…
Cancel
Save