Samsung Mobile SDK Tutorial 7

Samsung Mobile SDK TutorialWelcome to part 7 of my Samsung Mobile SDK Tutorial. In this part of the tutorial I’ll cover how to create toolbars for use with any Android app. I’ll then cover additional functionality that the Samsung S Pen provides as well as covering how to create settings windows, import images from the image gallery and more.

All of the code follows the video below. I recently announced the winners of my Samsung Galaxy Note 3 and Galaxy Gear Smart Watch contest. Congratulations to the winners and thank you Samsung for allowing me to have such a great contest!

If you like videos like this it helps to tell Google+ with a click here

Code From the Video

activity_background.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".PenSample1_5_Background" >

    <LinearLayout
        android:id="@+id/tool_menu"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <ImageView
            android:id="@+id/penBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="1dip"
            android:layout_weight="1"
            android:background="@drawable/selector_tool_bg"
            android:src="@drawable/selector_pen" />
        
        <ImageView
            android:id="@+id/eraserBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="1dip"
            android:layout_weight="1"
            android:background="@drawable/selector_tool_bg"
            android:src="@drawable/selector_eraser" />
        <ImageView
            android:id="@+id/undoBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/selector_tool_bg"
            android:src="@drawable/selector_undo"
            android:layout_weight="1"
            android:layout_margin="1dip" />
        <ImageView
            android:id="@+id/redoBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/selector_tool_bg"
            android:src="@drawable/selector_redo"
            android:layout_weight="1"
            android:layout_margin="1dip" />
        <ImageView
            android:id="@+id/bgImgBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/selector_tool_bg"
            android:src="@drawable/selector_image"
            android:layout_weight="1"
            android:layout_margin="1dip" />
    </LinearLayout>

    <FrameLayout
        android:id="@+id/spenViewContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <RelativeLayout
            android:id="@+id/spenViewLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </RelativeLayout>
    </FrameLayout>
</LinearLayout>

selector_tool_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<selector android:id="@+id/myselector" xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/tool_ic_area_center_02"/>
<item android:state_selected="false" android:state_pressed="true"  android:drawable="@drawable/tool_ic_area_bg_press"/>
<item android:state_selected="true"  android:state_pressed="false" android:drawable="@drawable/tool_ic_area_select_02"/>
<item android:state_selected="true"  android:state_pressed="true"  android:drawable="@drawable/tool_ic_area_bg_press"/>
</selector>

selector_pen.xml

<?xml version="1.0" encoding="utf-8"?>
<selector android:id="@+id/myselector" xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_enabled="true" android:state_pressed="false" android:drawable="@drawable/tool_ic_pen"/>
<item android:state_enabled="true" android:state_pressed="true" android:drawable="@drawable/tool_ic_pen_press"/>
<item android:state_enabled="true" android:state_selected="true" android:drawable="@drawable/tool_ic_pen_press"/>
<item android:state_enabled="false" android:drawable="@drawable/tool_ic_pen_dim"/>
</selector>

PenSample1_5_Background.java

package com.samsung.android.sdk.pen.pg.example1_5;

import java.io.IOException;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.Display;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

//Used to make sure the device supports the Samsung Mobile SDK
import com.samsung.android.sdk.SsdkUnsupportedException;

//Initializes and verifies that the S Pen is available
import com.samsung.android.sdk.pen.Spen;

// Allows you to manage SPD (S Pen Data Files)
// Loads and saves SPD files
// Adds and removes PageDocs from NoteDocs and attaches external files
import com.samsung.android.sdk.pen.document.SpenNoteDoc;

// Contains all the data and objects in a page
// Adds, deletes, retrieves and changes layers, objects and general
// settings for the page document.
import com.samsung.android.sdk.pen.document.SpenPageDoc;

// Receives history events like undo and redo
import com.samsung.android.sdk.pen.document.SpenPageDoc.HistoryListener;

// Forwards history information in regards to undo and redo
import com.samsung.android.sdk.pen.document.SpenPageDoc.HistoryUpdateInfo;

// Handles changes to the color for the S Pen stroke
import com.samsung.android.sdk.pen.engine.SpenColorPickerListener;

// Allows for editing of the drawing surface with both a finger or the SPen
import com.samsung.android.sdk.pen.engine.SpenSurfaceView;

// Stores Eraser settings stroke, Thickness, Eraser type
import com.samsung.android.sdk.pen.SpenSettingEraserInfo;

// Stores Pen settings like color, Pen class name, thickness
import com.samsung.android.sdk.pen.SpenSettingPenInfo;

// Reference to the class that handles all alert dialogs associated
// with making sure the user has the right device and the S Pen
import com.samsung.android.sdk.pen.pg.tool.SDKUtils;

// Provides methods for working with the Eraser pop up dialog
import com.samsung.android.sdk.pen.settingui.SpenSettingEraserLayout;

// Handles Eraser events
import com.samsung.android.sdk.pen.settingui.SpenSettingEraserLayout.EventListener;

//Provides methods for working with the Pen pop up dialog
import com.samsung.android.sdk.pen.settingui.SpenSettingPenLayout;
import com.samsung.spensdk3.example.R;

public class PenSample1_5_Background extends Activity {

	// startActivityForResult will be used to call an intent
	// by passing this code when the activity finishes this
	// code is returned to onActivityResult (Used for Tracking)
    private final int REQUEST_CODE_SELECT_IMAGE_BACKGROUND = 100;

    // A Context provides access to application resources
    private Context mContext;
    
    private SpenNoteDoc mSpenNoteDoc;
    
    private SpenPageDoc mSpenPageDoc;
    
    private SpenSurfaceView mSpenSurfaceView;
    
    private SpenSettingPenLayout mPenSettingView;
    
    private SpenSettingEraserLayout mEraserSettingView;

    // Initializes all the images used on buttons in the tool bar
    private ImageView mPenBtn;
    private ImageView mEraserBtn;
    private ImageView mUndoBtn;
    private ImageView mRedoBtn;
    private ImageView mBgImgBtn;

    // Stores the tool type used being the S Pen
    private int mToolType = SpenSurfaceView.TOOL_SPEN;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_background);
        mContext = this;

        // Sets the S Pen usage as false by default
        boolean isSpenFeatureEnabled = false;
        
        // Create an S Pen object
        Spen spenPackage = new Spen();
        
        // Try to initialize the Spen and if it doesn't exist
        // trigger an exception that is handled below
        try {
            spenPackage.initialize(this);
            isSpenFeatureEnabled = spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
        } 
        
        // Have SDKUtils create the right alert dialogs for this exception
        catch (SsdkUnsupportedException e) {
            if( SDKUtils.processUnsupportedException(this, e) == true) {
                return;
            }
        } 
        
        // Generate a Toast to warn the user of an error
        catch (Exception e1) {
            Toast.makeText(mContext, "Cannot initialize Spen.",
                Toast.LENGTH_SHORT).show();
            e1.printStackTrace();
            
            // Drop the Activity from memory
            finish();
        }

        // The FrameLayout will hold the Relative Layout that will be drawn on
        FrameLayout spenViewContainer =
            (FrameLayout) findViewById(R.id.spenViewContainer);
        RelativeLayout spenViewLayout =
            (RelativeLayout) findViewById(R.id.spenViewLayout);

        // To create the SpenSettingPenLayout that will allow
        // us to work with the Pen settings layout, pass it the
        // Context, an image file path if any and the RelativeLayout
        mPenSettingView =
            new SpenSettingPenLayout(mContext, new String(),
                spenViewLayout);
        
        // Notify the user of an error and kill the app
        if (mPenSettingView == null) {
            Toast.makeText(mContext, "Cannot create new PenSettingView.",
                Toast.LENGTH_SHORT).show();
            finish();
        }
        
        // Set up the settings window for the Eraser tool
        mEraserSettingView =
            new SpenSettingEraserLayout(mContext, new String(),
                spenViewLayout);
        if (mEraserSettingView == null) {
            Toast.makeText(mContext, "Cannot create new EraserSettingView.",
                Toast.LENGTH_SHORT).show();
            finish();
        }
        
        // Add the settings windows for the Pen and Eraser
        spenViewContainer.addView(mPenSettingView);
        spenViewContainer.addView(mEraserSettingView);

        // Create the drawing surface on the device or trigger an error
        mSpenSurfaceView = new SpenSurfaceView(mContext);
        if (mSpenSurfaceView == null) {
            Toast.makeText(mContext, "Cannot create new SpenSurfaceView.",
                Toast.LENGTH_SHORT).show();
            finish();
        }
        
        // Add the drawing surface to Relative Layout
        spenViewLayout.addView(mSpenSurfaceView);
        
        // Sets the canvas view
        mPenSettingView.setCanvasView(mSpenSurfaceView);
        mEraserSettingView.setCanvasView(mSpenSurfaceView);

        // Display provides information on the display
        Display display = getWindowManager().getDefaultDisplay();
        
        // Holds 4 integer coordinates for a rectangle being the display
        Rect rect = new Rect();
        
        // Get the size of the display as a Rect in pixels
        display.getRectSize(rect);
        
        // Create a SpenNoteDoc by passing the Context and the 
    	// width and height or handle errors
        try {
            mSpenNoteDoc =
                new SpenNoteDoc(mContext, rect.width(), rect.height());
        } catch (IOException e) {
            Toast.makeText(mContext, "Cannot create new NoteDoc",
                Toast.LENGTH_SHORT).show();
            e.printStackTrace();
            finish();
        } catch (Exception e) {
            e.printStackTrace();
            finish();
        }
        
        // Adds a page to the document
        mSpenPageDoc = mSpenNoteDoc.appendPage();
        
        // Changes the background color
        mSpenPageDoc.setBackgroundColor(0xFFD6E6F5);
        
        // Clear undo / redo history
        mSpenPageDoc.clearHistory();
        
        // Put the Spen document in the current view
        // and pass true to update the screen
        mSpenSurfaceView.setPageDoc(mSpenPageDoc, true);

        // Call to method below which sets default settings for 
        // the Pen and Eraser
        initSettingInfo();
        
     	// Set the method that will handle color changes
        mSpenSurfaceView.setColorPickerListener(mColorPickerListener);
        
        // Set the method that will handle history changes (Undo / Redo)
        mSpenPageDoc.setHistoryListener(mHistoryListener);
        
        // Set the method that will handle Eraser setting changes
        mEraserSettingView.setEraserListener(mEraserListener);

        // initialize all the icon images and add listeners for them
        mPenBtn = (ImageView) findViewById(R.id.penBtn);
        mPenBtn.setOnClickListener(mPenBtnClickListener);

        mEraserBtn = (ImageView) findViewById(R.id.eraserBtn);
        mEraserBtn.setOnClickListener(mEraserBtnClickListener);

        mUndoBtn = (ImageView) findViewById(R.id.undoBtn);
        mUndoBtn.setOnClickListener(undoNredoBtnClickListener);
        mUndoBtn.setEnabled(mSpenPageDoc.isUndoable());

        mRedoBtn = (ImageView) findViewById(R.id.redoBtn);
        mRedoBtn.setOnClickListener(undoNredoBtnClickListener);
        mRedoBtn.setEnabled(mSpenPageDoc.isRedoable());

        mBgImgBtn = (ImageView) findViewById(R.id.bgImgBtn);
        mBgImgBtn.setOnClickListener(mBgImgBtnClickListener);

        // Set the Pen button in the tool bar to be set by default
        selectButton(mPenBtn);

        // Check if the Spen is available or not
        if(isSpenFeatureEnabled == false) {
        	
        	// Set the tool type to the finger if not
            mToolType = SpenSurfaceView.TOOL_FINGER;
            mSpenSurfaceView.setToolTypeAction(mToolType,
                SpenSurfaceView.ACTION_STROKE);
            Toast.makeText(mContext,
                "Device does not support Spen. \n You can draw stroke by finger",
                Toast.LENGTH_SHORT).show();
        }
    }

    // Sets the default settings for the Pen and Eraser
    private void initSettingInfo() {
        
        SpenSettingPenInfo penInfo = new SpenSettingPenInfo();
        penInfo.color = Color.BLUE;
        penInfo.size = 10;
        mSpenSurfaceView.setPenSettingInfo(penInfo);
        mPenSettingView.setInfo(penInfo);

        
        SpenSettingEraserInfo eraserInfo = new SpenSettingEraserInfo();
        eraserInfo.size = 30;
        mSpenSurfaceView.setEraserSettingInfo(eraserInfo);
        mEraserSettingView.setInfo(eraserInfo);
    }

    // Handle what happens if the Pen icon is clicked on in the tool bar
    private final OnClickListener mPenBtnClickListener =
        new OnClickListener() {
            @Override
            public void onClick(View v) {
                
            	// Check if the current tool is the stroke or pen tool
                if (mSpenSurfaceView.getToolTypeAction(mToolType) ==
                        SpenSurfaceView.ACTION_STROKE) {
                    
                	// Check if the Pen settings window is open
                	// if it is close it and if not open it
                    if (mPenSettingView.isShown()) {
                        mPenSettingView.setVisibility(View.GONE);
                    
                    } else {
                        mPenSettingView
                            .setViewMode(SpenSettingPenLayout.VIEW_MODE_EXTENSION);
                        mPenSettingView.setVisibility(View.VISIBLE);
                    }
                
                } else {
                	
                	// If the Pen tool wasn't in use when the Pen icon
                	// was clicked change to the Pen tool rather then
                	// opening the Pen settings window
                    selectButton(mPenBtn);
                    mSpenSurfaceView.setToolTypeAction(mToolType,
                        SpenSurfaceView.ACTION_STROKE);
                }
            }
        };

    // Handle what happens if the Eraser icon is clicked on in the tool bar
    private final OnClickListener mEraserBtnClickListener =
        new OnClickListener() {
            @Override
            public void onClick(View v) {
                
            	// Check if the current tool is the Eraser tool
            	// and do the same as we did with Pen
                if (mSpenSurfaceView.getToolTypeAction(mToolType) ==
                        SpenSurfaceView.ACTION_ERASER) {
                    
                    if (mEraserSettingView.isShown()) {
                        mEraserSettingView.setVisibility(View.GONE);
                    
                    } else {
                        mEraserSettingView
                            .setViewMode(SpenSettingEraserLayout.VIEW_MODE_NORMAL);
                        mEraserSettingView.setVisibility(View.VISIBLE);
                    }
               
                } else {
                    selectButton(mEraserBtn);
                    mSpenSurfaceView.setToolTypeAction(mToolType,
                        SpenSurfaceView.ACTION_ERASER);
                }
            }
        };

    // If the background image button is clicked
    private final OnClickListener mBgImgBtnClickListener =
        new OnClickListener() {
            @Override
            public void onClick(View v) {
            	
            	// Method below that closes the Pen and Eraser 
            	// setting views
                closeSettingView();

                // Call a method below that opens up the picture gallery
                callGalleryForInputImage(REQUEST_CODE_SELECT_IMAGE_BACKGROUND);
            }
        };

    // If the Undo / Redo button is clicked
    private final OnClickListener undoNredoBtnClickListener =
        new OnClickListener() {
            @Override
            public void onClick(View v) {
            	
            	// Check if the SpenPageDoc is valid
                if (mSpenPageDoc == null) {
                    return;
                }
                
                // undo button click
                if (v.equals(mUndoBtn)) {
                	
                	// Check if it is possible to Undo
                    if (mSpenPageDoc.isUndoable()) {
                    	
                    	// Return the previous state history for the page
                        HistoryUpdateInfo[] userData = mSpenPageDoc.undo();
                        
                        // Update the undo state in the stack
                        mSpenSurfaceView.updateUndo(userData);
                    }
                // redo button click
                } else if (v.equals(mRedoBtn)) {
                	
                	// Check if it is possible to Redo
                    if (mSpenPageDoc.isRedoable()) {
                    	
                    	// Return the previous state history for the page
                        HistoryUpdateInfo[] userData = mSpenPageDoc.redo();
                        
                     // Update the redo state in the stack
                        mSpenSurfaceView.updateRedo(userData);
                    }
                }
            }
        };

    // Called if the color or other settings for Pen have changed
    private SpenColorPickerListener mColorPickerListener =
        new SpenColorPickerListener() {
            @Override
            public void onChanged(int color, int x, int y) {
                
            	// Get the settings changes set in the settings View
            	// and save them to the Pen object
                if (mPenSettingView != null) {
                    SpenSettingPenInfo penInfo = mPenSettingView.getInfo();
                    penInfo.color = color;
                    mPenSettingView.setInfo(penInfo);
                }
            }
        };

    // Catch when the eraser icon is clicked on
    private EventListener mEraserListener = new EventListener() {
        @Override
        public void onClearAll() {
            // Remove all objects from the current layer
            mSpenPageDoc.removeAllObject();
            mSpenSurfaceView.update();
        }
    };

    // Handle changing the state of Undo / Redo buttons based on
    // if there is an option to do so in the history stack
    private HistoryListener mHistoryListener = new HistoryListener() {
        @Override
        public void onCommit(SpenPageDoc page) {
        }

        // If there is nothing left to Undo in the history then 
        // disable the Undo button
        @Override
        public void onUndoable(SpenPageDoc page, boolean undoable) {
            // undo
            mUndoBtn.setEnabled(undoable);
        }

        // If there is nothing left to Redo in the history then 
        // disable the Undo button
        @Override
        public void onRedoable(SpenPageDoc page, boolean redoable) {
            // redo 
            mRedoBtn.setEnabled(redoable);
        }
    };

    // Called to set the button sent as active on the tool bar
    // while making the others inactive
    private void selectButton(View v) {
        
        mPenBtn.setSelected(false);
        mEraserBtn.setSelected(false);
        v.setSelected(true);

        // Close the Eraser and Pen settings Views
        closeSettingView();
    }

    // Close the Eraser and Pen settings Views
    private void closeSettingView() {
        
        mEraserSettingView.setVisibility(SpenSurfaceView.GONE);
        mPenSettingView.setVisibility(SpenSurfaceView.GONE);
    }

    private void callGalleryForInputImage(int nRequestCode) {
        
        try {
        	
        	// Create an Intent that will display the gallery, 
        	// allow the user to pick a picture and then return
        	// it to this app
            Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
            
            // Set the data type returned
            galleryIntent.setType("image/*");
            
            // Trigger the activity and then return the item selected
            // to onActivityResult (RequestCode signifies the intent
            // that triggered this action)
            startActivityForResult(galleryIntent, nRequestCode);
        } 
        
        // If gallery wasn't found
        catch (ActivityNotFoundException e) {
            Toast.makeText(mContext, "Cannot find gallery.",
                Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }

    // After the Intent triggered by startActivityForResult is finished
    // this method is sent data to process
    @Override
    protected void onActivityResult(int requestCode, int resultCode,
        Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // Check if everything went all right when the Intent was called
        if (resultCode == RESULT_OK) {
        	
        	// Check if the image is available
            if (data == null) {
                Toast.makeText(mContext, "Cannot find the image",
                    Toast.LENGTH_SHORT).show();
                return;
            }

            // Check that the Intent that was meant to return an
            // image from the gallery called onActivityResult
            if (requestCode == REQUEST_CODE_SELECT_IMAGE_BACKGROUND) {
                
            	// Get the path to the image
                Uri imageFileUri = data.getData();
                
                // A ContentResolver is returned by getContentResolver
                // A ContentResolver is used to access data in this case
                // the image
                // query returns a Cursor given the URI for the data
                // The Cursor allows you to read the image data
                Cursor cursor =
                    getContentResolver().query(
                        Uri.parse(imageFileUri.toString()), null, null,
                        null, null);
                
                // Cursor moves through the results
                cursor.moveToNext();
                
                // MediaStore has an index of all files in storage
                // DATA is the actual data stream for the file
                String imagePath =
                    cursor.getString(cursor
                        .getColumnIndex(MediaStore.MediaColumns.DATA));

                // Sets the background for the Doc to the image
                mSpenPageDoc.setBackgroundImage(imagePath);
                mSpenSurfaceView.update();
            }
        }
    }

    // The app is being shutdown so free memory
    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (mPenSettingView != null) {
            mPenSettingView.close();
        }
        if (mEraserSettingView != null) {
            mEraserSettingView.close();
        }
        if(mSpenSurfaceView != null) {
            mSpenSurfaceView.close();
            mSpenSurfaceView = null;
        }

        if(mSpenNoteDoc != null) {
            try {
                mSpenNoteDoc.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            mSpenNoteDoc = null;
        }
    };
}

2 Responses to “Samsung Mobile SDK Tutorial 7”

  1. Pradeep says:

    hello Derek,

    I really have to salute your magnanimous effort. Your tutotials are very understandable, thank you so much. I am working on c++ code to rewrite it in java for android applications, can you please check it once and make rough suggestions, like how it should look like and easy to understand.

    here is the code:
    https://www.dropbox.com/s/kehxdiibupjyob0/P2P%20cpp.docx

  2. nishant says:

    Hello admin,how does it works?i.e there are sites which have registratn form but some time they also give you option to login using facebook or any google accnt so do this sites have club or any link with fb or google acnt? whats the code that runs behind it?

Leave a Reply

Your email address will not be published.

Google+