Merge pull request #1498 from mfietz/v23

Support libraries v23
This commit is contained in:
Martin Fietz 2016-01-08 00:16:32 +01:00
commit a6a7310a38
42 changed files with 559 additions and 582 deletions

View File

@ -14,7 +14,7 @@ dependencies {
compile "com.android.support:gridlayout-v7:$supportVersion" compile "com.android.support:gridlayout-v7:$supportVersion"
compile "com.android.support:cardview-v7:$supportVersion" compile "com.android.support:cardview-v7:$supportVersion"
compile "com.android.support:design:$supportVersion" compile "com.android.support:design:$supportVersion"
compile "com.android.support:recyclerview-v7:22.2.+" compile "com.android.support:recyclerview-v7:$supportVersion"
compile "org.apache.commons:commons-lang3:$commonslangVersion" compile "org.apache.commons:commons-lang3:$commonslangVersion"
compile("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") { compile("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") {
exclude group: "org.json", module: "json" exclude group: "org.json", module: "json"
@ -31,9 +31,12 @@ dependencies {
compile "io.reactivex:rxjava:$rxJavaVersion" compile "io.reactivex:rxjava:$rxJavaVersion"
// And ProGuard rules for RxJava! // And ProGuard rules for RxJava!
compile "com.artemzin.rxjava:proguard-rules:$rxJavaRulesVersion" compile "com.artemzin.rxjava:proguard-rules:$rxJavaRulesVersion"
compile "com.joanzapata.iconify:android-iconify-fontawesome:2.1.0" compile "com.joanzapata.iconify:android-iconify-fontawesome:$iconifyFontawesomeVersion"
compile "com.afollestad:material-dialogs:0.7.8.1" compile "com.joanzapata.iconify:android-iconify-material:$iconifyFontawesomeVersion"
compile "com.yqritc:recyclerview-flexibledivider:1.2.6" compile("com.github.afollestad.material-dialogs:commons:$materialDialogsVersion") {
transitive = true
}
compile "com.yqritc:recyclerview-flexibledivider:$recyclerviewFlexibledividerVersion"
compile "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion" compile "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"

View File

@ -51,6 +51,7 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
adapter.close(); adapter.close();
// override first launch preference // override first launch preference
// do this BEFORE calling getActivity()!
prefs = getInstrumentation().getTargetContext().getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE); prefs = getInstrumentation().getTargetContext().getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE);
prefs.edit().putBoolean(MainActivity.PREF_IS_FIRST_LAUNCH, false).commit(); prefs.edit().putBoolean(MainActivity.PREF_IS_FIRST_LAUNCH, false).commit();
@ -71,7 +72,8 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
} }
private void openNavDrawer() { private void openNavDrawer() {
solo.clickOnScreen(50, 50); solo.clickOnImageButton(0);
getInstrumentation().waitForIdleSync();
} }
public void testAddFeed() throws Exception { public void testAddFeed() throws Exception {
@ -137,7 +139,7 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
} }
private String getActionbarTitle() { private String getActionbarTitle() {
return ((MainActivity)solo.getCurrentActivity()).getMainActivtyActionBar().getTitle().toString(); return ((MainActivity) solo.getCurrentActivity()).getSupportActionBar().getTitle().toString();
} }
@FlakyTest(tolerance = 3) @FlakyTest(tolerance = 3)

View File

@ -1,7 +1,6 @@
package de.test.antennapod.ui; package de.test.antennapod.ui;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -10,7 +9,6 @@ import android.preference.PreferenceManager;
import android.test.ActivityInstrumentationTestCase2; import android.test.ActivityInstrumentationTestCase2;
import android.test.FlakyTest; import android.test.FlakyTest;
import android.view.View; import android.view.View;
import android.widget.ImageButton;
import android.widget.ListView; import android.widget.ListView;
import com.robotium.solo.Solo; import com.robotium.solo.Solo;
@ -21,15 +19,12 @@ import java.util.List;
import de.danoeh.antennapod.R; import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlayerStatus; import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
/** /**
* test cases for starting and ending playback from the MainActivity and AudioPlayerActivity * test cases for starting and ending playback from the MainActivity and AudioPlayerActivity
@ -90,7 +85,7 @@ public class PlaybackSonicTest extends ActivityInstrumentationTestCase2<MainActi
} }
private void openNavDrawer() { private void openNavDrawer() {
solo.clickOnScreen(50, 50); solo.clickOnImageButton(0);
getInstrumentation().waitForIdleSync(); getInstrumentation().waitForIdleSync();
} }

View File

@ -79,9 +79,9 @@ public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity>
super.tearDown(); super.tearDown();
} }
private void openNavDrawer() { private void openNavDrawer() {
solo.clickOnScreen(50, 50); solo.clickOnImageButton(0);
getInstrumentation().waitForIdleSync();
} }
private void setContinuousPlaybackPreference(boolean value) { private void setContinuousPlaybackPreference(boolean value) {

View File

@ -1,15 +1,15 @@
package de.test.antennapod.ui; package de.test.antennapod.ui;
import android.test.InstrumentationTestCase; import android.test.InstrumentationTestCase;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import org.apache.http.HttpStatus;
import java.io.File; import java.io.File;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.util.List; import java.util.List;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
/** /**
* Test for the UITestUtils. Makes sure that all URLs are reachable and that the class does not cause any crashes. * Test for the UITestUtils. Makes sure that all URLs are reachable and that the class does not cause any crashes.
*/ */
@ -55,7 +55,7 @@ public class UITestUtilsTest extends InstrumentationTestCase {
conn.setRequestMethod("GET"); conn.setRequestMethod("GET");
conn.connect(); conn.connect();
int rc = conn.getResponseCode(); int rc = conn.getResponseCode();
assertEquals(HttpStatus.SC_OK, rc); assertEquals(HttpURLConnection.HTTP_OK, rc);
conn.disconnect(); conn.disconnect();
} }

View File

@ -1,6 +1,21 @@
package de.test.antennapod.util.service.download; package de.test.antennapod.util.service.download;
import java.io.*; import android.support.v4.util.ArrayMap;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.PushbackInputStream;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
@ -14,7 +29,6 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -281,7 +295,7 @@ public abstract class NanoHTTPD {
* @return HTTP response, see class Response for details * @return HTTP response, see class Response for details
*/ */
public Response serve(IHTTPSession session) { public Response serve(IHTTPSession session) {
Map<String, String> files = new HashMap<String, String>(); Map<String, String> files = new ArrayMap<>();
Method method = session.getMethod(); Method method = session.getMethod();
if (Method.PUT.equals(method) || Method.POST.equals(method)) { if (Method.PUT.equals(method) || Method.POST.equals(method)) {
try { try {
@ -334,7 +348,7 @@ public abstract class NanoHTTPD {
* @return a map of <code>String</code> (parameter name) to <code>List&lt;String&gt;</code> (a list of the values supplied). * @return a map of <code>String</code> (parameter name) to <code>List&lt;String&gt;</code> (a list of the values supplied).
*/ */
protected Map<String, List<String>> decodeParameters(String queryString) { protected Map<String, List<String>> decodeParameters(String queryString) {
Map<String, List<String>> parms = new HashMap<String, List<String>>(); Map<String, List<String>> parms = new ArrayMap<String, List<String>>();
if (queryString != null) { if (queryString != null) {
StringTokenizer st = new StringTokenizer(queryString, "&"); StringTokenizer st = new StringTokenizer(queryString, "&");
while (st.hasMoreTokens()) { while (st.hasMoreTokens()) {
@ -549,7 +563,7 @@ public abstract class NanoHTTPD {
/** /**
* Headers for the HTTP response. Use addHeader() to add lines. * Headers for the HTTP response. Use addHeader() to add lines.
*/ */
private Map<String, String> header = new HashMap<String, String>(); private Map<String, String> header = new ArrayMap<String, String>();
/** /**
* The request method that spawned this response. * The request method that spawned this response.
*/ */
@ -851,7 +865,7 @@ public abstract class NanoHTTPD {
this.inputStream = new PushbackInputStream(inputStream, BUFSIZE); this.inputStream = new PushbackInputStream(inputStream, BUFSIZE);
this.outputStream = outputStream; this.outputStream = outputStream;
String remoteIp = inetAddress.isLoopbackAddress() || inetAddress.isAnyLocalAddress() ? "127.0.0.1" : inetAddress.getHostAddress().toString(); String remoteIp = inetAddress.isLoopbackAddress() || inetAddress.isAnyLocalAddress() ? "127.0.0.1" : inetAddress.getHostAddress().toString();
headers = new HashMap<String, String>(); headers = new ArrayMap<String, String>();
headers.put("remote-addr", remoteIp); headers.put("remote-addr", remoteIp);
headers.put("http-client-ip", remoteIp); headers.put("http-client-ip", remoteIp);
@ -895,16 +909,16 @@ public abstract class NanoHTTPD {
inputStream.unread(buf, splitbyte, rlen - splitbyte); inputStream.unread(buf, splitbyte, rlen - splitbyte);
} }
parms = new HashMap<String, String>(); parms = new ArrayMap<String, String>();
if(null == headers) { if(null == headers) {
headers = new HashMap<String, String>(); headers = new ArrayMap<String, String>();
} }
// Create a BufferedReader for parsing the header. // Create a BufferedReader for parsing the header.
BufferedReader hin = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, rlen))); BufferedReader hin = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, rlen)));
// Decode the header into parms and header java properties // Decode the header into parms and header java properties
Map<String, String> pre = new HashMap<String, String>(); Map<String, String> pre = new ArrayMap<String, String>();
decodeHeader(hin, pre, parms, headers); decodeHeader(hin, pre, parms, headers);
method = Method.lookup(pre.get("method")); method = Method.lookup(pre.get("method"));
@ -1102,7 +1116,7 @@ public abstract class NanoHTTPD {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but next chunk does not start with boundary. Usage: GET /example/file.html"); throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but next chunk does not start with boundary. Usage: GET /example/file.html");
} }
boundarycount++; boundarycount++;
Map<String, String> item = new HashMap<String, String>(); Map<String, String> item = new ArrayMap<String, String>();
mpline = in.readLine(); mpline = in.readLine();
while (mpline != null && mpline.trim().length() > 0) { while (mpline != null && mpline.trim().length() > 0) {
int p = mpline.indexOf(':'); int p = mpline.indexOf(':');
@ -1117,7 +1131,7 @@ public abstract class NanoHTTPD {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but no content-disposition info found. Usage: GET /example/file.html"); throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but no content-disposition info found. Usage: GET /example/file.html");
} }
StringTokenizer st = new StringTokenizer(contentDisposition, ";"); StringTokenizer st = new StringTokenizer(contentDisposition, ";");
Map<String, String> disposition = new HashMap<String, String>(); Map<String, String> disposition = new ArrayMap<String, String>();
while (st.hasMoreTokens()) { while (st.hasMoreTokens()) {
String token = st.nextToken().trim(); String token = st.nextToken().trim();
int p = token.indexOf('='); int p = token.indexOf('=');
@ -1352,7 +1366,7 @@ public abstract class NanoHTTPD {
* @author LordFokas * @author LordFokas
*/ */
public class CookieHandler implements Iterable<String> { public class CookieHandler implements Iterable<String> {
private HashMap<String, String> cookies = new HashMap<String, String>(); private ArrayMap<String, String> cookies = new ArrayMap<String, String>();
private ArrayList<Cookie> queue = new ArrayList<Cookie>(); private ArrayList<Cookie> queue = new ArrayList<Cookie>();
public CookieHandler(Map<String, String> httpHeaders) { public CookieHandler(Map<String, String> httpHeaders) {

View File

@ -6,6 +6,7 @@ import android.os.StrictMode;
import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.fonts.FontAwesomeModule; import com.joanzapata.iconify.fonts.FontAwesomeModule;
import com.joanzapata.iconify.fonts.MaterialModule;
import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences; import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
@ -62,6 +63,7 @@ public class PodcastApp extends Application {
NetworkUtils.init(this); NetworkUtils.init(this);
EventDistributor.getInstance(); EventDistributor.getInstance();
Iconify.with(new FontAwesomeModule()); Iconify.with(new FontAwesomeModule());
Iconify.with(new MaterialModule());
SPAUtil.sendSPAppsQueryFeedsIntent(this); SPAUtil.sendSPAppsQueryFeedsIntent(this);
} }

View File

@ -15,12 +15,12 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.Log; import android.util.Log;
import android.util.TypedValue;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
@ -71,7 +71,7 @@ import rx.schedulers.Schedulers;
/** /**
* The activity that is shown when the user launches the app. * The activity that is shown when the user launches the app.
*/ */
public class MainActivity extends ActionBarActivity implements NavDrawerActivity { public class MainActivity extends AppCompatActivity implements NavDrawerActivity {
private static final String TAG = "MainActivity"; private static final String TAG = "MainActivity";
@ -125,7 +125,13 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
getSupportActionBar().setElevation(3.0f);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
findViewById(R.id.shadow).setVisibility(View.GONE);
int elevation = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4,
getResources().getDisplayMetrics());
getSupportActionBar().setElevation(elevation);
}
currentTitle = getTitle(); currentTitle = getTitle();
@ -252,10 +258,6 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
builder.create().show(); builder.create().show();
} }
public ActionBar getMainActivtyActionBar() {
return getSupportActionBar();
}
public boolean isDrawerOpen() { public boolean isDrawerOpen() {
return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer); return drawerLayout != null && navDrawer != null && drawerLayout.isDrawerOpen(navDrawer);
} }
@ -363,10 +365,6 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
getSupportFragmentManager().popBackStack(); getSupportFragmentManager().popBackStack();
} }
public Toolbar getToolbar() {
return toolbar;
}
private int getSelectedNavListIndex() { private int getSelectedNavListIndex() {
String currentFragment = getLastNavFragment(); String currentFragment = getLastNavFragment();
if(currentFragment == null) { if(currentFragment == null) {

View File

@ -39,7 +39,7 @@ public class StorageErrorActivity extends ActionBarActivity {
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
if (StorageUtils.storageAvailable(this)) { if (StorageUtils.storageAvailable()) {
leaveErrorState(); leaveErrorState();
} else { } else {
registerReceiver(mediaUpdate, new IntentFilter( registerReceiver(mediaUpdate, new IntentFilter(

View File

@ -5,6 +5,7 @@ import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.util.ArrayMap;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@ -22,7 +23,6 @@ import com.joanzapata.iconify.fonts.FontAwesomeIcons;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -58,7 +58,7 @@ public class EpisodesApplyActionFragment extends Fragment {
public EpisodesApplyActionFragment() { public EpisodesApplyActionFragment() {
this.episodes = new ArrayList<>(); this.episodes = new ArrayList<>();
this.idMap = new HashMap<>(); this.idMap = new ArrayMap<>();
} }
public void setEpisodes(List<FeedItem> episodes) { public void setEpisodes(List<FeedItem> episodes) {

View File

@ -45,7 +45,7 @@ public class AddFeedFragment extends Fragment {
Button butSearchITunes = (Button) root.findViewById(R.id.butSearchItunes); Button butSearchITunes = (Button) root.findViewById(R.id.butSearchItunes);
final MainActivity activity = (MainActivity) getActivity(); final MainActivity activity = (MainActivity) getActivity();
activity.getMainActivtyActionBar().setTitle(R.string.add_feed_label); activity.getSupportActionBar().setTitle(R.string.add_feed_label);
butSearchITunes.setOnClickListener(new View.OnClickListener() { butSearchITunes.setOnClickListener(new View.OnClickListener() {
@Override @Override

View File

@ -10,6 +10,7 @@ import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView; import android.support.v7.widget.SearchView;
import android.support.v7.widget.SimpleItemAnimator;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@ -303,7 +304,10 @@ public class AllEpisodesFragment extends Fragment {
View root = inflater.inflate(fragmentResource, container, false); View root = inflater.inflate(fragmentResource, container, false);
recyclerView = (RecyclerView) root.findViewById(android.R.id.list); recyclerView = (RecyclerView) root.findViewById(android.R.id.list);
recyclerView.getItemAnimator().setSupportsChangeAnimations(false); RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
}
layoutManager = new LinearLayoutManager(getActivity()); layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true); recyclerView.setHasFixedSize(true);

View File

@ -4,35 +4,33 @@ import android.annotation.TargetApi;
import android.content.ClipData; import android.content.ClipData;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.TypedArray;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.util.Pair; import android.support.v4.util.Pair;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.format.DateUtils; import android.text.format.DateUtils;
import android.util.Log; import android.util.Log;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.webkit.WebSettings; import android.webkit.WebSettings;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.widget.IconButton;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
@ -101,7 +99,6 @@ public class ItemFragment extends Fragment {
private List<Downloader> downloaderList; private List<Downloader> downloaderList;
private ViewGroup root; private ViewGroup root;
private View header;
private WebView webvDescription; private WebView webvDescription;
private TextView txtvTitle; private TextView txtvTitle;
private TextView txtvDuration; private TextView txtvDuration;
@ -109,10 +106,9 @@ public class ItemFragment extends Fragment {
private ImageView imgvCover; private ImageView imgvCover;
private ProgressBar progbarDownload; private ProgressBar progbarDownload;
private ProgressBar progbarLoading; private ProgressBar progbarLoading;
private Button butAction1; private IconButton butAction1;
private Button butAction2; private IconButton butAction2;
private ImageButton butMore; private Menu popupMenu;
private PopupMenu popupMenu;
private Subscription subscription; private Subscription subscription;
@ -125,7 +121,7 @@ public class ItemFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setRetainInstance(true); setRetainInstance(true);
setHasOptionsMenu(false); setHasOptionsMenu(true);
itemID = getArguments().getLong(ARG_FEEDITEM, -1); itemID = getArguments().getLong(ARG_FEEDITEM, -1);
} }
@ -134,15 +130,12 @@ public class ItemFragment extends Fragment {
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState); super.onCreateView(inflater, container, savedInstanceState);
((MainActivity) getActivity()).getSupportActionBar().setTitle("");
Toolbar toolbar = ((MainActivity) getActivity()).getToolbar();
View layout = inflater.inflate(R.layout.feeditem_fragment, container, false); View layout = inflater.inflate(R.layout.feeditem_fragment, container, false);
header = inflater.inflate(R.layout.feeditem_fragment_header, toolbar, false);
root = (ViewGroup) layout.findViewById(R.id.content_root); root = (ViewGroup) layout.findViewById(R.id.content_root);
txtvTitle = (TextView) header.findViewById(R.id.txtvTitle); txtvTitle = (TextView) layout.findViewById(R.id.txtvTitle);
txtvDuration = (TextView) header.findViewById(R.id.txtvDuration); txtvDuration = (TextView) layout.findViewById(R.id.txtvDuration);
txtvPublished = (TextView) header.findViewById(R.id.txtvPublished); txtvPublished = (TextView) layout.findViewById(R.id.txtvPublished);
if (Build.VERSION.SDK_INT >= 14) { // ellipsize is causing problems on old versions, see #448 if (Build.VERSION.SDK_INT >= 14) { // ellipsize is causing problems on old versions, see #448
txtvTitle.setEllipsize(TextUtils.TruncateAt.END); txtvTitle.setEllipsize(TextUtils.TruncateAt.END);
} }
@ -172,32 +165,24 @@ public class ItemFragment extends Fragment {
}); });
registerForContextMenu(webvDescription); registerForContextMenu(webvDescription);
imgvCover = (ImageView) header.findViewById(R.id.imgvCover); imgvCover = (ImageView) layout.findViewById(R.id.imgvCover);
progbarDownload = (ProgressBar) header.findViewById(R.id.progbarDownload); progbarDownload = (ProgressBar) layout.findViewById(R.id.progbarDownload);
progbarLoading = (ProgressBar) layout.findViewById(R.id.progbarLoading); progbarLoading = (ProgressBar) layout.findViewById(R.id.progbarLoading);
butAction1 = (Button) header.findViewById(R.id.butAction1); butAction1 = (IconButton) layout.findViewById(R.id.butAction1);
butAction2 = (Button) header.findViewById(R.id.butAction2); butAction2 = (IconButton) layout.findViewById(R.id.butAction2);
butMore = (ImageButton) header.findViewById(R.id.butMoreActions);
popupMenu = new PopupMenu(getActivity(), butMore);
butAction1.setOnClickListener(new View.OnClickListener() { butAction1.setOnClickListener(v -> {
DefaultActionButtonCallback actionButtonCallback = new DefaultActionButtonCallback(getActivity());
@Override
public void onClick(View v) {
if (item == null) { if (item == null) {
return; return;
} }
DefaultActionButtonCallback actionButtonCallback = new DefaultActionButtonCallback(getActivity());
actionButtonCallback.onActionButtonPressed(item); actionButtonCallback.onActionButtonPressed(item);
FeedMedia media = item.getMedia(); FeedMedia media = item.getMedia();
if (media != null && media.isDownloaded()) { if (media != null && media.isDownloaded()) {
// playback was started, dialog should close itself // playback was started, dialog should close itself
((MainActivity) getActivity()).dismissChildFragment(); ((MainActivity) getActivity()).dismissChildFragment();
} }
} });
}
);
butAction2.setOnClickListener(v -> { butAction2.setOnClickListener(v -> {
if (item == null) { if (item == null) {
@ -216,37 +201,7 @@ public class ItemFragment extends Fragment {
Uri uri = Uri.parse(item.getLink()); Uri uri = Uri.parse(item.getLink());
getActivity().startActivity(new Intent(Intent.ACTION_VIEW, uri)); getActivity().startActivity(new Intent(Intent.ACTION_VIEW, uri));
} }
} });
);
butMore.setOnClickListener(v -> {
if (item == null) {
return;
}
popupMenu.getMenu().clear();
popupMenu.inflate(R.menu.feeditem_options);
if (item.hasMedia()) {
FeedItemMenuHandler.onPrepareMenu(getActivity(), popupMenuInterface, item, true, queue);
} else {
// these are already available via button1 and button2
FeedItemMenuHandler.onPrepareMenu(getActivity(), popupMenuInterface, item, true, queue,
R.id.mark_read_item, R.id.visit_website_item);
}
popupMenu.show();
}
);
popupMenu.setOnMenuItemClickListener(menuItem -> {
try {
return FeedItemMenuHandler.onMenuItemClicked(getActivity(), menuItem.getItemId(), item);
} catch (DownloadRequestException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
return true;
}
}
);
return layout; return layout;
} }
@ -254,8 +209,6 @@ public class ItemFragment extends Fragment {
@Override @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) { public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
Toolbar toolbar = ((MainActivity) getActivity()).getToolbar();
toolbar.addView(header);
load(); load();
} }
@ -279,7 +232,6 @@ public class ItemFragment extends Fragment {
@Override @Override
public void onDestroyView() { public void onDestroyView() {
super.onDestroyView(); super.onDestroyView();
resetViewState();
if(subscription != null) { if(subscription != null) {
subscription.unsubscribe(); subscription.unsubscribe();
} }
@ -289,15 +241,37 @@ public class ItemFragment extends Fragment {
} }
} }
private void resetViewState() { @Override
Toolbar toolbar = ((MainActivity) getActivity()).getToolbar(); public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
toolbar.removeView(header); if(item == null) {
return;
}
inflater.inflate(R.menu.feeditem_options, menu);
popupMenu = menu;
if (item.hasMedia()) {
FeedItemMenuHandler.onPrepareMenu(getActivity(), popupMenuInterface, item, true, queue);
} else {
// these are already available via button1 and button2
FeedItemMenuHandler.onPrepareMenu(getActivity(), popupMenuInterface, item, true, queue,
R.id.mark_read_item, R.id.visit_website_item);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
try {
return FeedItemMenuHandler.onMenuItemClicked(getActivity(), menuItem.getItemId(), item);
} catch (DownloadRequestException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
return true;
}
} }
private final FeedItemMenuHandler.MenuInterface popupMenuInterface = new FeedItemMenuHandler.MenuInterface() { private final FeedItemMenuHandler.MenuInterface popupMenuInterface = new FeedItemMenuHandler.MenuInterface() {
@Override @Override
public void setItemVisibility(int id, boolean visible) { public void setItemVisibility(int id, boolean visible) {
MenuItem item = popupMenu.getMenu().findItem(id); MenuItem item = popupMenu.findItem(id);
if (item != null) { if (item != null) {
item.setVisible(visible); item.setVisible(visible);
} }
@ -319,7 +293,7 @@ public class ItemFragment extends Fragment {
Log.d(TAG, "updateAppearance item is null"); Log.d(TAG, "updateAppearance item is null");
return; return;
} }
getActivity().supportInvalidateOptionsMenu();
txtvTitle.setText(item.getTitle()); txtvTitle.setText(item.getTitle());
if (item.getPubDate() != null) { if (item.getPubDate() != null) {
@ -347,54 +321,55 @@ public class ItemFragment extends Fragment {
} }
FeedMedia media = item.getMedia(); FeedMedia media = item.getMedia();
String butAction1Icon = null;
int butAction1Text = 0;
String butAction2Icon = null;
int butAction2Text = 0;
if (media == null) { if (media == null) {
TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.navigation_accept,
R.attr.location_web_site});
if (!item.isPlayed()) { if (!item.isPlayed()) {
butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(0), null, null, null); butAction1Icon = "{fa-check 24sp}";
butAction1.setText(getActivity().getString(R.string.mark_read_label)); butAction1Text = R.string.mark_read_label;
}
if (item.getLink() != null) {
butAction2Icon = "{ma-web 24sp}";
butAction2Text = R.string.visit_website_label;
}
} else {
if(media.getDuration() > 0) {
txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
}
boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
if (!media.isDownloaded()) {
butAction2Icon = "{md-settings-input-antenna 24sp}";
butAction2Text = R.string.stream_label;
} else {
butAction2Icon = "{md-delete 24sp}";
butAction2Text = R.string.remove_label;
}
if (isDownloading) {
butAction1Icon = "{md-cancel 24sp}";
butAction1Text = R.string.cancel_label;
} else if (media.isDownloaded()) {
butAction1Icon = "{md-play-arrow 24sp}";
butAction1Text = R.string.play_label;
} else {
butAction1Icon = "{md-file-download 24sp}";
butAction1Text = R.string.download_label;
}
}
if(butAction1Icon != null && butAction1Text != 0) {
butAction1.setText(butAction1Icon +"\u0020\u0020" + getActivity().getString(butAction1Text));
Iconify.addIcons(butAction1);
butAction1.setVisibility(View.VISIBLE); butAction1.setVisibility(View.VISIBLE);
} else { } else {
butAction1.setVisibility(View.INVISIBLE); butAction1.setVisibility(View.INVISIBLE);
} }
if(butAction2Icon != null && butAction2Text != 0) {
if (item.getLink() != null) { butAction2.setText(butAction2Icon +"\u0020\u0020" + getActivity().getString(butAction2Text));
butAction2.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(1), null, null, null); Iconify.addIcons(butAction2);
butAction2.setText(getActivity().getString(R.string.visit_website_label)); butAction2.setVisibility(View.VISIBLE);
} else { } else {
butAction2.setEnabled(false); butAction2.setVisibility(View.INVISIBLE);
}
drawables.recycle();
} else {if(media.getDuration() > 0) {
txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
}
boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.av_play,
R.attr.av_download, R.attr.action_stream, R.attr.content_discard, R.attr.navigation_cancel});
if (!media.isDownloaded()) {
butAction2.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(2), null, null, null);
butAction2.setText(getActivity().getString(R.string.stream_label));
} else {
butAction2.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(3), null, null, null);
butAction2.setText(getActivity().getString(R.string.remove_episode_lable));
}
if (isDownloading) {
butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(4), null, null, null);
butAction1.setText(getActivity().getString(R.string.cancel_download_label));
} else if (media.isDownloaded()) {
butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(0), null, null, null);
butAction1.setText(getActivity().getString(R.string.play_label));
} else {
butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(1), null, null, null);
butAction1.setText(getActivity().getString(R.string.download_label));
}
drawables.recycle();
} }
} }

View File

@ -12,7 +12,6 @@ import android.os.Bundle;
import android.support.v4.app.ListFragment; import android.support.v4.app.ListFragment;
import android.support.v4.util.Pair; import android.support.v4.util.Pair;
import android.support.v4.view.MenuItemCompat; import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView; import android.support.v7.widget.SearchView;
import android.util.Log; import android.util.Log;
import android.view.ContextMenu; import android.view.ContextMenu;
@ -145,34 +144,26 @@ public class ItemlistFragment extends ListFragment {
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().registerSticky(this);
if (viewsCreated && itemsLoaded) { if (viewsCreated && itemsLoaded) {
onFragmentLoaded(); onFragmentLoaded();
} }
} }
@Override
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
if(subscription != null) {
subscription.unsubscribe();
}
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
Log.d(TAG, "onResume()"); EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().registerSticky(this);
((MainActivity)getActivity()).getSupportActionBar().setTitle("");
updateProgressBarVisibility(); updateProgressBarVisibility();
loadItems(); loadItems();
} }
@Override @Override
public void onDetach() { public void onPause() {
super.onDetach(); super.onPause();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
if(subscription != null) { if(subscription != null) {
subscription.unsubscribe(); subscription.unsubscribe();
} }
@ -368,7 +359,6 @@ public class ItemlistFragment extends ListFragment {
@Override @Override
public void onViewCreated(View view, Bundle savedInstanceState) { public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("");
registerForContextMenu(getListView()); registerForContextMenu(getListView());
@ -382,7 +372,9 @@ public class ItemlistFragment extends ListFragment {
public void onListItemClick(ListView l, View v, int position, long id) { public void onListItemClick(ListView l, View v, int position, long id) {
FeedItem selection = adapter.getItem(position - l.getHeaderViewsCount()); FeedItem selection = adapter.getItem(position - l.getHeaderViewsCount());
if (selection != null) { if (selection != null) {
((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(selection.getId())); MainActivity activity = (MainActivity) getActivity();
activity.loadChildFragment(ItemFragment.newInstance(selection.getId()));
activity.getSupportActionBar().setTitle(feed.getTitle());
} }
} }
@ -547,16 +539,13 @@ public class ItemlistFragment extends ListFragment {
.dontAnimate() .dontAnimate()
.into(imgvCover); .into(imgvCover);
butShowInfo.setOnClickListener(new View.OnClickListener() { butShowInfo.setOnClickListener(v -> {
@Override
public void onClick(View v) {
if (viewsCreated && itemsLoaded) { if (viewsCreated && itemsLoaded) {
Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class); Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class);
startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID, startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID,
feed.getId()); feed.getId());
startActivity(startIntent); startActivity(startIntent);
} }
}
}); });
} }
@ -573,9 +562,7 @@ public class ItemlistFragment extends ListFragment {
View header = inflater.inflate(R.layout.more_content_list_footer, lv, false); View header = inflater.inflate(R.layout.more_content_list_footer, lv, false);
lv.addFooterView(header); lv.addFooterView(header);
listFooter = new MoreContentListFooterUtil(header); listFooter = new MoreContentListFooterUtil(header);
listFooter.setClickListener(new MoreContentListFooterUtil.Listener() { listFooter.setClickListener(() -> {
@Override
public void onClick() {
if (feed != null) { if (feed != null) {
try { try {
DBTasks.loadNextPageOfFeed(getActivity(), feed, false); DBTasks.loadNextPageOfFeed(getActivity(), feed, false);
@ -584,7 +571,6 @@ public class ItemlistFragment extends ListFragment {
DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage()); DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage());
} }
} }
}
}); });
} }
} }
@ -629,7 +615,6 @@ public class ItemlistFragment extends ListFragment {
if(subscription != null) { if(subscription != null) {
subscription.unsubscribe(); subscription.unsubscribe();
} }
subscription = Observable.fromCallable(() -> loadData()) subscription = Observable.fromCallable(() -> loadData())
.subscribeOn(Schedulers.newThread()) .subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())

View File

@ -2,21 +2,20 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent; import android.content.Intent;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v7.widget.SearchView; import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.GridView; import android.widget.GridView;
import org.apache.http.HttpResponse; import com.squareup.okhttp.OkHttpClient;
import org.apache.http.client.HttpClient; import com.squareup.okhttp.Request;
import org.apache.http.client.methods.HttpGet; import com.squareup.okhttp.Response;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -30,13 +29,23 @@ import java.util.List;
import de.danoeh.antennapod.R; import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity; import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter; import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast; import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast;
//Searches iTunes store for given string and displays results in a list //Searches iTunes store for given string and displays results in a list
public class ItunesSearchFragment extends Fragment { public class ItunesSearchFragment extends Fragment {
final String TAG = "ItunesSearchFragment";
private static final String TAG = "ItunesSearchFragment";
private static final String API_URL = "https://itunes.apple.com/search?media=podcast&term=%s";
/** /**
* Search input field * Search input field
*/ */
@ -52,6 +61,8 @@ public class ItunesSearchFragment extends Fragment {
*/ */
private List<Podcast> searchResults; private List<Podcast> searchResults;
private Subscription subscription;
/** /**
* Replace adapter data with provided search results from SearchTask. * Replace adapter data with provided search results from SearchTask.
* @param result List of Podcast objects containing search results * @param result List of Podcast objects containing search results
@ -117,7 +128,7 @@ public class ItunesSearchFragment extends Fragment {
//This prevents onQueryTextSubmit() from being called twice when keyboard is used //This prevents onQueryTextSubmit() from being called twice when keyboard is used
//to submit the query. //to submit the query.
searchView.clearFocus(); searchView.clearFocus();
new SearchTask(s).execute(); search(s);
return false; return false;
} }
@ -137,77 +148,59 @@ public class ItunesSearchFragment extends Fragment {
return view; return view;
} }
/** private void search(String query) {
* Search the iTunes store for podcasts using the given query if (subscription != null) {
*/ subscription.unsubscribe();
class SearchTask extends AsyncTask<Void,Void,Void> { }
/** subscription = rx.Observable.create((Observable.OnSubscribe<List<Podcast>>) subscriber -> {
* Incomplete iTunes API search URL
*/
final String apiUrl = "https://itunes.apple.com/search?media=podcast&term=%s";
/**
* Search terms
*/
final String query;
/**
* Search result
*/
final List<Podcast> taskData = new ArrayList<>();
/**
* Constructor
*
* @param query Search string
*/
public SearchTask(String query) {
String encodedQuery = null; String encodedQuery = null;
try { try {
encodedQuery = URLEncoder.encode(query, "UTF-8"); encodedQuery = URLEncoder.encode(query, "UTF-8");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
// this won't ever be thrown // this won't ever be thrown
} }
if(encodedQuery != null) { if (encodedQuery == null) {
this.query = encodedQuery; encodedQuery = query; // failsafe
} else {
this.query = query; // failsafe
} }
}
//Get the podcast data
@Override
protected Void doInBackground(Void... params) {
//Spaces in the query need to be replaced with '+' character. //Spaces in the query need to be replaced with '+' character.
String formattedUrl = String.format(apiUrl, query).replace(' ', '+'); String formattedUrl = String.format(API_URL, query).replace(' ', '+');
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(formattedUrl);
OkHttpClient client = AntennapodHttpClient.getHttpClient();
Request.Builder httpReq = new Request.Builder()
.url(formattedUrl)
.header("User-Agent", ClientConfig.USER_AGENT);
List<Podcast> podcasts = new ArrayList<>();
try { try {
HttpResponse response = client.execute(get); Response response = client.newCall(httpReq.build()).execute();
String resultString = EntityUtils.toString(response.getEntity());
if(response.isSuccessful()) {
String resultString = response.body().string();
JSONObject result = new JSONObject(resultString); JSONObject result = new JSONObject(resultString);
JSONArray j = result.getJSONArray("results"); JSONArray j = result.getJSONArray("results");
for (int i = 0; i < j.length(); i++) { for (int i = 0; i < j.length(); i++) {
JSONObject podcastJson = j.getJSONObject(i); JSONObject podcastJson = j.getJSONObject(i);
Podcast podcast = new Podcast(podcastJson); Podcast podcast = new Podcast(podcastJson);
taskData.add(podcast); podcasts.add(podcast);
}
}
else {
subscriber.onError(new IOException("Unexpected error: " + response));
} }
} catch (IOException | JSONException e) { } catch (IOException | JSONException e) {
e.printStackTrace(); Log.e(TAG, Log.getStackTraceString(e));
} }
return null; subscriber.onNext(podcasts);
subscriber.onCompleted();
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(podcasts -> {
updateData(podcasts);
}, error -> {
Log.e(TAG, Log.getStackTraceString(error));
});
} }
//Save the data and update the list
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
updateData(taskData);
}
}
} }

View File

@ -1,6 +1,6 @@
package de.danoeh.antennapod.fragment; package de.danoeh.antennapod.fragment;
import android.app.Activity; import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.ListFragment; import android.support.v4.app.ListFragment;
@ -14,7 +14,6 @@ import android.view.View;
import android.widget.ListView; import android.widget.ListView;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import de.danoeh.antennapod.R; import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.activity.MainActivity;
@ -50,16 +49,13 @@ public class PlaybackHistoryFragment extends ListFragment {
private boolean itemsLoaded = false; private boolean itemsLoaded = false;
private boolean viewsCreated = false; private boolean viewsCreated = false;
private AtomicReference<Activity> activity = new AtomicReference<Activity>();
private List<Downloader> downloaderList; private List<Downloader> downloaderList;
private Subscription subscription; private Subscription subscription;
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Context context) {
super.onAttach(activity); super.onAttach(context);
this.activity.set(activity);
if (viewsCreated && itemsLoaded) { if (viewsCreated && itemsLoaded) {
onFragmentLoaded(); onFragmentLoaded();
} }
@ -123,7 +119,6 @@ public class PlaybackHistoryFragment extends ListFragment {
if(subscription != null) { if(subscription != null) {
subscription.unsubscribe(); subscription.unsubscribe();
} }
activity.set(null);
} }
@Override @Override
@ -210,7 +205,8 @@ public class PlaybackHistoryFragment extends ListFragment {
// played items shoudln't be transparent for this fragment since, *all* items // played items shoudln't be transparent for this fragment since, *all* items
// in this fragment will, by definition, be played. So it serves no purpose and can make // in this fragment will, by definition, be played. So it serves no purpose and can make
// it harder to read. // it harder to read.
adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(activity.get()), true, false); adapter = new FeedItemlistAdapter(getActivity(), itemAccess,
new DefaultActionButtonCallback(getActivity()), true, false);
setListAdapter(adapter); setListAdapter(adapter);
} }
setListShown(true); setListShown(true);

View File

@ -10,6 +10,7 @@ import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView; import android.support.v7.widget.SearchView;
import android.support.v7.widget.SimpleItemAnimator;
import android.support.v7.widget.helper.ItemTouchHelper; import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -365,7 +366,10 @@ public class QueueFragment extends Fragment {
View root = inflater.inflate(R.layout.queue_fragment, container, false); View root = inflater.inflate(R.layout.queue_fragment, container, false);
infoBar = (TextView) root.findViewById(R.id.info_bar); infoBar = (TextView) root.findViewById(R.id.info_bar);
recyclerView = (RecyclerView) root.findViewById(R.id.recyclerView); recyclerView = (RecyclerView) root.findViewById(R.id.recyclerView);
recyclerView.getItemAnimator().setSupportsChangeAnimations(false); RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
}
layoutManager = new LinearLayoutManager(getActivity()); layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build()); recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build());

View File

@ -45,7 +45,7 @@ public class TagFragment extends PodcastListFragment {
@Override @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) { public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
((MainActivity) getActivity()).getMainActivtyActionBar().setTitle(tag.getTitle()); ((MainActivity) getActivity()).getSupportActionBar().setTitle(tag.getTitle());
} }
@Override @Override

View File

@ -80,7 +80,7 @@ public class TagListFragment extends ListFragment {
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
((MainActivity) getActivity()).getMainActivtyActionBar().setTitle(R.string.add_feed_label); ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.add_feed_label);
} }
@Override @Override

View File

@ -0,0 +1,37 @@
package de.danoeh.antennapod.preferences;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.preference.CheckBoxPreference;
import android.util.AttributeSet;
import de.danoeh.antennapod.R;
public class SwitchCompatPreference extends CheckBoxPreference {
public SwitchCompatPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SwitchCompatPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public SwitchCompatPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SwitchCompatPreference(Context context) {
super(context);
init();
}
private void init() {
setWidgetLayoutResource(R.layout.preference_switch_layout);
}
}

View File

@ -0,0 +1,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="@android:color/transparent"
android:endColor="#40000000"
android:angle="90" />
</shape>

View File

@ -1,13 +1,141 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content_root" android:id="@+id/content_root"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="?attr/colorPrimary"
android:gravity="center_horizontal"
android:orientation="vertical"
tools:background="@android:color/darker_gray">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="horizontal"
android:layout_marginTop="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp">
<ImageView
android:id="@+id/imgvCover"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_vertical"
android:contentDescription="@string/cover_label"
android:gravity="center_vertical"
tools:src="@drawable/ic_stat_antenna_default"
tools:background="@android:color/holo_green_dark" />
<TextView
android:id="@+id/txtvPublished"
style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_marginLeft="8dp"
tools:text="Jan\n23"
tools:background="@android:color/holo_green_dark"
android:layout_below="@+id/txtvTitle"/>
<TextView
android:id="@+id/txtvTitle"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/imgvCover"
android:layout_marginLeft="16dp"
android:layout_toLeftOf="@id/txtvPublished"
android:layout_toRightOf="@id/imgvCover"
android:includeFontPadding="false"
android:maxLines="5"
tools:text="Podcast title"
tools:background="@android:color/holo_green_dark" />
<TextView
android:id="@+id/txtvDuration"
style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imgvCover"
android:layout_below="@id/txtvTitle"
android:layout_marginLeft="16dp"
tools:text="00:42:23"
tools:background="@android:color/holo_green_dark"/>
</RelativeLayout>
<ProgressBar
android:id="@+id/progbarDownload"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="8dp"
android:orientation="horizontal"
tools:background="@android:color/holo_blue_bright">
<com.joanzapata.iconify.widget.IconButton
android:id="@+id/butAction1"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:background="?attr/selectableItemBackground"
android:ellipsize="end"
android:gravity="center"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_small"
tools:text="Button 1"
tools:background="@android:color/holo_red_light" />
<com.joanzapata.iconify.widget.IconButton
android:id="@+id/butAction2"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
android:layout_weight="1"
android:background="?attr/selectableItemBackground"
android:ellipsize="end"
android:gravity="center"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_small"
tools:text="Button 2"
tools:background="@android:color/holo_orange_dark" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@color/light_gray"/>
</LinearLayout>
<WebView <WebView
android:id="@+id/webvDescription" android:id="@+id/webvDescription"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_below="@id/header"
android:layout_height="match_parent" android:layout_height="match_parent"
android:foreground="?android:windowContentOverlay" /> android:foreground="?android:windowContentOverlay" />
@ -22,4 +150,4 @@
android:layout_gravity="center" android:layout_gravity="center"
android:indeterminate="true" /> android:indeterminate="true" />
</FrameLayout> </FrameLayout>
</FrameLayout> </RelativeLayout>

View File

@ -1,136 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="?attr/colorPrimary"
android:gravity="center_horizontal"
android:orientation="vertical"
tools:background="@android:color/darker_gray">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="horizontal"
android:paddingBottom="0dp">
<ImageView
android:id="@+id/imgvCover"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_vertical"
android:layout_marginBottom="8dp"
android:layout_marginTop="16dp"
android:contentDescription="@string/cover_label"
android:gravity="center_vertical"
tools:src="@drawable/ic_stat_antenna_default"
tools:background="@android:color/holo_green_dark" />
<ImageButton
android:id="@+id/butMoreActions"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/butAction_label"
android:paddingTop="4dp"
android:src="?attr/ic_action_overflow"
tools:src="@drawable/ic_info_white_24dp"
tools:background="@android:color/holo_green_dark" />
<TextView
android:id="@+id/txtvTitle"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginBottom="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="8dp"
android:layout_marginTop="16dp"
android:layout_toLeftOf="@id/butMoreActions"
android:layout_toRightOf="@id/imgvCover"
android:maxLines="5"
tools:text="Podcast title"
tools:background="@android:color/holo_green_dark" />
<TextView
android:id="@+id/txtvDuration"
style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imgvCover"
android:layout_below="@id/txtvTitle"
android:layout_marginLeft="16dp"
tools:text="00:42:23"
tools:background="@android:color/holo_green_dark"/>
<TextView
android:id="@+id/txtvPublished"
style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/butMoreActions"
android:layout_marginRight="8dp"
tools:text="Jan 23"
tools:background="@android:color/holo_green_dark"
android:layout_below="@+id/txtvTitle"/>
</RelativeLayout>
<ProgressBar
android:id="@+id/progbarDownload"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:visibility="invisible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_marginRight="8dp"
android:orientation="horizontal"
tools:background="@android:color/holo_blue_bright">
<Button
android:id="@+id/butAction1"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:background="?attr/selectableItemBackground"
android:ellipsize="end"
android:paddingTop="4dp"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_small"
tools:text="Button 1"
tools:background="@android:color/holo_red_light" />
<Button
android:id="@+id/butAction2"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
android:layout_weight="1"
android:background="?attr/selectableItemBackground"
android:ellipsize="end"
android:paddingTop="4dp"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/text_size_small"
tools:text="Button 2"
tools:background="@android:color/holo_orange_dark" />
</LinearLayout>
</LinearLayout>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" <android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout" android:id="@+id/drawer_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -10,7 +11,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<FrameLayout <FrameLayout
android:id="@+id/playerFragment" android:id="@+id/playerFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -27,6 +27,14 @@
android:background="?attr/colorPrimary" android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize" android:minHeight="?attr/actionBarSize"
tools:background="@android:color/holo_blue_dark" /> tools:background="@android:color/holo_blue_dark" />
<View
android:id="@+id/shadow"
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_below="@id/toolbar"
android:background="@drawable/shadow" />
<FrameLayout <FrameLayout
android:id="@+id/main_view" android:id="@+id/main_view"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.SwitchCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:clickable="false"
android:focusable="false" />

View File

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory android:title="@string/user_interface_label"> <PreferenceCategory android:title="@string/user_interface_label">
<com.afollestad.materialdialogs.prefs.MaterialListPreference <com.afollestad.materialdialogs.prefs.MaterialListPreference
@ -8,7 +10,8 @@
android:title="@string/pref_set_theme_title" android:title="@string/pref_set_theme_title"
android:key="prefTheme" android:key="prefTheme"
android:summary="@string/pref_set_theme_sum" android:summary="@string/pref_set_theme_sum"
android:defaultValue="0"/> android:defaultValue="0"
app:useStockLayout="true"/>
<PreferenceScreen <PreferenceScreen
android:key="prefDrawerSettings" android:key="prefDrawerSettings"
android:summary="@string/pref_nav_drawer_sum" android:summary="@string/pref_nav_drawer_sum"
@ -23,34 +26,36 @@
android:title="@string/pref_nav_drawer_feed_order_title" android:title="@string/pref_nav_drawer_feed_order_title"
android:key="prefDrawerFeedOrder" android:key="prefDrawerFeedOrder"
android:summary="@string/pref_nav_drawer_feed_order_sum" android:summary="@string/pref_nav_drawer_feed_order_sum"
android:defaultValue="0"/> android:defaultValue="0"
app:useStockLayout="true"/>
<com.afollestad.materialdialogs.prefs.MaterialListPreference <com.afollestad.materialdialogs.prefs.MaterialListPreference
android:entryValues="@array/nav_drawer_feed_counter_values" android:entryValues="@array/nav_drawer_feed_counter_values"
android:entries="@array/nav_drawer_feed_counter_options" android:entries="@array/nav_drawer_feed_counter_options"
android:title="@string/pref_nav_drawer_feed_counter_title" android:title="@string/pref_nav_drawer_feed_counter_title"
android:key="prefDrawerFeedIndicator" android:key="prefDrawerFeedIndicator"
android:summary="@string/pref_nav_drawer_feed_counter_sum" android:summary="@string/pref_nav_drawer_feed_counter_sum"
android:defaultValue="0"/> android:defaultValue="0"
app:useStockLayout="true"/>
</PreferenceScreen> </PreferenceScreen>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
android:key="prefExpandNotify" android:key="prefExpandNotify"
android:summary="@string/pref_expandNotify_sum" android:summary="@string/pref_expandNotify_sum"
android:title="@string/pref_expandNotify_title"/> android:title="@string/pref_expandNotify_title"/>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="true" android:defaultValue="true"
android:enabled="true" android:enabled="true"
android:key="prefPersistNotify" android:key="prefPersistNotify"
android:summary="@string/pref_persistNotify_sum" android:summary="@string/pref_persistNotify_sum"
android:title="@string/pref_persistNotify_title"/> android:title="@string/pref_persistNotify_title"/>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="true" android:defaultValue="true"
android:enabled="true" android:enabled="true"
android:key="prefLockscreenBackground" android:key="prefLockscreenBackground"
android:summary="@string/pref_lockscreen_background_sum" android:summary="@string/pref_lockscreen_background_sum"
android:title="@string/pref_lockscreen_background_title"/> android:title="@string/pref_lockscreen_background_title"/>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="true" android:defaultValue="true"
android:enabled="true" android:enabled="true"
android:key="prefShowDownloadReport" android:key="prefShowDownloadReport"
@ -59,7 +64,7 @@
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/queue_label"> <PreferenceCategory android:title="@string/queue_label">
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
android:key="prefQueueAddToFront" android:key="prefQueueAddToFront"
@ -69,45 +74,45 @@
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/playback_pref"> <PreferenceCategory android:title="@string/playback_pref">
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="true" android:defaultValue="true"
android:enabled="true" android:enabled="true"
android:key="prefPauseOnHeadsetDisconnect" android:key="prefPauseOnHeadsetDisconnect"
android:summary="@string/pref_pauseOnDisconnect_sum" android:summary="@string/pref_pauseOnDisconnect_sum"
android:title="@string/pref_pauseOnHeadsetDisconnect_title"/> android:title="@string/pref_pauseOnHeadsetDisconnect_title"/>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="true" android:defaultValue="true"
android:enabled="true" android:enabled="true"
android:dependency="prefPauseOnHeadsetDisconnect" android:dependency="prefPauseOnHeadsetDisconnect"
android:key="prefUnpauseOnHeadsetReconnect" android:key="prefUnpauseOnHeadsetReconnect"
android:summary="@string/pref_unpauseOnHeadsetReconnect_sum" android:summary="@string/pref_unpauseOnHeadsetReconnect_sum"
android:title="@string/pref_unpauseOnHeadsetReconnect_title"/> android:title="@string/pref_unpauseOnHeadsetReconnect_title"/>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
android:dependency="prefPauseOnHeadsetDisconnect" android:dependency="prefPauseOnHeadsetDisconnect"
android:key="prefUnpauseOnBluetoothReconnect" android:key="prefUnpauseOnBluetoothReconnect"
android:summary="@string/pref_unpauseOnBluetoothReconnect_sum" android:summary="@string/pref_unpauseOnBluetoothReconnect_sum"
android:title="@string/pref_unpauseOnBluetoothReconnect_title"/> android:title="@string/pref_unpauseOnBluetoothReconnect_title"/>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
android:key="prefHardwareForwardButtonSkips" android:key="prefHardwareForwardButtonSkips"
android:summary="@string/pref_hardwareForwardButtonSkips_sum" android:summary="@string/pref_hardwareForwardButtonSkips_sum"
android:title="@string/pref_hardwareForwardButtonSkips_title"/> android:title="@string/pref_hardwareForwardButtonSkips_title"/>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="true" android:defaultValue="true"
android:enabled="true" android:enabled="true"
android:key="prefFollowQueue" android:key="prefFollowQueue"
android:summary="@string/pref_followQueue_sum" android:summary="@string/pref_followQueue_sum"
android:title="@string/pref_followQueue_title"/> android:title="@string/pref_followQueue_title"/>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="true" android:defaultValue="true"
android:enabled="true" android:enabled="true"
android:key="prefSkipKeepsEpisode" android:key="prefSkipKeepsEpisode"
android:summary="@string/pref_skip_keeps_episodes_sum" android:summary="@string/pref_skip_keeps_episodes_sum"
android:title="@string/pref_skip_keeps_episodes_title"/> android:title="@string/pref_skip_keeps_episodes_title"/>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
android:key="prefAutoDelete" android:key="prefAutoDelete"
@ -119,19 +124,20 @@
android:entryValues="@array/smart_mark_as_played_values" android:entryValues="@array/smart_mark_as_played_values"
android:key="prefSmartMarkAsPlayedSecs" android:key="prefSmartMarkAsPlayedSecs"
android:summary="@string/pref_smart_mark_as_played_sum" android:summary="@string/pref_smart_mark_as_played_sum"
android:title="@string/pref_smart_mark_as_played_title"/> android:title="@string/pref_smart_mark_as_played_title"
app:useStockLayout="true"/>
<Preference <Preference
android:key="prefPlaybackSpeedLauncher" android:key="prefPlaybackSpeedLauncher"
android:summary="@string/pref_playback_speed_sum" android:summary="@string/pref_playback_speed_sum"
android:title="@string/pref_playback_speed_title" /> android:title="@string/pref_playback_speed_title" />
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
android:key="prefPauseForFocusLoss" android:key="prefPauseForFocusLoss"
android:summary="@string/pref_pausePlaybackForFocusLoss_sum" android:summary="@string/pref_pausePlaybackForFocusLoss_sum"
android:title="@string/pref_pausePlaybackForFocusLoss_title" /> android:title="@string/pref_pausePlaybackForFocusLoss_title" />
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="true" android:defaultValue="true"
android:enabled="true" android:enabled="true"
android:key="prefResumeAfterCall" android:key="prefResumeAfterCall"
@ -144,46 +150,47 @@
android:key="prefAutoUpdateIntervall" android:key="prefAutoUpdateIntervall"
android:summary="@string/pref_autoUpdateIntervallOrTime_sum" android:summary="@string/pref_autoUpdateIntervallOrTime_sum"
android:title="@string/pref_autoUpdateIntervallOrTime_title"/> android:title="@string/pref_autoUpdateIntervallOrTime_title"/>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
android:key="prefMobileUpdate" android:key="prefMobileUpdate"
android:summary="@string/pref_mobileUpdate_sum" android:summary="@string/pref_mobileUpdate_sum"
android:title="@string/pref_mobileUpdate_title"/> android:title="@string/pref_mobileUpdate_title"/>
<com.afollestad.materialdialogs.prefs.MaterialListPreference <com.afollestad.materialdialogs.prefs.MaterialListPreference
android:defaultValue="-1" android:defaultValue="-1"
android:entries="@array/episode_cleanup_entries" android:entries="@array/episode_cleanup_entries"
android:key="prefEpisodeCleanup" android:key="prefEpisodeCleanup"
android:title="@string/pref_episode_cleanup_title" android:title="@string/pref_episode_cleanup_title"
android:summary="@string/pref_episode_cleanup_summary" android:summary="@string/pref_episode_cleanup_summary"
android:entryValues="@array/episode_cleanup_values"/> android:entryValues="@array/episode_cleanup_values"
app:useStockLayout="true"/>
<com.afollestad.materialdialogs.prefs.MaterialEditTextPreference <com.afollestad.materialdialogs.prefs.MaterialEditTextPreference
android:defaultValue="4" android:defaultValue="4"
android:inputType="number" android:inputType="number"
android:key="prefParallelDownloads" android:key="prefParallelDownloads"
android:title="@string/pref_parallel_downloads_title"/> android:title="@string/pref_parallel_downloads_title"
app:useStockLayout="true"/>
<com.afollestad.materialdialogs.prefs.MaterialListPreference <com.afollestad.materialdialogs.prefs.MaterialListPreference
android:defaultValue="20" android:defaultValue="20"
android:entries="@array/episode_cache_size_entries" android:entries="@array/episode_cache_size_entries"
android:key="prefEpisodeCacheSize" android:key="prefEpisodeCacheSize"
android:title="@string/pref_episode_cache_title" android:title="@string/pref_episode_cache_title"
android:entryValues="@array/episode_cache_size_values"/> android:entryValues="@array/episode_cache_size_values"
app:useStockLayout="true"/>
<PreferenceScreen <PreferenceScreen
android:summary="@string/pref_automatic_download_sum" android:summary="@string/pref_automatic_download_sum"
android:key="prefAutoDownloadSettings" android:key="prefAutoDownloadSettings"
android:title="@string/pref_automatic_download_title"> android:title="@string/pref_automatic_download_title">
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:key="prefEnableAutoDl" android:key="prefEnableAutoDl"
android:title="@string/pref_automatic_download_title" android:title="@string/pref_automatic_download_title"
android:defaultValue="false"/> android:defaultValue="false"/>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:key="prefEnableAutoDownloadOnBattery" android:key="prefEnableAutoDownloadOnBattery"
android:title="@string/pref_automatic_download_on_battery_title" android:title="@string/pref_automatic_download_on_battery_title"
android:summary="@string/pref_automatic_download_on_battery_sum" android:summary="@string/pref_automatic_download_on_battery_sum"
android:defaultValue="true"/> android:defaultValue="true"/>
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:key="prefEnableAutoDownloadWifiFilter" android:key="prefEnableAutoDownloadWifiFilter"
android:title="@string/pref_autodl_wifi_filter_title" android:title="@string/pref_autodl_wifi_filter_title"
android:summary="@string/pref_autodl_wifi_filter_sum"/> android:summary="@string/pref_autodl_wifi_filter_sum"/>
@ -258,7 +265,7 @@
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/experimental_pref"> <PreferenceCategory android:title="@string/experimental_pref">
<CheckBoxPreference <de.danoeh.antennapod.preferences.SwitchCompatPreference
android:defaultValue="false" android:defaultValue="false"
android:enabled="false" android:enabled="false"
android:key="prefSonic" android:key="prefSonic"

View File

@ -6,7 +6,7 @@ buildscript {
} }
dependencies { dependencies {
classpath "com.android.tools.build:gradle:1.5.0" classpath "com.android.tools.build:gradle:1.5.0"
classpath "me.tatarka:gradle-retrolambda:3.2.3" classpath "me.tatarka:gradle-retrolambda:3.2.4"
classpath "me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2" classpath "me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2"
// Exclude the version that the android plugin depends on. // Exclude the version that the android plugin depends on.
@ -36,27 +36,30 @@ subprojects {
} }
project.ext { project.ext {
compileSdkVersion = 22 compileSdkVersion = 23
buildToolsVersion = "22.0.1" buildToolsVersion = "23.0.2"
minSdkVersion = 10 minSdkVersion = 10
targetSdkVersion = 22 targetSdkVersion = 23
supportVersion = "22.2.1" supportVersion = "23.1.1"
commonsioVersion = "2.4" commonsioVersion = "2.4"
commonslangVersion = "3.4" commonslangVersion = "3.4"
eventbusVersion = "2.4.0" eventbusVersion = "2.4.0"
flattr4jVersion = "2.12" flattr4jVersion = "2.12"
glideVersion = "3.6.1" glideVersion = "3.6.1"
jsoupVersion = "1.7.3" jsoupVersion = "1.7.3"
rxAndroidVersion = "1.0.1" iconifyFontawesomeVersion = "2.1.1"
rxJavaVersion = "1.0.16" materialDialogsVersion = "0.8.5.3@aar"
rxJavaRulesVersion = "1.0.16.1" recyclerviewFlexibledividerVersion = "1.2.6"
okhttpVersion = "2.5.0" rxAndroidVersion = "1.1.0"
rxJavaVersion = "1.1.0"
rxJavaRulesVersion = "1.1.0.0"
okhttpVersion = "2.7.0"
okioVersion = "1.6.0" okioVersion = "1.6.0"
audioPlayerVersion = "v1.0.7" audioPlayerVersion = "v1.0.8"
} }
task wrapper(type: Wrapper) { task wrapper(type: Wrapper) {
gradleVersion = "2.4" gradleVersion = "2.10"
} }

View File

@ -4,6 +4,10 @@ general:
machine: machine:
java: java:
version: oraclejdk8 version: oraclejdk8
dependencies:
pre:
- echo y | android update sdk --no-ui --all --filter "tools,platform-tools,android-23"
- echo y | android update sdk --no-ui --all --filter "build-tools-23.0.2"
test: test:
override: override:
- ./gradlew assembleDebug -PdisablePreDex - ./gradlew assembleDebug -PdisablePreDex

View File

@ -46,7 +46,7 @@ dependencies {
exclude group: "org.json", module: "json" exclude group: "org.json", module: "json"
} }
compile "commons-io:commons-io:$commonsioVersion" compile "commons-io:commons-io:$commonsioVersion"
compile "com.jayway.android.robotium:robotium-solo:5.5.2" compile "com.jayway.android.robotium:robotium-solo:5.5.3"
compile "org.jsoup:jsoup:$jsoupVersion" compile "org.jsoup:jsoup:$jsoupVersion"
compile "com.github.bumptech.glide:glide:$glideVersion" compile "com.github.bumptech.glide:glide:$glideVersion"
compile "com.github.bumptech.glide:okhttp-integration:1.3.1" compile "com.github.bumptech.glide:okhttp-integration:1.3.1"

View File

@ -10,8 +10,6 @@ import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response; import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody; import com.squareup.okhttp.ResponseBody;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -19,6 +17,7 @@ import org.json.JSONObject;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@ -602,10 +601,7 @@ public class GpodnetService {
checkStatusCode(response); checkStatusCode(response);
body = response.body(); body = response.body();
result = getStringFromResponseBody(body); result = getStringFromResponseBody(body);
} catch (ClientProtocolException e) { } catch (Exception e) {
e.printStackTrace();
throw new GpodnetServiceException(e);
} catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
throw new GpodnetServiceException(e); throw new GpodnetServiceException(e);
} finally { } finally {
@ -652,12 +648,12 @@ public class GpodnetService {
private void checkStatusCode(@NonNull Response response) private void checkStatusCode(@NonNull Response response)
throws GpodnetServiceException { throws GpodnetServiceException {
int responseCode = response.code(); int responseCode = response.code();
if (responseCode != HttpStatus.SC_OK) { if (responseCode != HttpURLConnection.HTTP_OK) {
if (responseCode == HttpStatus.SC_UNAUTHORIZED) { if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
throw new GpodnetServiceAuthenticationException("Wrong username or password"); throw new GpodnetServiceAuthenticationException("Wrong username or password");
} else { } else {
throw new GpodnetServiceBadStatusCodeException( throw new GpodnetServiceBadStatusCodeException("Bad response code: "
"Bad response code: " + responseCode, responseCode); + responseCode, responseCode);
} }
} }
} }

View File

@ -1,12 +1,13 @@
package de.danoeh.antennapod.core.gpoddernet.model; package de.danoeh.antennapod.core.gpoddernet.model;
import android.support.v4.util.ArrayMap;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class GpodnetEpisodeActionPostResponse { public class GpodnetEpisodeActionPostResponse {
@ -36,8 +37,8 @@ public class GpodnetEpisodeActionPostResponse {
public static GpodnetEpisodeActionPostResponse fromJSONObject(String objectString) throws JSONException { public static GpodnetEpisodeActionPostResponse fromJSONObject(String objectString) throws JSONException {
final JSONObject object = new JSONObject(objectString); final JSONObject object = new JSONObject(objectString);
final long timestamp = object.getLong("timestamp"); final long timestamp = object.getLong("timestamp");
Map<String, String> updatedUrls = new HashMap<String, String>();
JSONArray urls = object.getJSONArray("update_urls"); JSONArray urls = object.getJSONArray("update_urls");
Map<String, String> updatedUrls = new ArrayMap<String, String>(urls.length());
for (int i = 0; i < urls.length(); i++) { for (int i = 0; i < urls.length(); i++) {
JSONArray urlPair = urls.getJSONArray(i); JSONArray urlPair = urls.getJSONArray(i);
updatedUrls.put(urlPair.getString(0), urlPair.getString(1)); updatedUrls.put(urlPair.getString(0), urlPair.getString(1));

View File

@ -1,10 +1,11 @@
package de.danoeh.antennapod.core.gpoddernet.model; package de.danoeh.antennapod.core.gpoddernet.model;
import android.support.v4.util.ArrayMap;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
@ -37,7 +38,7 @@ public class GpodnetUploadChangesResponse {
public static GpodnetUploadChangesResponse fromJSONObject(String objectString) throws JSONException { public static GpodnetUploadChangesResponse fromJSONObject(String objectString) throws JSONException {
final JSONObject object = new JSONObject(objectString); final JSONObject object = new JSONObject(objectString);
final long timestamp = object.getLong("timestamp"); final long timestamp = object.getLong("timestamp");
Map<String, String> updatedUrls = new HashMap<String, String>(); Map<String, String> updatedUrls = new ArrayMap<>();
JSONArray urls = object.getJSONArray("update_urls"); JSONArray urls = object.getJSONArray("update_urls");
for (int i = 0; i < urls.length(); i++) { for (int i = 0; i < urls.length(); i++) {
JSONArray urlPair = urls.getJSONArray(i); JSONArray urlPair = urls.getJSONArray(i);

View File

@ -8,12 +8,12 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.IBinder; import android.os.IBinder;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.support.v4.util.ArrayMap;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -226,7 +226,7 @@ public class GpodnetSyncService extends Service {
if(remoteActions.size() == 0) { if(remoteActions.size() == 0) {
return; return;
} }
Map<Pair<String, String>, GpodnetEpisodeAction> localMostRecentPlayAction = new HashMap<Pair<String, String>, GpodnetEpisodeAction>(); Map<Pair<String, String>, GpodnetEpisodeAction> localMostRecentPlayAction = new ArrayMap<>();
for(GpodnetEpisodeAction action : localActions) { for(GpodnetEpisodeAction action : localActions) {
Pair key = new Pair(action.getPodcast(), action.getEpisode()); Pair key = new Pair(action.getPodcast(), action.getEpisode());
GpodnetEpisodeAction mostRecent = localMostRecentPlayAction.get(key); GpodnetEpisodeAction mostRecent = localMostRecentPlayAction.get(key);
@ -238,7 +238,7 @@ public class GpodnetSyncService extends Service {
} }
// make sure more recent local actions are not overwritten by older remote actions // make sure more recent local actions are not overwritten by older remote actions
Map<Pair<String, String>, GpodnetEpisodeAction> mostRecentPlayAction = new HashMap<Pair<String, String>, GpodnetEpisodeAction>(); Map<Pair<String, String>, GpodnetEpisodeAction> mostRecentPlayAction = new ArrayMap<>();
for (GpodnetEpisodeAction action : remoteActions) { for (GpodnetEpisodeAction action : remoteActions) {
switch (action.getAction()) { switch (action.getAction()) {
case NEW: case NEW:

View File

@ -1,54 +0,0 @@
package de.danoeh.antennapod.core.service.download;
import android.util.Log;
import de.danoeh.antennapod.core.BuildConfig;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.impl.client.DefaultRedirectHandler;
import org.apache.http.protocol.HttpContext;
import java.net.URI;
public class APRedirectHandler extends DefaultRedirectHandler {
// Identifier for logger
private static final String TAG = "APRedirectHandler";
// Header field, which has to be potentially fixed
private static final String LOC = "Location";
// Regular expressions for character strings, which should not appear in URLs
private static final String CHi[] = { "\\{", "\\}", "\\|", "\\\\", "\\^", "~", "\\[", "\\]", "\\`"};
private static final String CHo[] = { "%7B", "%7D", "%7C", "%5C", "%5E", "%7E", "%5B", "%5D", "%60"};
/**
* Workaround for broken URLs in redirection.
* Proper solution involves LaxRedirectStrategy() which is not available in
* current API yet.
*/
@Override
public URI getLocationURI(HttpResponse response, HttpContext context)
throws org.apache.http.ProtocolException {
Header h[] = response.getHeaders(LOC);
if (h.length>0) {
String s = h[0].getValue();
// Fix broken URL
for(int i=0; i<CHi.length;i++)
s = s.replaceAll(CHi[i], CHo[i]);
// If anything had to be fixed, then replace the header
if (!s.equals(h[0].getValue()))
{
if (BuildConfig.DEBUG)
Log.d(TAG, "Original URL: " + h[0].getValue());
response.setHeader(LOC, s);
if (BuildConfig.DEBUG)
Log.d(TAG, "Fixed URL: " + s);
}
}
// call DefaultRedirectHandler with fixed URL
return super.getLocationURI(response, context);
}
}

View File

@ -22,7 +22,6 @@ import android.util.Log;
import android.webkit.URLUtil; import android.webkit.URLUtil;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.http.HttpStatus;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import java.io.File; import java.io.File;
@ -187,7 +186,7 @@ public class DownloadService extends Service {
if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) { if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) {
postAuthenticationNotification(downloader.getDownloadRequest()); postAuthenticationNotification(downloader.getDownloadRequest());
} else if (status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR } else if (status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR
&& Integer.valueOf(status.getReasonDetailed()) == HttpStatus.SC_REQUESTED_RANGE_NOT_SATISFIABLE) { && Integer.valueOf(status.getReasonDetailed()) == 416) {
Log.d(TAG, "Requested invalid range, restarting download from the beginning"); Log.d(TAG, "Requested invalid range, restarting download from the beginning");
FileUtils.deleteQuietly(new File(downloader.getDownloadRequest().getDestination())); FileUtils.deleteQuietly(new File(downloader.getDownloadRequest().getDestination()));

View File

@ -11,7 +11,6 @@ import com.squareup.okhttp.ResponseBody;
import com.squareup.okhttp.internal.http.HttpDate; import com.squareup.okhttp.internal.http.HttpDate;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpStatus;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.File; import java.io.File;
@ -162,7 +161,7 @@ public class HttpDownloader extends Downloader {
return; return;
} }
if (!StorageUtils.storageAvailable(ClientConfig.applicationCallbacks.getApplicationInstance())) { if (!StorageUtils.storageAvailable()) {
onFail(DownloadError.ERROR_DEVICE_NOT_FOUND, null); onFail(DownloadError.ERROR_DEVICE_NOT_FOUND, null);
return; return;
} }
@ -171,7 +170,7 @@ public class HttpDownloader extends Downloader {
String contentRangeHeader = (fileExists) ? response.header("Content-Range") : null; String contentRangeHeader = (fileExists) ? response.header("Content-Range") : null;
if (fileExists && response.code() == HttpStatus.SC_PARTIAL_CONTENT if (fileExists && response.code() == HttpURLConnection.HTTP_PARTIAL
&& !TextUtils.isEmpty(contentRangeHeader)) { && !TextUtils.isEmpty(contentRangeHeader)) {
String start = contentRangeHeader.substring("bytes ".length(), String start = contentRangeHeader.substring("bytes ".length(),
contentRangeHeader.indexOf("-")); contentRangeHeader.indexOf("-"));

View File

@ -5,7 +5,6 @@ import android.hardware.Sensor;
import android.hardware.SensorEvent; import android.hardware.SensorEvent;
import android.hardware.SensorEventListener; import android.hardware.SensorEventListener;
import android.hardware.SensorManager; import android.hardware.SensorManager;
import android.util.FloatMath;
import android.util.Log; import android.util.Log;
public class ShakeListener implements SensorEventListener public class ShakeListener implements SensorEventListener
@ -50,8 +49,8 @@ public class ShakeListener implements SensorEventListener
float gY = event.values[1] / SensorManager.GRAVITY_EARTH; float gY = event.values[1] / SensorManager.GRAVITY_EARTH;
float gZ = event.values[2] / SensorManager.GRAVITY_EARTH; float gZ = event.values[2] / SensorManager.GRAVITY_EARTH;
float gForce = FloatMath.sqrt(gX*gX + gY*gY + gZ*gZ); double gForce = Math.sqrt(gX*gX + gY*gY + gZ*gZ);
if (gForce > 2.25f) { if (gForce > 2.25) {
Log.d(TAG, "Detected shake " + gForce); Log.d(TAG, "Detected shake " + gForce);
mSleepTimer.onShake(); mSleepTimer.onShake();
} }

View File

@ -1,13 +1,13 @@
package de.danoeh.antennapod.core.storage; package de.danoeh.antennapod.core.storage;
import android.database.Cursor; import android.database.Cursor;
import android.support.v4.util.ArrayMap;
import android.util.Log; import android.util.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -229,7 +229,7 @@ public final class DBReader {
for(int i=0, len=itemIds.length; i < len; i++) { for(int i=0, len=itemIds.length; i < len; i++) {
ids[i] = String.valueOf(itemIds[i]); ids[i] = String.valueOf(itemIds[i]);
} }
Map<Long,FeedMedia> result = new HashMap<>(itemIds.length); Map<Long,FeedMedia> result = new ArrayMap<>(itemIds.length);
Cursor cursor = adapter.getFeedMediaCursor(ids); Cursor cursor = adapter.getFeedMediaCursor(ids);
try { try {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
@ -871,7 +871,7 @@ public final class DBReader {
ids[i] = String.valueOf(imageIds[i]); ids[i] = String.valueOf(imageIds[i]);
} }
Cursor cursor = adapter.getImageCursor(ids); Cursor cursor = adapter.getImageCursor(ids);
Map<Long, FeedImage> result = new HashMap<>(cursor.getCount()); Map<Long, FeedImage> result = new ArrayMap<>(cursor.getCount());
try { try {
if ((cursor.getCount() == 0) || !cursor.moveToFirst()) { if ((cursor.getCount() == 0) || !cursor.moveToFirst()) {
return Collections.emptyMap(); return Collections.emptyMap();

View File

@ -1,8 +1,8 @@
package de.danoeh.antennapod.core.syndication.handler; package de.danoeh.antennapod.core.syndication.handler;
import android.support.v4.util.ArrayMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Stack; import java.util.Stack;
@ -32,7 +32,7 @@ public class HandlerState {
/** /**
* Namespaces that have been defined so far. * Namespaces that have been defined so far.
*/ */
protected HashMap<String, Namespace> namespaces; protected Map<String, Namespace> namespaces;
protected Stack<Namespace> defaultNamespaces; protected Stack<Namespace> defaultNamespaces;
/** /**
* Buffer for saving characters. * Buffer for saving characters.
@ -42,16 +42,16 @@ public class HandlerState {
/** /**
* Temporarily saved objects. * Temporarily saved objects.
*/ */
protected HashMap<String, Object> tempObjects; protected Map<String, Object> tempObjects;
public HandlerState(Feed feed) { public HandlerState(Feed feed) {
this.feed = feed; this.feed = feed;
alternateUrls = new LinkedHashMap<String, String>(); alternateUrls = new ArrayMap<>();
items = new ArrayList<FeedItem>(); items = new ArrayList<FeedItem>();
tagstack = new Stack<SyndElement>(); tagstack = new Stack<SyndElement>();
namespaces = new HashMap<String, Namespace>(); namespaces = new ArrayMap<>();
defaultNamespaces = new Stack<Namespace>(); defaultNamespaces = new Stack<Namespace>();
tempObjects = new HashMap<String, Object>(); tempObjects = new ArrayMap<>();
} }
public Feed getFeed() { public Feed getFeed() {
@ -105,7 +105,7 @@ public class HandlerState {
alternateUrls.put(url, title); alternateUrls.put(url, title);
} }
public HashMap<String, Object> getTempObjects() { public Map<String, Object> getTempObjects() {
return tempObjects; return tempObjects;
} }
} }

View File

@ -1,14 +1,15 @@
package de.danoeh.antennapod.core.util; package de.danoeh.antennapod.core.util;
import android.support.v4.util.ArrayMap;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.HashMap;
public class LangUtils { public class LangUtils {
public static final Charset UTF_8 = Charset.forName("UTF-8"); public static final Charset UTF_8 = Charset.forName("UTF-8");
private static HashMap<String, String> languages; private static ArrayMap<String, String> languages;
static { static {
languages = new HashMap<String, String>(); languages = new ArrayMap<>();
languages.put("af", "Afrikaans"); languages.put("af", "Afrikaans");
languages.put("sq", "Albanian"); languages.put("sq", "Albanian");
languages.put("sq", "Albanian"); languages.put("sq", "Albanian");

View File

@ -1,14 +1,12 @@
package de.danoeh.antennapod.core.util; package de.danoeh.antennapod.core.util;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.os.Build; import android.os.Build;
import android.os.StatFs; import android.os.StatFs;
import android.util.Log; import android.util.Log;
import java.io.File; import java.io.File;
import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences;
@ -18,12 +16,11 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
public class StorageUtils { public class StorageUtils {
private static final String TAG = "StorageUtils"; private static final String TAG = "StorageUtils";
public static boolean storageAvailable(Context context) { public static boolean storageAvailable() {
File dir = UserPreferences.getDataFolder(null); File dir = UserPreferences.getDataFolder(null);
if (dir != null) { if (dir != null) {
return dir.exists() && dir.canRead() && dir.canWrite(); return dir.exists() && dir.canRead() && dir.canWrite();
} else { } else {
if (BuildConfig.DEBUG)
Log.d(TAG, "Storage not available: data folder is null"); Log.d(TAG, "Storage not available: data folder is null");
return false; return false;
} }
@ -39,7 +36,7 @@ public class StorageUtils {
* @return true if external storage is available * @return true if external storage is available
*/ */
public static boolean checkStorageAvailability(Activity activity) { public static boolean checkStorageAvailability(Activity activity) {
boolean storageAvailable = storageAvailable(activity); boolean storageAvailable = storageAvailable();
if (!storageAvailable) { if (!storageAvailable) {
activity.finish(); activity.finish();
activity.startActivity(ClientConfig.applicationCallbacks.getStorageErrorActivity(activity)); activity.startActivity(ClientConfig.applicationCallbacks.getStorageErrorActivity(activity));

View File

@ -1,6 +1,7 @@
package de.danoeh.antennapod.core.util.syndication; package de.danoeh.antennapod.core.util.syndication;
import android.net.Uri; import android.net.Uri;
import android.support.v4.util.ArrayMap;
import android.text.TextUtils; import android.text.TextUtils;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
@ -10,7 +11,6 @@ import org.jsoup.select.Elements;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
/** /**
@ -46,7 +46,7 @@ public class FeedDiscoverer {
} }
private Map<String, String> findLinks(Document document, String baseUrl) { private Map<String, String> findLinks(Document document, String baseUrl) {
Map<String, String> res = new LinkedHashMap<String, String>(); Map<String, String> res = new ArrayMap<>();
Elements links = document.head().getElementsByTag("link"); Elements links = document.head().getElementsByTag("link");
for (Element link : links) { for (Element link : links) {
String rel = link.attr("rel"); String rel = link.attr("rel");