Saturday, February 25, 2012

MediaPlayer: Playing Video and Audio files

With every activity, after onPause and onStop, if the activity is not destroyed, it will continue to run in the background, until it is killed so the system can free up the memory it is using. So until the activity is destroyed, the mediaplayer will continue to occupy space in the phones memory.

When done with the MediaPlayer, you should call release(), to free the resources. If not released, too many MediaPlayer instances will result in an exception." 
 Depending on your needs, you can put the mp.stop() in the onPause part, so if the activity goes to the background for whatever reason, it will only pause the playback, and it can continue it in onResume(). Just put mp.play() in onResume().
If you don't release the media player in the onDestroy part, it will continue to be in the memory, after the activity is stopped. The OS will handle this issue for you if it runs out of memory, but it's nicer, if You do it, so the OS will run out of memory later (much later in case of huge files).
private MediaPlayer mp;
 
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mp=new MediaPlayer();
    startAudioPlayer(context,uri);
//you could set up an onCompletionListener, so when the media playback is done, it will release the media player.
mp.setOnCompletionListener(new OnCompletionListener(){
    @Override
    public void onCompletion(MediaPlayer mp) {
        mp.release();
    }
 });

}
 
public void startAudioPlayer(Context context,Uri uri){
    mp= MediaPlayer.create(context, uri);
    mp.start();
}
 
@Override
protected void onPause() {
    super.onPause();
    if(mp.isPlaying()){ //you need to check if it is playing first, or you might get a null pointer exception!
        mp.stop();
    }
}
@Override
 public void onDestroy(){
 super.onDestroy();
    mp.release();
 }
   
Another way to play an audio file.
 
public void audioPlayer(String path, String fileName){

    //set up MediaPlayer    

    MediaPlayer mp = new MediaPlayer();



    try {

        mp.setDataSource(path+"/"+fileName);

    } catch (IllegalArgumentException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();

    } catch (IllegalStateException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();

    } catch (IOException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();

    }


    try {

        mp.prepare();

    } catch (IllegalStateException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();

    } catch (IOException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();

    }

    mp.start();

} 

Incase of Video File, use this method to play the video file

public void videoPlayer(String path, String fileName, boolean autoplay){
//get current window information, 
    //and set format, set it up differently, 
    //if you need some special effects
getWindow().setFormat(PixelFormat.TRANSLUCENT);
//the VideoView will hold the video
VideoView videoHolder = new VideoView(this);
//MediaController is the ui control howering above the video (just like in the default youtube player).
videoHolder.setMediaController(new MediaController(this));
//assing a video file to the video holder
videoHolder.setVideoURI(Uri.parse(path+"/"+fileName));
//get focus, before playing the video.
videoHolder.requestFocus();
if(autoplay){
videoHolder.start();
    }
}

Thursday, February 23, 2012

Infographics on Male Android Users

BlueStacks has released an infographics with some interesting facts on male Android users.
BlueStacks is the development company that created the popular “Android on Windows” app. A couple of days back, it released a new infographics of the average male Android user in 2011 based on the data pulled out from Nielsen as well as poll responses from its 145,000 Facebook fans. This infographics states that 33 percent of Android users never purchased an app for their phone.

Other interesting facts revealed by Mr. Android 2011 infographics


  • 9% of users own a tablet and not a smartphone.
  • 62% use Android for play.
  • 582 MB is the average monthly data usage.
  • 13% has more than 50 apps in their phone.
  • 32% of users are Americans.
  • 62% of users wear jeans, while 71% wear t-shirts.

Tuesday, February 21, 2012

Crash Reporting Feature to any ANDROID application

AIM: To enable crash Reporting feature to android app

Solution: 

A crash reporter is an feature whose function is to report crash data to a third party, usually to the party responsible for the crashed program. Crash reports often include data such as stack traces, type of crash, and version of software. This information helps software developers to diagnose and fix the underlying problem causing the crash.

The Android and iOS operating systems also have built in crash reporting functionality.
There are third party tools that also provide it, like

BugSense :
BugSense is made for mobile developers. Get the context of the errors, track errors in specific app version or filter errors by device. There was Internet connectivity at the time of the crash? BugSense collects all the information the mobile developer needs. 

ACRA (Application Crash Report for Android).

ACRA is a library enabling Android Application to automatically post their crash reports to a GoogleDoc form. It is targetted to android applications developers to help them get data from their applications when they crash or behave erroneously.  

However you can add this feature with the following code block.

---------------------------------------------------------------------------------
/**
 * Crash Error Reporter
 *
 * Captures any Uncaught exception to capture the conditions that caused the event.
 * The event will be written to the Log file and can be retrieved through LogCat.
 * In addition, the report will attempt to send an e-mail to <string name="CrashErrorReport_MailTo">xyz@GMail.com</string>
 * through the default mail application
 *  *
 */


public class CrashErrorReporter implements Thread.UncaughtExceptionHandler {
   
    private static final String LOG_TAG = "CrashErrorReporter";

    private Thread.UncaughtExceptionHandler mDfltExceptionHandler;
    private static CrashErrorReporter S_mInstance;
    private static Context mCurContext;

    // Even though these should be private variables,
    // they are public to avoid creating getters and setters
    String mPkg_VersionName;
    String mPkg_PackageName;
    String mCtx_FilePath;
   
    String mPkg_OSBld_PhoneModel;
    String mPkg_OSBld_AndroidVersion;
    String mPkg_OSBld_Board;
    String mPkg_OSBld_Brand;
    String mPkg_OSBld_Device;
    String mPkg_OSBld_Display;
    String mPkg_OSBld_FingerPrint;
    String mPkg_OSBld_Host;
    String mPkg_OSBld_ID;
    String mPkg_OSBld_Manufacturer;
    String mPkg_OSBld_Model;
    String mPkg_OSBld_Product;
    String mPkg_OSBld_Tags;
    long   mPkg_OSBld_Time;
    String mPkg_OSBld_Type;
    String mPkg_OSBld_User;

    /**
     * Manages the uncaught exception.
     */
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        Log.d(LOG_TAG, "@Override uncaughtException");

        Date CurDate = new Date();

        String Report = "Error Report collected on : " + CurDate.toString() + "\n\n";
        Report += "Environment Details : \n";
        Report += "===================== \n";
        Report += CreateInformationString();
       
        Report += "Stack : \n";
        Report += "======= \n";
        final Writer result = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(result);
        e.printStackTrace(printWriter);
        String stacktrace = result.toString();
        Report += stacktrace  + "\n";

        // If the exception was thrown in a background thread inside
        // AsyncTask, then the actual exception can be found with getCause
        Throwable cause = e.getCause();
        while (cause != null) {
            Report += "Cause : \n";
            Report += "======= \n";
            cause.printStackTrace( printWriter );
            Report += result.toString();
            cause = cause.getCause();
        }
        printWriter.close();
        Report += "**** End of current Report ***";
        SaveAsFile(Report);
       
        // Try and send out the report now before calling the default handler
        CheckCrashErrorAndSendMail(mCurContext);
        mDfltExceptionHandler.uncaughtException(t, e);
    }
   
    /**
     * Capture the newly created instance for singleton class management
     */
    public static CrashErrorReporter getInstance() {
        if ( S_mInstance == null )
            S_mInstance = new CrashErrorReporter();
        return S_mInstance;
    }

    public void Init( Context context ) {
        mDfltExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler( this );
        mCurContext = context;
    }
   
    /**
     * Obtains the available internal memory size
     * @return long  - integer with memory size available
     */
    public long getAvailableInternalMemorySize() {
        File   path = Environment.getDataDirectory();
        StatFs stat = new StatFs(path.getPath());
       
        // place in stack variables for debugging purposes.
        long blockSize       = stat.getBlockSize();
        long availableBlocks = stat.getAvailableBlocks();
       
        return( availableBlocks * blockSize );
    }

    /**
     * Obtains the Total internal memory size
     * @return long - integer with total memory size
     */
    public long getTotalInternalMemorySize() {
        File path = Environment.getDataDirectory();
        StatFs stat = new StatFs(path.getPath());
       
        // place in stack variables for debugging purposes.
        long blockSize = stat.getBlockSize();
        long totalBlocks = stat.getBlockCount();
       
        return( totalBlocks * blockSize );
    }
   
    void CollectPackageInformation( Context context )     {
        Log.d(LOG_TAG, "@CollectPackageInformation");

        try {
            PackageManager pm = context.getPackageManager();
            PackageInfo    pi = pm.getPackageInfo(context.getPackageName(), 0);
           
            mPkg_VersionName        = pi.versionName;
            mPkg_PackageName        = pi.packageName;
            mCtx_FilePath           = context.getFilesDir().getAbsolutePath();
           
            mPkg_OSBld_PhoneModel         = android.os.Build.MODEL;
            mPkg_OSBld_AndroidVersion     = android.os.Build.VERSION.RELEASE;
            mPkg_OSBld_Board              = android.os.Build.BOARD;
            mPkg_OSBld_Brand             = android.os.Build.BRAND;
            mPkg_OSBld_Device             = android.os.Build.DEVICE;
            mPkg_OSBld_Display             = android.os.Build.DISPLAY;
            mPkg_OSBld_FingerPrint         = android.os.Build.FINGERPRINT;
            mPkg_OSBld_Host             = android.os.Build.HOST;
            mPkg_OSBld_ID                 = android.os.Build.ID;
            mPkg_OSBld_Model             = android.os.Build.MODEL;
            mPkg_OSBld_Product             = android.os.Build.PRODUCT;
            mPkg_OSBld_Tags             = android.os.Build.TAGS;
            mPkg_OSBld_Time             = android.os.Build.TIME;
            mPkg_OSBld_Type             = android.os.Build.TYPE;
            mPkg_OSBld_User             = android.os.Build.USER;
        } catch( Exception e ) {
            Log.e(LOG_TAG, "!Error CollectPackageInformation: " + e.getMessage());
            // e.printStackTrace()
        }
    }
   
    /**
     * Assemble the package information in a string format
     * @return String - Package information collected
     */
    private String CreateInformationString() {
        CollectPackageInformation( mCurContext );

        String ReturnVal = "";
        ReturnVal  = "  Version  : " + mPkg_VersionName + "\n";
        ReturnVal += "  Package  : " + mPkg_PackageName + "\n";
        ReturnVal += "  FilePath : " + mCtx_FilePath    + "\n\n";
        ReturnVal += "  Package Data \n";
        ReturnVal += "      Phone Model : " + mPkg_OSBld_PhoneModel     + "\n";
        ReturnVal += "      Android Ver : " + mPkg_OSBld_AndroidVersion + "\n";
        ReturnVal += "      Board       : " + mPkg_OSBld_Board          + "\n";
        ReturnVal += "      Brand       : " + mPkg_OSBld_Brand          + "\n";
        ReturnVal += "      Device      : " + mPkg_OSBld_Device         + "\n";
        ReturnVal += "      Display     : " + mPkg_OSBld_Display        + "\n";
        ReturnVal += "      Finger Print: " + mPkg_OSBld_FingerPrint    + "\n";
        ReturnVal += "      Host        : " + mPkg_OSBld_Host           + "\n";
        ReturnVal += "      ID          : " + mPkg_OSBld_ID             + "\n";
        ReturnVal += "      Model       : " + mPkg_OSBld_Model          + "\n";
        ReturnVal += "      Product     : " + mPkg_OSBld_Product        + "\n";
        ReturnVal += "      Tags        : " + mPkg_OSBld_Tags           + "\n";
        ReturnVal += "      Time        : " + mPkg_OSBld_Time           + "\n";
        ReturnVal += "      Type        : " + mPkg_OSBld_Type           + "\n";
        ReturnVal += "      User        : " + mPkg_OSBld_User           + "\n";
        ReturnVal += "  Internal Memory\n";
        ReturnVal += "      Total    : " + (getTotalInternalMemorySize()     /1024) + "k\n";
        ReturnVal += "      Available: " + (getAvailableInternalMemorySize() /1024) + "k\n\n";

        return ReturnVal;
    }
   
    /**
     *Saves the Crash Report to a File with the name stack-timestamp.stacktrace in SD card
     *
           */
    private void SaveAsFile( String ErrorContent ) {
        try    {
            long timestamp = System.currentTimeMillis();
            String ErrFileName = "stack-" + timestamp + ".stacktrace";
           
            FileOutputStream trace = mCurContext.openFileOutput( ErrFileName, Context.MODE_PRIVATE);
            trace.write(ErrorContent.getBytes());
            trace.flush();
            trace.close();
            Log.e(LOG_TAG, "!Error Report: " + ErrFileName + "\n" + ErrorContent);
        } catch( Exception e ) {
            Log.e(LOG_TAG, "!Error SaveAsFile: " + e.getMessage());
        }
    }

    /**
     * Returns an array containing the names of available crash report files.
     *
     * @return an array containing the names of available crash report files.
     */
    private String[] GetCrashErrorFileList() {
        File dir = mCurContext.getFilesDir();

        Log.d(LOG_TAG, "Looking for error files in " + dir.getAbsolutePath());

        // Filter for "stack trace" files
        FilenameFilter filter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".stacktrace");
            }
        };
        return dir.list(filter);
    }
   
    /**
     * Checks to see if there are any crash reports to send and sends them if they exist
     * Once finished with the report, then the report file is deleted from the system
     *
     * @param _context
     */
    public void CheckCrashErrorAndSendMail(Context _context )
    {
        try {
            if( null == mCtx_FilePath ) {
                mCtx_FilePath = _context.getFilesDir().getAbsolutePath();
            }
            String[] reportFilesList = GetCrashErrorFileList();
            TreeSet<String> sortedFiles = new TreeSet<String>();
            sortedFiles.addAll(Arrays.asList(reportFilesList));
            if((null != reportFilesList) && (0 < reportFilesList.length)) {
               
                String line;
                String WholeErrorText = "";
                int curIndex = 0;
                final int MaxSendMail = 5;
               
                for ( String curString : sortedFiles )
                {
                    if ( curIndex++ <= MaxSendMail )
                    {
                        WholeErrorText+="New Trace collected :\n";
                        WholeErrorText+="=====================\n ";
                        String filePath = mCtx_FilePath + "/" + curString;
                        BufferedReader input = new BufferedReader(new FileReader(filePath));
                        while (( line = input.readLine()) != null) {
                            WholeErrorText += line + "\n";
                        }
                        input.close();
                    }

                    // DELETE FILES !!!!
                    File curFile = new File( mCtx_FilePath + "/" + curString );
                    curFile.delete();
                }
                SendCrashErrorMail( _context , WholeErrorText,_context.getString(R.string.CrashErrorReport_MailTo) );
            }
        } catch( Exception e ) {
            Log.e(LOG_TAG, "!Error CheckCrashErrorAndSendMail: " + e.getMessage());
            // e.printStackTrace();
        }
    }
   
    /**
     * Send out the crash error report via e-mail
     *
     * @param _context
     * @param ErrorContent
     */
    private void SendCrashErrorMail( Context _context, String ErrorContent,String mailTo)    {
        Log.d(LOG_TAG, "SendCrashErrorMail: " + _context.getString(R.string.CrashErrorReport_MailTo));
       
        //Toast.makeText(_context, _context.getString(R.string.CrashErrorReport_ToastText), Toast.LENGTH_LONG).show();

        Intent sendIntent = new Intent(Intent.ACTION_SEND);
        sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        sendIntent.putExtra(Intent.EXTRA_EMAIL,    new String[]{_context.getString(R.string.CrashErrorReport_MailTo)});
        sendIntent.putExtra(Intent.EXTRA_SUBJECT, _context.getString(R.string.CrashErrorReport_MailSubject));
        sendIntent.putExtra(Intent.EXTRA_TEXT, ErrorContent + "\n");
        sendIntent.setType("message/rfc822");
        _context.startActivity( sendIntent );
    }
   
    /**
     * Send out the crash report via HTTP connection
     * NOTE: This is currently not used, but here for future implementation
     * @param _context
     * @param ErrorContent
     *
     * The below code would need to be placed on an server to receive HTTP transmissions.
     * upload_server.php
     * <?php       
     *   if ( $_POST['stacktrace'] == "" || $_POST['package_version'] == "" || $_POST['package_name'] == "" ) {       
     *           die("This script is used to collect field test crash stacktraces. No personal information is transmitted, collected or stored.<br/>For more information, please contact <a href='mailto:support@nullwire.com'>email@domain.com</a>");       
     *  }       
     *   $random = rand(1000,9999);       
     *   $version = $_POST['package_version'];       
     *   $package = $_POST['package_name'];       
     *   $handle = fopen($package."-trace-".$version."-".time()."-".$random, "w+");       
     *   fwrite($handle, $_POST['stacktrace']);       
     *   fclose($handle);       
      *  
     *    ?>
     *
     */
    @SuppressWarnings("unused")
    private void SendCrashErrorHTTP( Context _context, String ErrorContent ) {
        Log.d(LOG_TAG, "SendCrashErrorHTTP: " + _context.getString(R.string.CrashErrorReport_URL));
        Toast.makeText(_context, _context.getString(R.string.CrashErrorReport_ToastText), Toast.LENGTH_LONG).show();

        String sError = null;
        // Transmit stack trace with POST request
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(_context.getString(R.string.CrashErrorReport_URL));
        List <NameValuePair> nvps = new ArrayList <NameValuePair>(); 
        nvps.add(new BasicNameValuePair("package_name", mPkg_PackageName));
        nvps.add(new BasicNameValuePair("package_version", mPkg_VersionName));
        nvps.add(new BasicNameValuePair("phone_model", mPkg_OSBld_PhoneModel));
        nvps.add(new BasicNameValuePair("android_version", mPkg_OSBld_AndroidVersion));
        nvps.add(new BasicNameValuePair("stacktrace", ErrorContent));
       
        try {
             httpPost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
             // We don't care about the response, so we just hope it went well and on with it
            httpClient.execute(httpPost);
        } catch (UnsupportedEncodingException e) {
            sError = e.getMessage();
        } catch (ClientProtocolException e) {
            sError = e.getMessage();
        } catch (IOException e) {
            sError = e.getMessage();
        } finally {
            sError = "Unknown Error condition";
        }
        if( null != sError ) {
            Log.e(LOG_TAG, "!Error SendCrashErrorHTTP: " + sError);
        }
    }
   
// End Class   
}

------------------------------------------------------

You can add this feature by intiating this code in any activity like Loading,SplashScreen.

// Register the Crash Reporting feature
------------------------------------------
        // Initialize ErrorReporter with all required data
        CrashErrorReporter mCrashErrorReporter = CrashErrorReporter.getInstance();
       
       // Activate the ErrorReporter
        mCrashErrorReporter.Init(getApplicationContext());
        mCrashErrorReporter.CheckCrashErrorAndSendMail(getApplicationContext());

-------------------------------------------------

This just works amazing...

Let me know if any problems you have.

Wednesday, February 15, 2012

Possible ways to Generate Revenue from iOS,Android Mobile Applications

Every developer wants to make money. When comparing between web apps and mobile, web apps today use 3 tactics to monetize: online ads, transactions within the website, and subscriptions. These same monetization strategies are available to mobile apps. Below are some in each area will appeal to different verticals and company sizes, and each will call for different expertise and tools.

Idea #1: Ads
Best for: Consumer apps with large audiences (ex. Pandora); highly targeted apps


Some developers will be able to monetize with ads, but unless your app is a big consumer mobile app with a large audience or a highly targeted app within a vertical, it’s not your best bet. Size and targeting will matter here: if you have the sheer number of eyeballs, then you won’t need targeted ads. One way to compensate for size is by offering a targeted audience to your advertisers.
Idea #2: In-app transactions
Best for: Mobile commerce apps; gaming apps; lead gen apps; publishers with a large number of apps in their portfolio

using in-app purchases, iOS, Android developers are starting to scratch the surface of in-app transactions. Off the top of our heads, developers could cross sell to another portfolio app, up-sell to a pro version of the app, or generate online or offline leads. (In-app transactions encapsulate more than just in-app purchases. Consider lead generation; the transmission of information is a very powerful, and monetize-able, transaction.) 

Idea #3: Subscription models
Best for: Content (e.g. magazine, newspaper) apps; professional & consumer services apps (e.g.  “Business Model Canvas iPad App”, Life 360); telecom apps (e.g. Skype,textplus)


Good examples currently come from telecom apps, but expect the subscription trend to pick up. Subscription models help developers increase the life value of their customers. The key success factors here will be lowering customer acquisition costs and reducing churn over time. And don’t forget strategy—monthly trials or free offers will be valuable approaches.
 Tried any of these ways. please share with your opinions and experiences.

Android Developers Blog

Ram's shared items