Crash Reporting with ACRA

 Using crash reporting tools is a great way to unearth the hidden bugs that are causing crashes. This tutorial will demonstrate an easy to use crash reporting tool ACRA (Application Crash Reports for Android) to send crash logs when crash occurs.

At first step we shall include the dependency of ACRA in our build.gradle file. The version 4.9.2 was the latest at the time of writing this tutorial.

compile 'ch.acra:acra:4.9.2'

At next step we have to create our Application class integrate ACRA there.

@ReportsCrashes(
        formUri = "",
        mailTo = "yourmail@yourdomain.com",
        customReportContent = {
                ReportField.APP_VERSION_CODE,
                ReportField.APP_VERSION_NAME,
                ReportField.ANDROID_VERSION,
                ReportField.PHONE_MODEL,
                ReportField.BRAND,
                ReportField.CUSTOM_DATA,
                ReportField.INITIAL_CONFIGURATION,
                ReportField.CRASH_CONFIGURATION,
                ReportField.USER_CRASH_DATE,
                ReportField.STACK_TRACE,
                ReportField.LOGCAT},
        resToastText = R.string.crash_toast_text,
        mode = ReportingInteractionMode.TOAST)
public class MyApplication extends Application {
 
    @Override
    public void onCreate() {
        super.onCreate();
        ACRA.init(this);
    }
}

The code is very much self explanatory, we need to set the email address to whom crash report will be send, set some content and select how will the app interact with the user when it is crashed.

We have to set the MyApplication as the application class and add the following internet, read logs and read phone state permission. The AndroidManifest.xml file will look like the following.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.acrademo">
 
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_LOGS" />
 
    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
 
</manifest>

Finally in our MainActivity, we shall add a button and add code that will force the app crash when button is clicked to test our app.

public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
 
    public void onCrash(View view){
        throw new RuntimeException("App Crashed");
    }
}

Playing audio stream using ExoPlayer 2

 Exoplayer is an Android application level media player developed by google for playing audio, video both locally and over the internet. Unlike the MediaPlayer API it is highly customizable. Minimum supported version for Exoplayer is Android 4.1 (API level 16). In this we are going to see a simple example of playing an audio stream URL using ‘Exoplayer 2’.

At first step we need to add the library in dependency section of the the build.gradle file by adding the following line

dependencies {
...
compile 'com.google.android.exoplayer:exoplayer:r2.4.2'
}

In this tutorial we are going to use a SimpleExoPlayer instance that requires three objects RendersFactory, TracSelector and LoadControl. Let’s create the objects one by one with appropriate parameters.

RendersFactory interface is used to build Renderer instances for use by a SimpleExoPlayer. Renderers are used to render individual components of the media. Let’s implement the RendersFactory by using the DefaultRendersFactory like below

renderersFactory = new DefaultRenderersFactory(getApplicationContext());

TrackSelector is used to select tracks provided by the MediaSource to be consumed by each of the available Renderers. We shall have look at how to build MediaSource object later on. Let’s create the TrackSelector by adding the following lines

bandwidthMeter = new DefaultBandwidthMeter(); //Provides estimates of the currently available bandwidth.
trackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
trackSelector = new DefaultTrackSelector(trackSelectionFactory);

LoadControl is used to control when the MediaSource buffers more media, and how much media is buffered. In this example, we are going to use the default buffer settings.

loadControl = new DefaultLoadControl();

At this point we are ready to create the SimpleExoPlayer instance. We could also implement the ExoPlayer.EventListener in our Activity class and add this listener to our SimpleExoPlayer instance.

player = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector, loadControl);
player.addListener(this);

Now its time to create MediaSource. MediaSource defines the media to be played, loads the media, and from which the loaded media can be read. Let’s create the MediaSource in the following way

dataSourceFactory = new DefaultDataSourceFactory(getApplicationContext(), "ExoplayerDemo");
extractorsFactory = new DefaultExtractorsFactory();
mainHandler = new Handler();
mediaSource = new ExtractorMediaSource(Uri.parse(streamUrl),
                dataSourceFactory,
                extractorsFactory,
                mainHandler,
                null);

In the above we used DefaultDataSource instance that delegates to DefaultHttpDataSources for non-file/asset/content URIs and DefaultExtractorsFactory that provides an array of extractors for the formats MP4, fMP4, Matroska and WebM, Ogg Vorbis/FLAC, MP3, AAC, MPEG TS, MPEG PS, FLV, WAV, AC3, FLAC.
We have defined our streamUrl at the top like the following

private final String streamUrl = "http://bbcwssc.ic.llnwd.net/stream/bbcwssc_mp1_ws-einws"; //bbc world service url

Finally we need to prepare the player with the MediaSource in the following way.

player.prepare(mediaSource);

To keep the example simple no user interface was created to play or pause the media stream. We are going to play the stream when the activity resumes by including the following line inside the Activity lifecycle method onResume()

player.setPlayWhenReady(true);

and going to pause the stream when the Activity is on pause state by adding the following line inside Activity life cycle method onPause()

player.setPlayWhenReady(true);

Our MainActivity class now looks like the following.

public class MainActivity extends AppCompatActivity implements ExoPlayer.EventListener {
 
 
    private Handler mainHandler;
    private RenderersFactory renderersFactory;
    private BandwidthMeter bandwidthMeter;
    private LoadControl loadControl;
    private DataSource.Factory dataSourceFactory;
    private ExtractorsFactory extractorsFactory;
    private MediaSource mediaSource;
    private TrackSelection.Factory trackSelectionFactory;
    private SimpleExoPlayer player;
    private final String streamUrl = "http://bbcwssc.ic.llnwd.net/stream/bbcwssc_mp1_ws-einws"; //bbc world service url
    private TrackSelector trackSelector;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        renderersFactory = new DefaultRenderersFactory(getApplicationContext());
        bandwidthMeter = new DefaultBandwidthMeter();
        trackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
        trackSelector = new DefaultTrackSelector(trackSelectionFactory);
        loadControl = new DefaultLoadControl();
 
        player = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector, loadControl);
        player.addListener(this);
 
        dataSourceFactory = new DefaultDataSourceFactory(getApplicationContext(), "ExoplayerDemo");
        extractorsFactory = new DefaultExtractorsFactory();
        mainHandler = new Handler();
        mediaSource = new ExtractorMediaSource(Uri.parse(streamUrl),
                dataSourceFactory,
                extractorsFactory,
                mainHandler,
                null);
 
        player.prepare(mediaSource);
 
    }
 
    @Override
    protected void onResume() {
        super.onResume();
        player.setPlayWhenReady(true);
        Toast.makeText(MainActivity.this, "Exoplayer is playing.", Toast.LENGTH_SHORT).show();
    }
 
    @Override
    protected void onPause() {
        super.onPause();
        player.setPlayWhenReady(false);
        Toast.makeText(MainActivity.this, "Exoplayer is on pause.", Toast.LENGTH_SHORT).show();
    }
 
    @Override
    public void onTimelineChanged(Timeline timeline, Object manifest) {
 
    }
 
    @Override
    public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
 
    }
 
    @Override
    public void onLoadingChanged(boolean isLoading) {
 
    }
 
    @Override
    public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
 
    }
 
    @Override
    public void onPlayerError(ExoPlaybackException error) {
 
    }
 
    @Override
    public void onPositionDiscontinuity() {
 
    }
 
    @Override
    public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
 
    }
}

How to extract filename from Uri?

Now, we can extract filename with and without extension :) You will convert your bitmap to uri and get the real path of your file. Now w...