Clover Coverage Report - Subsonic-Android Coverage Report
Coverage timestamp: ven dic 19 2014 17:57:13 EST
../../../../../img/srcFileCovDistChart7.png 55% of files have more coverage
156   387   64   5,2
50   308   0,41   15
30     2,13  
2    
This report was generated with an evaluation server license. Purchase Clover or configure your license.
 
  SubsonicTabActivity       Line # 57 138 60 71% 0.71028036
  SubsonicTabActivity.SubsonicUncaughtExceptionHandler       Line # 350 18 4 13,6% 0.13636364
 
No Tests
 
1    /*
2    This file is part of Subsonic.
3   
4    Subsonic is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8   
9    Subsonic is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12    GNU General Public License for more details.
13   
14    You should have received a copy of the GNU General Public License
15    along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
16   
17    Copyright 2009 (C) Sindre Mehus
18    */
19    package net.sourceforge.subsonic.androidapp.activity;
20   
21    import java.io.File;
22    import java.io.PrintWriter;
23    import java.util.LinkedList;
24    import java.util.List;
25   
26    import android.app.Activity;
27    import android.content.Context;
28    import android.content.Intent;
29    import android.content.pm.PackageInfo;
30    import android.graphics.Typeface;
31    import android.media.AudioManager;
32    import android.os.Build;
33    import android.os.Bundle;
34    import android.os.Environment;
35    import android.util.Log;
36    import android.view.KeyEvent;
37    import android.view.Menu;
38    import android.view.MenuInflater;
39    import android.view.MenuItem;
40    import android.view.View;
41    import android.view.Window;
42    import android.widget.TextView;
43    import net.sourceforge.subsonic.androidapp.R;
44    import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
45    import net.sourceforge.subsonic.androidapp.service.DownloadService;
46    import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
47    import net.sourceforge.subsonic.androidapp.service.MusicService;
48    import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
49    import net.sourceforge.subsonic.androidapp.util.Constants;
50    import net.sourceforge.subsonic.androidapp.util.ImageLoader;
51    import net.sourceforge.subsonic.androidapp.util.ModalBackgroundTask;
52    import net.sourceforge.subsonic.androidapp.util.Util;
53   
54    /**
55    * @author Sindre Mehus
56    */
 
57    public class SubsonicTabActivity extends Activity {
58   
59    private static final String TAG = SubsonicTabActivity.class.getSimpleName();
60    private static ImageLoader IMAGE_LOADER;
61   
62    private boolean destroyed;
63    private View homeButton;
64    private View musicButton;
65    private View searchButton;
66    private View playlistButton;
67    private View nowPlayingButton;
68   
 
69  38 toggle @Override
70    protected void onCreate(Bundle bundle) {
71  38 setUncaughtExceptionHandler();
72  38 applyTheme();
73  38 super.onCreate(bundle);
74  38 requestWindowFeature(Window.FEATURE_NO_TITLE);
75  38 startService(new Intent(this, DownloadServiceImpl.class));
76  38 setVolumeControlStream(AudioManager.STREAM_MUSIC);
77    }
78   
 
79  38 toggle @Override
80    protected void onPostCreate(Bundle bundle) {
81  38 super.onPostCreate(bundle);
82   
83  38 homeButton = findViewById(R.id.button_bar_home);
84  38 homeButton.setOnClickListener(new View.OnClickListener() {
 
85  4 toggle @Override
86    public void onClick(View view) {
87  4 Intent intent = new Intent(SubsonicTabActivity.this, MainActivity.class);
88  4 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
89  4 Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
90    }
91    });
92   
93  38 musicButton = findViewById(R.id.button_bar_music);
94  38 musicButton.setOnClickListener(new View.OnClickListener() {
 
95  3 toggle @Override
96    public void onClick(View view) {
97  3 Intent intent = new Intent(SubsonicTabActivity.this, SelectArtistActivity.class);
98  3 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
99  3 Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
100    }
101    });
102   
103  38 searchButton = findViewById(R.id.button_bar_search);
104  38 searchButton.setOnClickListener(new View.OnClickListener() {
 
105  4 toggle @Override
106    public void onClick(View view) {
107  4 Intent intent = new Intent(SubsonicTabActivity.this, SearchActivity.class);
108  4 intent.putExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, true);
109  4 Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
110    }
111    });
112   
113  38 playlistButton = findViewById(R.id.button_bar_playlists);
114  38 playlistButton.setOnClickListener(new View.OnClickListener() {
 
115  4 toggle @Override
116    public void onClick(View view) {
117  4 Intent intent = new Intent(SubsonicTabActivity.this, SelectPlaylistActivity.class);
118  4 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
119  4 Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent);
120    }
121    });
122   
123  38 nowPlayingButton = findViewById(R.id.button_bar_now_playing);
124  38 nowPlayingButton.setOnClickListener(new View.OnClickListener() {
 
125  2 toggle @Override
126    public void onClick(View view) {
127  2 Util.startActivityWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class);
128    }
129    });
130   
131  38 if (this instanceof MainActivity) {
132  10 homeButton.setEnabled(false);
133  28 } else if (this instanceof SelectAlbumActivity || this instanceof SelectArtistActivity) {
134  14 musicButton.setEnabled(false);
135  14 } else if (this instanceof SearchActivity) {
136  3 searchButton.setEnabled(false);
137  11 } else if (this instanceof SelectPlaylistActivity) {
138  4 playlistButton.setEnabled(false);
139  7 } else if (this instanceof DownloadActivity || this instanceof LyricsActivity) {
140  7 nowPlayingButton.setEnabled(false);
141    }
142   
143  38 updateButtonVisibility();
144    }
145   
 
146  50 toggle @Override
147    protected void onResume() {
148  50 super.onResume();
149  50 Util.registerMediaButtonEventReceiver(this);
150    }
151   
 
152  1 toggle @Override
153    public boolean onCreateOptionsMenu(Menu menu) {
154  1 MenuInflater inflater = getMenuInflater();
155  1 inflater.inflate(R.menu.main, menu);
156  1 return true;
157    }
158   
 
159  5 toggle @Override
160    public boolean onOptionsItemSelected(MenuItem item) {
161  5 switch (item.getItemId()) {
162   
163  0 case R.id.menu_exit:
164  0 Intent intent = new Intent(this, MainActivity.class);
165  0 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
166  0 intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
167  0 Util.startActivityWithoutTransition(this, intent);
168  0 return true;
169   
170  2 case R.id.menu_settings:
171  2 startActivity(new Intent(this, SettingsActivity.class));
172  2 return true;
173   
174  1 case R.id.menu_help:
175  1 startActivity(new Intent(this, HelpActivity.class));
176  1 return true;
177    }
178   
179  2 return false;
180    }
181   
 
182  32 toggle @Override
183    protected void onDestroy() {
184  32 super.onDestroy();
185  32 destroyed = true;
186  32 getImageLoader().clear();
187    }
188   
189   
 
190  2 toggle @Override
191    public boolean onKeyDown(int keyCode, KeyEvent event) {
192  2 boolean isVolumeDown = keyCode == KeyEvent.KEYCODE_VOLUME_DOWN;
193  2 boolean isVolumeUp = keyCode == KeyEvent.KEYCODE_VOLUME_UP;
194  2 boolean isVolumeAdjust = isVolumeDown || isVolumeUp;
195  2 boolean isJukebox = getDownloadService() != null && getDownloadService().isJukeboxEnabled();
196   
197  2 if (isVolumeAdjust && isJukebox) {
198  0 getDownloadService().adjustJukeboxVolume(isVolumeUp);
199  0 return true;
200    }
201  2 return super.onKeyDown(keyCode, event);
202    }
203   
 
204  3 toggle @Override
205    public void finish() {
206  3 super.finish();
207  3 Util.disablePendingTransition(this);
208    }
209   
 
210  31 toggle @Override
211    public void setTitle(CharSequence title) {
212  31 super.setTitle(title);
213   
214    // Set the font of title in the action bar.
215  31 TextView text = (TextView) findViewById(R.id.actionbar_title_text);
216  31 Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Roboto-Regular.ttf");
217  31 text.setTypeface(typeface);
218   
219  31 text.setText(title);
220    }
221   
 
222  24 toggle @Override
223    public void setTitle(int titleId) {
224  24 setTitle(getString(titleId));
225    }
226   
 
227  38 toggle private void applyTheme() {
228  38 String theme = Util.getTheme(this);
229  38 if ("dark".equals(theme)) {
230  0 setTheme(R.style.Dark);
231  38 } else if ("light".equals(theme)) {
232  0 setTheme(R.style.Light);
233  38 } else if ("fullscreen".equals(theme)) {
234  0 setTheme(R.style.Fullscreen);
235  38 } else if ("fullscreenlight".equals(theme)) {
236  11 setTheme(R.style.Fullscreenlight);
237    }
238    }
239   
 
240  20 toggle public boolean isDestroyed() {
241  20 return destroyed;
242    }
243   
 
244  38 toggle private void updateButtonVisibility() {
245  38 int visibility = Util.isOffline(this) ? View.GONE : View.VISIBLE;
246  38 searchButton.setVisibility(visibility);
247  38 playlistButton.setVisibility(visibility);
248    }
249   
 
250  40 toggle public void setProgressVisible(boolean visible) {
251  40 View view = findViewById(R.id.tab_progress);
252  40 if (view != null) {
253  40 view.setVisibility(visible ? View.VISIBLE : View.GONE);
254    }
255    }
256   
 
257  57 toggle public void updateProgress(String message) {
258  57 TextView view = (TextView) findViewById(R.id.tab_progress_message);
259  57 if (view != null) {
260  57 view.setText(message);
261    }
262    }
263   
 
264  2310 toggle public DownloadService getDownloadService() {
265    // If service is not available, request it to start and wait for it.
266  2310 for (int i = 0; i < 5; i++) {
267  2310 DownloadService downloadService = DownloadServiceImpl.getInstance();
268  2310 if (downloadService != null) {
269  2310 return downloadService;
270    }
271  0 Log.w(TAG, "DownloadService not running. Attempting to start it.");
272  0 startService(new Intent(this, DownloadServiceImpl.class));
273  0 Util.sleepQuietly(50L);
274    }
275  0 return DownloadServiceImpl.getInstance();
276    }
277   
 
278  48 toggle protected void warnIfNetworkOrStorageUnavailable() {
279  48 if (!Util.isExternalStoragePresent()) {
280  0 Util.toast(this, R.string.select_album_no_sdcard);
281  48 } else if (!Util.isOffline(this) && !Util.isNetworkConnected(this)) {
282  0 Util.toast(this, R.string.select_album_no_network);
283    }
284    }
285   
 
286  99 toggle protected synchronized ImageLoader getImageLoader() {
287  99 if (IMAGE_LOADER == null) {
288  1 IMAGE_LOADER = new ImageLoader(this);
289    }
290  99 return IMAGE_LOADER;
291    }
292   
 
293  0 toggle protected void downloadRecursively(final String id, final boolean save, final boolean append, final boolean autoplay) {
294  0 ModalBackgroundTask<List<MusicDirectory.Entry>> task = new ModalBackgroundTask<List<MusicDirectory.Entry>>(this, false) {
295   
296    private static final int MAX_SONGS = 500;
297   
 
298  0 toggle @Override
299    protected List<MusicDirectory.Entry> doInBackground() throws Throwable {
300  0 MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
301  0 MusicDirectory root = musicService.getMusicDirectory(id, false, SubsonicTabActivity.this, this);
302  0 List<MusicDirectory.Entry> songs = new LinkedList<MusicDirectory.Entry>();
303  0 getSongsRecursively(root, songs);
304  0 return songs;
305    }
306   
 
307  0 toggle private void getSongsRecursively(MusicDirectory parent, List<MusicDirectory.Entry> songs) throws Exception {
308  0 if (songs.size() > MAX_SONGS) {
309  0 return;
310    }
311   
312  0 for (MusicDirectory.Entry song : parent.getChildren(false, true)) {
313  0 if (!song.isVideo()) {
314  0 songs.add(song);
315    }
316    }
317  0 for (MusicDirectory.Entry dir : parent.getChildren(true, false)) {
318  0 MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
319  0 getSongsRecursively(musicService.getMusicDirectory(dir.getId(), false, SubsonicTabActivity.this, this), songs);
320    }
321    }
322   
 
323  0 toggle @Override
324    protected void done(List<MusicDirectory.Entry> songs) {
325  0 DownloadService downloadService = getDownloadService();
326  0 if (!songs.isEmpty() && downloadService != null) {
327  0 if (!append) {
328  0 downloadService.clear();
329    }
330  0 warnIfNetworkOrStorageUnavailable();
331  0 downloadService.download(songs, save, autoplay, false);
332  0 Util.startActivityWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class);
333    }
334    }
335    };
336   
337  0 task.execute();
338    }
339   
 
340  38 toggle private void setUncaughtExceptionHandler() {
341  38 Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler();
342  38 if (!(handler instanceof SubsonicUncaughtExceptionHandler)) {
343  1 Thread.setDefaultUncaughtExceptionHandler(new SubsonicUncaughtExceptionHandler(this));
344    }
345    }
346   
347    /**
348    * Logs the stack trace of uncaught exceptions to a file on the SD card.
349    */
 
350    private static class SubsonicUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
351   
352    private final Thread.UncaughtExceptionHandler defaultHandler;
353    private final Context context;
354   
 
355  1 toggle private SubsonicUncaughtExceptionHandler(Context context) {
356  1 this.context = context;
357  1 defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
358    }
359   
 
360  0 toggle @Override
361    public void uncaughtException(Thread thread, Throwable throwable) {
362  0 File file = null;
363  0 PrintWriter printWriter = null;
364  0 try {
365   
366  0 PackageInfo packageInfo = context.getPackageManager().getPackageInfo("net.sourceforge.subsonic.androidapp", 0);
367  0 file = new File(Environment.getExternalStorageDirectory(), "subsonic-stacktrace.txt");
368  0 printWriter = new PrintWriter(file);
369  0 printWriter.println("Android API level: " + Build.VERSION.SDK);
370  0 printWriter.println("Subsonic version name: " + packageInfo.versionName);
371  0 printWriter.println("Subsonic version code: " + packageInfo.versionCode);
372  0 printWriter.println();
373  0 throwable.printStackTrace(printWriter);
374  0 Log.i(TAG, "Stack trace written to " + file);
375    } catch (Throwable x) {
376  0 Log.e(TAG, "Failed to write stack trace to " + file, x);
377    } finally {
378  0 Util.close(printWriter);
379  0 if (defaultHandler != null) {
380  0 defaultHandler.uncaughtException(thread, throwable);
381    }
382   
383    }
384    }
385    }
386    }
387